Tree cutter fixes and compat improvements (issue #54, issue #59). Experimental Fluid Collection Funnel implementation.
This commit is contained in:
parent
8746491095
commit
7592c9d494
50 changed files with 1718 additions and 96 deletions
|
@ -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" }
|
Binary file not shown.
After Width: | Height: | Size: 618 B |
Binary file not shown.
After Width: | Height: | Size: 572 B |
Binary file not shown.
After Width: | Height: | Size: 579 B |
Binary file not shown.
After Width: | Height: | Size: 575 B |
Binary file not shown.
After Width: | Height: | Size: 572 B |
Binary file not shown.
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
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue