Fix some interactions with clouds and reimplement fallthrough logic

This commit is contained in:
Sollace 2020-04-26 19:33:47 +02:00
parent cd4b74b2ce
commit 91e84e7551
15 changed files with 223 additions and 199 deletions

View file

@ -2,7 +2,7 @@ package com.minelittlepony.unicopia.block;
import java.util.Random; import java.util.Random;
import com.minelittlepony.unicopia.gas.CloudType; import com.minelittlepony.unicopia.gas.GasState;
import com.minelittlepony.unicopia.gas.Gas; import com.minelittlepony.unicopia.gas.Gas;
import com.minelittlepony.unicopia.particles.MagicParticleEffect; import com.minelittlepony.unicopia.particles.MagicParticleEffect;
@ -168,8 +168,8 @@ public class GlowingGemBlock extends TorchBlock implements Gas {
} }
@Override @Override
public CloudType getGasType(BlockState blockState) { public GasState getGasState(BlockState blockState) {
return CloudType.ENCHANTED; return GasState.ENCHANTED;
} }
@Override @Override

View file

@ -8,7 +8,7 @@ import com.minelittlepony.unicopia.gas.CloudFarmlandBlock;
import com.minelittlepony.unicopia.gas.CloudFenceBlock; import com.minelittlepony.unicopia.gas.CloudFenceBlock;
import com.minelittlepony.unicopia.gas.CloudSlabBlock; import com.minelittlepony.unicopia.gas.CloudSlabBlock;
import com.minelittlepony.unicopia.gas.CloudStairsBlock; import com.minelittlepony.unicopia.gas.CloudStairsBlock;
import com.minelittlepony.unicopia.gas.CloudType; import com.minelittlepony.unicopia.gas.GasState;
import com.minelittlepony.unicopia.item.UItems; import com.minelittlepony.unicopia.item.UItems;
import com.minelittlepony.unicopia.structure.CustomSaplingGenerator; import com.minelittlepony.unicopia.structure.CustomSaplingGenerator;
@ -24,15 +24,15 @@ import net.minecraft.util.registry.Registry;
public interface UBlocks { public interface UBlocks {
CloudFarmlandBlock CLOUD_FARMLAND = register(new CloudFarmlandBlock(FabricBlockSettings.of(UMaterials.CLOUD).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.WOOL).build()), "cloud_farmland"); CloudFarmlandBlock CLOUD_FARMLAND = register(new CloudFarmlandBlock(FabricBlockSettings.of(UMaterials.CLOUD).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.WOOL).build()), "cloud_farmland");
CloudBlock CLOUD_BLOCK = register(new CloudBlock(CloudType.NORMAL), "cloud_block"); CloudBlock CLOUD_BLOCK = register(new CloudBlock(GasState.NORMAL), "cloud_block");
CloudBlock ENCHANTED_CLOUD_BLOCK = register(new CloudBlock(CloudType.ENCHANTED), "enchanted_cloud_block"); CloudBlock ENCHANTED_CLOUD_BLOCK = register(new CloudBlock(GasState.ENCHANTED), "enchanted_cloud_block");
CloudBlock DENSE_CLOUD_BLOCK = register(new CloudBlock(CloudType.DENSE), "dense_cloud_block"); CloudBlock DENSE_CLOUD_BLOCK = register(new CloudBlock(GasState.DENSE), "dense_cloud_block");
CloudStairsBlock<CloudBlock> CLOUD_STAIRS = register(new CloudStairsBlock<>(CLOUD_BLOCK.getDefaultState(), CloudType.NORMAL.configure().build()), "cloud_stairs"); CloudStairsBlock<CloudBlock> CLOUD_STAIRS = register(new CloudStairsBlock<>(CLOUD_BLOCK.getDefaultState(), GasState.NORMAL.configure().build()), "cloud_stairs");
CloudSlabBlock<CloudBlock> CLOUD_SLAB = register(new CloudSlabBlock<>(CLOUD_BLOCK.getDefaultState(), CloudType.NORMAL.configure().build()), "cloud_slab"); CloudSlabBlock<CloudBlock> CLOUD_SLAB = register(new CloudSlabBlock<>(CLOUD_BLOCK.getDefaultState(), GasState.NORMAL.configure().build()), "cloud_slab");
CloudSlabBlock<CloudBlock> ENCHANTED_CLOUD_SLAB = register(new CloudSlabBlock<>(ENCHANTED_CLOUD_BLOCK.getDefaultState(), CloudType.ENCHANTED.configure().build()), "enchanted_cloud_slab"); CloudSlabBlock<CloudBlock> ENCHANTED_CLOUD_SLAB = register(new CloudSlabBlock<>(ENCHANTED_CLOUD_BLOCK.getDefaultState(), GasState.ENCHANTED.configure().build()), "enchanted_cloud_slab");
CloudSlabBlock<CloudBlock> DENSE_CLOUD_SLAB = register(new CloudSlabBlock<>(ENCHANTED_CLOUD_BLOCK.getDefaultState(), CloudType.DENSE.configure().build()), "dense_cloud_slab"); CloudSlabBlock<CloudBlock> DENSE_CLOUD_SLAB = register(new CloudSlabBlock<>(ENCHANTED_CLOUD_BLOCK.getDefaultState(), GasState.DENSE.configure().build()), "dense_cloud_slab");
CloudDoorBlock MISTED_GLASS_DOOR = register(new CloudDoorBlock(), "misted_glass_door"); CloudDoorBlock MISTED_GLASS_DOOR = register(new CloudDoorBlock(), "misted_glass_door");
DutchDoorBlock LIBRARY_DOOR = register(new DutchDoorBlock(FabricBlockSettings.of(Material.WOOD).sounds(BlockSoundGroup.WOOD).hardness(3).build()), "library_door"); DutchDoorBlock LIBRARY_DOOR = register(new DutchDoorBlock(FabricBlockSettings.of(Material.WOOD).sounds(BlockSoundGroup.WOOD).hardness(3).build()), "library_door");
@ -43,7 +43,7 @@ public interface UBlocks {
CloudAnvilBlock CLOUD_ANVIL = register(new CloudAnvilBlock(), "cloud_anvil"); CloudAnvilBlock CLOUD_ANVIL = register(new CloudAnvilBlock(), "cloud_anvil");
CloudFenceBlock CLOUD_FENCE = register(new CloudFenceBlock(CloudType.NORMAL), "cloud_fence"); CloudFenceBlock CLOUD_FENCE = register(new CloudFenceBlock(GasState.NORMAL), "cloud_fence");
TallCropBlock ALFALFA_CROPS = register(new TallCropBlock(FabricBlockSettings.of(Material.PLANT).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP).build()), "alfalfa_crops"); TallCropBlock ALFALFA_CROPS = register(new TallCropBlock(FabricBlockSettings.of(Material.PLANT).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP).build()), "alfalfa_crops");

View file

@ -4,12 +4,15 @@ import java.util.Random;
import com.minelittlepony.unicopia.util.WorldEvent; import com.minelittlepony.unicopia.util.WorldEvent;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.fabricmc.fabric.api.block.FabricBlockSettings; import net.fabricmc.fabric.api.block.FabricBlockSettings;
import net.fabricmc.fabric.api.tools.FabricToolTags; import net.fabricmc.fabric.api.tools.FabricToolTags;
import net.minecraft.block.AnvilBlock; import net.minecraft.block.AnvilBlock;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.block.Material; import net.minecraft.block.Material;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityContext;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.server.world.ServerWorld; import net.minecraft.server.world.ServerWorld;
import net.minecraft.sound.BlockSoundGroup; import net.minecraft.sound.BlockSoundGroup;
@ -17,6 +20,8 @@ import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand; import net.minecraft.util.Hand;
import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.shape.VoxelShape;
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;
@ -63,15 +68,17 @@ public class CloudAnvilBlock extends AnvilBlock implements Gas {
@Override @Override
public void scheduledTick(BlockState state, ServerWorld world, BlockPos pos, Random rand) { public void scheduledTick(BlockState state, ServerWorld world, BlockPos pos, Random rand) {
BlockState below = world.getBlockState(pos.down()); if (!(world.getBlockState(pos.down()).getBlock() instanceof Gas)) {
super.scheduledTick(state, world, pos, rand);
if (below.getBlock() instanceof Gas) {
if (((Gas)below.getBlock()).getGasType(below).isDense()) {
return;
}
} }
}
super.scheduledTick(state, world, pos, rand); @Override
@Environment(EnvType.CLIENT)
public void randomDisplayTick(BlockState state, World world, BlockPos pos, Random random) {
if (!(world.getBlockState(pos.down()).getBlock() instanceof Gas)) {
super.randomDisplayTick(state, world, pos, random);
}
} }
@Override @Override
@ -81,10 +88,32 @@ public class CloudAnvilBlock extends AnvilBlock implements Gas {
} }
} }
@Override
public VoxelShape getOutlineShape(BlockState state, BlockView view, BlockPos pos, EntityContext context) {
CloudInteractionContext ctx = (CloudInteractionContext)context;
if (!getGasState(state).canPlace(ctx)) {
return VoxelShapes.empty();
}
return super.getOutlineShape(state, view, pos, context);
}
@Override
public VoxelShape getCollisionShape(BlockState state, BlockView view, BlockPos pos, EntityContext context) {
CloudInteractionContext ctx = (CloudInteractionContext)context;
if (!getGasState(state).canTouch(ctx)) {
return VoxelShapes.empty();
}
return super.getCollisionShape(state, view, pos, context);
}
@Deprecated @Deprecated
@Override @Override
public float calcBlockBreakingDelta(BlockState state, PlayerEntity player, BlockView world, BlockPos pos) { public float calcBlockBreakingDelta(BlockState state, PlayerEntity player, BlockView world, BlockPos pos) {
if (!CloudType.NORMAL.canInteract(player)) { if (!GasState.NORMAL.canTouch(player)) {
return -1; return -1;
} }
return super.calcBlockBreakingDelta(state, player, world, pos); return super.calcBlockBreakingDelta(state, player, world, pos);
@ -92,7 +121,7 @@ public class CloudAnvilBlock extends AnvilBlock implements Gas {
@Override @Override
public CloudType getGasType(BlockState blockState) { public GasState getGasState(BlockState blockState) {
return CloudType.NORMAL; return GasState.NORMAL;
} }
} }

View file

@ -26,9 +26,9 @@ import net.minecraft.world.World;
public class CloudBlock extends Block implements Gas, HoeUtil.Tillable { public class CloudBlock extends Block implements Gas, HoeUtil.Tillable {
private final CloudType variant; private final GasState variant;
public CloudBlock(CloudType variant) { public CloudBlock(GasState variant) {
super(variant.configure() super(variant.configure()
.ticksRandomly() .ticksRandomly()
.build() .build()
@ -39,29 +39,29 @@ public class CloudBlock extends Block implements Gas, HoeUtil.Tillable {
@Override @Override
public boolean isTranslucent(BlockState state, BlockView world, BlockPos pos) { public boolean isTranslucent(BlockState state, BlockView world, BlockPos pos) {
return getGasType(state).isTranslucent(); return getGasState(state).isTranslucent();
} }
@Override @Override
public VoxelShape getOutlineShape(BlockState state, BlockView view, BlockPos pos, EntityContext context) { public VoxelShape getOutlineShape(BlockState state, BlockView view, BlockPos pos, EntityContext context) {
CloudInteractionContext ctx = (CloudInteractionContext)context; CloudInteractionContext ctx = (CloudInteractionContext)context;
if (!ctx.canTouch(getGasType(state))) { if (!getGasState(state).canPlace(ctx)) {
return VoxelShapes.empty(); return VoxelShapes.empty();
} }
return super.getOutlineShape(state, view, pos, context); return VoxelShapes.fullCube();
} }
@Override @Override
public VoxelShape getCollisionShape(BlockState state, BlockView view, BlockPos pos, EntityContext context) { public VoxelShape getCollisionShape(BlockState state, BlockView view, BlockPos pos, EntityContext context) {
CloudInteractionContext ctx = (CloudInteractionContext)context; CloudInteractionContext ctx = (CloudInteractionContext)context;
if (!ctx.canTouch(getGasType(state))) { if (!getGasState(state).canTouch(ctx)) {
return VoxelShapes.empty(); return VoxelShapes.empty();
} }
return super.getCollisionShape(state, view, pos, context); return collidable ? VoxelShapes.fullCube() : VoxelShapes.empty();
} }
@Override @Override
@ -115,14 +115,14 @@ public class CloudBlock extends Block implements Gas, HoeUtil.Tillable {
@Deprecated @Deprecated
@Override @Override
public float calcBlockBreakingDelta(BlockState state, PlayerEntity player, BlockView worldIn, BlockPos pos) { public float calcBlockBreakingDelta(BlockState state, PlayerEntity player, BlockView worldIn, BlockPos pos) {
if (CloudType.NORMAL.canInteract(player)) { if (GasState.NORMAL.canTouch(player)) {
return super.calcBlockBreakingDelta(state, player, worldIn, pos); return super.calcBlockBreakingDelta(state, player, worldIn, pos);
} }
return -1; return -1;
} }
@Override @Override
public CloudType getGasType(BlockState blockState) { public GasState getGasState(BlockState blockState) {
return variant; return variant;
} }

View file

@ -26,13 +26,13 @@ public class CloudDoorBlock extends AbstractDoorBlock implements Gas {
} }
@Override @Override
public CloudType getGasType(BlockState blockState) { public GasState getGasState(BlockState blockState) {
return CloudType.NORMAL; return GasState.NORMAL;
} }
@Override @Override
public ActionResult onUse(BlockState state, World worldIn, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) { public ActionResult onUse(BlockState state, World worldIn, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) {
if (!getCanInteract(state, player)) { if (!getGasState(state).canTouch(player)) {
return ActionResult.PASS; return ActionResult.PASS;
} }
return super.onUse(state, worldIn, pos, player, hand, hit); return super.onUse(state, worldIn, pos, player, hand, hit);
@ -56,7 +56,7 @@ public class CloudDoorBlock extends AbstractDoorBlock implements Gas {
@Deprecated @Deprecated
@Override @Override
public float calcBlockBreakingDelta(BlockState state, PlayerEntity player, BlockView worldIn, BlockPos pos) { public float calcBlockBreakingDelta(BlockState state, PlayerEntity player, BlockView worldIn, BlockPos pos) {
if (CloudType.NORMAL.canInteract(player)) { if (GasState.NORMAL.canTouch(player)) {
return super.calcBlockBreakingDelta(state, player, worldIn, pos); return super.calcBlockBreakingDelta(state, player, worldIn, pos);
} }
return -1; return -1;

View file

@ -29,7 +29,7 @@ public class CloudFarmlandBlock extends FarmlandBlock implements Farmland, Gas {
Gas cloud = ((Gas)beside.getBlock()); Gas cloud = ((Gas)beside.getBlock());
if (face.getAxis() == Axis.Y || cloud == this) { if (face.getAxis() == Axis.Y || cloud == this) {
if (cloud.getGasType(beside) == getGasType(state)) { if (cloud.getGasState(beside) == getGasState(state)) {
return true; return true;
} }
} }
@ -63,7 +63,7 @@ public class CloudFarmlandBlock extends FarmlandBlock implements Farmland, Gas {
public VoxelShape getOutlineShape(BlockState state, BlockView view, BlockPos pos, EntityContext context) { public VoxelShape getOutlineShape(BlockState state, BlockView view, BlockPos pos, EntityContext context) {
CloudInteractionContext ctx = (CloudInteractionContext)context; CloudInteractionContext ctx = (CloudInteractionContext)context;
if (!ctx.canTouch(getGasType(state))) { if (!getGasState(state).canPlace(ctx)) {
return VoxelShapes.empty(); return VoxelShapes.empty();
} }
@ -74,7 +74,7 @@ public class CloudFarmlandBlock extends FarmlandBlock implements Farmland, Gas {
public VoxelShape getCollisionShape(BlockState state, BlockView view, BlockPos pos, EntityContext context) { public VoxelShape getCollisionShape(BlockState state, BlockView view, BlockPos pos, EntityContext context) {
CloudInteractionContext ctx = (CloudInteractionContext)context; CloudInteractionContext ctx = (CloudInteractionContext)context;
if (!ctx.canTouch(getGasType(state))) { if (!getGasState(state).canTouch(ctx)) {
return VoxelShapes.empty(); return VoxelShapes.empty();
} }
@ -84,15 +84,15 @@ public class CloudFarmlandBlock extends FarmlandBlock implements Farmland, Gas {
@Deprecated @Deprecated
@Override @Override
public float calcBlockBreakingDelta(BlockState state, PlayerEntity player, BlockView world, BlockPos pos) { public float calcBlockBreakingDelta(BlockState state, PlayerEntity player, BlockView world, BlockPos pos) {
if (CloudType.NORMAL.canInteract(player)) { if (GasState.NORMAL.canTouch(player)) {
return super.calcBlockBreakingDelta(state, player, world, pos); return super.calcBlockBreakingDelta(state, player, world, pos);
} }
return -1; return -1;
} }
@Override @Override
public CloudType getGasType(BlockState blockState) { public GasState getGasState(BlockState blockState) {
return CloudType.NORMAL; return GasState.NORMAL;
} }
@Override @Override

View file

@ -13,20 +13,20 @@ import net.minecraft.world.World;
public class CloudFenceBlock extends FenceBlock implements Gas { public class CloudFenceBlock extends FenceBlock implements Gas {
private final CloudType variant; private final GasState variant;
public CloudFenceBlock(CloudType variant) { public CloudFenceBlock(GasState variant) {
super(variant.configure().build()); super(variant.configure().build());
this.variant = variant; this.variant = variant;
} }
@Override @Override
public boolean isTranslucent(BlockState state, BlockView world, BlockPos pos) { public boolean isTranslucent(BlockState state, BlockView world, BlockPos pos) {
return getGasType(state).isTranslucent(); return getGasState(state).isTranslucent();
} }
@Override @Override
public CloudType getGasType(BlockState blockState) { public GasState getGasState(BlockState blockState) {
return variant; return variant;
} }
@ -48,7 +48,7 @@ public class CloudFenceBlock extends FenceBlock implements Gas {
public VoxelShape getOutlineShape(BlockState state, BlockView view, BlockPos pos, EntityContext context) { public VoxelShape getOutlineShape(BlockState state, BlockView view, BlockPos pos, EntityContext context) {
CloudInteractionContext ctx = (CloudInteractionContext)context; CloudInteractionContext ctx = (CloudInteractionContext)context;
if (!ctx.canTouch(getGasType(state))) { if (!getGasState(state).canPlace(ctx)) {
return VoxelShapes.empty(); return VoxelShapes.empty();
} }
@ -59,7 +59,7 @@ public class CloudFenceBlock extends FenceBlock implements Gas {
public VoxelShape getCollisionShape(BlockState state, BlockView view, BlockPos pos, EntityContext context) { public VoxelShape getCollisionShape(BlockState state, BlockView view, BlockPos pos, EntityContext context) {
CloudInteractionContext ctx = (CloudInteractionContext)context; CloudInteractionContext ctx = (CloudInteractionContext)context;
if (!ctx.canTouch(getGasType(state))) { if (!getGasState(state).canTouch(ctx)) {
return VoxelShapes.empty(); return VoxelShapes.empty();
} }
@ -76,7 +76,7 @@ public class CloudFenceBlock extends FenceBlock implements Gas {
@Deprecated @Deprecated
@Override @Override
public float calcBlockBreakingDelta(BlockState state, PlayerEntity player, BlockView world, BlockPos pos) { public float calcBlockBreakingDelta(BlockState state, PlayerEntity player, BlockView world, BlockPos pos) {
if (CloudType.NORMAL.canInteract(player)) { if (GasState.NORMAL.canTouch(player)) {
return super.calcBlockBreakingDelta(state, player, world, pos); return super.calcBlockBreakingDelta(state, player, world, pos);
} }
return -1; return -1;

View file

@ -2,12 +2,17 @@ package com.minelittlepony.unicopia.gas;
import com.minelittlepony.unicopia.EquinePredicates; import com.minelittlepony.unicopia.EquinePredicates;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.item.ItemStack;
public interface CloudInteractionContext { public interface CloudInteractionContext {
static CloudInteractionContext of(Entity entity) { static CloudInteractionContext of(Entity entity) {
return entity == null ? Impl.EMPTY : new Impl(entity); return entity == null ? empty() : new Impl(entity);
}
static CloudInteractionContext empty() {
return Impl.EMPTY;
} }
default boolean isPlayer() { default boolean isPlayer() {
@ -18,7 +23,15 @@ public interface CloudInteractionContext {
return false; return false;
} }
boolean canTouch(CloudType type); default ItemStack getHeldStack() {
return ItemStack.EMPTY;
}
default boolean isEmpty() {
return this == empty();
}
boolean canTouch(GasState type);
interface Holder extends CloudInteractionContext { interface Holder extends CloudInteractionContext {
CloudInteractionContext getCloudInteractionContext(); CloudInteractionContext getCloudInteractionContext();
@ -34,20 +47,39 @@ public interface CloudInteractionContext {
} }
@Override @Override
default boolean canTouch(CloudType type) { default ItemStack getHeldStack() {
return getCloudInteractionContext().getHeldStack();
}
@Override
default boolean canTouch(GasState type) {
return getCloudInteractionContext().canTouch(type); return getCloudInteractionContext().canTouch(type);
} }
@Override
default boolean isEmpty() {
return getCloudInteractionContext().isEmpty();
}
} }
class Impl implements CloudInteractionContext { class Impl implements CloudInteractionContext {
public static final CloudInteractionContext EMPTY = type -> true; private static final CloudInteractionContext EMPTY = type -> true;
private final boolean isPlayer; private final boolean isPlayer;
private final boolean isPegasis; private final boolean isPegasis;
private ItemStack main = ItemStack.EMPTY;
private Impl(Entity entity) { private Impl(Entity entity) {
this.isPlayer = entity instanceof PlayerEntity; this.isPlayer = EquinePredicates.IS_PLAYER.test(entity);
this.isPegasis = EquinePredicates.ENTITY_INTERACT_WITH_CLOUD_BLOCKS.test(entity); this.isPegasis = EquinePredicates.ENTITY_INTERACT_WITH_CLOUD_BLOCKS.test(entity);
if (entity instanceof LivingEntity) {
main = ((LivingEntity)entity).getMainHandStack();
if (main.isEmpty()) {
main = ((LivingEntity)entity).getOffHandStack();
}
}
} }
@Override @Override
@ -61,8 +93,13 @@ public interface CloudInteractionContext {
} }
@Override @Override
public boolean canTouch(CloudType type) { public boolean canTouch(GasState type) {
return type.isTouchable(isPlayer()) || isPegasis(); return type.isTouchable(isPlayer(), isPegasis());
}
@Override
public ItemStack getHeldStack() {
return main;
} }
} }
} }

View file

@ -21,15 +21,15 @@ public class CloudSlabBlock<T extends Block & Gas> extends AbstractSlabBlock<T>
} }
@Override @Override
public CloudType getGasType(BlockState blockState) { public GasState getGasState(BlockState blockState) {
return modelBlock.getGasType(blockState); return modelBlock.getGasState(blockState);
} }
@Override @Override
public VoxelShape getOutlineShape(BlockState state, BlockView view, BlockPos pos, EntityContext context) { public VoxelShape getOutlineShape(BlockState state, BlockView view, BlockPos pos, EntityContext context) {
CloudInteractionContext ctx = (CloudInteractionContext)context; CloudInteractionContext ctx = (CloudInteractionContext)context;
if (!ctx.canTouch(getGasType(state))) { if (!getGasState(state).canTouch(ctx)) {
return VoxelShapes.empty(); return VoxelShapes.empty();
} }
@ -40,7 +40,7 @@ public class CloudSlabBlock<T extends Block & Gas> extends AbstractSlabBlock<T>
public VoxelShape getCollisionShape(BlockState state, BlockView view, BlockPos pos, EntityContext context) { public VoxelShape getCollisionShape(BlockState state, BlockView view, BlockPos pos, EntityContext context) {
CloudInteractionContext ctx = (CloudInteractionContext)context; CloudInteractionContext ctx = (CloudInteractionContext)context;
if (!ctx.canTouch(getGasType(state))) { if (!getGasState(state).canPlace(ctx)) {
return VoxelShapes.empty(); return VoxelShapes.empty();
} }

View file

@ -21,15 +21,15 @@ public class CloudStairsBlock<T extends Block & Gas> extends AbstractStairsBlock
} }
@Override @Override
public CloudType getGasType(BlockState state) { public GasState getGasState(BlockState state) {
return baseBlock.getGasType(baseBlockState); return baseBlock.getGasState(baseBlockState);
} }
@Override @Override
public VoxelShape getOutlineShape(BlockState state, BlockView view, BlockPos pos, EntityContext context) { public VoxelShape getOutlineShape(BlockState state, BlockView view, BlockPos pos, EntityContext context) {
CloudInteractionContext ctx = (CloudInteractionContext)context; CloudInteractionContext ctx = (CloudInteractionContext)context;
if (!ctx.canTouch(getGasType(state))) { if (!getGasState(state).canPlace(ctx)) {
return VoxelShapes.empty(); return VoxelShapes.empty();
} }
@ -40,7 +40,7 @@ public class CloudStairsBlock<T extends Block & Gas> extends AbstractStairsBlock
public VoxelShape getCollisionShape(BlockState state, BlockView view, BlockPos pos, EntityContext context) { public VoxelShape getCollisionShape(BlockState state, BlockView view, BlockPos pos, EntityContext context) {
CloudInteractionContext ctx = (CloudInteractionContext)context; CloudInteractionContext ctx = (CloudInteractionContext)context;
if (!ctx.canTouch(getGasType(state))) { if (!getGasState(state).canPlace(ctx)) {
return VoxelShapes.empty(); return VoxelShapes.empty();
} }

View file

@ -1,156 +1,53 @@
package com.minelittlepony.unicopia.gas; package com.minelittlepony.unicopia.gas;
import com.minelittlepony.unicopia.EquinePredicates;
import net.minecraft.block.BedBlock;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.block.ChestBlock;
import net.minecraft.block.FallingBlock;
import net.minecraft.block.TorchBlock;
import net.minecraft.client.MinecraftClient;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.ItemEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.world.BlockView;
import net.minecraft.world.World;
public interface Gas { public interface Gas {
CloudType getGasType(BlockState blockState); GasState getGasState(BlockState blockState);
default boolean handleRayTraceSpecialCases(World world, BlockPos pos, BlockState state) { default boolean applyLanding(Entity entity, float fallDistance) {
if (world.isClient) { if (entity.isSneaking()) {
PlayerEntity player = MinecraftClient.getInstance().player; return true;
if (player.abilities.creativeMode) {
return false;
}
if (!getCanInteract(state, player)) {
return true;
}
CloudType type = getGasType(state);
ItemStack main = player.getMainHandStack();
if (main.isEmpty()) {
main = player.getOffHandStack();
}
if (!main.isEmpty() && main.getItem() instanceof BlockItem) {
Block block = ((BlockItem)main.getItem()).getBlock();
BlockState heldState = block.getDefaultState();
if (block == null || block.isAir(heldState)) {
return false;
}
if (block instanceof Gas) {
CloudType other = ((Gas)block).getGasType(heldState);
if (other.canInteract(player)) {
return false;
}
}
if (!EquinePredicates.PLAYER_PEGASUS.test(player)) {
return type != CloudType.ENCHANTED;
}
if (type == CloudType.NORMAL) {
return !isPlacementExcempt(block);
}
}
} }
entity.handleFallDamage(fallDistance, 0);
return false; return false;
} }
default boolean isPlacementExcempt(Block block) { default boolean applyRebound(Entity entity) {
return block instanceof TorchBlock double y = entity.getVelocity().y;
|| block instanceof BedBlock
|| block instanceof ChestBlock;
}
default boolean applyLanding(Entity entity, float fallDistance) {
if (!entity.isSneaking()) {
entity.handleFallDamage(fallDistance, 0);
if (entity.isSneaking() || y >= 0 || Math.abs(y) < 0.25) {
return false; return false;
} }
entity.setVelocity(entity.getVelocity().multiply(1, -1.2, 1));
return true; return true;
} }
default boolean applyRebound(Entity entity) {
Vec3d vel = entity.getVelocity();
double y = vel.y;
if (!entity.isSneaking() && y < 0) {
if (Math.abs(y) >= 0.25) {
y = -y * 1.2;
} else {
y = 0;
}
entity.setVelocity(vel.x, y, vel.z);
return true;
}
return false;
}
default boolean applyBouncyness(BlockState state, Entity entity) { default boolean applyBouncyness(BlockState state, Entity entity) {
if (getCanInteract(state, entity)) { if (!getGasState(state).canTouch(entity)) {
Vec3d vel = entity.getVelocity();
double y = vel.y;
if (!entity.isSneaking() && Math.abs(y) >= 0.25) {
y += 0.0155 * (entity.fallDistance < 1 ? 1 : entity.fallDistance);
} else {
y = 0;
}
entity.setVelocity(vel.x, y, vel.z);
return true;
}
return false;
}
default boolean getCanInteract(BlockState state, Entity e) {
if (getGasType(state).canInteract(e)) {
if (e instanceof ItemEntity) {
// @FUF(reason = "There is no TickEvents.EntityTickEvent. Waiting on mixins...")
e.setNoGravity(true);
}
return true;
}
return false;
}
/**
* Determines whether falling sand entities should fall through this block.
* @param state Our block state
* @param world The current world
* @param pos The current position
*
* @return True to allow blocks to pass.
*
* @fuf Hacked until we can get mixins to implement a proper hook
*/
default boolean allowsFallingBlockToPass(BlockState state, BlockView world, BlockPos pos) {
if (this.getGasType(state).isDense()) {
return false; return false;
} }
Block above = world.getBlockState(pos.up()).getBlock(); Vec3d vel = entity.getVelocity();
return !(above instanceof Gas) && above instanceof FallingBlock; double y = vel.y;
if (entity.isSneaking() || Math.abs(y) < 0.25) {
y = 0;
} else {
y += 0.0155 * Math.max(1, entity.fallDistance);
}
entity.setVelocity(vel.x, y, vel.z);
return true;
}
default boolean isSupporting(BlockState state) {
return getGasState(state).isDense();
} }
} }

View file

@ -1,11 +1,18 @@
package com.minelittlepony.unicopia.gas; package com.minelittlepony.unicopia.gas;
import com.minelittlepony.unicopia.EquinePredicates;
import com.minelittlepony.unicopia.block.UMaterials; import com.minelittlepony.unicopia.block.UMaterials;
import net.fabricmc.fabric.api.block.FabricBlockSettings; import net.fabricmc.fabric.api.block.FabricBlockSettings;
import net.minecraft.block.BedBlock;
import net.minecraft.block.Block;
import net.minecraft.block.ChestBlock;
import net.minecraft.block.TorchBlock;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemStack;
import net.minecraft.sound.BlockSoundGroup; import net.minecraft.sound.BlockSoundGroup;
public enum CloudType { public enum GasState {
NORMAL, NORMAL,
DENSE, DENSE,
ENCHANTED; ENCHANTED;
@ -25,11 +32,39 @@ public enum CloudType {
return this != NORMAL; return this != NORMAL;
} }
public boolean isTouchable(boolean isPlayer) { public boolean isTouchable(boolean isPlayer, boolean isPegasus) {
return this == ENCHANTED || (this == DENSE && isPlayer); return isPegasus || this == ENCHANTED || (this == DENSE && isPlayer);
} }
public boolean canInteract(Entity e) { public boolean canTouch(Entity e) {
return CloudInteractionContext.of(e).canTouch(this); return isTouchable(EquinePredicates.IS_PLAYER.test(e), EquinePredicates.ENTITY_INTERACT_WITH_CLOUD_BLOCKS.test(e));
} }
public boolean canTouch(CloudInteractionContext context) {
return context.canTouch(this);
}
public boolean canPlace(CloudInteractionContext context) {
return context.isEmpty() || canTouch(context) && heldCanTouch(context);
}
private boolean heldCanTouch(CloudInteractionContext context) {
ItemStack main = context.getHeldStack();
if (main.getItem() instanceof BlockItem) {
Block block = ((BlockItem)main.getItem()).getBlock();
if (block instanceof Gas && ((Gas)block).getGasState(block.getDefaultState()).canTouch(context)) {
return true;
}
return this == GasState.NORMAL && (
block instanceof TorchBlock
|| block instanceof BedBlock
|| block instanceof ChestBlock);
}
return main.isEmpty();
}
} }

View file

@ -20,6 +20,6 @@ abstract class MixinEntityContextImpl implements CloudInteractionContext.Holder
@Override @Override
public CloudInteractionContext getCloudInteractionContext() { public CloudInteractionContext getCloudInteractionContext() {
return cloudContext == null ? CloudInteractionContext.Impl.EMPTY : cloudContext; return cloudContext == null ? CloudInteractionContext.empty() : cloudContext;
} }
} }

View file

@ -0,0 +1,25 @@
package com.minelittlepony.unicopia.mixin;
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.callback.CallbackInfoReturnable;
import com.minelittlepony.unicopia.gas.Gas;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.FallingBlock;
@Mixin(FallingBlock.class)
abstract class MixinFallingBlock extends Block {
MixinFallingBlock() { super(null); }
@Inject(method = "canFallThrough(Lnet/minecraft/block/BlockState;)Z",
at = @At("HEAD"),
cancellable = true)
private static void onCanFallThrough(BlockState state, CallbackInfoReturnable<Boolean> info) {
if (state.getBlock() instanceof Gas) {
info.setReturnValue(!((Gas)state.getBlock()).isSupporting(state));
}
}
}

View file

@ -8,6 +8,7 @@
"CriterionsRegistry", "CriterionsRegistry",
"MixinBlockItem", "MixinBlockItem",
"MixinEntityContextImpl", "MixinEntityContextImpl",
"MixinFallingBlock",
"MixinFarmlandBlock", "MixinFarmlandBlock",
"MixinHoeItem", "MixinHoeItem",
"MixinItem", "MixinItem",