Tree cutter fixes and compat improvements (issue #54, issue #59). Experimental Fluid Collection Funnel implementation.
|
@ -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.15-b2
|
||||
version_engineersdecor=1.0.15
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"homepage": "https://www.curseforge.com/minecraft/mc-mods/engineers-decor/",
|
||||
"1.12.2": {
|
||||
"1.0.15": "[R] Release based on v1.0.15-b2. Release-to-release changes: * Added Small Block Breaker * Small Tree Cutter fixes and compatability improved. * Crafting table compat fixes.\n[M] Small Tree Cutter log detection bug fixed (issue #59).\n[M] Small Tree Cutter supports Menril chopping (issue #54).",
|
||||
"1.0.15-b2": "[A] Added Small Block Breaker\n[M] Crafting Table: Allowing NBT \"Damage\" mismatch only items that are declared damagable (issue #56).\n[M] Tree Cutter: Loosened the strict mod namespace requirement for Dynamic Trees log detection (issue #52) to enable checking DT compat mod log blocks.",
|
||||
"1.0.15-b1": "[A] Added Floor Edge Light.\n[A] Added Factory Block Placer and Planter.",
|
||||
"1.0.14": "[R] Release based on v1.0.14-b1. Release-to-release changes: * Factory Hopper added. * Small Waste Incinerator improved. * Lang updates. * Recipe fixes.",
|
||||
|
@ -64,7 +65,7 @@
|
|||
"1.0.0-b1": "[A] Initial structure.\n[A] Added clinker bricks and clinker brick stairs.\n[A] Added slag bricks and slag brick stairs.\n[A] Added metal rung ladder.\n[A] Added staggered metal steps ladder.\n[A] Added treated wood ladder.\n[A] Added treated wood pole.\n[A] Added treated wood table."
|
||||
},
|
||||
"promos": {
|
||||
"1.12.2-recommended": "1.0.14",
|
||||
"1.12.2-latest": "1.0.15-b2"
|
||||
"1.12.2-recommended": "1.0.15",
|
||||
"1.12.2-latest": "1.0.15"
|
||||
}
|
||||
}
|
|
@ -10,6 +10,15 @@ Mod sources for Minecraft version 1.12.2.
|
|||
----
|
||||
## Version history
|
||||
|
||||
-------------------------------------------------------------------
|
||||
- v1.0.15 [R] Release based on v1.0.15-b2. Release-to-release changes:
|
||||
* Added Small Block Breaker
|
||||
* Small Tree Cutter fixes and compatability improved.
|
||||
* Crafting table compat fixes.
|
||||
-------------------------------------------------------------------
|
||||
[M] Small Tree Cutter log detection bug fixed (issue #59).
|
||||
[M] Small Tree Cutter supports Menril chopping (issue #54).
|
||||
|
||||
- v1.0.15-b2 [A] Added Small Block Breaker
|
||||
[M] Crafting Table: Allowing NBT "Damage" mismatch only
|
||||
items that are declared damagable (issue #56).
|
||||
|
|
|
@ -193,6 +193,13 @@ public class ModContent
|
|||
ModAuxiliaries.getPixeledAABB(0,0,0, 16,16,16)
|
||||
);
|
||||
|
||||
public static final BlockDecorFluidFunnel SMALL_FLUID_FUNNEL = new BlockDecorFluidFunnel(
|
||||
"small_fluid_funnel",
|
||||
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_ELECTRICAL|BlockDecor.CFG_REDSTONE_CONTROLLED,
|
||||
Material.IRON, 1f, 15f, SoundType.METAL,
|
||||
ModAuxiliaries.getPixeledAABB(0,0,0, 16,16,16)
|
||||
);
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
public static final BlockDecorStraightPole TREATED_WOOD_POLE = new BlockDecorStraightPole(
|
||||
|
@ -468,6 +475,9 @@ public class ModContent
|
|||
private static final TileEntityRegistrationData PASSIVE_FLUID_ACCUMULATOR_TEI = new TileEntityRegistrationData(
|
||||
BlockDecorPassiveFluidAccumulator.BTileEntity.class, "te_passive_fluid_accumulator"
|
||||
);
|
||||
private static final TileEntityRegistrationData SMALL_FLUID_FUNNEL_TEI = new TileEntityRegistrationData(
|
||||
BlockDecorFluidFunnel.BTileEntity.class, "te_small_fluid_funnel"
|
||||
);
|
||||
private static final TileEntityRegistrationData WASTE_INCINERATOR_TEI = new TileEntityRegistrationData(
|
||||
BlockDecorWasteIncinerator.BTileEntity.class, "te_small_waste_incinerator"
|
||||
);
|
||||
|
@ -568,6 +578,7 @@ public class ModContent
|
|||
PANZERGLASS_SLAB, // @todo: check if another class is needed due to is_side_visible
|
||||
TREATED_WOOD_FLOOR, // @todo: check if textures need improvement
|
||||
TEST_BLOCK,TEST_BLOCK_TEI,
|
||||
SMALL_FLUID_FUNNEL,SMALL_FLUID_FUNNEL_TEI
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------
|
||||
|
|
|
@ -116,6 +116,7 @@ public class ModEngineersDecor
|
|||
if(RecipeCondModSpecific.num_skipped > 0) logger.info("Excluded " + RecipeCondModSpecific.num_skipped + " recipes due to config opt-out.");
|
||||
if(ModConfig.zmisc.with_experimental) logger.info("Included experimental features due to mod config.");
|
||||
ExtItems.onPostInit();
|
||||
BlockCategories.reload();
|
||||
TreeCutting.reload();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,387 @@
|
|||
/*
|
||||
* @file BlockDecorFluidFunnel.java
|
||||
* @author Stefan Wilhelm (wile)
|
||||
* @copyright (C) 2019 Stefan Wilhelm
|
||||
* @license MIT (see https://opensource.org/licenses/MIT)
|
||||
*
|
||||
* A device that collects and stores fluid blocks above it.
|
||||
* Tracks flowing fluid to their source blocks. Compatible
|
||||
* with vanilla infinite water source.
|
||||
*/
|
||||
package wile.engineersdecor.blocks;
|
||||
|
||||
import net.minecraft.block.*;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.block.properties.PropertyInteger;
|
||||
import net.minecraft.block.state.BlockStateContainer;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.item.EntityItem;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.math.*;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.util.ITickable;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.EnumHand;
|
||||
import net.minecraftforge.common.capabilities.Capability;
|
||||
import net.minecraftforge.common.capabilities.ICapabilityProvider;
|
||||
import net.minecraftforge.fluids.*;
|
||||
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
|
||||
import net.minecraftforge.fluids.capability.IFluidHandler;
|
||||
import net.minecraftforge.fluids.capability.IFluidTankProperties;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
public class BlockDecorFluidFunnel extends BlockDecor
|
||||
{
|
||||
public static final int FILL_LEVEL_MAX = 3;
|
||||
public static final PropertyInteger FILL_LEVEL = PropertyInteger.create("level", 0, FILL_LEVEL_MAX);
|
||||
|
||||
public BlockDecorFluidFunnel(@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
|
||||
protected BlockStateContainer createBlockState()
|
||||
{ return new BlockStateContainer(this, FILL_LEVEL); }
|
||||
|
||||
@Override
|
||||
public IBlockState getStateFromMeta(int meta)
|
||||
{ return super.getStateFromMeta(meta).withProperty(FILL_LEVEL, meta & 0x3); }
|
||||
|
||||
@Override
|
||||
public int getMetaFromState(IBlockState state)
|
||||
{ return super.getMetaFromState(state) | (state.getValue(FILL_LEVEL)); }
|
||||
|
||||
@Override
|
||||
public IBlockState getStateForPlacement(World world, BlockPos pos, EnumFacing facing, float hitX, float hitY, float hitZ, int meta, EntityLivingBase placer, EnumHand hand)
|
||||
{ return super.getStateForPlacement(world, pos, facing, hitX, hitY, hitZ, meta, placer, hand).withProperty(FILL_LEVEL, 0); }
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public int getComparatorInputOverride(IBlockState state, World world, BlockPos pos)
|
||||
{ return MathHelper.clamp((state.getValue(FILL_LEVEL)*5), 0, 15); }
|
||||
|
||||
@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).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 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;
|
||||
TileEntity te = world.getTileEntity(pos);
|
||||
if(!(te instanceof BTileEntity)) return false;
|
||||
return FluidUtil.interactWithFluidHandler(player, hand, world, pos, facing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void neighborChanged(IBlockState state, World world, BlockPos pos, Block block, BlockPos fromPos)
|
||||
{ TileEntity te = world.getTileEntity(pos); if(te instanceof BTileEntity) ((BTileEntity)te).block_changed(); }
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------
|
||||
// Tile entity
|
||||
//--------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
public static class BTileEntity extends TileEntity implements IFluidHandler, IFluidTankProperties, ICapabilityProvider, ITickable
|
||||
{
|
||||
public static final int TANK_CAPACITY = 3000;
|
||||
public static final int TICK_INTERVAL = 10; // ca 500ms
|
||||
public static final int COLLECTION_INTERVAL = 40; // ca 2000ms, simulates suction delay and saves CPU when not drained.
|
||||
public static final int MAX_TRACK_RADIUS = 16;
|
||||
public static final int MAX_TRACKING_STEPS_PER_CYCLE = 72;
|
||||
public static final int MAX_TRACKING_STEPS_PER_CYCLE_INTENSIVE = 1024;
|
||||
public static final int MAX_TRACK_RADIUS_SQ = MAX_TRACK_RADIUS*MAX_TRACK_RADIUS;
|
||||
public static final int INTENSIVE_SEARCH_TRIGGER_THRESHOLD = 16;
|
||||
private final IFluidTankProperties[] fluid_props_ = {this};
|
||||
private FluidStack tank_ = null;
|
||||
private int tick_timer_ = 0;
|
||||
private int collection_timer_ = 0;
|
||||
private BlockPos last_pick_pos_ = BlockPos.ORIGIN;
|
||||
private ArrayList<Vec3i> search_offsets_ = null;
|
||||
private int no_fluid_found_counter_ = 0;
|
||||
private int intensive_search_counter_ = 0;
|
||||
private int total_pick_counter_ = 0;
|
||||
|
||||
public BTileEntity()
|
||||
{}
|
||||
|
||||
public void block_changed()
|
||||
{ tick_timer_ = TICK_INTERVAL; } // collect after flowing fluid has a stable state, otherwise it looks odd.
|
||||
|
||||
public void readnbt(NBTTagCompound nbt, boolean update_packet)
|
||||
{
|
||||
tank_ = (!nbt.hasKey("tank")) ? (null) : (FluidStack.loadFluidStackFromNBT(nbt.getCompoundTag("tank")));
|
||||
}
|
||||
|
||||
protected void writenbt(NBTTagCompound nbt, boolean update_packet)
|
||||
{
|
||||
if(tank_ != null) nbt.setTag("tank", tank_.writeToNBT(new NBTTagCompound()));
|
||||
}
|
||||
|
||||
// TileEntity ------------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public boolean shouldRefresh(World world, BlockPos pos, IBlockState os, IBlockState ns)
|
||||
{
|
||||
block_changed();
|
||||
return (os.getBlock() != ns.getBlock()) || (!(ns.getBlock() instanceof BlockDecorFluidFunnel));
|
||||
}
|
||||
|
||||
@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; }
|
||||
|
||||
// ICapabilityProvider --------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public boolean hasCapability(@Nonnull Capability<?> capability, @Nullable EnumFacing facing)
|
||||
{ return ((capability==CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY)) || super.hasCapability(capability, facing); }
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getCapability(@Nonnull Capability<T> capability, @Nullable EnumFacing facing)
|
||||
{
|
||||
if(capability != CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) return super.getCapability(capability, facing);
|
||||
return ((T)this);
|
||||
}
|
||||
|
||||
// IFluidHandler of the output port --------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public IFluidTankProperties[] getTankProperties()
|
||||
{ return fluid_props_; }
|
||||
|
||||
@Override
|
||||
public int fill(FluidStack resource, boolean doFill)
|
||||
{ return 0; }
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public FluidStack drain(FluidStack resource, boolean doDrain)
|
||||
{
|
||||
if((resource==null) || (tank_==null)) return null;
|
||||
return (!(tank_.isFluidEqual(resource))) ? (null) : drain(resource.amount, doDrain);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public FluidStack drain(int maxDrain, boolean doDrain)
|
||||
{
|
||||
if(tank_==null) return null;
|
||||
maxDrain = MathHelper.clamp(maxDrain ,0 , tank_.amount);
|
||||
FluidStack res = tank_.copy();
|
||||
res.amount = maxDrain;
|
||||
if(doDrain) tank_.amount -= maxDrain;
|
||||
if(tank_.amount <= 0) tank_= null;
|
||||
return res;
|
||||
}
|
||||
|
||||
// IFluidTankProperties --------------------------------------------------------------------
|
||||
|
||||
@Override @Nullable public FluidStack getContents() { return (tank_==null) ? (null) : (tank_.copy()); }
|
||||
@Override public int getCapacity() { return TANK_CAPACITY; }
|
||||
@Override public boolean canFill() { return false; }
|
||||
@Override public boolean canDrain() { return true; }
|
||||
@Override public boolean canFillFluidType(FluidStack fluidStack) { return false; }
|
||||
@Override public boolean canDrainFluidType(FluidStack fluidStack) { return true; }
|
||||
|
||||
// ITickable--------------------------------------------------------------------------------
|
||||
|
||||
private Fluid get_fluid(BlockPos pos)
|
||||
{ return FluidRegistry.lookupFluidForBlock(world.getBlockState(pos).getBlock()); }
|
||||
|
||||
private boolean try_pick(BlockPos pos)
|
||||
{
|
||||
IFluidHandler hnd = FluidUtil.getFluidHandler(world, pos, null);
|
||||
if(hnd == null) return false;
|
||||
FluidStack fs = hnd.drain((tank_==null) ? (TANK_CAPACITY) : (TANK_CAPACITY-tank_.amount), true);
|
||||
if(fs == null) return false;
|
||||
if(tank_ == null) {
|
||||
tank_ = fs.copy();
|
||||
} else if(tank_.isFluidEqual(fs)) {
|
||||
tank_.amount = MathHelper.clamp(tank_.amount+fs.amount, 0, TANK_CAPACITY);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
world.setBlockToAir(pos);
|
||||
world.notifyNeighborsOfStateChange(pos, world.getBlockState(pos).getBlock(), true); // explicitly update neighbours to allow these start flowing
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean can_pick(BlockPos pos, Fluid fluid)
|
||||
{
|
||||
IFluidHandler hnd = FluidUtil.getFluidHandler(world, pos, null);
|
||||
if(hnd == null) return false;
|
||||
FluidStack fs = hnd.drain((tank_==null) ? (TANK_CAPACITY) : (TANK_CAPACITY-tank_.amount), false);
|
||||
return (fs != null) && (fs.getFluid().equals(fluid));
|
||||
}
|
||||
|
||||
private void rebuild_search_offsets(boolean intensive)
|
||||
{
|
||||
search_offsets_ = new ArrayList<>(9);
|
||||
search_offsets_.add(new Vec3i(0, 1, 0)); // up first
|
||||
{
|
||||
ArrayList<Vec3i> ofs = new ArrayList<Vec3i>(Arrays.asList(new Vec3i(-1, 0, 0), new Vec3i( 1, 0, 0), new Vec3i( 0, 0,-1), new Vec3i( 0, 0, 1)));
|
||||
if(intensive || (total_pick_counter_ > 50)) Collections.shuffle(ofs);
|
||||
search_offsets_.addAll(ofs);
|
||||
}
|
||||
if(intensive) {
|
||||
ArrayList<Vec3i> ofs = new ArrayList<Vec3i>(Arrays.asList(new Vec3i(-1, 1, 0), new Vec3i( 1, 1, 0), new Vec3i( 0, 1,-1), new Vec3i( 0, 1, 1)));
|
||||
Collections.shuffle(ofs);
|
||||
search_offsets_.addAll(ofs);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean try_collect(BlockPos collection_pos)
|
||||
{
|
||||
final Block collection_block = world.getBlockState(collection_pos).getBlock();
|
||||
if((!(collection_block instanceof IFluidBlock)) && (!(collection_block instanceof BlockLiquid))) return false;
|
||||
final Fluid fluid_to_collect = FluidRegistry.lookupFluidForBlock(collection_block);
|
||||
if(fluid_to_collect == null) return false; // not sure if that can return null
|
||||
if((tank_!=null) && (!tank_.getFluid().equals(fluid_to_collect))) return false;
|
||||
if(try_pick(collection_pos)) { last_pick_pos_ = collection_pos; return true; } // Blocks directly always first. Allows water source blocks to recover/reflow to source blocks.
|
||||
// Not picked, not a source block -> search highest allowed source block to pick
|
||||
// ---------------------------------------------------------------------------------------------------------------
|
||||
// Plan is to pick preferably surface blocks whilst not wasting much mem and cpu. Blocks will dynamically change due to flowing.
|
||||
// Basic assumptions: fluid flows straight (not diagonal) and not up the hill. Only falling fluid streams are long, lateral streams are about max 16 blocks (water 8).
|
||||
// Problem resolving: Threre are fluids going all over the place, and do not sometimes continue flowing without a source block.
|
||||
// - Stack based trail tracking is used
|
||||
// - Turtle motion with reset on fail, preferrs up, remaining motion order is shuffled to pick not in the same direction.
|
||||
// - Calculation time capping, reset on fail, extended search for far blocks (e.g. stream from a high position) on many fails.
|
||||
// - Preferrs fluid surface blocks if possible and anough calculation time left.
|
||||
// - On fail, replace last flowing block with air and cause a block update, in case previous block updates or strange fluid block behaviour does not prevent advancing.
|
||||
// - Assumption is: The search can go much further than fluids can flow, except top-bottom falling streams. so
|
||||
if((last_pick_pos_==null) || (last_pick_pos_.distanceSq(collection_pos) > MAX_TRACK_RADIUS_SQ)) { last_pick_pos_ = collection_pos; search_offsets_ = null; }
|
||||
BlockPos pos = last_pick_pos_;
|
||||
HashSet<BlockPos> checked = new HashSet<>();
|
||||
Stack<BlockPos> trail = new Stack<BlockPos>();
|
||||
trail.add(pos);
|
||||
checked.add(pos);
|
||||
int steps=0;
|
||||
boolean intensive = (no_fluid_found_counter_ >= INTENSIVE_SEARCH_TRIGGER_THRESHOLD);
|
||||
if(intensive) { no_fluid_found_counter_ = 0; ++intensive_search_counter_; }
|
||||
if(search_offsets_ == null) rebuild_search_offsets(intensive);
|
||||
int max = intensive ? MAX_TRACKING_STEPS_PER_CYCLE_INTENSIVE : MAX_TRACKING_STEPS_PER_CYCLE;
|
||||
while(++steps <= max) {
|
||||
int num_adjacent = 0;
|
||||
for(int i=0; i<search_offsets_.size(); ++i) {
|
||||
BlockPos p = pos.add(search_offsets_.get(i));
|
||||
if(checked.contains(p)) continue;
|
||||
checked.add(p);
|
||||
++steps;
|
||||
if(fluid_to_collect.equals(get_fluid(p))) {
|
||||
++num_adjacent;
|
||||
pos = p;
|
||||
trail.push(pos);
|
||||
if(steps < MAX_TRACKING_STEPS_PER_CYCLE_INTENSIVE/2) {
|
||||
// check for same fluid above (only source blocks)
|
||||
final int max_surface_search = (MAX_TRACKING_STEPS_PER_CYCLE_INTENSIVE/2)-steps;
|
||||
for(int k=0; k<max_surface_search; ++k) {
|
||||
if(!can_pick(pos.up(), fluid_to_collect)) break;
|
||||
pos = pos.up();
|
||||
trail.push(pos);
|
||||
}
|
||||
}
|
||||
if(try_pick(pos)) {
|
||||
last_pick_pos_ = pos;
|
||||
no_fluid_found_counter_ = 0;
|
||||
search_offsets_ = null;
|
||||
// probability reset, so it's not turteling too far away, mainly for large nether lava seas, not desert lakes.
|
||||
if((++total_pick_counter_ > 50) && world.rand.nextInt(10)==0) last_pick_pos_ = collection_pos;
|
||||
//println("PASS " + steps + " - " + (pos.subtract(collection_pos)));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(trail.isEmpty()) break; // reset search
|
||||
if(num_adjacent==0) pos = trail.pop();
|
||||
}
|
||||
//println("FAIL=" + steps + " - " + (pos.subtract(collection_pos))); String s = new String(); for(BlockPos p:checked) s += "\n" + p; System.out.println(s);
|
||||
if(intensive_search_counter_ > 2) world.setBlockToAir(pos);
|
||||
last_pick_pos_ = collection_pos;
|
||||
search_offsets_ = null; // try other search order
|
||||
++no_fluid_found_counter_;
|
||||
return false;
|
||||
}
|
||||
|
||||
public void update()
|
||||
{
|
||||
if((world.isRemote) || (--tick_timer_ > 0)) return;
|
||||
tick_timer_ = TICK_INTERVAL;
|
||||
collection_timer_ += TICK_INTERVAL;
|
||||
boolean dirty = false;
|
||||
// Collection
|
||||
if((collection_timer_ >= COLLECTION_INTERVAL) && ((tank_==null) || (tank_.amount <= (TANK_CAPACITY-1000)))) {
|
||||
collection_timer_ = 0;
|
||||
if(!world.isBlockPowered(pos)) { // redstone disable feature
|
||||
if(last_pick_pos_==null) last_pick_pos_ = pos.up();
|
||||
if(try_collect(pos.up())) dirty = true;
|
||||
}
|
||||
}
|
||||
// Gravity fluid transfer
|
||||
if((tank_!=null) && (tank_.amount >= 1000)) {
|
||||
IFluidHandler fh = FluidUtil.getFluidHandler(world, pos.down(), EnumFacing.UP);
|
||||
if(fh != null) {
|
||||
FluidStack fs = new FluidStack(tank_.getFluid(), 1000);
|
||||
int nfilled = MathHelper.clamp(fh.fill(fs, true), 0, 1000);
|
||||
tank_.amount -= nfilled;
|
||||
if(tank_.amount <= 0) tank_ = null;
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
// Block state
|
||||
int fill_level = (tank_==null) ? 0 : (MathHelper.clamp(tank_.amount/1000,0,FILL_LEVEL_MAX));
|
||||
final IBlockState funnel_state = world.getBlockState(pos);
|
||||
if(funnel_state.getValue(FILL_LEVEL) != fill_level) world.setBlockState(pos, funnel_state.withProperty(FILL_LEVEL, fill_level), 2|16);
|
||||
if(dirty) markDirty();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -124,7 +124,7 @@ public class BlockDecorPassiveFluidAccumulator extends BlockDecorDirected
|
|||
public boolean shouldRefresh(World world, BlockPos pos, IBlockState os, IBlockState ns)
|
||||
{
|
||||
block_changed();
|
||||
return (os.getBlock() != ns.getBlock()) || (!(ns.getBlock() instanceof BlockDecorPipeValve));
|
||||
return (os.getBlock() != ns.getBlock()) || (!(ns.getBlock() instanceof BlockDecorPassiveFluidAccumulator));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -26,6 +26,7 @@ public class BlockCategories
|
|||
{
|
||||
private static Set<Block> logs_ = new HashSet<Block>();
|
||||
private static Set<Block> leaves_ = new HashSet<Block>();
|
||||
private static Set<Block> variant_logs_ = new HashSet<Block>(); // logs that are not checked for log equivalence
|
||||
|
||||
public static final Set<Block> logs()
|
||||
{ return logs_; } // wrap in case immutable needed one time.
|
||||
|
@ -33,7 +34,6 @@ public class BlockCategories
|
|||
public static final Set<Block> leaves()
|
||||
{ return leaves_; }
|
||||
|
||||
|
||||
public static boolean isLog(IBlockState state)
|
||||
{
|
||||
final Block block = state.getBlock();
|
||||
|
@ -48,23 +48,27 @@ public class BlockCategories
|
|||
}
|
||||
|
||||
public static final boolean isSameLeaves(IBlockState a, IBlockState b)
|
||||
{ return (a.getBlock() == b.getBlock()); }
|
||||
{
|
||||
if(!isLeaves(a)) return false;
|
||||
final Block block = a.getBlock();
|
||||
if(block != b.getBlock()) return false;
|
||||
if(block instanceof BlockNewLeaf) return a.getValue(BlockNewLeaf.VARIANT) == b.getValue(BlockNewLeaf.VARIANT);
|
||||
if(block instanceof BlockOldLeaf) return a.getValue(BlockOldLeaf.VARIANT) == b.getValue(BlockOldLeaf.VARIANT);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static final boolean isSameLog(IBlockState a, IBlockState b)
|
||||
{
|
||||
// very strange ...
|
||||
if(a.getBlock()!=b.getBlock()) {
|
||||
return false;
|
||||
} else if(a.getBlock() instanceof BlockNewLog) {
|
||||
return a.getValue(BlockNewLog.VARIANT) == b.getValue(BlockNewLog.VARIANT);
|
||||
} else if(a.getBlock() instanceof BlockOldLog) {
|
||||
return a.getValue(BlockOldLog.VARIANT) == b.getValue(BlockOldLog.VARIANT);
|
||||
} else {
|
||||
// Uagh, that hurts the heart of performance ...
|
||||
final IProperty<?> prop = a.getPropertyKeys().stream().filter( (IProperty<?> p) -> (p.getName().contains("variant") || p.getName().contains("type"))).findFirst().orElse(null);
|
||||
if(prop==null) return false;
|
||||
return a.getValue(prop).equals(b.getValue(prop));
|
||||
}
|
||||
if((!isLog(a)) || (!isLog(b))) return false;
|
||||
if(variant_logs_.contains(a.getBlock()) || (variant_logs_.contains(b.getBlock()))) return true;
|
||||
if(a.getBlock()!=b.getBlock()) return false;
|
||||
if(a.getBlock() instanceof BlockNewLog) return a.getValue(BlockNewLog.VARIANT) == b.getValue(BlockNewLog.VARIANT);
|
||||
if(a.getBlock() instanceof BlockOldLog) return a.getValue(BlockOldLog.VARIANT)==b.getValue(BlockOldLog.VARIANT);
|
||||
// Uagh, that hurts the heart of performance ...
|
||||
final IProperty<?> prop = a.getPropertyKeys().stream().filter( (IProperty<?> p) -> (p.getName().contains("variant") || p.getName().contains("type"))).findFirst().orElse(null);
|
||||
if(prop!=null) return a.getValue(prop).equals(b.getValue(prop));
|
||||
// All other: We have to assume that there are no variants for this block, and the block type denotes the log type unambiguously.
|
||||
return true;
|
||||
}
|
||||
|
||||
public static final void reload()
|
||||
|
@ -77,11 +81,17 @@ public class BlockCategories
|
|||
for(ItemStack stack : stacks) {
|
||||
final Item item = stack.getItem();
|
||||
if(!(item instanceof ItemBlock)) continue;
|
||||
logs.add(((ItemBlock)item).getBlock());
|
||||
Block block = ((ItemBlock)item).getBlock();
|
||||
logs.add(block);
|
||||
// @todo: make this configurable
|
||||
if(block.getRegistryName().getPath().contains("menril")) variant_logs_.add(block);
|
||||
}
|
||||
}
|
||||
logs_ = logs;
|
||||
ModEngineersDecor.logger.info("Found "+logs.size()+" types of 'choppable' log.");
|
||||
if(ModConfig.zmisc.with_experimental) {
|
||||
for(Block b:logs_) ModEngineersDecor.logger.info(" - choppable log: " + b.getRegistryName());
|
||||
}
|
||||
}
|
||||
{
|
||||
HashSet<Block> leaves = new HashSet<Block>();
|
||||
|
@ -96,6 +106,9 @@ public class BlockCategories
|
|||
}
|
||||
leaves_ = leaves;
|
||||
ModEngineersDecor.logger.info("Found "+leaves.size()+" types of leaves.");
|
||||
if(ModConfig.zmisc.with_experimental) {
|
||||
for(Block b:leaves_) ModEngineersDecor.logger.info(" - choppable leaf: " + b.getRegistryName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,9 @@ import java.util.*;
|
|||
public class TreeCutting
|
||||
{
|
||||
private static org.apache.logging.log4j.Logger LOGGER = ModEngineersDecor.logger;
|
||||
private static int max_log_tracing_steps = 128;
|
||||
private static int max_cutting_height = 128;
|
||||
private static int max_cutting_radius = 12;
|
||||
|
||||
private static class Compat
|
||||
{
|
||||
|
@ -39,27 +42,28 @@ public class TreeCutting
|
|||
choppable_states.clear();
|
||||
if(ModAuxiliaries.isModLoaded("dynamictrees")) {
|
||||
ForgeRegistries.BLOCKS.getKeys().forEach((regname)->{
|
||||
//if("dynamictrees".equals(regname.getNamespace())) { ... let's see if that also work with dyntrees compat mods
|
||||
if(!regname.getPath().contains("branch")) return;
|
||||
try {
|
||||
Block block = ForgeRegistries.BLOCKS.getValue(regname);
|
||||
IBlockState state = block.getDefaultState();
|
||||
for(IProperty<?> vaprop: state.getProperties().keySet()) {
|
||||
if(!("radius".equals(vaprop.getName())) || (vaprop.getValueClass() != Integer.class)) continue;
|
||||
@SuppressWarnings("unchecked")
|
||||
IProperty<Integer> prop = (IProperty<Integer>)vaprop;
|
||||
Integer max = ((Collection<Integer>)prop.getAllowedValues()).stream().max(Integer::compare).orElse(0);
|
||||
if(max<7) continue;
|
||||
for(int r=7; r<=max; ++r) choppable_states.put(state.withProperty(prop, r), ChoppingMethod.RootBlockBreaking);
|
||||
}
|
||||
} catch(Throwable e) {
|
||||
LOGGER.warn("Failed to register chopping for " + regname.toString());
|
||||
return;
|
||||
if(!regname.getPath().contains("branch")) return;
|
||||
try {
|
||||
Block block = ForgeRegistries.BLOCKS.getValue(regname);
|
||||
IBlockState state = block.getDefaultState();
|
||||
for(IProperty<?> vaprop: state.getProperties().keySet()) {
|
||||
if(!("radius".equals(vaprop.getName())) || (vaprop.getValueClass() != Integer.class)) continue;
|
||||
@SuppressWarnings("unchecked")
|
||||
IProperty<Integer> prop = (IProperty<Integer>)vaprop;
|
||||
Integer max = ((Collection<Integer>)prop.getAllowedValues()).stream().max(Integer::compare).orElse(0);
|
||||
if(max<7) continue;
|
||||
for(int r=7; r<=max; ++r) choppable_states.put(state.withProperty(prop, r), ChoppingMethod.RootBlockBreaking);
|
||||
}
|
||||
//}
|
||||
} catch(Throwable e) {
|
||||
LOGGER.warn("Failed to register chopping for " + regname.toString());
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
LOGGER.info("Dynamic Trees chopping compat: " + choppable_states.size() + " choppable states found.");
|
||||
if(ModConfig.zmisc.with_experimental) {
|
||||
for(IBlockState b:choppable_states.keySet()) ModEngineersDecor.logger.info(" - dynamic tree state: " + b);
|
||||
}
|
||||
} catch(Throwable e) {
|
||||
choppable_states.clear();
|
||||
LOGGER.warn("Failed to determine choppings for dynamic trees compat, skipping that:" + e);
|
||||
|
@ -100,7 +104,13 @@ public class TreeCutting
|
|||
);
|
||||
|
||||
public static void reload()
|
||||
{ Compat.reload(); }
|
||||
{
|
||||
Compat.reload();
|
||||
// later config, now keep IJ from suggesting that a private variable should be used.
|
||||
max_log_tracing_steps = 128;
|
||||
max_cutting_height = 128;
|
||||
max_cutting_radius = 12;
|
||||
}
|
||||
|
||||
private static List<BlockPos> findBlocksAround(final World world, final BlockPos centerPos, final IBlockState leaf_type_state, final Set<BlockPos> checked, int recursion_left)
|
||||
{
|
||||
|
@ -121,6 +131,17 @@ public class TreeCutting
|
|||
return to_decay;
|
||||
}
|
||||
|
||||
private static boolean too_far(BlockPos start, BlockPos pos)
|
||||
{
|
||||
int dy = pos.getY()-start.getY();
|
||||
if((dy < 0) || (dy>max_cutting_height)) return true;
|
||||
final int dx = Math.abs(pos.getX()-start.getX());
|
||||
final int dz = Math.abs(pos.getZ()-start.getZ());
|
||||
if(dy > max_cutting_radius) dy = max_cutting_radius;
|
||||
if((dx >= dy+3) || (dz >= dy+3)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean canChop(IBlockState state)
|
||||
{ return BlockCategories.isLog(state) || Compat.canChop(state); }
|
||||
|
||||
|
@ -144,11 +165,13 @@ public class TreeCutting
|
|||
LinkedList<BlockPos> upqueue = new LinkedList<BlockPos>();
|
||||
queue.add(startPos);
|
||||
int cutlevel = 0;
|
||||
int steps_left = 64;
|
||||
int steps_left = max_log_tracing_steps;
|
||||
IBlockState tracked_leaves_state = null;
|
||||
while(!queue.isEmpty() && (--steps_left >= 0)) {
|
||||
final BlockPos pos = queue.removeFirst();
|
||||
// Vertical search
|
||||
final BlockPos uppos = pos.up();
|
||||
if(too_far(startPos, uppos)) { checked.add(uppos); continue; }
|
||||
final IBlockState upstate = world.getBlockState(uppos);
|
||||
if(!checked.contains(uppos)) {
|
||||
checked.add(uppos);
|
||||
|
@ -156,11 +179,18 @@ public class TreeCutting
|
|||
// Up is log
|
||||
upqueue.add(uppos);
|
||||
to_break.add(uppos);
|
||||
steps_left = 64;
|
||||
steps_left = max_log_tracing_steps;
|
||||
} else {
|
||||
boolean isleaf = BlockCategories.isLeaves(upstate);
|
||||
if(isleaf || world.isAirBlock(uppos) || (upstate.getBlock() instanceof BlockVine)) {
|
||||
if(isleaf) to_decay.add(uppos);
|
||||
if(isleaf) {
|
||||
if(tracked_leaves_state==null) {
|
||||
tracked_leaves_state=upstate;
|
||||
to_decay.add(uppos);
|
||||
} else if(BlockCategories.isSameLeaves(upstate, tracked_leaves_state)) {
|
||||
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);
|
||||
|
@ -172,7 +202,9 @@ public class TreeCutting
|
|||
queue.add(p);
|
||||
to_break.add(p);
|
||||
} else if(BlockCategories.isLeaves(st)) {
|
||||
to_decay.add(p);
|
||||
if((tracked_leaves_state==null) || (BlockCategories.isSameLeaves(st, tracked_leaves_state))) {
|
||||
to_decay.add(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -183,14 +215,15 @@ public class TreeCutting
|
|||
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 IBlockState st = world.getBlockState(p);
|
||||
final Block bl = st.getBlock();
|
||||
if(BlockCategories.isSameLog(st, broken_state)) {
|
||||
queue.add(p);
|
||||
to_break.add(p);
|
||||
} else if(BlockCategories.isLeaves(st)) {
|
||||
to_decay.add(p);
|
||||
if((tracked_leaves_state==null) || (BlockCategories.isSameLeaves(st, tracked_leaves_state))) {
|
||||
to_decay.add(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(queue.isEmpty() && (!upqueue.isEmpty())) {
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"forge_marker": 1,
|
||||
"defaults": { "model": "engineersdecor:device/small_fluid_funnel_model_s0" },
|
||||
"variants": {
|
||||
"normal": [{}],
|
||||
"inventory": [{}],
|
||||
"level": {
|
||||
"0":{},
|
||||
"1":{"model": "engineersdecor:device/small_fluid_funnel_model_s1"},
|
||||
"2":{"model": "engineersdecor:device/small_fluid_funnel_model_s2"},
|
||||
"3":{"model": "engineersdecor:device/small_fluid_funnel_model_s3"}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -150,6 +150,11 @@ tile.engineersdecor.straight_pipe_valve_redstone_analog.help=§6Straight fluid p
|
|||
tile.engineersdecor.passive_fluid_accumulator.name=Passive Fluid Accumulator
|
||||
tile.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.
|
||||
tile.engineersdecor.small_fluid_funnel.name=Small Fluid Collection Funnel
|
||||
tile.engineersdecor.small_fluid_funnel.help=§6Collects fluids above it.§r Has an internal tank with three buckets capacity. Traces \
|
||||
flowing fluids to nearby source blocks. The fluid can be obtained with fluid transfer systems \
|
||||
or a bucket. Fills only tanks below (gravity transfer). Compatible with vanilla \
|
||||
infinite-water-source creation.
|
||||
#-----------------------------------------------------------------------------------------------------------
|
||||
tile.engineersdecor.factory_dropper.name=Factory Dropper
|
||||
tile.engineersdecor.factory_dropper.help=§6Dropper suitable for advanced factory automation.§r Has twelve round-robin selected slots. \
|
||||
|
|
|
@ -145,6 +145,11 @@ tile.engineersdecor.straight_pipe_valve_redstone_analog.help=§6Фрагмент
|
|||
tile.engineersdecor.passive_fluid_accumulator.name=Пассивный жидкостный накопитель
|
||||
tile.engineersdecor.passive_fluid_accumulator.help=§6Вакуумный всасывающий жидкостный коллектор.§r Имеет один выход, все остальные стороны входные. \
|
||||
Сливает жидкости из соседних резервуаров при выкачивании жидкости из выходного порта.
|
||||
tile.engineersdecor.small_fluid_funnel.name=Small Fluid Collection Funnel
|
||||
#tile.engineersdecor.small_fluid_funnel.help=§6Collects fluids above it.§r Has an internal tank with three buckets capacity. Traces \
|
||||
flowing fluids to nearby source blocks. The fluid can be obtained with fluid transfer systems \
|
||||
or a bucket. Fills only tanks below (gravity transfer). Compatible with vanilla \
|
||||
infinite-water-source creation.
|
||||
#-----------------------------------------------------------------------------------------------------------
|
||||
tile.engineersdecor.factory_dropper.name=Фабричный выбрасыватель
|
||||
tile.engineersdecor.factory_dropper.help=§6Выбрасыватель подходит для продвинутой автоматизации производства.§r Имеет 12 выборочных слотов. \
|
||||
|
|
|
@ -149,6 +149,11 @@ tile.engineersdecor.straight_pipe_valve_redstone_analog.help=§6一段直输液
|
|||
tile.engineersdecor.passive_fluid_accumulator.name=被动流体累积器。
|
||||
tile.engineersdecor.passive_fluid_accumulator.help=§6基于真空吸力的流体收集器。§r有一个输出面,其他面都是输入。\
|
||||
当从输出面被泵抽取时,从输入面邻接储罐抽取液体。
|
||||
tile.engineersdecor.small_fluid_funnel.name=Small Fluid Collection Funnel
|
||||
#tile.engineersdecor.small_fluid_funnel.help=§6Collects fluids above it.§r Has an internal tank with three buckets capacity. Traces \
|
||||
flowing fluids to nearby source blocks. The fluid can be obtained with fluid transfer systems \
|
||||
or a bucket. Fills only tanks below (gravity transfer). Compatible with vanilla \
|
||||
infinite-water-source creation.
|
||||
#-----------------------------------------------------------------------------------------------------------
|
||||
tile.engineersdecor.factory_dropper.name=工厂掉落器
|
||||
tile.engineersdecor.factory_dropper.help=§6适用于高级工厂自动化的掉落器。§r有十二个轮询选择的储物格。\
|
||||
|
|
|
@ -0,0 +1,295 @@
|
|||
{
|
||||
"parent": "block/cube",
|
||||
"textures": {
|
||||
"top": "engineersdecor:blocks/device/small_fluid_funnel_top",
|
||||
"bottom": "engineersdecor:blocks/device/small_fluid_funnel_bottom",
|
||||
"side": "engineersdecor:blocks/device/small_fluid_funnel_side_s0",
|
||||
"particle": "engineersdecor:blocks/device/small_fluid_funnel_side_s0"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"from": [0, 0, 0],
|
||||
"to": [16, 14, 16],
|
||||
"faces": {
|
||||
"north": {"uv": [0, 2, 16, 16], "texture": "#side"},
|
||||
"east": {"uv": [0, 2, 16, 16], "texture": "#side"},
|
||||
"south": {"uv": [0, 2, 16, 16], "texture": "#side"},
|
||||
"west": {"uv": [0, 2, 16, 16], "texture": "#side"},
|
||||
"up": {"uv": [0, 0, 16, 16], "texture": "#top"},
|
||||
"down": {"uv": [0, 0, 16, 16], "texture": "#bottom"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [14, 15, 0],
|
||||
"to": [16, 16, 16],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [8, 22, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [0, 0, 2, 1], "texture": "#side"},
|
||||
"east": {"uv": [0, 0, 16, 1], "texture": "#side"},
|
||||
"south": {"uv": [14, 0, 16, 1], "texture": "#side"},
|
||||
"west": {"uv": [0, 0, 16, 1], "texture": "#side"},
|
||||
"up": {"uv": [14, 0, 16, 16], "texture": "#top"},
|
||||
"down": {"uv": [14, 0, 16, 16], "texture": "#bottom"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [13, 14, 2],
|
||||
"to": [15, 15, 14],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [7, 20, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [1, 1, 3, 2], "texture": "#side"},
|
||||
"east": {"uv": [2, 1, 14, 2], "texture": "#side"},
|
||||
"south": {"uv": [13, 1, 15, 2], "texture": "#side"},
|
||||
"west": {"uv": [2, 1, 14, 2], "texture": "#side"},
|
||||
"up": {"uv": [13, 2, 15, 14], "texture": "#top"},
|
||||
"down": {"uv": [13, 2, 15, 14], "texture": "#bottom"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [2, 15, 0],
|
||||
"to": [15, 16, 2],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [5, 22, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [1, 0, 14, 1], "texture": "#side"},
|
||||
"east": {"uv": [14, 0, 16, 1], "texture": "#side"},
|
||||
"south": {"uv": [2, 0, 15, 1], "texture": "#side"},
|
||||
"west": {"uv": [0, 0, 2, 1], "texture": "#side"},
|
||||
"up": {"uv": [2, 0, 15, 2], "texture": "#top"},
|
||||
"down": {"uv": [2, 14, 15, 16], "texture": "#bottom"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [3, 14, 1],
|
||||
"to": [13, 15, 3],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [5, 20, 9]},
|
||||
"faces": {
|
||||
"north": {"uv": [3, 1, 13, 2], "texture": "#side"},
|
||||
"east": {"uv": [13, 1, 15, 2], "texture": "#side"},
|
||||
"south": {"uv": [3, 1, 13, 2], "texture": "#side"},
|
||||
"west": {"uv": [1, 1, 3, 2], "texture": "#side"},
|
||||
"up": {"uv": [3, 1, 13, 3], "texture": "#top"},
|
||||
"down": {"uv": [3, 13, 13, 15], "texture": "#bottom"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [2, 15, 14],
|
||||
"to": [15, 16, 16],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [5, 22, 22]},
|
||||
"faces": {
|
||||
"north": {"uv": [1, 0, 14, 1], "texture": "#side"},
|
||||
"east": {"uv": [0, 0, 2, 1], "texture": "#side"},
|
||||
"south": {"uv": [2, 0, 15, 1], "texture": "#side"},
|
||||
"west": {"uv": [14, 0, 16, 1], "texture": "#side"},
|
||||
"up": {"uv": [2, 14, 15, 16], "texture": "#top"},
|
||||
"down": {"uv": [2, 0, 15, 2], "texture": "#bottom"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [3, 14, 13],
|
||||
"to": [13, 15, 15],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [5, 20, 21]},
|
||||
"faces": {
|
||||
"north": {"uv": [3, 1, 13, 2], "texture": "#side"},
|
||||
"east": {"uv": [1, 1, 3, 2], "texture": "#side"},
|
||||
"south": {"uv": [3, 1, 13, 2], "texture": "#side"},
|
||||
"west": {"uv": [13, 1, 15, 2], "texture": "#side"},
|
||||
"up": {"uv": [3, 13, 13, 15], "texture": "#top"},
|
||||
"down": {"uv": [3, 1, 13, 3], "texture": "#bottom"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [2, 14, 2],
|
||||
"to": [2.5, 16, 14],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [-4, 22, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [13.5, 0, 14, 2], "texture": "#side"},
|
||||
"east": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"south": {"uv": [2, 0, 2.5, 2], "texture": "#side"},
|
||||
"west": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"up": {"uv": [2, 2, 2.5, 14], "texture": "#top"},
|
||||
"down": {"uv": [2, 2, 2.5, 14], "texture": "#bottom"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [3, 14, 2],
|
||||
"to": [3.5, 16, 14],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [-3, 22, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [12.5, 0, 13, 2], "texture": "#side"},
|
||||
"east": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"south": {"uv": [3, 0, 3.5, 2], "texture": "#side"},
|
||||
"west": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"up": {"uv": [3, 2, 3.5, 14], "texture": "#top"},
|
||||
"down": {"uv": [3, 2, 3.5, 14], "texture": "#bottom"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [4, 14, 2],
|
||||
"to": [4.5, 16, 14],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [-1, 22, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [11.5, 0, 12, 2], "texture": "#side"},
|
||||
"east": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"south": {"uv": [4, 0, 4.5, 2], "texture": "#side"},
|
||||
"west": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"up": {"uv": [4, 2, 4.5, 14], "texture": "#top"},
|
||||
"down": {"uv": [4, 2, 4.5, 14], "texture": "#bottom"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [5, 14, 2],
|
||||
"to": [5.5, 16, 14],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [0, 22, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [10.5, 0, 11, 2], "texture": "#side"},
|
||||
"east": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"south": {"uv": [5, 0, 5.5, 2], "texture": "#side"},
|
||||
"west": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"up": {"uv": [5, 2, 5.5, 14], "texture": "#top"},
|
||||
"down": {"uv": [5, 2, 5.5, 14], "texture": "#bottom"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [6, 14, 2],
|
||||
"to": [6.5, 16, 14],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [1, 22, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [9.5, 0, 10, 2], "texture": "#side"},
|
||||
"east": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"south": {"uv": [6, 0, 6.5, 2], "texture": "#side"},
|
||||
"west": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"up": {"uv": [6, 2, 6.5, 14], "texture": "#top"},
|
||||
"down": {"uv": [6, 2, 6.5, 14], "texture": "#bottom"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [7, 14, 2],
|
||||
"to": [7.5, 16, 14],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [2, 22, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [8.5, 0, 9, 2], "texture": "#side"},
|
||||
"east": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"south": {"uv": [7, 0, 7.5, 2], "texture": "#side"},
|
||||
"west": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"up": {"uv": [7, 2, 7.5, 14], "texture": "#top"},
|
||||
"down": {"uv": [7, 2, 7.5, 14], "texture": "#bottom"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [8, 14, 2],
|
||||
"to": [8.5, 16, 14],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [3, 22, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [7.5, 0, 8, 2], "texture": "#side"},
|
||||
"east": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"south": {"uv": [8, 0, 8.5, 2], "texture": "#side"},
|
||||
"west": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"up": {"uv": [8, 2, 8.5, 14], "texture": "#top"},
|
||||
"down": {"uv": [8, 2, 8.5, 14], "texture": "#bottom"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [9, 14, 2],
|
||||
"to": [9.5, 16, 14],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [4, 22, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [6.5, 0, 7, 2], "texture": "#side"},
|
||||
"east": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"south": {"uv": [9, 0, 9.5, 2], "texture": "#side"},
|
||||
"west": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"up": {"uv": [9, 2, 9.5, 14], "texture": "#top"},
|
||||
"down": {"uv": [9, 2, 9.5, 14], "texture": "#bottom"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [10, 14, 2],
|
||||
"to": [10.5, 16, 14],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [5, 22, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [5.5, 0, 6, 2], "texture": "#side"},
|
||||
"east": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"south": {"uv": [10, 0, 10.5, 2], "texture": "#side"},
|
||||
"west": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"up": {"uv": [10, 2, 10.5, 14], "texture": "#top"},
|
||||
"down": {"uv": [10, 2, 10.5, 14], "texture": "#bottom"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [11, 14, 2],
|
||||
"to": [11.5, 16, 14],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [6, 22, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [4.5, 0, 5, 2], "texture": "#side"},
|
||||
"east": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"south": {"uv": [11, 0, 11.5, 2], "texture": "#side"},
|
||||
"west": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"up": {"uv": [11, 2, 11.5, 14], "texture": "#top"},
|
||||
"down": {"uv": [11, 2, 11.5, 14], "texture": "#bottom"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [12, 14, 2],
|
||||
"to": [12.5, 16, 14],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [7, 22, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [3.5, 0, 4, 2], "texture": "#side"},
|
||||
"east": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"south": {"uv": [12, 0, 12.5, 2], "texture": "#side"},
|
||||
"west": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"up": {"uv": [12, 2, 12.5, 14], "texture": "#top"},
|
||||
"down": {"uv": [12, 2, 12.5, 14], "texture": "#bottom"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [13, 14, 2],
|
||||
"to": [13.5, 16, 14],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [8, 22, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [2.5, 0, 3, 2], "texture": "#side"},
|
||||
"east": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"south": {"uv": [13, 0, 13.5, 2], "texture": "#side"},
|
||||
"west": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"up": {"uv": [13, 2, 13.5, 14], "texture": "#top"},
|
||||
"down": {"uv": [13, 2, 13.5, 14], "texture": "#bottom"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [0, 15, 0],
|
||||
"to": [2, 16, 16],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [-6, 22, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [14, 0, 16, 1], "texture": "#side"},
|
||||
"east": {"uv": [0, 0, 16, 1], "texture": "#side"},
|
||||
"south": {"uv": [0, 0, 2, 1], "texture": "#side"},
|
||||
"west": {"uv": [0, 0, 16, 1], "texture": "#side"},
|
||||
"up": {"uv": [0, 0, 2, 16], "texture": "#top"},
|
||||
"down": {"uv": [0, 0, 2, 16], "texture": "#bottom"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [1, 14, 2],
|
||||
"to": [3, 15, 14],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [-5, 20, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [13, 1, 15, 2], "texture": "#side"},
|
||||
"east": {"uv": [2, 1, 14, 2], "texture": "#side"},
|
||||
"south": {"uv": [1, 1, 3, 2], "texture": "#side"},
|
||||
"west": {"uv": [2, 1, 14, 2], "texture": "#side"},
|
||||
"up": {"uv": [1, 2, 3, 14], "texture": "#top"},
|
||||
"down": {"uv": [1, 2, 3, 14], "texture": "#bottom"}
|
||||
}
|
||||
}
|
||||
],
|
||||
"display": {
|
||||
"ground": {
|
||||
"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]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"parent": "engineersdecor:block/device/small_fluid_funnel_model_s0",
|
||||
"textures": { "side": "engineersdecor:blocks/device/small_fluid_funnel_side_s1" }
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"parent": "engineersdecor:block/device/small_fluid_funnel_model_s0",
|
||||
"textures": { "side": "engineersdecor:blocks/device/small_fluid_funnel_side_s2" }
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"parent": "engineersdecor:block/device/small_fluid_funnel_model_s0",
|
||||
"textures": { "side": "engineersdecor:blocks/device/small_fluid_funnel_side_s3" }
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"conditions": [
|
||||
{
|
||||
"type": "engineersdecor:grc",
|
||||
"result": "engineersdecor:small_fluid_funnel",
|
||||
"missing": ["immersiveengineering:metal_device1"]
|
||||
}
|
||||
],
|
||||
"type": "minecraft:crafting_shaped",
|
||||
"pattern": [
|
||||
"HHH",
|
||||
"IBI",
|
||||
"III"
|
||||
],
|
||||
"key": {
|
||||
"B": {
|
||||
"item": "minecraft:bucket",
|
||||
"data": 0
|
||||
},
|
||||
"I": {
|
||||
"item": "#ingotIron",
|
||||
"data": 0
|
||||
},
|
||||
"H": {
|
||||
"item": "#anyHopper",
|
||||
"data": 0
|
||||
}
|
||||
},
|
||||
"result": {
|
||||
"item": "engineersdecor:small_fluid_funnel",
|
||||
"count": 1
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"conditions": [
|
||||
{
|
||||
"type": "engineersdecor:grc",
|
||||
"result": "engineersdecor:small_fluid_funnel",
|
||||
"required": ["immersiveengineering:metal_device1"]
|
||||
}
|
||||
],
|
||||
"type": "minecraft:crafting_shaped",
|
||||
"pattern": [
|
||||
"HHH",
|
||||
"PBP",
|
||||
"PPP"
|
||||
],
|
||||
"key": {
|
||||
"B": {
|
||||
"item": "#itemSteelBarrel",
|
||||
"data": 0
|
||||
},
|
||||
"P": {
|
||||
"item": "#plateAnyMetal",
|
||||
"data": 0
|
||||
},
|
||||
"H": {
|
||||
"item": "#anyHopper",
|
||||
"data": 0
|
||||
}
|
||||
},
|
||||
"result": {
|
||||
"item": "engineersdecor:small_fluid_funnel",
|
||||
"count": 1
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 618 B |
After Width: | Height: | Size: 572 B |
After Width: | Height: | Size: 579 B |
After Width: | Height: | Size: 575 B |
After Width: | Height: | Size: 572 B |
After Width: | Height: | Size: 431 B |
|
@ -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-b3
|
||||
version_engineersdecor=1.0.15-b4
|
||||
|
|
|
@ -11,6 +11,8 @@ Mod sources for Minecraft version 1.14.4.
|
|||
|
||||
## Version history
|
||||
|
||||
~ v1.0.15-b4 [A] Added Fluid Collection Funnel.
|
||||
|
||||
- v1.0.15-b3 [A] Added Small Block Breaker.
|
||||
[M] Mineral Smelter fluid handler/transfer added.
|
||||
|
||||
|
|
|
@ -434,6 +434,12 @@ public class ModContent
|
|||
ModAuxiliaries.getPixeledAABB(0,0,0, 16,16,16)
|
||||
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "passive_fluid_accumulator"));
|
||||
|
||||
public static final BlockDecorFluidFunnel SMALL_FLUID_FUNNEL = (BlockDecorFluidFunnel)(new BlockDecorFluidFunnel(
|
||||
BlockDecor.CFG_CUTOUT|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, "small_fluid_funnel"));
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
public static final BlockDecorWall CONCRETE_WALL = (BlockDecorWall)(new BlockDecorWall(
|
||||
|
@ -497,6 +503,11 @@ public class ModContent
|
|||
SMALL_SOLAR_PANEL,
|
||||
SMALL_WASTE_INCINERATOR,
|
||||
SMALL_MINERAL_SMELTER,
|
||||
STRAIGHT_CHECK_VALVE,
|
||||
STRAIGHT_REDSTONE_VALVE,
|
||||
STRAIGHT_REDSTONE_ANALOG_VALVE,
|
||||
PASSIVE_FLUID_ACCUMULATOR,
|
||||
SMALL_FLUID_FUNNEL,
|
||||
CLINKER_BRICK_BLOCK,
|
||||
CLINKER_BRICK_SLAB,
|
||||
CLINKER_BRICK_STAIRS,
|
||||
|
@ -558,10 +569,6 @@ public class ModContent
|
|||
};
|
||||
|
||||
private static final Block devBlocks[] = {
|
||||
STRAIGHT_CHECK_VALVE,
|
||||
STRAIGHT_REDSTONE_VALVE,
|
||||
STRAIGHT_REDSTONE_ANALOG_VALVE,
|
||||
PASSIVE_FLUID_ACCUMULATOR,
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------
|
||||
|
@ -618,6 +625,11 @@ public class ModContent
|
|||
.build(null)
|
||||
.setRegistryName(ModEngineersDecor.MODID, "te_passive_fluid_accumulator");
|
||||
|
||||
public static final TileEntityType<?> TET_SMALL_FLUID_FUNNEL = TileEntityType.Builder
|
||||
.create(BlockDecorFluidFunnel.BTileEntity::new, SMALL_FLUID_FUNNEL)
|
||||
.build(null)
|
||||
.setRegistryName(ModEngineersDecor.MODID, "te_small_fluid_funnel");
|
||||
|
||||
public static final TileEntityType<?> TET_MINERAL_SMELTER = TileEntityType.Builder
|
||||
.create(BlockDecorMineralSmelter.BTileEntity::new, SMALL_MINERAL_SMELTER)
|
||||
.build(null)
|
||||
|
@ -648,6 +660,7 @@ public class ModContent
|
|||
TET_SMALL_SOLAR_PANEL,
|
||||
TET_STRAIGHT_PIPE_VALVE,
|
||||
TET_PASSIVE_FLUID_ACCUMULATOR,
|
||||
TET_SMALL_FLUID_FUNNEL,
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------
|
||||
|
|
|
@ -40,6 +40,7 @@ public class ModEngineersDecor
|
|||
public static final String MODID = "engineersdecor";
|
||||
public static final int VERSION_DATAFIXER = 0;
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private static boolean config_loaded = false;
|
||||
|
||||
public ModEngineersDecor()
|
||||
{
|
||||
|
@ -63,6 +64,16 @@ public class ModEngineersDecor
|
|||
LOGGER.info("Registering recipe condition processor ...");
|
||||
CraftingHelper.register(Serializer.INSTANCE);
|
||||
Networking.init();
|
||||
if(config_loaded) {
|
||||
try {
|
||||
logger().info("Applying loaded config file.");
|
||||
ModConfig.apply();
|
||||
} catch(Throwable e) {
|
||||
logger().error("Failed to apply config: " + e.getMessage());
|
||||
}
|
||||
} else {
|
||||
logger().info("Cannot apply config, load event was not casted yet.");
|
||||
}
|
||||
}
|
||||
|
||||
private void onClientSetup(final FMLClientSetupEvent event)
|
||||
|
@ -101,16 +112,9 @@ public class ModEngineersDecor
|
|||
public static void onServerStarting(FMLServerStartingEvent event)
|
||||
{}
|
||||
|
||||
// @SubscribeEvent
|
||||
@SubscribeEvent
|
||||
public static void onConfigLoad(net.minecraftforge.fml.config.ModConfig.Loading configEvent)
|
||||
{
|
||||
try {
|
||||
ModEngineersDecor.logger().info("Loaded config file {}", configEvent.getConfig().getFileName());
|
||||
ModConfig.apply();
|
||||
} catch(Throwable e) {
|
||||
ModEngineersDecor.logger().error("Failed to load config: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
{ config_loaded = true; }
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onConfigFileChange(net.minecraftforge.fml.config.ModConfig.ConfigReloading configEvent)
|
||||
|
@ -128,7 +132,6 @@ public class ModEngineersDecor
|
|||
{
|
||||
event.getGenerator().addProvider(new ModLootTables(event.getGenerator()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
@ -0,0 +1,392 @@
|
|||
/*
|
||||
* @file BlockDecorFluidFunnel.java
|
||||
* @author Stefan Wilhelm (wile)
|
||||
* @copyright (C) 2019 Stefan Wilhelm
|
||||
* @license MIT (see https://opensource.org/licenses/MIT)
|
||||
*
|
||||
* A device that collects and stores fluid blocks above it.
|
||||
* Tracks flowing fluid to their source blocks. Compatible
|
||||
* with vanilla infinite water source.
|
||||
*/
|
||||
package wile.engineersdecor.blocks;
|
||||
|
||||
import wile.engineersdecor.ModContent;
|
||||
import net.minecraft.block.*;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.BlockItemUseContext;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.state.IntegerProperty;
|
||||
import net.minecraft.state.StateContainer;
|
||||
import net.minecraft.fluid.Fluid;
|
||||
import net.minecraft.fluid.Fluids;
|
||||
import net.minecraft.fluid.IFluidState;
|
||||
import net.minecraft.tileentity.ITickableTileEntity;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.tileentity.TileEntityType;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.math.*;
|
||||
import net.minecraft.world.IBlockReader;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.capabilities.ICapabilityProvider;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.fluids.*;
|
||||
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
|
||||
import net.minecraftforge.fluids.capability.IFluidHandler;
|
||||
import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
public class BlockDecorFluidFunnel extends BlockDecor
|
||||
{
|
||||
public static final int FILL_LEVEL_MAX = 3;
|
||||
public static final IntegerProperty FILL_LEVEL = IntegerProperty.create("level", 0, FILL_LEVEL_MAX);
|
||||
|
||||
public BlockDecorFluidFunnel(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(FILL_LEVEL); }
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public BlockState getStateForPlacement(BlockItemUseContext context)
|
||||
{ return super.getStateForPlacement(context).with(FILL_LEVEL, 0); }
|
||||
|
||||
@Override
|
||||
public boolean hasTileEntity(BlockState state)
|
||||
{ return true; }
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public TileEntity createTileEntity(BlockState state, IBlockReader world)
|
||||
{ return new BTileEntity(); }
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public boolean hasComparatorInputOverride(BlockState state)
|
||||
{ return true; }
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public int getComparatorInputOverride(BlockState state, World world, BlockPos pos)
|
||||
{ return MathHelper.clamp((state.get(FILL_LEVEL)*5), 0, 15); }
|
||||
|
||||
@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);
|
||||
((BTileEntity)te).markDirty();
|
||||
world.setBlockState(pos, state.with(FILL_LEVEL, 0));
|
||||
}
|
||||
|
||||
@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 = new CompoundNBT();
|
||||
((BTileEntity)te).writenbt(te_nbt);
|
||||
if(!te_nbt.isEmpty()) {
|
||||
CompoundNBT nbt = new CompoundNBT();
|
||||
nbt.put("tedata", te_nbt);
|
||||
stack.setTag(nbt);
|
||||
}
|
||||
stacks.add(stack);
|
||||
} else {
|
||||
stacks.add(new ItemStack(this, 1));
|
||||
}
|
||||
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;
|
||||
TileEntity te = world.getTileEntity(pos);
|
||||
if(!(te instanceof BTileEntity)) return false;
|
||||
return FluidUtil.interactWithFluidHandler(player, hand, world, pos, rayTraceResult.getFace());
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public void neighborChanged(BlockState state, World world, BlockPos pos, Block block, BlockPos fromPos, boolean unused)
|
||||
{ TileEntity te = world.getTileEntity(pos); if(te instanceof BTileEntity) ((BTileEntity)te).block_changed(); }
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------
|
||||
// Tile entity
|
||||
//--------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
public static class BTileEntity extends TileEntity implements ITickableTileEntity, ICapabilityProvider
|
||||
{
|
||||
public static final int TANK_CAPACITY = 3000;
|
||||
public static final int TICK_INTERVAL = 10; // ca 500ms
|
||||
public static final int COLLECTION_INTERVAL = 40; // ca 2000ms, simulates suction delay and saves CPU when not drained.
|
||||
public static final int MAX_TRACK_RADIUS = 16;
|
||||
public static final int MAX_TRACKING_STEPS_PER_CYCLE = 72;
|
||||
public static final int MAX_TRACKING_STEPS_PER_CYCLE_INTENSIVE = 1024;
|
||||
public static final int MAX_TRACK_RADIUS_SQ = MAX_TRACK_RADIUS*MAX_TRACK_RADIUS;
|
||||
public static final int INTENSIVE_SEARCH_TRIGGER_THRESHOLD = 16;
|
||||
private FluidStack tank_ = FluidStack.EMPTY.copy();
|
||||
private int tick_timer_ = 0;
|
||||
private int collection_timer_ = 0;
|
||||
private int no_fluid_found_counter_ = 0;
|
||||
private int intensive_search_counter_ = 0;
|
||||
private int total_pick_counter_ = 0;
|
||||
private BlockPos last_pick_pos_ = BlockPos.ZERO;
|
||||
private ArrayList<Vec3i> search_offsets_ = null;
|
||||
|
||||
public void block_changed()
|
||||
{ tick_timer_ = TICK_INTERVAL; } // collect after flowing fluid has a stable state, otherwise it looks odd.
|
||||
|
||||
public BTileEntity()
|
||||
{ this(ModContent.TET_SMALL_FLUID_FUNNEL); }
|
||||
|
||||
public BTileEntity(TileEntityType<?> te_type)
|
||||
{ super(te_type); }
|
||||
|
||||
public void readnbt(CompoundNBT nbt)
|
||||
{
|
||||
tank_ = (!nbt.contains("tank")) ? (FluidStack.EMPTY.copy()) : (FluidStack.loadFluidStackFromNBT(nbt.getCompound("tank")));
|
||||
}
|
||||
|
||||
public void writenbt(CompoundNBT nbt)
|
||||
{
|
||||
if(!tank_.isEmpty()) nbt.put("tank", tank_.writeToNBT(new CompoundNBT()));
|
||||
}
|
||||
|
||||
// TileEntity -----------------------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public void read(CompoundNBT nbt)
|
||||
{ super.read(nbt); readnbt(nbt); }
|
||||
|
||||
@Override
|
||||
public CompoundNBT write(CompoundNBT nbt)
|
||||
{ super.write(nbt); writenbt(nbt); return nbt; }
|
||||
|
||||
// ICapabilityProvider / Output flow handler ----------------------------------------------------------
|
||||
|
||||
private static class OutputFluidHandler implements IFluidHandler
|
||||
{
|
||||
private final BTileEntity te;
|
||||
OutputFluidHandler(BTileEntity parent) { te = parent; }
|
||||
@Override public int getTanks() { return 1; }
|
||||
@Override public FluidStack getFluidInTank(int tank) { return te.tank_.copy(); }
|
||||
@Override public int getTankCapacity(int tank) { return TANK_CAPACITY; }
|
||||
@Override public boolean isFluidValid(int tank, @Nonnull FluidStack stack) { return true; }
|
||||
@Override public int fill(FluidStack resource, FluidAction action) { return 0; }
|
||||
|
||||
@Override public FluidStack drain(FluidStack resource, FluidAction action)
|
||||
{
|
||||
if((resource==null) || (te.tank_.isEmpty())) return FluidStack.EMPTY.copy();
|
||||
return (!(te.tank_.isFluidEqual(resource))) ? (FluidStack.EMPTY.copy()) : drain(resource.getAmount(), action);
|
||||
}
|
||||
|
||||
@Override public FluidStack drain(int maxDrain, FluidAction action)
|
||||
{
|
||||
FluidStack res = te.tank_.copy();
|
||||
if(res.isEmpty()) return res;
|
||||
maxDrain = MathHelper.clamp(maxDrain ,0 , te.tank_.getAmount());
|
||||
res.setAmount(maxDrain);
|
||||
if(action != FluidAction.EXECUTE) return res;
|
||||
te.tank_.setAmount(te.tank_.getAmount()-maxDrain);
|
||||
if(te.tank_.getAmount() <= 0) te.tank_ = FluidStack.EMPTY.copy();
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
private final LazyOptional<IFluidHandler> fluid_handler_ = LazyOptional.of(() -> new OutputFluidHandler(this));
|
||||
|
||||
@Override
|
||||
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing)
|
||||
{
|
||||
if(capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) return fluid_handler_.cast();
|
||||
return super.getCapability(capability, facing);
|
||||
}
|
||||
|
||||
// ITickableTileEntity --------------------------------------------------------------------------------
|
||||
|
||||
private IFluidState get_fluidstate(BlockPos pos)
|
||||
{
|
||||
// todo: check if getFluidState() is enough
|
||||
final Block collection_block = world.getBlockState(pos).getBlock();
|
||||
if((!(collection_block instanceof IFluidBlock)) && (!(collection_block instanceof FlowingFluidBlock)) && (!(collection_block instanceof IWaterLoggable))) {
|
||||
return Fluids.EMPTY.getDefaultState();
|
||||
}
|
||||
return world.getFluidState(pos);
|
||||
}
|
||||
|
||||
private boolean try_pick(BlockPos pos, IFluidState fluidstate)
|
||||
{
|
||||
if(!fluidstate.isSource()) return false;
|
||||
IFluidHandler hnd = FluidUtil.getFluidHandler(world, pos, null).orElse(null);
|
||||
FluidStack fs;
|
||||
if(hnd != null) {
|
||||
fs = hnd.drain(TANK_CAPACITY, FluidAction.EXECUTE); // IFluidBlock
|
||||
} else {
|
||||
fs = new FluidStack(fluidstate.getFluid(), 1000);
|
||||
BlockState state = world.getBlockState(pos);
|
||||
if(state instanceof IBucketPickupHandler) {
|
||||
((IBucketPickupHandler)state).pickupFluid(world, pos, state);
|
||||
} else {
|
||||
world.setBlockState(pos, Blocks.AIR.getDefaultState(), 1|2); // ok we can't leave the block, that would be an infinite source of an unknown fluid.
|
||||
}
|
||||
}
|
||||
if((fs==null) || (fs.isEmpty())) return false; // it's marked nonnull but I don't trust every modder - including meself ...
|
||||
if(tank_.isEmpty()) {
|
||||
tank_ = fs.copy();
|
||||
} else if(tank_.isFluidEqual(fs)) {
|
||||
tank_.setAmount(MathHelper.clamp(tank_.getAmount()+fs.getAmount(), 0, TANK_CAPACITY));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean can_pick(BlockPos pos, IFluidState fluidstate)
|
||||
{
|
||||
if(fluidstate.isSource()) return true;
|
||||
IFluidHandler hnd = FluidUtil.getFluidHandler(world, pos, null).orElse(null);
|
||||
if(hnd == null) return false;
|
||||
FluidStack fs = hnd.drain(TANK_CAPACITY, FluidAction.SIMULATE); // don't trust that everyone returns nonnull
|
||||
return ((fs!=null) && (!fs.isEmpty())) && (fluidstate.getFluid().isEquivalentTo(fs.getFluid()));
|
||||
}
|
||||
|
||||
private void rebuild_search_offsets(boolean intensive)
|
||||
{
|
||||
search_offsets_ = new ArrayList<>(9);
|
||||
search_offsets_.add(new Vec3i(0, 1, 0)); // up first
|
||||
{
|
||||
ArrayList<Vec3i> ofs = new ArrayList<Vec3i>(Arrays.asList(new Vec3i(-1, 0, 0), new Vec3i( 1, 0, 0), new Vec3i( 0, 0,-1), new Vec3i( 0, 0, 1)));
|
||||
if(intensive || (total_pick_counter_ > 50)) Collections.shuffle(ofs);
|
||||
search_offsets_.addAll(ofs);
|
||||
}
|
||||
if(intensive) {
|
||||
ArrayList<Vec3i> ofs = new ArrayList<Vec3i>(Arrays.asList(new Vec3i(-1, 1, 0), new Vec3i( 1, 1, 0), new Vec3i( 0, 1,-1), new Vec3i( 0, 1, 1)));
|
||||
Collections.shuffle(ofs);
|
||||
search_offsets_.addAll(ofs);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean try_collect(final BlockPos collection_pos)
|
||||
{
|
||||
IFluidState collection_fluidstate = get_fluidstate(collection_pos);
|
||||
if(collection_fluidstate.isEmpty()) return false;
|
||||
Fluid fluid_to_collect = collection_fluidstate.getFluid();
|
||||
if((!tank_.isEmpty()) && (!tank_.getFluid().isEquivalentTo(fluid_to_collect))) return false;
|
||||
if(try_pick(collection_pos, collection_fluidstate)) { last_pick_pos_ = collection_pos; return true; } // Blocks directly always first. Allows water source blocks to recover/reflow to source blocks.
|
||||
if((last_pick_pos_==null) || (last_pick_pos_.distanceSq(collection_pos) > MAX_TRACK_RADIUS_SQ)) { last_pick_pos_ = collection_pos; search_offsets_ = null; }
|
||||
BlockPos pos = last_pick_pos_;
|
||||
HashSet<BlockPos> checked = new HashSet<>();
|
||||
Stack<BlockPos> trail = new Stack<BlockPos>();
|
||||
trail.add(pos);
|
||||
checked.add(pos);
|
||||
int steps=0;
|
||||
boolean intensive = (no_fluid_found_counter_ >= INTENSIVE_SEARCH_TRIGGER_THRESHOLD);
|
||||
if(intensive) { no_fluid_found_counter_ = 0; ++intensive_search_counter_; }
|
||||
if(search_offsets_ == null) rebuild_search_offsets(intensive);
|
||||
int max = intensive ? MAX_TRACKING_STEPS_PER_CYCLE_INTENSIVE : MAX_TRACKING_STEPS_PER_CYCLE;
|
||||
while(++steps <= max) {
|
||||
int num_adjacent = 0;
|
||||
for(int i=0; i<search_offsets_.size(); ++i) {
|
||||
BlockPos p = pos.add(search_offsets_.get(i));
|
||||
if(checked.contains(p)) continue;
|
||||
checked.add(p);
|
||||
++steps;
|
||||
IFluidState fluidstate = get_fluidstate(p);
|
||||
|
||||
// @todo: nice thing in 1.14: the fluid level is easily readable,
|
||||
// so lateral motion can be restricted to higher fill levels.
|
||||
|
||||
if(fluidstate.getFluid().isEquivalentTo(fluid_to_collect)) {
|
||||
++num_adjacent;
|
||||
pos = p;
|
||||
trail.push(pos);
|
||||
if(steps < MAX_TRACKING_STEPS_PER_CYCLE_INTENSIVE/2) {
|
||||
// check for same fluid above (only source blocks)
|
||||
final int max_surface_search = (MAX_TRACKING_STEPS_PER_CYCLE_INTENSIVE/2)-steps;
|
||||
for(int k=0; k<max_surface_search; ++k) {
|
||||
IFluidState fs = get_fluidstate(pos.up());
|
||||
if(!can_pick(pos.up(), fs)) break;
|
||||
fluidstate = fs;
|
||||
pos = pos.up();
|
||||
trail.push(pos);
|
||||
}
|
||||
}
|
||||
if(try_pick(pos, fluidstate)) {
|
||||
last_pick_pos_ = pos;
|
||||
no_fluid_found_counter_ = 0;
|
||||
search_offsets_ = null;
|
||||
// probability reset, so it's not turteling too far away, mainly for large nether lava seas, not desert lakes.
|
||||
if((++total_pick_counter_ > 50) && world.rand.nextInt(10)==0) last_pick_pos_ = collection_pos;
|
||||
//println("PASS " + steps + " - " + (pos.subtract(collection_pos)));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(trail.isEmpty()) break; // reset search
|
||||
if(num_adjacent==0) pos = trail.pop();
|
||||
}
|
||||
//println("FAIL=" + steps + " - " + (pos.subtract(collection_pos)));
|
||||
//String s = new String(); for(BlockPos p:checked) s += "\n" + p; println(s);
|
||||
if(intensive_search_counter_ > 2) world.removeBlock(pos, false);
|
||||
last_pick_pos_ = collection_pos;
|
||||
search_offsets_ = null; // try other search order
|
||||
++no_fluid_found_counter_;
|
||||
return false;
|
||||
}
|
||||
|
||||
public void tick()
|
||||
{
|
||||
if((world.isRemote) || (--tick_timer_ > 0)) return;
|
||||
tick_timer_ = TICK_INTERVAL;
|
||||
collection_timer_ += TICK_INTERVAL;
|
||||
boolean dirty = false;
|
||||
// Collection
|
||||
if((collection_timer_ >= COLLECTION_INTERVAL) && ((tank_==null) || (tank_.getAmount() <= (TANK_CAPACITY-1000)))) {
|
||||
collection_timer_ = 0;
|
||||
if(!world.isBlockPowered(pos)) { // redstone disable feature
|
||||
if(last_pick_pos_==null) last_pick_pos_ = pos.up();
|
||||
if(try_collect(pos.up())) dirty = true;
|
||||
}
|
||||
}
|
||||
// Gravity fluid transfer
|
||||
if((tank_.getAmount() >= 1000)) {
|
||||
IFluidHandler fh = FluidUtil.getFluidHandler(world, pos.down(), Direction.UP).orElse(null);
|
||||
if(fh != null) {
|
||||
FluidStack fs = new FluidStack(tank_.getFluid(), 1000);
|
||||
int nfilled = MathHelper.clamp(fh.fill(fs, FluidAction.EXECUTE), 0, 1000);
|
||||
tank_.shrink(nfilled);
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
// Block state
|
||||
int fill_level = (tank_==null) ? 0 : (MathHelper.clamp(tank_.getAmount()/1000,0,FILL_LEVEL_MAX));
|
||||
final BlockState funnel_state = world.getBlockState(pos);
|
||||
if(funnel_state.get(FILL_LEVEL) != fill_level) world.setBlockState(pos, funnel_state.with(FILL_LEVEL, fill_level), 2|16);
|
||||
if(dirty) markDirty();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -484,7 +484,7 @@ public class BlockDecorMineralSmelter extends BlockDecorDirectedHorizontal
|
|||
@Override
|
||||
public FluidStack drain(FluidStack resource, FluidAction action)
|
||||
{
|
||||
if(!resource.isFluidEqual(lava) || (te.fluid_level() <= 0)) return FluidStack.EMPTY;
|
||||
if(!resource.isFluidEqual(lava) || (te.fluid_level() <= 0)) return FluidStack.EMPTY.copy();
|
||||
FluidStack stack = new FluidStack(lava, te.fluid_level());
|
||||
if(action == FluidAction.EXECUTE) te.fluid_level_drain(te.fluid_level());
|
||||
return stack;
|
||||
|
@ -493,7 +493,7 @@ public class BlockDecorMineralSmelter extends BlockDecorDirectedHorizontal
|
|||
@Override
|
||||
public FluidStack drain(int maxDrain, FluidAction action)
|
||||
{
|
||||
if(te.fluid_level() <= 0) return FluidStack.EMPTY;
|
||||
if(te.fluid_level() <= 0) return FluidStack.EMPTY.copy();
|
||||
maxDrain = (action==FluidAction.EXECUTE) ? (te.fluid_level_drain(maxDrain)) : (Math.min(maxDrain, te.fluid_level()));
|
||||
return new FluidStack(lava, maxDrain);
|
||||
}
|
||||
|
|
|
@ -15,21 +15,23 @@ package wile.engineersdecor.blocks;
|
|||
|
||||
import wile.engineersdecor.ModContent;
|
||||
import wile.engineersdecor.detail.ModAuxiliaries;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.util.math.BlockRayTraceResult;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.tileentity.TileEntityType;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.IBlockReader;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.tileentity.TileEntityType;
|
||||
import net.minecraft.tileentity.ITickableTileEntity;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.util.math.BlockRayTraceResult;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.common.capabilities.ICapabilityProvider;
|
||||
import net.minecraftforge.fluids.FluidStack;
|
||||
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
|
||||
import net.minecraftforge.fluids.capability.IFluidHandler;
|
||||
|
@ -67,7 +69,6 @@ public class BlockDecorPassiveFluidAccumulator extends BlockDecorDirected
|
|||
@SuppressWarnings("deprecation")
|
||||
public void neighborChanged(BlockState state, World world, BlockPos pos, Block block, BlockPos fromPos, boolean unused)
|
||||
{
|
||||
// @todo double check if this is actually needed
|
||||
TileEntity te = world.getTileEntity(pos);
|
||||
if(te instanceof BlockDecorPipeValve.BTileEntity) ((BTileEntity)te).block_changed();
|
||||
}
|
||||
|
@ -76,7 +77,7 @@ public class BlockDecorPassiveFluidAccumulator extends BlockDecorDirected
|
|||
// Tile entity
|
||||
//--------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
public static class BTileEntity extends TileEntity // implements ITickableTileEntity, IFluidHandler, IFluidTankProperties, ICapabilityProvider
|
||||
public static class BTileEntity extends TileEntity implements ITickableTileEntity, ICapabilityProvider
|
||||
{
|
||||
protected static int tick_idle_interval = 20; // ca 1000ms, simulates suction delay and saves CPU when not drained.
|
||||
protected static int max_flowrate = 1000;
|
||||
|
@ -99,7 +100,30 @@ public class BlockDecorPassiveFluidAccumulator extends BlockDecorDirected
|
|||
public void block_changed()
|
||||
{ initialized_ = false; tick_timer_ = MathHelper.clamp(tick_timer_ , 0, tick_idle_interval); }
|
||||
|
||||
// Output flow handler ---------------------------------------------------------------------
|
||||
// TileEntity ------------------------------------------------------------------------------
|
||||
|
||||
public BTileEntity()
|
||||
{ this(ModContent.TET_PASSIVE_FLUID_ACCUMULATOR); }
|
||||
|
||||
public BTileEntity(TileEntityType<?> te_type)
|
||||
{ super(te_type); }
|
||||
|
||||
@Override
|
||||
public void read(CompoundNBT nbt)
|
||||
{
|
||||
super.read(nbt);
|
||||
tank_ = (!nbt.contains("tank")) ? (FluidStack.EMPTY.copy()) : (FluidStack.loadFluidStackFromNBT(nbt.getCompound("tank")));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundNBT write(CompoundNBT nbt)
|
||||
{
|
||||
super.write(nbt);
|
||||
if(!tank_.isEmpty()) nbt.put("tank", tank_.writeToNBT(new CompoundNBT()));
|
||||
return nbt;
|
||||
}
|
||||
|
||||
// Input flow handler ---------------------------------------------------------------------
|
||||
|
||||
private static class InputFillHandler implements IFluidHandler
|
||||
{
|
||||
|
@ -114,7 +138,7 @@ public class BlockDecorPassiveFluidAccumulator extends BlockDecorDirected
|
|||
@Override public FluidStack drain(int maxDrain, FluidAction action) { return FluidStack.EMPTY.copy(); }
|
||||
}
|
||||
|
||||
// Input flow handler ---------------------------------------------------------------------
|
||||
// Output flow handler ---------------------------------------------------------------------
|
||||
|
||||
private static class OutputFlowHandler implements IFluidHandler
|
||||
{
|
||||
|
@ -148,29 +172,6 @@ public class BlockDecorPassiveFluidAccumulator extends BlockDecorDirected
|
|||
}
|
||||
}
|
||||
|
||||
// TileEntity ------------------------------------------------------------------------------
|
||||
|
||||
public BTileEntity()
|
||||
{ this(ModContent.TET_PASSIVE_FLUID_ACCUMULATOR); }
|
||||
|
||||
public BTileEntity(TileEntityType<?> te_type)
|
||||
{ super(te_type); }
|
||||
|
||||
@Override
|
||||
public void read(CompoundNBT nbt)
|
||||
{
|
||||
super.read(nbt);
|
||||
tank_ = (!nbt.contains("tank")) ? (FluidStack.EMPTY.copy()) : (FluidStack.loadFluidStackFromNBT(nbt.getCompound("tank")));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundNBT write(CompoundNBT nbt)
|
||||
{
|
||||
super.write(nbt);
|
||||
if(!tank_.isEmpty()) nbt.put("tank", tank_.writeToNBT(new CompoundNBT()));
|
||||
return nbt;
|
||||
}
|
||||
|
||||
// ICapabilityProvider --------------------------------------------------------------------
|
||||
|
||||
private final LazyOptional<IFluidHandler> fluid_handler_ = LazyOptional.of(() -> new OutputFlowHandler(this));
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"forge_marker": 1,
|
||||
"defaults": { "model": "engineersdecor:block/device/small_fluid_funnel_model_s0" },
|
||||
"variants": {
|
||||
"level": {
|
||||
"0":{},
|
||||
"1":{"model": "engineersdecor:block/device/small_fluid_funnel_model_s1"},
|
||||
"2":{"model": "engineersdecor:block/device/small_fluid_funnel_model_s2"},
|
||||
"3":{"model": "engineersdecor:block/device/small_fluid_funnel_model_s3"}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -155,6 +155,8 @@
|
|||
"block.engineersdecor.straight_pipe_valve_redstone_analog.help": "§6Straight fluid pipe fragment.§r Conducts fluids only in one direction. Does not connect to the sides. Sneak to place in reverse direction. Blocks if not redstone powered, reduces the flow rate linear from power 1 to 14, opens to maximum possible valve flow rate for power 15.",
|
||||
"block.engineersdecor.passive_fluid_accumulator": "Passive Fluid Accumulator",
|
||||
"block.engineersdecor.passive_fluid_accumulator.help": "§6Vacuum suction based fluid collector.§r Has one output, all other sides are input. Drains fluids from adjacent tanks when being drained from the output port by a pump.",
|
||||
"block.engineersdecor.small_fluid_funnel": "Small Fluid Collection Funnel",
|
||||
"block.engineersdecor.small_fluid_funnel.help": "§6Collects fluids above it.§r Has an internal tank with three buckets capacity. Traces flowing fluids to nearby source blocks. The fluid can be obtained with fluid transfer systems or a bucket. Fills only tanks below (gravity transfer). Compatible with vanilla infinite-water-source creation.",
|
||||
"block.engineersdecor.factory_dropper": "Factory Dropper",
|
||||
"block.engineersdecor.factory_dropper.help": "§6Dropper suitable for advanced factory automation.§r Has twelve round-robin selected slots. Drop force, angle, stack size, and cool-down delay adjustable using sliders in the GUI. Three stack compare slots (below the inventory slots) with logical AND or OR can be used as internal trigger source. The internal trigger can be AND'ed or OR'ed with the external redstone signal trigger. Trigger simulation buttons for testing. Pre-opens shutter door when internal trigger conditions are met. Drops all matching stacks simultaneously. Simply click on all elements in the GUI to see how it works.",
|
||||
"block.engineersdecor.factory_hopper": "Factory Hopper",
|
||||
|
|
|
@ -151,6 +151,7 @@
|
|||
"block.engineersdecor.straight_pipe_valve_redstone_analog.help": "§6Фрагмент прямой трубы.§r Проводит жидкости только в одном направлении. Не соединяется по бокам. SHIFT для размещения в обратном направлении. Не пропускает при отсутствии сигнала красного камня, уменьшает расход линейно с мощности 1 до 14, открывается максимально-возможно при уровне сигнала красного камня 15.",
|
||||
"block.engineersdecor.passive_fluid_accumulator": "Пассивный жидкостный накопитель",
|
||||
"block.engineersdecor.passive_fluid_accumulator.help": "§6Вакуумный всасывающий жидкостный коллектор.§r Имеет один выход, все остальные стороны входные. Сливает жидкости из соседних резервуаров при выкачивании жидкости из выходного порта.",
|
||||
"block.engineersdecor.small_fluid_funnel": "Small Fluid Collection Funnel",
|
||||
"block.engineersdecor.factory_dropper": "Фабричный выбрасыватель",
|
||||
"block.engineersdecor.factory_dropper.help": "§6Выбрасыватель подходит для продвинутой автоматизации производства.§r Имеет 12 выборочных слотов. Сила броска, угол, размер стопки и задержка настраиваются в GUI. 3 слота сравнения стека с логическим И или ИЛИ могут использоваться в качестве внутреннего источника запуска. Внутренний триггер может быть И или ИЛИ с внешним триггерным сигналом красного камня. Триггерные кнопки симуляции для тестирования. Предварительно открывает дверцу затвора, когда выполняются условия внутреннего запуска. Сбрасывает все соответствующие стеки одновременно. Нажмите на все элементы в GUI, чтобы увидеть, как это работает.",
|
||||
"block.engineersdecor.factory_hopper": "Factory Hopper",
|
||||
|
|
|
@ -154,6 +154,7 @@
|
|||
"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.small_fluid_funnel": "Small Fluid Collection Funnel",
|
||||
"block.engineersdecor.factory_dropper": "工厂掉落器",
|
||||
"block.engineersdecor.factory_dropper.help": "§6适用于高级工厂自动化的掉落器。§r有十二个轮询选择的储物格。 掉落的力度、角度、一叠数量和冷却延时可在GUI调节。三个 内部比较槽带有逻辑与或逻辑或功能,可用作内部触发源。内部触发 还能和外部红石信号触发再进行逻辑与或逻辑或。触发模拟按钮仅作测试用途。 当内部触发条件满足时,预先打开卷帘门。所有符合条件的物品 会同时掉落。点击GUI的各处来了解如何运作。",
|
||||
"block.engineersdecor.factory_hopper": "Factory Hopper",
|
||||
|
|
|
@ -0,0 +1,295 @@
|
|||
{
|
||||
"parent": "block/cube",
|
||||
"textures": {
|
||||
"top": "engineersdecor:block/device/small_fluid_funnel_top",
|
||||
"bottom": "engineersdecor:block/device/small_fluid_funnel_bottom",
|
||||
"side": "engineersdecor:block/device/small_fluid_funnel_side_s0",
|
||||
"particle": "engineersdecor:block/device/small_fluid_funnel_side_s0"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"from": [0, 0, 0],
|
||||
"to": [16, 14, 16],
|
||||
"faces": {
|
||||
"north": {"uv": [0, 2, 16, 16], "texture": "#side"},
|
||||
"east": {"uv": [0, 2, 16, 16], "texture": "#side"},
|
||||
"south": {"uv": [0, 2, 16, 16], "texture": "#side"},
|
||||
"west": {"uv": [0, 2, 16, 16], "texture": "#side"},
|
||||
"up": {"uv": [0, 0, 16, 16], "texture": "#top"},
|
||||
"down": {"uv": [0, 0, 16, 16], "texture": "#bottom"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [14, 15, 0],
|
||||
"to": [16, 16, 16],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [8, 22, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [0, 0, 2, 1], "texture": "#side"},
|
||||
"east": {"uv": [0, 0, 16, 1], "texture": "#side"},
|
||||
"south": {"uv": [14, 0, 16, 1], "texture": "#side"},
|
||||
"west": {"uv": [0, 0, 16, 1], "texture": "#side"},
|
||||
"up": {"uv": [14, 0, 16, 16], "texture": "#top"},
|
||||
"down": {"uv": [14, 0, 16, 16], "texture": "#bottom"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [13, 14, 2],
|
||||
"to": [15, 15, 14],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [7, 20, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [1, 1, 3, 2], "texture": "#side"},
|
||||
"east": {"uv": [2, 1, 14, 2], "texture": "#side"},
|
||||
"south": {"uv": [13, 1, 15, 2], "texture": "#side"},
|
||||
"west": {"uv": [2, 1, 14, 2], "texture": "#side"},
|
||||
"up": {"uv": [13, 2, 15, 14], "texture": "#top"},
|
||||
"down": {"uv": [13, 2, 15, 14], "texture": "#bottom"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [2, 15, 0],
|
||||
"to": [15, 16, 2],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [5, 22, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [1, 0, 14, 1], "texture": "#side"},
|
||||
"east": {"uv": [14, 0, 16, 1], "texture": "#side"},
|
||||
"south": {"uv": [2, 0, 15, 1], "texture": "#side"},
|
||||
"west": {"uv": [0, 0, 2, 1], "texture": "#side"},
|
||||
"up": {"uv": [2, 0, 15, 2], "texture": "#top"},
|
||||
"down": {"uv": [2, 14, 15, 16], "texture": "#bottom"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [3, 14, 1],
|
||||
"to": [13, 15, 3],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [5, 20, 9]},
|
||||
"faces": {
|
||||
"north": {"uv": [3, 1, 13, 2], "texture": "#side"},
|
||||
"east": {"uv": [13, 1, 15, 2], "texture": "#side"},
|
||||
"south": {"uv": [3, 1, 13, 2], "texture": "#side"},
|
||||
"west": {"uv": [1, 1, 3, 2], "texture": "#side"},
|
||||
"up": {"uv": [3, 1, 13, 3], "texture": "#top"},
|
||||
"down": {"uv": [3, 13, 13, 15], "texture": "#bottom"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [2, 15, 14],
|
||||
"to": [15, 16, 16],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [5, 22, 22]},
|
||||
"faces": {
|
||||
"north": {"uv": [1, 0, 14, 1], "texture": "#side"},
|
||||
"east": {"uv": [0, 0, 2, 1], "texture": "#side"},
|
||||
"south": {"uv": [2, 0, 15, 1], "texture": "#side"},
|
||||
"west": {"uv": [14, 0, 16, 1], "texture": "#side"},
|
||||
"up": {"uv": [2, 14, 15, 16], "texture": "#top"},
|
||||
"down": {"uv": [2, 0, 15, 2], "texture": "#bottom"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [3, 14, 13],
|
||||
"to": [13, 15, 15],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [5, 20, 21]},
|
||||
"faces": {
|
||||
"north": {"uv": [3, 1, 13, 2], "texture": "#side"},
|
||||
"east": {"uv": [1, 1, 3, 2], "texture": "#side"},
|
||||
"south": {"uv": [3, 1, 13, 2], "texture": "#side"},
|
||||
"west": {"uv": [13, 1, 15, 2], "texture": "#side"},
|
||||
"up": {"uv": [3, 13, 13, 15], "texture": "#top"},
|
||||
"down": {"uv": [3, 1, 13, 3], "texture": "#bottom"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [2, 14, 2],
|
||||
"to": [2.5, 16, 14],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [-4, 22, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [13.5, 0, 14, 2], "texture": "#side"},
|
||||
"east": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"south": {"uv": [2, 0, 2.5, 2], "texture": "#side"},
|
||||
"west": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"up": {"uv": [2, 2, 2.5, 14], "texture": "#top"},
|
||||
"down": {"uv": [2, 2, 2.5, 14], "texture": "#bottom"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [3, 14, 2],
|
||||
"to": [3.5, 16, 14],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [-3, 22, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [12.5, 0, 13, 2], "texture": "#side"},
|
||||
"east": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"south": {"uv": [3, 0, 3.5, 2], "texture": "#side"},
|
||||
"west": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"up": {"uv": [3, 2, 3.5, 14], "texture": "#top"},
|
||||
"down": {"uv": [3, 2, 3.5, 14], "texture": "#bottom"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [4, 14, 2],
|
||||
"to": [4.5, 16, 14],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [-1, 22, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [11.5, 0, 12, 2], "texture": "#side"},
|
||||
"east": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"south": {"uv": [4, 0, 4.5, 2], "texture": "#side"},
|
||||
"west": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"up": {"uv": [4, 2, 4.5, 14], "texture": "#top"},
|
||||
"down": {"uv": [4, 2, 4.5, 14], "texture": "#bottom"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [5, 14, 2],
|
||||
"to": [5.5, 16, 14],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [0, 22, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [10.5, 0, 11, 2], "texture": "#side"},
|
||||
"east": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"south": {"uv": [5, 0, 5.5, 2], "texture": "#side"},
|
||||
"west": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"up": {"uv": [5, 2, 5.5, 14], "texture": "#top"},
|
||||
"down": {"uv": [5, 2, 5.5, 14], "texture": "#bottom"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [6, 14, 2],
|
||||
"to": [6.5, 16, 14],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [1, 22, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [9.5, 0, 10, 2], "texture": "#side"},
|
||||
"east": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"south": {"uv": [6, 0, 6.5, 2], "texture": "#side"},
|
||||
"west": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"up": {"uv": [6, 2, 6.5, 14], "texture": "#top"},
|
||||
"down": {"uv": [6, 2, 6.5, 14], "texture": "#bottom"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [7, 14, 2],
|
||||
"to": [7.5, 16, 14],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [2, 22, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [8.5, 0, 9, 2], "texture": "#side"},
|
||||
"east": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"south": {"uv": [7, 0, 7.5, 2], "texture": "#side"},
|
||||
"west": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"up": {"uv": [7, 2, 7.5, 14], "texture": "#top"},
|
||||
"down": {"uv": [7, 2, 7.5, 14], "texture": "#bottom"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [8, 14, 2],
|
||||
"to": [8.5, 16, 14],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [3, 22, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [7.5, 0, 8, 2], "texture": "#side"},
|
||||
"east": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"south": {"uv": [8, 0, 8.5, 2], "texture": "#side"},
|
||||
"west": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"up": {"uv": [8, 2, 8.5, 14], "texture": "#top"},
|
||||
"down": {"uv": [8, 2, 8.5, 14], "texture": "#bottom"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [9, 14, 2],
|
||||
"to": [9.5, 16, 14],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [4, 22, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [6.5, 0, 7, 2], "texture": "#side"},
|
||||
"east": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"south": {"uv": [9, 0, 9.5, 2], "texture": "#side"},
|
||||
"west": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"up": {"uv": [9, 2, 9.5, 14], "texture": "#top"},
|
||||
"down": {"uv": [9, 2, 9.5, 14], "texture": "#bottom"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [10, 14, 2],
|
||||
"to": [10.5, 16, 14],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [5, 22, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [5.5, 0, 6, 2], "texture": "#side"},
|
||||
"east": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"south": {"uv": [10, 0, 10.5, 2], "texture": "#side"},
|
||||
"west": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"up": {"uv": [10, 2, 10.5, 14], "texture": "#top"},
|
||||
"down": {"uv": [10, 2, 10.5, 14], "texture": "#bottom"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [11, 14, 2],
|
||||
"to": [11.5, 16, 14],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [6, 22, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [4.5, 0, 5, 2], "texture": "#side"},
|
||||
"east": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"south": {"uv": [11, 0, 11.5, 2], "texture": "#side"},
|
||||
"west": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"up": {"uv": [11, 2, 11.5, 14], "texture": "#top"},
|
||||
"down": {"uv": [11, 2, 11.5, 14], "texture": "#bottom"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [12, 14, 2],
|
||||
"to": [12.5, 16, 14],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [7, 22, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [3.5, 0, 4, 2], "texture": "#side"},
|
||||
"east": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"south": {"uv": [12, 0, 12.5, 2], "texture": "#side"},
|
||||
"west": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"up": {"uv": [12, 2, 12.5, 14], "texture": "#top"},
|
||||
"down": {"uv": [12, 2, 12.5, 14], "texture": "#bottom"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [13, 14, 2],
|
||||
"to": [13.5, 16, 14],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [8, 22, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [2.5, 0, 3, 2], "texture": "#side"},
|
||||
"east": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"south": {"uv": [13, 0, 13.5, 2], "texture": "#side"},
|
||||
"west": {"uv": [2, 0, 14, 2], "texture": "#side"},
|
||||
"up": {"uv": [13, 2, 13.5, 14], "texture": "#top"},
|
||||
"down": {"uv": [13, 2, 13.5, 14], "texture": "#bottom"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [0, 15, 0],
|
||||
"to": [2, 16, 16],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [-6, 22, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [14, 0, 16, 1], "texture": "#side"},
|
||||
"east": {"uv": [0, 0, 16, 1], "texture": "#side"},
|
||||
"south": {"uv": [0, 0, 2, 1], "texture": "#side"},
|
||||
"west": {"uv": [0, 0, 16, 1], "texture": "#side"},
|
||||
"up": {"uv": [0, 0, 2, 16], "texture": "#top"},
|
||||
"down": {"uv": [0, 0, 2, 16], "texture": "#bottom"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [1, 14, 2],
|
||||
"to": [3, 15, 14],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [-5, 20, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [13, 1, 15, 2], "texture": "#side"},
|
||||
"east": {"uv": [2, 1, 14, 2], "texture": "#side"},
|
||||
"south": {"uv": [1, 1, 3, 2], "texture": "#side"},
|
||||
"west": {"uv": [2, 1, 14, 2], "texture": "#side"},
|
||||
"up": {"uv": [1, 2, 3, 14], "texture": "#top"},
|
||||
"down": {"uv": [1, 2, 3, 14], "texture": "#bottom"}
|
||||
}
|
||||
}
|
||||
],
|
||||
"display": {
|
||||
"ground": {
|
||||
"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]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"parent": "engineersdecor:block/device/small_fluid_funnel_model_s0",
|
||||
"textures": { "side": "engineersdecor:block/device/small_fluid_funnel_side_s1" }
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"parent": "engineersdecor:block/device/small_fluid_funnel_model_s0",
|
||||
"textures": { "side": "engineersdecor:block/device/small_fluid_funnel_side_s2" }
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"parent": "engineersdecor:block/device/small_fluid_funnel_model_s0",
|
||||
"textures": { "side": "engineersdecor:block/device/small_fluid_funnel_side_s3" }
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
{ "parent": "engineersdecor:block/device/small_fluid_funnel_model_s0" }
|
After Width: | Height: | Size: 618 B |
After Width: | Height: | Size: 572 B |
After Width: | Height: | Size: 579 B |
After Width: | Height: | Size: 575 B |
After Width: | Height: | Size: 572 B |
After Width: | Height: | Size: 431 B |
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"conditions": [
|
||||
{
|
||||
"type": "engineersdecor:optional",
|
||||
"result": "engineersdecor:small_fluid_funnel",
|
||||
"missing": ["immersiveengineering:metal_device1"]
|
||||
}
|
||||
],
|
||||
"type": "minecraft:crafting_shaped",
|
||||
"pattern": [
|
||||
"HHH",
|
||||
"IBI",
|
||||
"III"
|
||||
],
|
||||
"key": {
|
||||
"B": { "item": "minecraft:bucket" },
|
||||
"I": { "item": "minecraft:iron_ingot" },
|
||||
"H": { "item": "minecraft:hopper" }
|
||||
},
|
||||
"result": {
|
||||
"item": "engineersdecor:small_fluid_funnel",
|
||||
"count": 1
|
||||
}
|
||||
}
|
|
@ -1,12 +1,13 @@
|
|||
{
|
||||
"homepage": "https://www.curseforge.com/minecraft/mc-mods/engineers-decor/",
|
||||
"promos": {
|
||||
"1.12.2-recommended": "1.0.14",
|
||||
"1.12.2-latest": "1.0.15-b2",
|
||||
"1.12.2-recommended": "1.0.15",
|
||||
"1.12.2-latest": "1.0.15",
|
||||
"1.14.4-recommended": "",
|
||||
"1.14.4-latest": "1.0.15-b3"
|
||||
},
|
||||
"1.12.2": {
|
||||
"1.0.15": "[R] Release based on v1.0.15-b2. Release-to-release changes: * Added Small Block Breaker * Small Tree Cutter fixes and compatability improved. * Crafting table compat fixes.\n[M] Small Tree Cutter log detection bug fixed (issue #59).\n[M] Small Tree Cutter supports Menril chopping (issue #54).",
|
||||
"1.0.15-b2": "[A] Added Small Block Breaker\n[M] Crafting Table: Allowing NBT \"Damage\" mismatch only items that are declared damagable (issue #56).\n[M] Tree Cutter: Loosened the strict mod namespace requirement for Dynamic Trees log detection (issue #52) to enable checking DT compat mod log blocks.",
|
||||
"1.0.15-b1": "[A] Added Floor Edge Light.\n[A] Added Factory Block Placer and Planter.",
|
||||
"1.0.14": "[R] Release based on v1.0.14-b1. Release-to-release changes: * Factory Hopper added. * Small Waste Incinerator improved. * Lang updates. * Recipe fixes.",
|
||||
|
|
|
@ -168,6 +168,11 @@ looking manufacturing contraptions. Current feature set:
|
|||
finally to lava. Needs a lot of power. When the lava is cooled down in the smelter by removing
|
||||
the RF power, obsidian is generated.
|
||||
|
||||
- *Fluid Collection Funnel*: Collects fluids above it. Has an internal tank with three buckets
|
||||
capacity. Traces flowing fluids to nearby source blocks. The fluid can be obtained with fluid
|
||||
transfer systems or a bucket. Fills only tanks below (gravity). Compatible with vanilla
|
||||
infinite-water-source creation.
|
||||
|
||||
More to come slowly but steadily.
|
||||
|
||||
----
|
||||
|
|