Basic Grate implementation

This commit is contained in:
Shadowfacts 2020-03-28 23:31:21 -04:00
parent 5e42cbddce
commit 22891a9692
Signed by: shadowfacts
GPG Key ID: 94A5AB95422746E5
15 changed files with 388 additions and 2 deletions

View File

@ -0,0 +1,58 @@
package net.shadowfacts.extrahoppers.mixin;
import net.minecraft.block.BlockState;
import net.minecraft.fluid.BaseFluid;
import net.minecraft.fluid.FluidState;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.BlockView;
import net.minecraft.world.WorldView;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyVariable;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import net.shadowfacts.extrahoppers.util.FluidFlowControllable;
import net.shadowfacts.extrahoppers.util.PositionedFluidStateProvider;
/**
* @author shadowfacts
*/
@Mixin(BaseFluid.class)
public abstract class MixinBaseFluid {
@ModifyVariable(
method = "getUpdatedState(Lnet/minecraft/world/WorldView;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;)Lnet/minecraft/fluid/FluidState;",
at = @At(value = "INVOKE", target = "Lnet/minecraft/fluid/FluidState;isEmpty()Z", shift = At.Shift.BEFORE),
index = 8,
ordinal = 0,
require = 1
)
private FluidState getUpdatedState(FluidState initial, WorldView world, BlockPos pos, BlockState state) {
BlockPos up = pos.up();
BlockState upState = world.getBlockState(up);
if (upState.getBlock() instanceof PositionedFluidStateProvider) {
return ((PositionedFluidStateProvider)upState.getBlock()).getFluidState(upState, world, up);
}
return initial;
}
@Inject(
method = "receivesFlow(Lnet/minecraft/util/math/Direction;Lnet/minecraft/world/BlockView;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;)Z",
at = @At("HEAD"),
cancellable = true
)
private void receivesFlow(Direction direction, BlockView world, BlockPos pos, BlockState state, BlockPos fromPos, BlockState fromState, CallbackInfoReturnable<Boolean> cir) {
FluidFlowControllable.Result result = FluidFlowControllable.Result.DEFAULT;
if (state.getBlock() instanceof FluidFlowControllable) {
result = ((FluidFlowControllable)state.getBlock()).allowsFlow(direction, state, world, pos);
}
if (result != FluidFlowControllable.Result.DENY && fromState.getBlock() instanceof FluidFlowControllable) {
result = ((FluidFlowControllable)fromState.getBlock()).allowsFlow(direction, fromState, world, fromPos);
}
if (result != FluidFlowControllable.Result.DEFAULT) {
cir.setReturnValue(result == FluidFlowControllable.Result.ALLOW);
}
}
}

View File

@ -0,0 +1,36 @@
package net.shadowfacts.extrahoppers.mixin;
import net.minecraft.block.BlockState;
import net.minecraft.fluid.FluidState;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.WorldChunk;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import net.shadowfacts.extrahoppers.util.PositionedFluidStateProvider;
/**
* @author shadowfacts
*/
@Mixin(WorldChunk.class)
public abstract class MixinWorldChunk implements Chunk {
@Shadow
private World world;
@Inject(method = "getFluidState(III)Lnet/minecraft/fluid/FluidState;", at = @At("HEAD"), cancellable = true)
public void getFluidState(int x, int y, int z, CallbackInfoReturnable<FluidState> cir) {
BlockPos pos = new BlockPos(x, y, z);
BlockState state = getBlockState(pos);
if (state.getBlock() instanceof PositionedFluidStateProvider) {
FluidState fluidState = ((PositionedFluidStateProvider)state.getBlock()).getFluidState(state, world, pos);
cir.setReturnValue(fluidState);
cir.cancel();
}
}
}

View File

@ -0,0 +1,23 @@
package net.shadowfacts.extrahoppers.util;
import net.minecraft.block.BlockState;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.BlockView;
import org.jetbrains.annotations.NotNull;
/**
* @author shadowfacts
*/
public interface FluidFlowControllable {
@NotNull
Result allowsFlow(@NotNull Direction toSide, @NotNull BlockState state, @NotNull BlockView world, @NotNull BlockPos pos);
enum Result {
ALLOW,
DENY,
DEFAULT
}
}

View File

@ -0,0 +1,14 @@
package net.shadowfacts.extrahoppers.util;
import net.minecraft.block.BlockState;
import net.minecraft.fluid.FluidState;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.BlockView;
import org.jetbrains.annotations.NotNull;
/**
* @author shadowfacts
*/
public interface PositionedFluidStateProvider {
FluidState getFluidState(@NotNull BlockState state, @NotNull BlockView world, @NotNull BlockPos pos);
}

View File

@ -0,0 +1,121 @@
package net.shadowfacts.extrahoppers.block.grate
import net.fabricmc.fabric.api.block.FabricBlockSettings
import net.minecraft.block.*
import net.minecraft.block.enums.BlockHalf
import net.minecraft.entity.EntityContext
import net.minecraft.fluid.Fluid
import net.minecraft.fluid.FluidState
import net.minecraft.fluid.Fluids
import net.minecraft.item.ItemPlacementContext
import net.minecraft.sound.BlockSoundGroup
import net.minecraft.state.StateManager
import net.minecraft.state.property.Properties
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.world.BlockView
import net.minecraft.world.IWorld
import net.shadowfacts.extrahoppers.block.base.BlockWithEntity
import net.shadowfacts.extrahoppers.util.FluidFlowControllable
import net.shadowfacts.extrahoppers.util.PositionedFluidStateProvider
/**
* @author shadowfacts
*/
class GrateBlock: BlockWithEntity<GrateBlockEntity>(
FabricBlockSettings.of(Material.METAL, MaterialColor.AIR)
.strength(5f, 6f)
.sounds(BlockSoundGroup.METAL)
.nonOpaque()
.build()
), PositionedFluidStateProvider, FluidFlowControllable, FluidFillable, FluidDrainable {
companion object {
val ID = Identifier("extrahoppers", "grate")
val HALF = Properties.BLOCK_HALF
val TOP_SHAPE = createCuboidShape(0.0, 15.0, 0.0, 16.0, 16.0, 16.0)
val BOTTOM_SHAPE = createCuboidShape(0.0, 0.0, 0.0, 16.0, 1.0, 16.0)
}
init {
defaultState = stateManager.defaultState.with(HALF, BlockHalf.BOTTOM)
}
override fun appendProperties(builder: StateManager.Builder<Block, BlockState>) {
builder.add(HALF)
}
override fun getOutlineShape(state: BlockState, world: BlockView, pos: BlockPos, entityContext: EntityContext): VoxelShape {
return when (state.get(HALF)) {
BlockHalf.TOP -> TOP_SHAPE
BlockHalf.BOTTOM -> BOTTOM_SHAPE
}
}
override fun getRayTraceShape(state: BlockState, world: BlockView, pos: BlockPos): VoxelShape {
return when (state.get(HALF)) {
BlockHalf.TOP -> TOP_SHAPE
BlockHalf.BOTTOM -> BOTTOM_SHAPE
}
}
override fun getPlacementState(context: ItemPlacementContext): BlockState {
val half = when (context.side) {
Direction.DOWN -> BlockHalf.TOP
Direction.UP -> BlockHalf.BOTTOM
else -> if (context.hitPos.y - context.blockPos.y > 0.5) BlockHalf.TOP else BlockHalf.BOTTOM
}
return defaultState.with(HALF, half)
}
override fun createBlockEntity(world: BlockView) = GrateBlockEntity()
override fun getFluidState(state: BlockState, world: BlockView, pos: BlockPos): FluidState {
return getBlockEntity(world, pos)?.fluidState ?: Fluids.EMPTY.defaultState
}
override fun allowsFlow(toSide: Direction, state: BlockState, world: BlockView, pos: BlockPos): FluidFlowControllable.Result {
return FluidFlowControllable.Result.ALLOW
}
// Fluid Fillable
override fun canFillWithFluid(world: BlockView, pos: BlockPos, state: BlockState, fluid: Fluid): Boolean {
val be = getBlockEntity(world, pos)
return be != null && be.fluidState == null
}
override fun tryFillWithFluid(world: IWorld, pos: BlockPos, state: BlockState, fluidState: FluidState): Boolean {
val be = getBlockEntity(world, pos)
return if (be != null) {
if (!world.isClient) {
be.fluidState = fluidState
world.fluidTickScheduler.schedule(pos, fluidState.fluid, fluidState.fluid.getTickRate(world))
be.sync()
}
true
} else {
false
}
}
override fun tryDrainFluid(world: IWorld, pos: BlockPos, state: BlockState): Fluid {
val be = getBlockEntity(world, pos) ?: return Fluids.EMPTY
val fluidState = be.fluidState ?: return Fluids.EMPTY
return if (fluidState.isStill) {
if (!world.isClient) {
be.fluidState = null
be.sync()
}
fluidState.fluid
} else {
Fluids.EMPTY
}
}
}

View File

@ -0,0 +1,45 @@
package net.shadowfacts.extrahoppers.block.grate
import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable
import net.fabricmc.fabric.api.util.NbtType
import net.minecraft.block.entity.BlockEntity
import net.minecraft.fluid.FluidState
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.NbtHelper
import net.shadowfacts.extrahoppers.init.EHBlockEntities
/**
* @author shadowfacts
*/
class GrateBlockEntity: BlockEntity(EHBlockEntities.GRATE), BlockEntityClientSerializable {
var fluidState: FluidState? = null
override fun toTag(tag: CompoundTag): CompoundTag {
fluidState?.also {
tag.put("fluid", NbtHelper.fromBlockState(it.blockState))
}
return super.toTag(tag)
}
override fun fromTag(tag: CompoundTag) {
super.fromTag(tag)
if (tag.contains("fluid", NbtType.COMPOUND)) {
fluidState = NbtHelper.toBlockState(tag.getCompound("fluid")).fluidState
}
}
override fun toClientTag(tag: CompoundTag): CompoundTag {
fluidState?.also {
tag.put("fluid", NbtHelper.fromBlockState(it.blockState))
}
return tag
}
override fun fromClientTag(tag: CompoundTag) {
if (tag.contains("fluid", NbtType.COMPOUND)) {
fluidState = NbtHelper.toBlockState(tag.getCompound("fluid")).fluidState
}
}
}

View File

@ -8,6 +8,8 @@ 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.grate.GrateBlock
import net.shadowfacts.extrahoppers.block.grate.GrateBlockEntity
import net.shadowfacts.extrahoppers.block.wood.WoodHopperBlock
import net.shadowfacts.extrahoppers.block.wood.WoodHopperBlockEntity
@ -16,12 +18,13 @@ object EHBlockEntities {
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)
val GRATE = create(::GrateBlockEntity, EHBlocks.GRATE)
fun init() {
register(WoodHopperBlock.ID, WOOD_HOPPER)
register(GoldHopperBlock.ID, GOLD_HOPPER)
register(InvertedGoldHopperBlock.ID, INVERTED_GOLD_HOPPER)
register(GrateBlock.ID, GRATE)
}
private fun <T: BlockEntity> create(builder: () -> T, block: Block): BlockEntityType<T> {

View File

@ -5,6 +5,7 @@ import net.minecraft.util.Identifier
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.grate.GrateBlock
import net.shadowfacts.extrahoppers.block.wood.WoodHopperBlock
object EHBlocks {
@ -12,11 +13,13 @@ object EHBlocks {
val WOOD_HOPPER = WoodHopperBlock()
val GOLD_HOPPER = GoldHopperBlock()
val INVERTED_GOLD_HOPPER = InvertedGoldHopperBlock()
val GRATE = GrateBlock()
fun init() {
register(WoodHopperBlock.ID, WOOD_HOPPER)
register(GoldHopperBlock.ID, GOLD_HOPPER)
register(InvertedGoldHopperBlock.ID, INVERTED_GOLD_HOPPER)
register(GrateBlock.ID, GRATE)
}
private fun register(id: Identifier, block: Block) {

View File

@ -6,6 +6,7 @@ import net.minecraft.util.Identifier
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.grate.GrateBlock
import net.shadowfacts.extrahoppers.block.wood.WoodHopperBlock
object EHItems {
@ -13,11 +14,13 @@ object EHItems {
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())
val GRATE = BlockItem(EHBlocks.GRATE, Item.Settings())
fun init() {
register(WoodHopperBlock.ID, WOOD_HOPPER)
register(GoldHopperBlock.ID, GOLD_HOPPER)
register(InvertedGoldHopperBlock.ID, INVERTED_GOLD_HOPPER)
register(GrateBlock.ID, GRATE)
}
private fun register(id: Identifier, item: Item) {

View File

@ -0,0 +1,6 @@
{
"variants": {
"half=top": { "model": "extrahoppers:block/grate" },
"half=bottom": { "model": "extrahoppers:block/grate", "x": 180 }
}
}

View File

@ -1,5 +1,6 @@
{
"block.extrahoppers.wood_hopper": "Wooden Hopper",
"block.extrahoppers.gold_hopper": "Golden Hopper",
"block.extrahoppers.inverted_gold_hopper": "Inverted Golden Hopper"
"block.extrahoppers.inverted_gold_hopper": "Inverted Golden Hopper",
"block.extrahoppers.grate": "Grate"
}

View File

@ -0,0 +1,53 @@
{
"ambientocclusion": false,
"textures": {
"face": "extrahoppers:block/grate/face",
"edge": "extrahoppers:block/grate/edge"
},
"elements": [
{
"from": [0, 15, 0],
"to": [16, 16, 16],
"faces": {
"down": {"texture": "#face"},
"up": {"texture": "#face", "cullface": "up"},
"north": {"texture": "#edge", "cullface": "north"},
"south": {"texture": "#edge", "cullface": "south"},
"west": {"texture": "#edge", "cullface": "west"},
"east": {"texture": "#edge", "cullface": "east"}
}
}
],
"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 ]
}
}
}

View File

@ -0,0 +1,3 @@
{
"parent": "extrahoppers:block/grate"
}

View File

@ -0,0 +1,14 @@
{
"required": true,
"package": "net.shadowfacts.extrahoppers.mixin",
"compatibilityLevel": "JAVA_8",
"mixins": [
"MixinWorldChunk",
"MixinBaseFluid"
],
"client": [
],
"injectors": {
"defaultRequire": 1
}
}

View File

@ -17,6 +17,9 @@
}
]
},
"mixins": [
"extrahoppers.mixins.json"
],
"depends": {
}