Extra base hopper code
This commit is contained in:
parent
b8d374b982
commit
7b134f688d
|
@ -0,0 +1,92 @@
|
||||||
|
package net.shadowfacts.extrahoppers.block.base
|
||||||
|
|
||||||
|
import net.minecraft.block.Block
|
||||||
|
import net.minecraft.block.BlockPlacementEnvironment
|
||||||
|
import net.minecraft.block.BlockState
|
||||||
|
import net.minecraft.block.entity.Hopper
|
||||||
|
import net.minecraft.entity.EntityContext
|
||||||
|
import net.minecraft.item.ItemPlacementContext
|
||||||
|
import net.minecraft.state.StateManager
|
||||||
|
import net.minecraft.state.property.Properties
|
||||||
|
import net.minecraft.util.BooleanBiFunction
|
||||||
|
import net.minecraft.util.ItemScatterer
|
||||||
|
import net.minecraft.util.math.BlockPos
|
||||||
|
import net.minecraft.util.math.Direction
|
||||||
|
import net.minecraft.util.shape.VoxelShape
|
||||||
|
import net.minecraft.util.shape.VoxelShapes
|
||||||
|
import net.minecraft.world.BlockView
|
||||||
|
import net.minecraft.world.World
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
|
abstract class BaseHopperBlock<T: BaseHopperBlockEntity>(settings: Settings): BlockWithEntity<T>(settings) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val FACING = Properties.HOPPER_FACING
|
||||||
|
// todo: redstone support
|
||||||
|
// val ENABLED = Properties.ENABLED
|
||||||
|
val TOP_SHAPE = createCuboidShape(0.0, 10.0, 0.0, 16.0, 16.0, 16.0)
|
||||||
|
val MIDDLE_SHAPE = createCuboidShape(4.0, 4.0, 4.0, 12.0, 10.0, 12.0)
|
||||||
|
val OUTSIDE_SHAPE = VoxelShapes.union(MIDDLE_SHAPE, TOP_SHAPE)
|
||||||
|
val DEFAULT_SHAPE = VoxelShapes.combineAndSimplify(OUTSIDE_SHAPE, Hopper.INSIDE_SHAPE, BooleanBiFunction.ONLY_FIRST)
|
||||||
|
val DOWN_SHAPE = VoxelShapes.union(DEFAULT_SHAPE, createCuboidShape(6.0, 0.0, 6.0, 10.0, 4.0, 10.0))
|
||||||
|
val EAST_SHAPE = VoxelShapes.union(DEFAULT_SHAPE, createCuboidShape(12.0, 4.0, 6.0, 16.0, 8.0, 10.0))
|
||||||
|
val NORTH_SHAPE = VoxelShapes.union(DEFAULT_SHAPE, createCuboidShape(6.0, 4.0, 0.0, 10.0, 8.0, 4.0))
|
||||||
|
val SOUTH_SHAPE = VoxelShapes.union(DEFAULT_SHAPE, createCuboidShape(6.0, 4.0, 12.0, 10.0, 8.0, 16.0))
|
||||||
|
val WEST_SHAPE = VoxelShapes.union(DEFAULT_SHAPE, createCuboidShape(0.0, 4.0, 6.0, 4.0, 8.0, 10.0))
|
||||||
|
val DOWN_RAY_TRACE_SHAPE = Hopper.INSIDE_SHAPE
|
||||||
|
val EAST_RAY_TRACE_SHAPE = VoxelShapes.union(Hopper.INSIDE_SHAPE, createCuboidShape(12.0, 8.0, 6.0, 16.0, 10.0, 10.0))
|
||||||
|
val NORTH_RAY_TRACE_SHAPE = VoxelShapes.union(Hopper.INSIDE_SHAPE, createCuboidShape(6.0, 8.0, 0.0, 10.0, 10.0, 4.0))
|
||||||
|
val SOUTH_RAY_TRACE_SHAPE = VoxelShapes.union(Hopper.INSIDE_SHAPE, createCuboidShape(6.0, 8.0, 12.0, 10.0, 10.0, 16.0))
|
||||||
|
val WEST_RAY_TRACE_SHAPE = VoxelShapes.union(Hopper.INSIDE_SHAPE, createCuboidShape(0.0, 8.0, 6.0, 4.0, 10.0, 10.0))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun appendProperties(builder: StateManager.Builder<Block, BlockState>) {
|
||||||
|
builder.add(FACING)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun getOutlineShape(state: BlockState, world: BlockView, pos: BlockPos, entityContext: EntityContext): VoxelShape {
|
||||||
|
return when (state.get(FACING)) {
|
||||||
|
Direction.DOWN -> DOWN_SHAPE
|
||||||
|
Direction.NORTH -> NORTH_SHAPE
|
||||||
|
Direction.SOUTH -> SOUTH_SHAPE
|
||||||
|
Direction.WEST -> WEST_SHAPE
|
||||||
|
Direction.EAST -> EAST_SHAPE
|
||||||
|
else -> DEFAULT_SHAPE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getRayTraceShape(state: BlockState, world: BlockView, pos: BlockPos): VoxelShape {
|
||||||
|
return when (state.get(FACING)) {
|
||||||
|
Direction.DOWN -> DOWN_RAY_TRACE_SHAPE
|
||||||
|
Direction.NORTH -> NORTH_RAY_TRACE_SHAPE
|
||||||
|
Direction.SOUTH -> SOUTH_RAY_TRACE_SHAPE
|
||||||
|
Direction.WEST -> WEST_RAY_TRACE_SHAPE
|
||||||
|
Direction.EAST -> EAST_RAY_TRACE_SHAPE
|
||||||
|
else -> Hopper.INSIDE_SHAPE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getPlacementState(context: ItemPlacementContext): BlockState {
|
||||||
|
val hitFacing = context.side.opposite
|
||||||
|
val facing = if (hitFacing.axis == Direction.Axis.Y) Direction.DOWN else hitFacing
|
||||||
|
return defaultState.with(FACING, facing)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBlockRemoved(oldState: BlockState, world: World, pos: BlockPos, newState: BlockState, bl: Boolean) {
|
||||||
|
if (oldState.block != newState.block) {
|
||||||
|
getBlockEntity(world, pos)?.also {
|
||||||
|
ItemScatterer.spawn(world, pos, it)
|
||||||
|
world.updateHorizontalAdjacent(pos, this)
|
||||||
|
}
|
||||||
|
super.onBlockRemoved(oldState, world, pos, newState, bl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun canPlaceAtSide(blockState: BlockState?, blockView: BlockView?, blockPos: BlockPos?, blockPlacementEnvironment: BlockPlacementEnvironment?): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,169 @@
|
||||||
|
package net.shadowfacts.extrahoppers.block.base
|
||||||
|
|
||||||
|
import net.minecraft.block.entity.BlockEntity
|
||||||
|
import net.minecraft.block.entity.BlockEntityType
|
||||||
|
import net.minecraft.block.entity.Hopper
|
||||||
|
import net.minecraft.block.entity.HopperBlockEntity
|
||||||
|
import net.minecraft.entity.Entity
|
||||||
|
import net.minecraft.entity.ItemEntity
|
||||||
|
import net.minecraft.entity.player.PlayerEntity
|
||||||
|
import net.minecraft.inventory.Inventories
|
||||||
|
import net.minecraft.inventory.Inventory
|
||||||
|
import net.minecraft.inventory.SidedInventory
|
||||||
|
import net.minecraft.item.ItemStack
|
||||||
|
import net.minecraft.nbt.CompoundTag
|
||||||
|
import net.minecraft.util.BooleanBiFunction
|
||||||
|
import net.minecraft.util.DefaultedList
|
||||||
|
import net.minecraft.util.Tickable
|
||||||
|
import net.minecraft.util.math.Direction
|
||||||
|
import net.minecraft.util.shape.VoxelShapes
|
||||||
|
import net.shadowfacts.extrahoppers.util.toVec3d
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
|
abstract class BaseHopperBlockEntity(type: BlockEntityType<*>): BlockEntity(type), Inventory, Hopper, Tickable {
|
||||||
|
|
||||||
|
protected open val inventorySize = 5
|
||||||
|
protected open val maxTransferCooldown = 8
|
||||||
|
var inventory: DefaultedList<ItemStack> = DefaultedList.ofSize(inventorySize, ItemStack.EMPTY)
|
||||||
|
protected var transferCooldown = -1
|
||||||
|
|
||||||
|
override fun toTag(tag: CompoundTag): CompoundTag {
|
||||||
|
Inventories.toTag(tag, inventory)
|
||||||
|
tag.putInt("transferCooldown", transferCooldown)
|
||||||
|
return super.toTag(tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun fromTag(tag: CompoundTag) {
|
||||||
|
super.fromTag(tag)
|
||||||
|
inventory.clear()
|
||||||
|
Inventories.fromTag(tag, inventory)
|
||||||
|
transferCooldown = tag.getInt("transferCooldown")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun tick() {
|
||||||
|
val world = world
|
||||||
|
if (world == null || world.isClient) return
|
||||||
|
|
||||||
|
transferCooldown -= 1
|
||||||
|
if (transferCooldown <= 0) {
|
||||||
|
transferCooldown = 0
|
||||||
|
insertAndExtract()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onEntityCollision(entity: Entity) {
|
||||||
|
if (entity is ItemEntity) {
|
||||||
|
if (VoxelShapes.matchesAnywhere(VoxelShapes.cuboid(entity.boundingBox.offset(-pos.x.toDouble(), -pos.y.toDouble(), -pos.z.toDouble())), inputAreaShape, BooleanBiFunction.AND)) {
|
||||||
|
insertAndExtract {
|
||||||
|
HopperBlockEntity.extract(this, entity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun insertAndExtract(extractor: (() -> Boolean)? = null) {
|
||||||
|
val world = world
|
||||||
|
if (world == null || world.isClient) return
|
||||||
|
|
||||||
|
var didWork = false
|
||||||
|
if (!isInvEmpty && insert()) {
|
||||||
|
didWork = true
|
||||||
|
}
|
||||||
|
if (!isFull() && (extractor != null && extractor()) || HopperBlockEntity.extract(this)) {
|
||||||
|
didWork = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (didWork) {
|
||||||
|
transferCooldown = maxTransferCooldown
|
||||||
|
markDirty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun insert(): Boolean {
|
||||||
|
val outputInv = getOutputInventory() ?: return false
|
||||||
|
|
||||||
|
val insertionSide = cachedState.get(BaseHopperBlock.FACING).opposite
|
||||||
|
if (isInventoryFull(outputInv, insertionSide)) return false
|
||||||
|
|
||||||
|
for (slot in 0 until invSize) {
|
||||||
|
if (getInvStack(slot).isEmpty) continue
|
||||||
|
|
||||||
|
val stackCopy = getInvStack(slot).copy()
|
||||||
|
|
||||||
|
val remaining = HopperBlockEntity.transfer(this, outputInv, takeInvStack(slot, 1), insertionSide)
|
||||||
|
if (remaining.isEmpty) {
|
||||||
|
outputInv.markDirty()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
setInvStack(slot, stackCopy)
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isFull(): Boolean {
|
||||||
|
return inventory.none(ItemStack::isEmpty)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getOutputInventory(): Inventory? {
|
||||||
|
val facing = cachedState.get(BaseHopperBlock.FACING)
|
||||||
|
return HopperBlockEntity.getInventoryAt(world!!, pos.offset(facing))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun inventorySlots(inv: Inventory, side: Direction): Sequence<Int> {
|
||||||
|
return if (inv is SidedInventory) {
|
||||||
|
inv.getInvAvailableSlots(side).asSequence()
|
||||||
|
} else {
|
||||||
|
(0 until inv.invSize).asSequence()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isInventoryFull(inv: Inventory, side: Direction): Boolean {
|
||||||
|
val slots = inventorySlots(inv, side)
|
||||||
|
return slots.map(inv::getInvStack).none(ItemStack::isEmpty)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inventory
|
||||||
|
|
||||||
|
|
||||||
|
override fun getInvSize() = inventory.size
|
||||||
|
|
||||||
|
override fun takeInvStack(slot: Int, amount: Int): ItemStack {
|
||||||
|
return Inventories.splitStack(inventory, slot, amount)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isInvEmpty() = inventory.isEmpty()
|
||||||
|
|
||||||
|
override fun getInvStack(slot: Int) = inventory[slot]
|
||||||
|
|
||||||
|
override fun clear() {
|
||||||
|
inventory.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setInvStack(slot: Int, stack: ItemStack) {
|
||||||
|
inventory[slot] = stack
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun removeInvStack(slot: Int): ItemStack {
|
||||||
|
return Inventories.removeStack(inventory, slot)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun canPlayerUseInv(player: PlayerEntity): Boolean {
|
||||||
|
return if (world?.getBlockEntity(pos) != this) {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
val distance = player.squaredDistanceTo(this.pos.toVec3d())
|
||||||
|
distance < 64
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hopper
|
||||||
|
|
||||||
|
override fun getHopperX() = pos.x.toDouble()
|
||||||
|
override fun getHopperY() = pos.y.toDouble()
|
||||||
|
override fun getHopperZ() = pos.z.toDouble()
|
||||||
|
|
||||||
|
}
|
|
@ -20,69 +20,24 @@ import net.minecraft.util.shape.VoxelShape
|
||||||
import net.minecraft.util.shape.VoxelShapes
|
import net.minecraft.util.shape.VoxelShapes
|
||||||
import net.minecraft.world.BlockView
|
import net.minecraft.world.BlockView
|
||||||
import net.minecraft.world.World
|
import net.minecraft.world.World
|
||||||
|
import net.shadowfacts.extrahoppers.block.base.BaseHopperBlock
|
||||||
import net.shadowfacts.extrahoppers.block.base.BlockWithEntity
|
import net.shadowfacts.extrahoppers.block.base.BlockWithEntity
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
class WoodHopperBlock: BlockWithEntity<WoodHopperBlockEntity>(FabricBlockSettings.of(Material.WOOD).strength(2f, 3f).sounds(BlockSoundGroup.WOOD).nonOpaque().build()) {
|
class WoodHopperBlock: BaseHopperBlock<WoodHopperBlockEntity>(
|
||||||
|
FabricBlockSettings.of(Material.WOOD)
|
||||||
|
.strength(2f, 3f)
|
||||||
|
.sounds(BlockSoundGroup.WOOD)
|
||||||
|
.nonOpaque()
|
||||||
|
.build()
|
||||||
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
val ID = Identifier("extrahoppers", "wood_hopper")
|
val ID = Identifier("extrahoppers", "wood_hopper")
|
||||||
|
|
||||||
val FACING = Properties.HOPPER_FACING
|
|
||||||
// todo: redstone support
|
|
||||||
// val ENABLED = Properties.ENABLED
|
|
||||||
val TOP_SHAPE = createCuboidShape(0.0, 10.0, 0.0, 16.0, 16.0, 16.0)
|
|
||||||
val MIDDLE_SHAPE = createCuboidShape(4.0, 4.0, 4.0, 12.0, 10.0, 12.0)
|
|
||||||
val OUTSIDE_SHAPE = VoxelShapes.union(MIDDLE_SHAPE, TOP_SHAPE)
|
|
||||||
val DEFAULT_SHAPE = VoxelShapes.combineAndSimplify(OUTSIDE_SHAPE, Hopper.INSIDE_SHAPE, BooleanBiFunction.ONLY_FIRST)
|
|
||||||
val DOWN_SHAPE = VoxelShapes.union(DEFAULT_SHAPE, createCuboidShape(6.0, 0.0, 6.0, 10.0, 4.0, 10.0))
|
|
||||||
val EAST_SHAPE = VoxelShapes.union(DEFAULT_SHAPE, createCuboidShape(12.0, 4.0, 6.0, 16.0, 8.0, 10.0))
|
|
||||||
val NORTH_SHAPE = VoxelShapes.union(DEFAULT_SHAPE, createCuboidShape(6.0, 4.0, 0.0, 10.0, 8.0, 4.0))
|
|
||||||
val SOUTH_SHAPE = VoxelShapes.union(DEFAULT_SHAPE, createCuboidShape(6.0, 4.0, 12.0, 10.0, 8.0, 16.0))
|
|
||||||
val WEST_SHAPE = VoxelShapes.union(DEFAULT_SHAPE, createCuboidShape(0.0, 4.0, 6.0, 4.0, 8.0, 10.0))
|
|
||||||
val DOWN_RAY_TRACE_SHAPE = Hopper.INSIDE_SHAPE
|
|
||||||
val EAST_RAY_TRACE_SHAPE = VoxelShapes.union(Hopper.INSIDE_SHAPE, createCuboidShape(12.0, 8.0, 6.0, 16.0, 10.0, 10.0))
|
|
||||||
val NORTH_RAY_TRACE_SHAPE = VoxelShapes.union(Hopper.INSIDE_SHAPE, createCuboidShape(6.0, 8.0, 0.0, 10.0, 10.0, 4.0))
|
|
||||||
val SOUTH_RAY_TRACE_SHAPE = VoxelShapes.union(Hopper.INSIDE_SHAPE, createCuboidShape(6.0, 8.0, 12.0, 10.0, 10.0, 16.0))
|
|
||||||
val WEST_RAY_TRACE_SHAPE = VoxelShapes.union(Hopper.INSIDE_SHAPE, createCuboidShape(0.0, 8.0, 6.0, 4.0, 10.0, 10.0))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun appendProperties(builder: StateManager.Builder<Block, BlockState>) {
|
override fun createBlockEntity(world: BlockView) = WoodHopperBlockEntity()
|
||||||
builder.add(FACING)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getOutlineShape(state: BlockState, world: BlockView, pos: BlockPos, entityContext: EntityContext): VoxelShape {
|
|
||||||
return when (state.get(FACING)) {
|
|
||||||
Direction.DOWN -> DOWN_SHAPE
|
|
||||||
Direction.NORTH -> NORTH_SHAPE
|
|
||||||
Direction.SOUTH -> SOUTH_SHAPE
|
|
||||||
Direction.WEST -> WEST_SHAPE
|
|
||||||
Direction.EAST -> EAST_SHAPE
|
|
||||||
else -> DEFAULT_SHAPE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getRayTraceShape(state: BlockState, world: BlockView, pos: BlockPos): VoxelShape {
|
|
||||||
return when (state.get(FACING)) {
|
|
||||||
Direction.DOWN -> DOWN_RAY_TRACE_SHAPE
|
|
||||||
Direction.NORTH -> NORTH_RAY_TRACE_SHAPE
|
|
||||||
Direction.SOUTH -> SOUTH_RAY_TRACE_SHAPE
|
|
||||||
Direction.WEST -> WEST_RAY_TRACE_SHAPE
|
|
||||||
Direction.EAST -> EAST_RAY_TRACE_SHAPE
|
|
||||||
else -> Hopper.INSIDE_SHAPE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getPlacementState(context: ItemPlacementContext): BlockState {
|
|
||||||
val hitFacing = context.side.opposite
|
|
||||||
val facing = if (hitFacing.axis == Direction.Axis.Y) Direction.DOWN else hitFacing
|
|
||||||
return defaultState.with(FACING, facing)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun createBlockEntity(world: BlockView): WoodHopperBlockEntity {
|
|
||||||
return WoodHopperBlockEntity()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onUse(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand, hitResult: BlockHitResult): ActionResult {
|
override fun onUse(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand, hitResult: BlockHitResult): ActionResult {
|
||||||
if (!world.isClient) {
|
if (!world.isClient) {
|
||||||
|
@ -94,24 +49,10 @@ class WoodHopperBlock: BlockWithEntity<WoodHopperBlockEntity>(FabricBlockSetting
|
||||||
return ActionResult.SUCCESS
|
return ActionResult.SUCCESS
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBlockRemoved(oldState: BlockState, world: World, pos: BlockPos, newState: BlockState, bl: Boolean) {
|
|
||||||
if (oldState.block != newState.block) {
|
|
||||||
getBlockEntity(world, pos)?.also {
|
|
||||||
ItemScatterer.spawn(world, pos, it)
|
|
||||||
world.updateHorizontalAdjacent(pos, this)
|
|
||||||
}
|
|
||||||
super.onBlockRemoved(oldState, world, pos, newState, bl)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onEntityCollision(state: BlockState, world: World, pos: BlockPos, entity: Entity) {
|
override fun onEntityCollision(state: BlockState, world: World, pos: BlockPos, entity: Entity) {
|
||||||
getBlockEntity(world, pos)?.also {
|
getBlockEntity(world, pos)?.also {
|
||||||
it.onEntityCollision(entity)
|
it.onEntityCollision(entity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun canPlaceAtSide(blockState: BlockState?, blockView: BlockView?, blockPos: BlockPos?, blockPlacementEnvironment: BlockPlacementEnvironment?): Boolean {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,167 +1,15 @@
|
||||||
package net.shadowfacts.extrahoppers.block.wood
|
package net.shadowfacts.extrahoppers.block.wood
|
||||||
|
|
||||||
import net.minecraft.block.entity.BlockEntity
|
|
||||||
import net.minecraft.block.entity.Hopper
|
|
||||||
import net.minecraft.block.entity.HopperBlockEntity
|
|
||||||
import net.minecraft.entity.Entity
|
|
||||||
import net.minecraft.entity.ItemEntity
|
|
||||||
import net.minecraft.entity.player.PlayerEntity
|
|
||||||
import net.minecraft.inventory.Inventories
|
|
||||||
import net.minecraft.inventory.Inventory
|
|
||||||
import net.minecraft.inventory.SidedInventory
|
|
||||||
import net.minecraft.item.ItemStack
|
|
||||||
import net.minecraft.nbt.CompoundTag
|
|
||||||
import net.minecraft.util.BooleanBiFunction
|
|
||||||
import net.minecraft.util.DefaultedList
|
|
||||||
import net.minecraft.util.Tickable
|
import net.minecraft.util.Tickable
|
||||||
import net.minecraft.util.math.Direction
|
import net.shadowfacts.extrahoppers.block.base.BaseHopperBlockEntity
|
||||||
import net.minecraft.util.shape.VoxelShapes
|
|
||||||
import net.shadowfacts.extrahoppers.init.EHBlockEntities
|
import net.shadowfacts.extrahoppers.init.EHBlockEntities
|
||||||
import net.shadowfacts.extrahoppers.util.toVec3d
|
|
||||||
|
|
||||||
class WoodHopperBlockEntity: BlockEntity(EHBlockEntities.WOOD_HOPPER), Inventory, Hopper, Tickable {
|
/**
|
||||||
companion object {
|
* @author shadowfacts
|
||||||
val TRANSFER_COOLDOWN = 40
|
*/
|
||||||
}
|
class WoodHopperBlockEntity: BaseHopperBlockEntity(EHBlockEntities.WOOD_HOPPER), Tickable {
|
||||||
|
|
||||||
var inventory: DefaultedList<ItemStack> = DefaultedList.ofSize(1, ItemStack.EMPTY)
|
override val inventorySize = 1
|
||||||
private set
|
override val maxTransferCooldown = 40
|
||||||
var transferCooldown = -1
|
|
||||||
var lastTickTime = 0L
|
|
||||||
|
|
||||||
override fun toTag(tag: CompoundTag): CompoundTag {
|
|
||||||
Inventories.toTag(tag, inventory)
|
|
||||||
tag.putInt("transferCooldown", transferCooldown)
|
|
||||||
return super.toTag(tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun fromTag(tag: CompoundTag) {
|
|
||||||
super.fromTag(tag)
|
|
||||||
inventory.clear()
|
|
||||||
Inventories.fromTag(tag, inventory)
|
|
||||||
transferCooldown = tag.getInt("transferCooldown")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun tick() {
|
|
||||||
val world = world
|
|
||||||
if (world == null || world.isClient) return
|
|
||||||
|
|
||||||
transferCooldown -= 1
|
|
||||||
lastTickTime = world.time
|
|
||||||
if (transferCooldown <= 0) {
|
|
||||||
transferCooldown = 0
|
|
||||||
insertAndExtract()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onEntityCollision(entity: Entity) {
|
|
||||||
if (entity is ItemEntity) {
|
|
||||||
if (VoxelShapes.matchesAnywhere(VoxelShapes.cuboid(entity.boundingBox.offset(-pos.x.toDouble(), -pos.y.toDouble(), -pos.z.toDouble())), inputAreaShape, BooleanBiFunction.AND)) {
|
|
||||||
insertAndExtract()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun insertAndExtract(extractor: (() -> Boolean)? = null) {
|
|
||||||
val world = world
|
|
||||||
if (world == null || world.isClient) return
|
|
||||||
|
|
||||||
var didWork = false
|
|
||||||
if (!isInvEmpty && insert()) {
|
|
||||||
didWork = true
|
|
||||||
}
|
|
||||||
if (!isFull() && ((extractor != null && extractor()) || HopperBlockEntity.extract(this))) {
|
|
||||||
didWork = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if (didWork) {
|
|
||||||
transferCooldown = TRANSFER_COOLDOWN
|
|
||||||
markDirty()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun insert(): Boolean {
|
|
||||||
val outputInv = getOutputInventory() ?: return false
|
|
||||||
|
|
||||||
val insertionSide = cachedState.get(WoodHopperBlock.FACING).opposite
|
|
||||||
if (isInventoryFull(outputInv, insertionSide)) return false
|
|
||||||
|
|
||||||
for (slot in 0 until invSize) {
|
|
||||||
if (getInvStack(slot).isEmpty) continue
|
|
||||||
|
|
||||||
val stackCopy = getInvStack(slot).copy()
|
|
||||||
|
|
||||||
val remaining = HopperBlockEntity.transfer(this, outputInv, takeInvStack(slot, 1), insertionSide)
|
|
||||||
if (remaining.isEmpty) {
|
|
||||||
outputInv.markDirty()
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
setInvStack(slot, stackCopy)
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
fun isFull(): Boolean {
|
|
||||||
return inventory.none(ItemStack::isEmpty)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getOutputInventory(): Inventory? {
|
|
||||||
val facing = cachedState.get(WoodHopperBlock.FACING)
|
|
||||||
return HopperBlockEntity.getInventoryAt(world!!, pos.offset(facing))
|
|
||||||
}
|
|
||||||
|
|
||||||
fun inventorySlots(inv: Inventory, side: Direction): Sequence<Int> {
|
|
||||||
return if (inv is SidedInventory) {
|
|
||||||
inv.getInvAvailableSlots(side).asSequence()
|
|
||||||
} else {
|
|
||||||
(0 until inv.invSize).asSequence()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun isInventoryFull(inv: Inventory, side: Direction): Boolean {
|
|
||||||
val slots = inventorySlots(inv, side)
|
|
||||||
return slots.map(inv::getInvStack).none(ItemStack::isEmpty)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Inventory
|
|
||||||
|
|
||||||
override fun getInvSize() = inventory.size
|
|
||||||
|
|
||||||
override fun takeInvStack(slot: Int, amount: Int): ItemStack {
|
|
||||||
return Inventories.splitStack(inventory, slot, amount)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun isInvEmpty() = inventory.isEmpty()
|
|
||||||
|
|
||||||
override fun getInvStack(slot: Int) = inventory[slot]
|
|
||||||
|
|
||||||
override fun clear() {
|
|
||||||
inventory.clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setInvStack(slot: Int, stack: ItemStack) {
|
|
||||||
inventory[slot] = stack
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun removeInvStack(slot: Int): ItemStack {
|
|
||||||
return Inventories.removeStack(inventory, slot)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun canPlayerUseInv(player: PlayerEntity): Boolean {
|
|
||||||
return if (world?.getBlockEntity(pos) != this) {
|
|
||||||
false
|
|
||||||
} else {
|
|
||||||
val distance = player.squaredDistanceTo(this.pos.toVec3d())
|
|
||||||
distance < 64
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hopper
|
|
||||||
|
|
||||||
override fun getHopperX() = pos.x.toDouble()
|
|
||||||
override fun getHopperY() = pos.y.toDouble()
|
|
||||||
override fun getHopperZ() = pos.z.toDouble()
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue