Compare commits
3 Commits
b8d374b982
...
5e42cbddce
Author | SHA1 | Date |
---|---|---|
Shadowfacts | 5e42cbddce | |
Shadowfacts | e9e28f5625 | |
Shadowfacts | 7b134f688d |
|
@ -3,6 +3,7 @@ package net.shadowfacts.extrahoppers
|
||||||
import net.fabricmc.api.ModInitializer
|
import net.fabricmc.api.ModInitializer
|
||||||
import net.fabricmc.fabric.api.container.ContainerFactory
|
import net.fabricmc.fabric.api.container.ContainerFactory
|
||||||
import net.fabricmc.fabric.api.container.ContainerProviderRegistry
|
import net.fabricmc.fabric.api.container.ContainerProviderRegistry
|
||||||
|
import net.shadowfacts.extrahoppers.block.gold.GoldHopperContainer
|
||||||
import net.shadowfacts.extrahoppers.block.wood.WoodHopperContainer
|
import net.shadowfacts.extrahoppers.block.wood.WoodHopperContainer
|
||||||
import net.shadowfacts.extrahoppers.init.EHBlockEntities
|
import net.shadowfacts.extrahoppers.init.EHBlockEntities
|
||||||
import net.shadowfacts.extrahoppers.init.EHBlocks
|
import net.shadowfacts.extrahoppers.init.EHBlocks
|
||||||
|
@ -16,6 +17,7 @@ object ExtraHoppers: ModInitializer {
|
||||||
EHItems.init()
|
EHItems.init()
|
||||||
|
|
||||||
ContainerProviderRegistry.INSTANCE.registerFactory(WoodHopperContainer.ID, ContainerFactory(WoodHopperContainer.Companion::create))
|
ContainerProviderRegistry.INSTANCE.registerFactory(WoodHopperContainer.ID, ContainerFactory(WoodHopperContainer.Companion::create))
|
||||||
|
ContainerProviderRegistry.INSTANCE.registerFactory(GoldHopperContainer.ID, ContainerFactory(GoldHopperContainer.Companion::create))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@ package net.shadowfacts.extrahoppers
|
||||||
import net.fabricmc.api.ClientModInitializer
|
import net.fabricmc.api.ClientModInitializer
|
||||||
import net.fabricmc.fabric.api.client.screen.ContainerScreenFactory
|
import net.fabricmc.fabric.api.client.screen.ContainerScreenFactory
|
||||||
import net.fabricmc.fabric.api.client.screen.ScreenProviderRegistry
|
import net.fabricmc.fabric.api.client.screen.ScreenProviderRegistry
|
||||||
|
import net.shadowfacts.extrahoppers.block.gold.GoldHopperContainer
|
||||||
|
import net.shadowfacts.extrahoppers.block.gold.GoldHopperScreen
|
||||||
import net.shadowfacts.extrahoppers.block.wood.WoodHopperContainer
|
import net.shadowfacts.extrahoppers.block.wood.WoodHopperContainer
|
||||||
import net.shadowfacts.extrahoppers.block.wood.WoodHopperScreen
|
import net.shadowfacts.extrahoppers.block.wood.WoodHopperScreen
|
||||||
|
|
||||||
|
@ -10,6 +12,7 @@ object ExtraHoppersClient: ClientModInitializer {
|
||||||
|
|
||||||
override fun onInitializeClient() {
|
override fun onInitializeClient() {
|
||||||
ScreenProviderRegistry.INSTANCE.registerFactory(WoodHopperContainer.ID, ContainerScreenFactory(WoodHopperScreen.Companion::create))
|
ScreenProviderRegistry.INSTANCE.registerFactory(WoodHopperContainer.ID, ContainerScreenFactory(WoodHopperScreen.Companion::create))
|
||||||
|
ScreenProviderRegistry.INSTANCE.registerFactory(GoldHopperContainer.ID, ContainerScreenFactory(GoldHopperScreen.Companion::create))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
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,223 @@
|
||||||
|
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.state.property.DirectionProperty
|
||||||
|
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 {
|
||||||
|
|
||||||
|
abstract val inventorySize: Int
|
||||||
|
abstract val maxTransferCooldown: Int
|
||||||
|
abstract val facingProp: DirectionProperty
|
||||||
|
abstract val inputSide: Direction
|
||||||
|
val inventory: DefaultedList<ItemStack> by lazy { 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()) || extract()) {
|
||||||
|
didWork = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (didWork) {
|
||||||
|
transferCooldown = maxTransferCooldown
|
||||||
|
markDirty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun insert(): Boolean {
|
||||||
|
val outputInv = getOutputInventory() ?: return false
|
||||||
|
|
||||||
|
val insertionSide = cachedState.get(facingProp).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 extract(): Boolean {
|
||||||
|
val inputInv = getInputInventory()
|
||||||
|
return if (inputInv != null) {
|
||||||
|
val extractionSide = inputSide.opposite
|
||||||
|
if (!isInventoryEmpty(inputInv, extractionSide)) {
|
||||||
|
inventorySlots(inputInv, extractionSide).any { slot ->
|
||||||
|
extractFromInv(inputInv, slot, extractionSide)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
HopperBlockEntity.getInputItemEntities(this).any {
|
||||||
|
HopperBlockEntity.extract(this, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun extractFromInv(inventory: Inventory, slot: Int, extractonSide: Direction): Boolean {
|
||||||
|
val stack = inventory.getInvStack(slot)
|
||||||
|
if (!stack.isEmpty && canExtract(inventory, stack, slot, extractonSide)) {
|
||||||
|
val stackCopy = stack.copy()
|
||||||
|
val remaining = HopperBlockEntity.transfer(inventory, this, inventory.takeInvStack(slot, 1), null)
|
||||||
|
if (remaining.isEmpty) {
|
||||||
|
inventory.markDirty()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
inventory.setInvStack(slot, stackCopy)
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isFull(): Boolean {
|
||||||
|
return inventory.none(ItemStack::isEmpty)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getOutputInventory(): Inventory? {
|
||||||
|
val facing = cachedState.get(facingProp)
|
||||||
|
return HopperBlockEntity.getInventoryAt(world!!, pos.offset(facing))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getInputInventory(): Inventory? {
|
||||||
|
return HopperBlockEntity.getInventoryAt(world!!, pos.offset(inputSide))
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isInventoryEmpty(inv: Inventory, side: Direction): Boolean {
|
||||||
|
val slots = inventorySlots(inv, side)
|
||||||
|
return slots.map(inv::getInvStack).all(ItemStack::isEmpty)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun canExtract(inv: Inventory, stack: ItemStack, slot: Int, extractionSide: Direction): Boolean {
|
||||||
|
return if (inv is SidedInventory) {
|
||||||
|
inv.canExtractInvStack(slot, stack, extractionSide)
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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()
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
package net.shadowfacts.extrahoppers.block.base
|
||||||
|
|
||||||
|
import net.minecraft.container.Container
|
||||||
|
import net.minecraft.container.Slot
|
||||||
|
import net.minecraft.entity.player.PlayerEntity
|
||||||
|
import net.minecraft.entity.player.PlayerInventory
|
||||||
|
import net.minecraft.item.ItemStack
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
|
abstract class BaseHopperContainer<T: BaseHopperBlockEntity>(
|
||||||
|
syncId: Int,
|
||||||
|
playerInv: PlayerInventory,
|
||||||
|
val hopper: T
|
||||||
|
): Container(null, syncId) {
|
||||||
|
|
||||||
|
init {
|
||||||
|
addHopperSlots()
|
||||||
|
|
||||||
|
// player inv
|
||||||
|
for (y in 0 until 3) {
|
||||||
|
for (x in 0 until 9) {
|
||||||
|
addSlot(Slot(playerInv, x + y * 9 + 9, 8 + x * 18, 51 + y * 18))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// hotbar
|
||||||
|
for (x in 0 until 9) {
|
||||||
|
addSlot(Slot(playerInv, x, 8 + x * 18, 109))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract fun addHopperSlots()
|
||||||
|
|
||||||
|
override fun canUse(player: PlayerEntity): Boolean {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun close(player: PlayerEntity) {
|
||||||
|
super.close(player)
|
||||||
|
|
||||||
|
hopper.onInvClose(player)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun transferSlot(player: PlayerEntity, slotIndex: Int): ItemStack {
|
||||||
|
var remaining = ItemStack.EMPTY
|
||||||
|
val slot = slots[slotIndex]
|
||||||
|
if (slot != null && slot.hasStack()) {
|
||||||
|
val slotStack = slot.stack
|
||||||
|
remaining = slotStack.copy()
|
||||||
|
if (slotIndex < hopper.invSize) {
|
||||||
|
if (!insertItem(slotStack, hopper.invSize, slots.size, true)) {
|
||||||
|
return ItemStack.EMPTY;
|
||||||
|
}
|
||||||
|
} else if (!insertItem(slotStack, 0, hopper.invSize, false)) {
|
||||||
|
return ItemStack.EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slotStack.isEmpty) {
|
||||||
|
slot.stack = ItemStack.EMPTY;
|
||||||
|
} else {
|
||||||
|
slot.markDirty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return remaining
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
package net.shadowfacts.extrahoppers.block.base
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.platform.GlStateManager
|
||||||
|
import net.minecraft.client.gui.screen.ingame.ContainerScreen
|
||||||
|
import net.minecraft.entity.player.PlayerInventory
|
||||||
|
import net.minecraft.text.Text
|
||||||
|
import net.minecraft.util.Identifier
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
|
abstract class BaseHopperScreen<T: BaseHopperContainer<*>>(
|
||||||
|
container: T,
|
||||||
|
playerInv: PlayerInventory,
|
||||||
|
title: Text
|
||||||
|
): ContainerScreen<T>(container, playerInv, title) {
|
||||||
|
|
||||||
|
abstract val background: Identifier
|
||||||
|
|
||||||
|
init {
|
||||||
|
containerHeight = 133
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun render(i: Int, j: Int, f: Float) {
|
||||||
|
this.renderBackground()
|
||||||
|
super.render(i, j, f)
|
||||||
|
drawMouseoverTooltip(i, j)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun drawForeground(mouseX: Int, mouseY: Int) {
|
||||||
|
font.draw(title.asFormattedString(), 8f, 6f, 0x404040)
|
||||||
|
font.draw(playerInventory.displayName.asFormattedString(), 8f, containerHeight - 94f, 0x404040)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun drawBackground(delta: Float, mouseX: Int, mouseY: Int) {
|
||||||
|
GlStateManager.color4f(1f, 1f, 1f, 1f)
|
||||||
|
minecraft!!.textureManager.bindTexture(background)
|
||||||
|
val x = (width - containerWidth) / 2
|
||||||
|
val y = (height - containerHeight) / 2
|
||||||
|
blit(x, y, 0, 0, containerWidth, containerHeight)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
package net.shadowfacts.extrahoppers.block.gold
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.block.FabricBlockSettings
|
||||||
|
import net.fabricmc.fabric.api.container.ContainerProviderRegistry
|
||||||
|
import net.minecraft.block.BlockState
|
||||||
|
import net.minecraft.block.Material
|
||||||
|
import net.minecraft.entity.player.PlayerEntity
|
||||||
|
import net.minecraft.sound.BlockSoundGroup
|
||||||
|
import net.minecraft.stat.Stats
|
||||||
|
import net.minecraft.util.ActionResult
|
||||||
|
import net.minecraft.util.Hand
|
||||||
|
import net.minecraft.util.Identifier
|
||||||
|
import net.minecraft.util.hit.BlockHitResult
|
||||||
|
import net.minecraft.util.math.BlockPos
|
||||||
|
import net.minecraft.world.BlockView
|
||||||
|
import net.minecraft.world.World
|
||||||
|
import net.shadowfacts.extrahoppers.block.base.BaseHopperBlock
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
|
open class GoldHopperBlock: BaseHopperBlock<GoldHopperBlockEntity>(
|
||||||
|
FabricBlockSettings.of(Material.METAL)
|
||||||
|
.strength(3f, 6f)
|
||||||
|
.sounds(BlockSoundGroup.METAL)
|
||||||
|
.nonOpaque()
|
||||||
|
.build()
|
||||||
|
) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val ID = Identifier("extrahoppers", "gold_hopper")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createBlockEntity(world: BlockView) = GoldHopperBlockEntity(false)
|
||||||
|
|
||||||
|
override fun onUse(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand, hitResult: BlockHitResult): ActionResult {
|
||||||
|
if (!world.isClient) {
|
||||||
|
player.incrementStat(Stats.INSPECT_HOPPER)
|
||||||
|
ContainerProviderRegistry.INSTANCE.openContainer(GoldHopperContainer.ID, player) { buf ->
|
||||||
|
buf.writeBlockPos(pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ActionResult.SUCCESS
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
package net.shadowfacts.extrahoppers.block.gold
|
||||||
|
|
||||||
|
import net.minecraft.block.Block
|
||||||
|
import net.minecraft.block.entity.Hopper
|
||||||
|
import net.minecraft.nbt.CompoundTag
|
||||||
|
import net.minecraft.util.math.Direction
|
||||||
|
import net.minecraft.util.shape.VoxelShape
|
||||||
|
import net.minecraft.util.shape.VoxelShapes
|
||||||
|
import net.shadowfacts.extrahoppers.block.base.BaseHopperBlock
|
||||||
|
import net.shadowfacts.extrahoppers.block.base.BaseHopperBlockEntity
|
||||||
|
import net.shadowfacts.extrahoppers.init.EHBlockEntities
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
|
open class GoldHopperBlockEntity(var inverted: Boolean): BaseHopperBlockEntity(
|
||||||
|
if (inverted) EHBlockEntities.INVERTED_GOLD_HOPPER else EHBlockEntities.GOLD_HOPPER
|
||||||
|
) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val INVERTED_INSIDE_SHAPE = Block.createCuboidShape(2.0, 5.0, 2.0, 14.0, 0.0, 14.0)
|
||||||
|
val INVERTED_BELOW_SHAPE = Block.createCuboidShape(0.0, 0.0, 0.0, 16.0, -16.0, 16.0)
|
||||||
|
val INVERTED_INPUT_AREA_SHAPE = VoxelShapes.union(INVERTED_INSIDE_SHAPE, INVERTED_BELOW_SHAPE)
|
||||||
|
}
|
||||||
|
|
||||||
|
override val inventorySize = 5
|
||||||
|
override val maxTransferCooldown = 4
|
||||||
|
override val facingProp = if (inverted) InvertedGoldHopperBlock.INVERTED_FACING else BaseHopperBlock.FACING
|
||||||
|
override val inputSide = if (inverted) Direction.DOWN else Direction.UP
|
||||||
|
|
||||||
|
@Deprecated("only used for deserializing")
|
||||||
|
constructor(): this(false)
|
||||||
|
|
||||||
|
override fun toTag(tag: CompoundTag): CompoundTag {
|
||||||
|
tag.putBoolean("inverted", inverted)
|
||||||
|
return super.toTag(tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun fromTag(tag: CompoundTag) {
|
||||||
|
super.fromTag(tag)
|
||||||
|
inverted = tag.getBoolean("inverted")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getInputAreaShape(): VoxelShape {
|
||||||
|
return if (inverted) {
|
||||||
|
INVERTED_INPUT_AREA_SHAPE
|
||||||
|
} else {
|
||||||
|
Hopper.INPUT_AREA_SHAPE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package net.shadowfacts.extrahoppers.block.gold
|
||||||
|
|
||||||
|
import net.minecraft.container.Slot
|
||||||
|
import net.minecraft.entity.player.PlayerEntity
|
||||||
|
import net.minecraft.entity.player.PlayerInventory
|
||||||
|
import net.minecraft.util.Identifier
|
||||||
|
import net.minecraft.util.PacketByteBuf
|
||||||
|
import net.shadowfacts.extrahoppers.block.base.BaseHopperContainer
|
||||||
|
import net.shadowfacts.extrahoppers.init.EHBlocks
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
|
class GoldHopperContainer(
|
||||||
|
syncId: Int,
|
||||||
|
playerInv: PlayerInventory,
|
||||||
|
hopper: GoldHopperBlockEntity
|
||||||
|
): BaseHopperContainer<GoldHopperBlockEntity>(syncId, playerInv, hopper) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val ID = Identifier("extrahoppers", "gold_hopper")
|
||||||
|
|
||||||
|
fun create(syncId: Int, identifier: Identifier, player: PlayerEntity, buf: PacketByteBuf): GoldHopperContainer {
|
||||||
|
val pos = buf.readBlockPos()
|
||||||
|
val blockEntity = EHBlocks.GOLD_HOPPER.getBlockEntity(player.world, pos)!!
|
||||||
|
return GoldHopperContainer(syncId, player.inventory, blockEntity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun addHopperSlots() {
|
||||||
|
for (i in 0 until 5) {
|
||||||
|
addSlot(Slot(hopper, i, 44 + i * 18, 20))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package net.shadowfacts.extrahoppers.block.gold
|
||||||
|
|
||||||
|
import net.minecraft.client.MinecraftClient
|
||||||
|
import net.minecraft.entity.player.PlayerInventory
|
||||||
|
import net.minecraft.text.TranslatableText
|
||||||
|
import net.minecraft.util.Identifier
|
||||||
|
import net.shadowfacts.extrahoppers.block.base.BaseHopperScreen
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
|
class GoldHopperScreen(
|
||||||
|
container: GoldHopperContainer,
|
||||||
|
playerInv: PlayerInventory
|
||||||
|
): BaseHopperScreen<GoldHopperContainer>(container, playerInv, TranslatableText("block.extrahoppers.${if (container.hopper.inverted) "inverted_" else ""}gold_hopper")) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun create(container: GoldHopperContainer): GoldHopperScreen {
|
||||||
|
return GoldHopperScreen(container, MinecraftClient.getInstance().player!!.inventory)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override val background = Identifier("minecraft", "textures/gui/container/hopper.png")
|
||||||
|
}
|
|
@ -0,0 +1,78 @@
|
||||||
|
package net.shadowfacts.extrahoppers.block.gold
|
||||||
|
|
||||||
|
import net.minecraft.block.Block
|
||||||
|
import net.minecraft.block.BlockState
|
||||||
|
import net.minecraft.entity.EntityContext
|
||||||
|
import net.minecraft.item.ItemPlacementContext
|
||||||
|
import net.minecraft.state.StateManager
|
||||||
|
import net.minecraft.state.property.DirectionProperty
|
||||||
|
import net.minecraft.util.BooleanBiFunction
|
||||||
|
import net.minecraft.util.Identifier
|
||||||
|
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
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
|
class InvertedGoldHopperBlock: GoldHopperBlock() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val ID = Identifier("extrahoppers", "inverted_gold_hopper")
|
||||||
|
|
||||||
|
val INVERTED_FACING = DirectionProperty.of("inverted_facing") { direction: Direction -> direction != Direction.DOWN }
|
||||||
|
|
||||||
|
val INVERTED_TOP_SHAPE = createCuboidShape(0.0, 6.0, 0.0, 16.0, 0.0, 16.0)
|
||||||
|
val INVERTED_MIDDLE_SHAPE = createCuboidShape(4.0, 12.0, 4.0, 12.0, 6.0, 12.0)
|
||||||
|
val INVERTED_INSIDE_SHAPE = createCuboidShape(2.0, 5.0, 2.0, 14.0, 0.0, 14.0)
|
||||||
|
val INVERTED_OUTSIDE_SHAPE = VoxelShapes.union(INVERTED_MIDDLE_SHAPE, INVERTED_TOP_SHAPE)
|
||||||
|
val INVERTED_DEFAULT_SHAPE = VoxelShapes.combineAndSimplify(INVERTED_OUTSIDE_SHAPE, INVERTED_INSIDE_SHAPE, BooleanBiFunction.ONLY_FIRST)
|
||||||
|
val INVERTED_DOWN_SHAPE = VoxelShapes.union(INVERTED_DEFAULT_SHAPE, createCuboidShape(6.0, 16.0, 6.0, 10.0, 12.0, 10.0))
|
||||||
|
val INVERTED_EAST_SHAPE = VoxelShapes.union(INVERTED_DEFAULT_SHAPE, createCuboidShape(12.0, 12.0, 6.0, 16.0, 8.0, 10.0))
|
||||||
|
val INVERTED_NORTH_SHAPE = VoxelShapes.union(INVERTED_DEFAULT_SHAPE, createCuboidShape(6.0, 12.0, 0.0, 10.0, 8.0, 4.0))
|
||||||
|
val INVERTED_SOUTH_SHAPE = VoxelShapes.union(INVERTED_DEFAULT_SHAPE, createCuboidShape(6.0, 12.0, 12.0, 10.0, 8.0, 16.0))
|
||||||
|
val INVERTED_WEST_SHAPE = VoxelShapes.union(INVERTED_DEFAULT_SHAPE, createCuboidShape(0.0, 12.0, 6.0, 4.0, 8.0, 10.0))
|
||||||
|
val INVERTED_DOWN_RAY_TRACE_SHAPE = INVERTED_INSIDE_SHAPE
|
||||||
|
val INVERTED_EAST_RAY_TRACE_SHAPE = VoxelShapes.union(INVERTED_INSIDE_SHAPE, createCuboidShape(12.0, 8.0, 6.0, 16.0, 6.0, 10.0))
|
||||||
|
val INVERTED_NORTH_RAY_TRACE_SHAPE = VoxelShapes.union(INVERTED_INSIDE_SHAPE, createCuboidShape(6.0, 8.0, 0.0, 10.0, 6.0, 4.0))
|
||||||
|
val INVERTED_SOUTH_RAY_TRACE_SHAPE = VoxelShapes.union(INVERTED_INSIDE_SHAPE, createCuboidShape(6.0, 8.0, 12.0, 10.0, 6.0, 16.0))
|
||||||
|
val INVERTED_WEST_RAY_TRACE_SHAPE = VoxelShapes.union(INVERTED_INSIDE_SHAPE, createCuboidShape(0.0, 8.0, 6.0, 4.0, 6.0, 10.0))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun appendProperties(builder: StateManager.Builder<Block, BlockState>) {
|
||||||
|
builder.add(INVERTED_FACING)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getOutlineShape(state: BlockState, world: BlockView, pos: BlockPos, entityContext: EntityContext): VoxelShape {
|
||||||
|
return when (state.get(INVERTED_FACING)) {
|
||||||
|
Direction.DOWN -> INVERTED_DOWN_SHAPE
|
||||||
|
Direction.NORTH -> INVERTED_NORTH_SHAPE
|
||||||
|
Direction.SOUTH -> INVERTED_SOUTH_SHAPE
|
||||||
|
Direction.WEST -> INVERTED_WEST_SHAPE
|
||||||
|
Direction.EAST -> INVERTED_EAST_SHAPE
|
||||||
|
else -> INVERTED_DEFAULT_SHAPE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getRayTraceShape(state: BlockState, world: BlockView, pos: BlockPos): VoxelShape {
|
||||||
|
return when (state.get(INVERTED_FACING)) {
|
||||||
|
Direction.DOWN -> INVERTED_DOWN_RAY_TRACE_SHAPE
|
||||||
|
Direction.NORTH -> INVERTED_NORTH_RAY_TRACE_SHAPE
|
||||||
|
Direction.SOUTH -> INVERTED_SOUTH_RAY_TRACE_SHAPE
|
||||||
|
Direction.WEST -> INVERTED_WEST_RAY_TRACE_SHAPE
|
||||||
|
Direction.EAST -> INVERTED_EAST_RAY_TRACE_SHAPE
|
||||||
|
else -> INVERTED_INSIDE_SHAPE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getPlacementState(context: ItemPlacementContext): BlockState {
|
||||||
|
val hitFacing = context.side.opposite
|
||||||
|
val facing = if (hitFacing.axis == Direction.Axis.Y) Direction.UP else hitFacing
|
||||||
|
return defaultState.with(INVERTED_FACING, facing)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createBlockEntity(world: BlockView) = GoldHopperBlockEntity(true)
|
||||||
|
|
||||||
|
}
|
|
@ -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,19 @@
|
||||||
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.minecraft.util.math.Direction
|
||||||
import net.minecraft.util.shape.VoxelShapes
|
import net.shadowfacts.extrahoppers.block.base.BaseHopperBlock
|
||||||
|
import net.shadowfacts.extrahoppers.block.base.BaseHopperBlockEntity
|
||||||
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
|
override val facingProp = BaseHopperBlock.FACING
|
||||||
var lastTickTime = 0L
|
override val inputSide = Direction.UP
|
||||||
|
|
||||||
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()
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,19 @@
|
||||||
package net.shadowfacts.extrahoppers.block.wood
|
package net.shadowfacts.extrahoppers.block.wood
|
||||||
|
|
||||||
import net.minecraft.container.Container
|
|
||||||
import net.minecraft.container.Slot
|
import net.minecraft.container.Slot
|
||||||
import net.minecraft.entity.player.PlayerEntity
|
import net.minecraft.entity.player.PlayerEntity
|
||||||
import net.minecraft.entity.player.PlayerInventory
|
import net.minecraft.entity.player.PlayerInventory
|
||||||
import net.minecraft.inventory.Inventory
|
import net.minecraft.inventory.Inventory
|
||||||
import net.minecraft.item.ItemStack
|
|
||||||
import net.minecraft.util.Identifier
|
import net.minecraft.util.Identifier
|
||||||
import net.minecraft.util.PacketByteBuf
|
import net.minecraft.util.PacketByteBuf
|
||||||
|
import net.shadowfacts.extrahoppers.block.base.BaseHopperContainer
|
||||||
import net.shadowfacts.extrahoppers.init.EHBlocks
|
import net.shadowfacts.extrahoppers.init.EHBlocks
|
||||||
|
|
||||||
class WoodHopperContainer(syncId: Int, playerInv: PlayerInventory, val hopperInv: Inventory): Container(null, syncId) {
|
class WoodHopperContainer(
|
||||||
|
syncId: Int,
|
||||||
|
playerInv: PlayerInventory,
|
||||||
|
hopper: WoodHopperBlockEntity
|
||||||
|
): BaseHopperContainer<WoodHopperBlockEntity>(syncId, playerInv, hopper) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val ID = Identifier("extrahoppers", "wood_hopper")
|
val ID = Identifier("extrahoppers", "wood_hopper")
|
||||||
|
@ -22,53 +25,8 @@ class WoodHopperContainer(syncId: Int, playerInv: PlayerInventory, val hopperInv
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
override fun addHopperSlots() {
|
||||||
addSlot(Slot(hopperInv, 0, 80, 20))
|
addSlot(Slot(hopper, 0, 80, 20))
|
||||||
|
|
||||||
// player inv
|
|
||||||
for (y in 0 until 3) {
|
|
||||||
for (x in 0 until 9) {
|
|
||||||
addSlot(Slot(playerInv, x + y * 9 + 9, 8 + x * 18, 51 + y * 18))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// hotbar
|
|
||||||
for (x in 0 until 9) {
|
|
||||||
addSlot(Slot(playerInv, x, 8 + x * 18, 109))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun canUse(player: PlayerEntity): Boolean {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun close(player: PlayerEntity) {
|
|
||||||
super.close(player)
|
|
||||||
|
|
||||||
hopperInv.onInvClose(player)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun transferSlot(player: PlayerEntity, slotIndex: Int): ItemStack {
|
|
||||||
var remaining = ItemStack.EMPTY
|
|
||||||
val slot = slots[slotIndex]
|
|
||||||
if (slot != null && slot.hasStack()) {
|
|
||||||
val slotStack = slot.stack
|
|
||||||
remaining = slotStack.copy()
|
|
||||||
if (slotIndex < hopperInv.invSize) {
|
|
||||||
if (!insertItem(slotStack, hopperInv.invSize, slots.size, true)) {
|
|
||||||
return ItemStack.EMPTY;
|
|
||||||
}
|
|
||||||
} else if (!insertItem(slotStack, 0, hopperInv.invSize, false)) {
|
|
||||||
return ItemStack.EMPTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (slotStack.isEmpty) {
|
|
||||||
slot.stack = ItemStack.EMPTY;
|
|
||||||
} else {
|
|
||||||
slot.markDirty()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return remaining
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,37 +1,22 @@
|
||||||
package net.shadowfacts.extrahoppers.block.wood
|
package net.shadowfacts.extrahoppers.block.wood
|
||||||
|
|
||||||
import com.mojang.blaze3d.platform.GlStateManager
|
|
||||||
import net.minecraft.client.MinecraftClient
|
import net.minecraft.client.MinecraftClient
|
||||||
import net.minecraft.client.gui.screen.ingame.ContainerScreen
|
|
||||||
import net.minecraft.entity.player.PlayerInventory
|
import net.minecraft.entity.player.PlayerInventory
|
||||||
import net.minecraft.text.LiteralText
|
import net.minecraft.text.TranslatableText
|
||||||
import net.minecraft.util.Identifier
|
import net.minecraft.util.Identifier
|
||||||
|
import net.shadowfacts.extrahoppers.block.base.BaseHopperScreen
|
||||||
|
|
||||||
class WoodHopperScreen(container: WoodHopperContainer, playerInv: PlayerInventory): ContainerScreen<WoodHopperContainer>(container, playerInv, LiteralText("Wooden Hopper")) {
|
class WoodHopperScreen(
|
||||||
|
container: WoodHopperContainer,
|
||||||
|
playerInv: PlayerInventory
|
||||||
|
): BaseHopperScreen<WoodHopperContainer>(container, playerInv, TranslatableText("block.extrahoppers.gold_hopper")) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val BACKGROUND = Identifier("extrahoppers", "textures/gui/wood_hopper.png")
|
|
||||||
|
|
||||||
fun create(container: WoodHopperContainer): WoodHopperScreen {
|
fun create(container: WoodHopperContainer): WoodHopperScreen {
|
||||||
return WoodHopperScreen(container, MinecraftClient.getInstance().player!!.inventory)
|
return WoodHopperScreen(container, MinecraftClient.getInstance().player!!.inventory)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
override val background = Identifier("extrahoppers", "textures/gui/wood_hopper.png")
|
||||||
containerHeight = 133
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun drawForeground(mouseX: Int, mouseY: Int) {
|
|
||||||
font.draw(title.asFormattedString(), 8f, 6f, 0x404040)
|
|
||||||
font.draw(playerInventory.displayName.asFormattedString(), 8f, containerHeight - 94f, 0x404040)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun drawBackground(f: Float, i: Int, j: Int) {
|
|
||||||
GlStateManager.color4f(1f, 1f, 1f, 1f)
|
|
||||||
minecraft!!.textureManager.bindTexture(BACKGROUND)
|
|
||||||
val x = (width - containerWidth) / 2
|
|
||||||
val y = (height - containerHeight) / 2
|
|
||||||
blit(x, y, 0, 0, containerWidth, containerHeight)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,15 +5,23 @@ import net.minecraft.block.entity.BlockEntity
|
||||||
import net.minecraft.block.entity.BlockEntityType
|
import net.minecraft.block.entity.BlockEntityType
|
||||||
import net.minecraft.util.Identifier
|
import net.minecraft.util.Identifier
|
||||||
import net.minecraft.util.registry.Registry
|
import net.minecraft.util.registry.Registry
|
||||||
|
import net.shadowfacts.extrahoppers.block.gold.GoldHopperBlock
|
||||||
|
import net.shadowfacts.extrahoppers.block.gold.GoldHopperBlockEntity
|
||||||
|
import net.shadowfacts.extrahoppers.block.gold.InvertedGoldHopperBlock
|
||||||
import net.shadowfacts.extrahoppers.block.wood.WoodHopperBlock
|
import net.shadowfacts.extrahoppers.block.wood.WoodHopperBlock
|
||||||
import net.shadowfacts.extrahoppers.block.wood.WoodHopperBlockEntity
|
import net.shadowfacts.extrahoppers.block.wood.WoodHopperBlockEntity
|
||||||
|
|
||||||
object EHBlockEntities {
|
object EHBlockEntities {
|
||||||
|
|
||||||
val WOOD_HOPPER = create(::WoodHopperBlockEntity, EHBlocks.WOOD_HOPPER)
|
val WOOD_HOPPER = create(::WoodHopperBlockEntity, EHBlocks.WOOD_HOPPER)
|
||||||
|
val GOLD_HOPPER = create({ GoldHopperBlockEntity(false) }, EHBlocks.GOLD_HOPPER)
|
||||||
|
val INVERTED_GOLD_HOPPER = create({ GoldHopperBlockEntity(true) }, EHBlocks.INVERTED_GOLD_HOPPER)
|
||||||
|
// val INVERTED_GOLD_HOPPER = create(::InvertedGoldHopperBlockEntity, EHBlocks.INVERTED_GOLD_HOPPER)
|
||||||
|
|
||||||
fun init() {
|
fun init() {
|
||||||
register(WoodHopperBlock.ID, WOOD_HOPPER)
|
register(WoodHopperBlock.ID, WOOD_HOPPER)
|
||||||
|
register(GoldHopperBlock.ID, GOLD_HOPPER)
|
||||||
|
register(InvertedGoldHopperBlock.ID, INVERTED_GOLD_HOPPER)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <T: BlockEntity> create(builder: () -> T, block: Block): BlockEntityType<T> {
|
private fun <T: BlockEntity> create(builder: () -> T, block: Block): BlockEntityType<T> {
|
||||||
|
|
|
@ -3,14 +3,20 @@ package net.shadowfacts.extrahoppers.init
|
||||||
import net.minecraft.block.Block
|
import net.minecraft.block.Block
|
||||||
import net.minecraft.util.Identifier
|
import net.minecraft.util.Identifier
|
||||||
import net.minecraft.util.registry.Registry
|
import net.minecraft.util.registry.Registry
|
||||||
|
import net.shadowfacts.extrahoppers.block.gold.GoldHopperBlock
|
||||||
|
import net.shadowfacts.extrahoppers.block.gold.InvertedGoldHopperBlock
|
||||||
import net.shadowfacts.extrahoppers.block.wood.WoodHopperBlock
|
import net.shadowfacts.extrahoppers.block.wood.WoodHopperBlock
|
||||||
|
|
||||||
object EHBlocks {
|
object EHBlocks {
|
||||||
|
|
||||||
val WOOD_HOPPER = WoodHopperBlock()
|
val WOOD_HOPPER = WoodHopperBlock()
|
||||||
|
val GOLD_HOPPER = GoldHopperBlock()
|
||||||
|
val INVERTED_GOLD_HOPPER = InvertedGoldHopperBlock()
|
||||||
|
|
||||||
fun init() {
|
fun init() {
|
||||||
register(WoodHopperBlock.ID, WOOD_HOPPER)
|
register(WoodHopperBlock.ID, WOOD_HOPPER)
|
||||||
|
register(GoldHopperBlock.ID, GOLD_HOPPER)
|
||||||
|
register(InvertedGoldHopperBlock.ID, INVERTED_GOLD_HOPPER)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun register(id: Identifier, block: Block) {
|
private fun register(id: Identifier, block: Block) {
|
||||||
|
|
|
@ -4,14 +4,20 @@ import net.minecraft.item.BlockItem
|
||||||
import net.minecraft.item.Item
|
import net.minecraft.item.Item
|
||||||
import net.minecraft.util.Identifier
|
import net.minecraft.util.Identifier
|
||||||
import net.minecraft.util.registry.Registry
|
import net.minecraft.util.registry.Registry
|
||||||
|
import net.shadowfacts.extrahoppers.block.gold.GoldHopperBlock
|
||||||
|
import net.shadowfacts.extrahoppers.block.gold.InvertedGoldHopperBlock
|
||||||
import net.shadowfacts.extrahoppers.block.wood.WoodHopperBlock
|
import net.shadowfacts.extrahoppers.block.wood.WoodHopperBlock
|
||||||
|
|
||||||
object EHItems {
|
object EHItems {
|
||||||
|
|
||||||
val WOOD_HOPPER = BlockItem(EHBlocks.WOOD_HOPPER, Item.Settings())
|
val WOOD_HOPPER = BlockItem(EHBlocks.WOOD_HOPPER, Item.Settings())
|
||||||
|
val GOLD_HOPPER = BlockItem(EHBlocks.GOLD_HOPPER, Item.Settings())
|
||||||
|
val INVERTED_GOLD_HOPPER = BlockItem(EHBlocks.INVERTED_GOLD_HOPPER, Item.Settings())
|
||||||
|
|
||||||
fun init() {
|
fun init() {
|
||||||
register(WoodHopperBlock.ID, WOOD_HOPPER)
|
register(WoodHopperBlock.ID, WOOD_HOPPER)
|
||||||
|
register(GoldHopperBlock.ID, GOLD_HOPPER)
|
||||||
|
register(InvertedGoldHopperBlock.ID, INVERTED_GOLD_HOPPER)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun register(id: Identifier, item: Item) {
|
private fun register(id: Identifier, item: Item) {
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"facing=down": { "model": "extrahoppers:block/gold_hopper" },
|
||||||
|
"facing=north": { "model": "extrahoppers:block/gold_hopper_side" },
|
||||||
|
"facing=south": { "model": "extrahoppers:block/gold_hopper_side", "y": 180 },
|
||||||
|
"facing=west": { "model": "extrahoppers:block/gold_hopper_side", "y": 270 },
|
||||||
|
"facing=east": { "model": "extrahoppers:block/gold_hopper_side", "y": 90 }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"inverted_facing=up": { "model": "extrahoppers:block/inverted_gold_hopper" },
|
||||||
|
"inverted_facing=north": { "model": "extrahoppers:block/gold_hopper_side", "x": 180, "y": 180 },
|
||||||
|
"inverted_facing=south": { "model": "extrahoppers:block/gold_hopper_side", "x": 180 },
|
||||||
|
"inverted_facing=west": { "model": "extrahoppers:block/gold_hopper_side", "x": 180, "y": 90 },
|
||||||
|
"inverted_facing=east": { "model": "extrahoppers:block/gold_hopper_side", "x": 180, "y": 270 }
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
{
|
{
|
||||||
"block.extrahoppers.wood_hopper": "Wooden Hopper"
|
"block.extrahoppers.wood_hopper": "Wooden Hopper",
|
||||||
|
"block.extrahoppers.gold_hopper": "Golden Hopper",
|
||||||
|
"block.extrahoppers.inverted_gold_hopper": "Inverted Golden Hopper"
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
{
|
||||||
|
"parent": "block/hopper",
|
||||||
|
"textures": {
|
||||||
|
"particle": "block/gold_block",
|
||||||
|
"top": "block/gold_block",
|
||||||
|
"side": "block/gold_block",
|
||||||
|
"inside": "block/gold_block"
|
||||||
|
},
|
||||||
|
"display": {
|
||||||
|
"gui": {
|
||||||
|
"rotation": [ 30, 225, 0 ],
|
||||||
|
"translation": [ 0, 0, 0],
|
||||||
|
"scale":[ 0.625, 0.625, 0.625 ]
|
||||||
|
},
|
||||||
|
"ground": {
|
||||||
|
"rotation": [ 0, 0, 0 ],
|
||||||
|
"translation": [ 0, 3, 0],
|
||||||
|
"scale":[ 0.25, 0.25, 0.25 ]
|
||||||
|
},
|
||||||
|
"fixed": {
|
||||||
|
"rotation": [ 0, 0, 0 ],
|
||||||
|
"translation": [ 0, 0, 0],
|
||||||
|
"scale":[ 0.5, 0.5, 0.5 ]
|
||||||
|
},
|
||||||
|
"thirdperson_righthand": {
|
||||||
|
"rotation": [ 75, 45, 0 ],
|
||||||
|
"translation": [ 0, 2.5, 0],
|
||||||
|
"scale": [ 0.375, 0.375, 0.375 ]
|
||||||
|
},
|
||||||
|
"firstperson_righthand": {
|
||||||
|
"rotation": [ 0, 45, 0 ],
|
||||||
|
"translation": [ 0, 0, 0 ],
|
||||||
|
"scale": [ 0.40, 0.40, 0.40 ]
|
||||||
|
},
|
||||||
|
"firstperson_lefthand": {
|
||||||
|
"rotation": [ 0, 225, 0 ],
|
||||||
|
"translation": [ 0, 0, 0 ],
|
||||||
|
"scale": [ 0.40, 0.40, 0.40 ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"parent": "block/hopper_side",
|
||||||
|
"textures": {
|
||||||
|
"particle": "block/gold_block",
|
||||||
|
"top": "block/gold_block",
|
||||||
|
"side": "block/gold_block",
|
||||||
|
"inside": "block/gold_block"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,127 @@
|
||||||
|
{
|
||||||
|
"ambientocclusion": false,
|
||||||
|
"textures": {
|
||||||
|
"particle": "block/gold_block",
|
||||||
|
"top": "block/gold_block",
|
||||||
|
"side": "block/gold_block",
|
||||||
|
"inside": "block/gold_block"
|
||||||
|
},
|
||||||
|
"elements": [
|
||||||
|
{
|
||||||
|
"from": [ 0, 5, 0 ],
|
||||||
|
"to": [ 16, 6, 16 ],
|
||||||
|
"faces": {
|
||||||
|
"down": { "texture": "#inside" },
|
||||||
|
"up": { "texture": "#side" },
|
||||||
|
"north": { "texture": "#side" },
|
||||||
|
"south": { "texture": "#side" },
|
||||||
|
"west": { "texture": "#side" },
|
||||||
|
"east": { "texture": "#side" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": [ 0, 0, 0 ],
|
||||||
|
"to": [ 2, 5, 16 ],
|
||||||
|
"faces": {
|
||||||
|
"down": { "texture": "#top" },
|
||||||
|
"up": { "texture": "#side" },
|
||||||
|
"north": { "texture": "#side" },
|
||||||
|
"south": { "texture": "#side" },
|
||||||
|
"west": { "texture": "#side" },
|
||||||
|
"east": { "texture": "#side" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": [ 14, 0, 0 ],
|
||||||
|
"to": [ 16, 5, 16 ],
|
||||||
|
"faces": {
|
||||||
|
"down": { "texture": "#top" },
|
||||||
|
"up": { "texture": "#side" },
|
||||||
|
"north": { "texture": "#side" },
|
||||||
|
"south": { "texture": "#side" },
|
||||||
|
"west": { "texture": "#side" },
|
||||||
|
"east": { "texture": "#side" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": [ 2, 0, 0 ],
|
||||||
|
"to": [ 14, 5, 2 ],
|
||||||
|
"faces": {
|
||||||
|
"down": { "texture": "#top" },
|
||||||
|
"up": { "texture": "#side" },
|
||||||
|
"north": { "texture": "#side" },
|
||||||
|
"south": { "texture": "#side" },
|
||||||
|
"west": { "texture": "#side" },
|
||||||
|
"east": { "texture": "#side" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": [ 2, 0, 14 ],
|
||||||
|
"to": [ 14, 5, 16 ],
|
||||||
|
"faces": {
|
||||||
|
"down": { "texture": "#top" },
|
||||||
|
"up": { "texture": "#side" },
|
||||||
|
"north": { "texture": "#side" },
|
||||||
|
"south": { "texture": "#side" },
|
||||||
|
"west": { "texture": "#side" },
|
||||||
|
"east": { "texture": "#side" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": [ 4, 6, 4 ],
|
||||||
|
"to": [ 12, 12, 12 ],
|
||||||
|
"faces": {
|
||||||
|
"down": { "texture": "#side" },
|
||||||
|
"up": { "texture": "#side" },
|
||||||
|
"north": { "texture": "#side" },
|
||||||
|
"south": { "texture": "#side" },
|
||||||
|
"west": { "texture": "#side" },
|
||||||
|
"east": { "texture": "#side" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": [ 6, 12, 6 ],
|
||||||
|
"to": [ 10, 16, 10 ],
|
||||||
|
"faces": {
|
||||||
|
"down": { "texture": "#side" },
|
||||||
|
"up": { "texture": "#side" },
|
||||||
|
"north": { "texture": "#side" },
|
||||||
|
"south": { "texture": "#side" },
|
||||||
|
"west": { "texture": "#side" },
|
||||||
|
"east": { "texture": "#side" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"display": {
|
||||||
|
"gui": {
|
||||||
|
"rotation": [ 30, 225, 0 ],
|
||||||
|
"translation": [ 0, 0, 0],
|
||||||
|
"scale":[ 0.625, 0.625, 0.625 ]
|
||||||
|
},
|
||||||
|
"ground": {
|
||||||
|
"rotation": [ 0, 0, 0 ],
|
||||||
|
"translation": [ 0, 3, 0],
|
||||||
|
"scale":[ 0.25, 0.25, 0.25 ]
|
||||||
|
},
|
||||||
|
"fixed": {
|
||||||
|
"rotation": [ 0, 0, 0 ],
|
||||||
|
"translation": [ 0, 0, 0],
|
||||||
|
"scale":[ 0.5, 0.5, 0.5 ]
|
||||||
|
},
|
||||||
|
"thirdperson_righthand": {
|
||||||
|
"rotation": [ 75, 45, 0 ],
|
||||||
|
"translation": [ 0, 2.5, 0],
|
||||||
|
"scale": [ 0.375, 0.375, 0.375 ]
|
||||||
|
},
|
||||||
|
"firstperson_righthand": {
|
||||||
|
"rotation": [ 0, 45, 0 ],
|
||||||
|
"translation": [ 0, 0, 0 ],
|
||||||
|
"scale": [ 0.40, 0.40, 0.40 ]
|
||||||
|
},
|
||||||
|
"firstperson_lefthand": {
|
||||||
|
"rotation": [ 0, 225, 0 ],
|
||||||
|
"translation": [ 0, 0, 0 ],
|
||||||
|
"scale": [ 0.40, 0.40, 0.40 ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"parent": "extrahoppers:block/gold_hopper"
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"parent": "extrahoppers:block/inverted_gold_hopper"
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
{
|
||||||
|
"parent": "minecraft:recipes/root",
|
||||||
|
"rewards": {
|
||||||
|
"recipes": [
|
||||||
|
"extrahoppers:gold_hopper"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"criteria": {
|
||||||
|
"has_hopper_and_gold": {
|
||||||
|
"trigger": "minecraft:inventory_changed",
|
||||||
|
"conditions": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"item": "minecraft:hopper"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item": "minecraft:gold_ingot"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"has_the_recipe": {
|
||||||
|
"trigger": "minecraft:recipe_unlocked",
|
||||||
|
"conditions": {
|
||||||
|
"recipe": "extrahoppers:gold_hopper"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"requirements": [
|
||||||
|
[
|
||||||
|
"has_hopper_and_gold",
|
||||||
|
"has_the_recipe"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"type": "minecraft:block",
|
||||||
|
"pools": [
|
||||||
|
{
|
||||||
|
"rolls": 1,
|
||||||
|
"entries": [
|
||||||
|
{
|
||||||
|
"type": "minecraft:item",
|
||||||
|
"name": "extrahoppers:gold_hopper"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"conditions": [
|
||||||
|
{
|
||||||
|
"condition": "minecraft:survives_explosion"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"type": "minecraft:crafting_shaped",
|
||||||
|
"pattern": [
|
||||||
|
"G G",
|
||||||
|
"GCG",
|
||||||
|
" G "
|
||||||
|
],
|
||||||
|
"key": {
|
||||||
|
"C": {
|
||||||
|
"item": "minecraft:chest"
|
||||||
|
},
|
||||||
|
"G": {
|
||||||
|
"item": "minecraft:gold_ingot"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"result": {
|
||||||
|
"item": "extrahoppers:gold_hopper"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"type": "minecraft:crafting_shapeless",
|
||||||
|
"ingredients": [
|
||||||
|
{
|
||||||
|
"item": "extrahoppers:gold_hopper"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"result": {
|
||||||
|
"item": "extrahoppers:inverted_gold_hopper"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"type": "minecraft:crafting_shapeless",
|
||||||
|
"ingredients": [
|
||||||
|
{
|
||||||
|
"item": "extrahoppers:inverted_gold_hopper"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"result": {
|
||||||
|
"item": "extrahoppers:gold_hopper"
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue