mirror of
https://github.com/Sollace/Unicopia.git
synced 2025-03-04 09:11:28 +01:00
Fix bugs and allow for storing bucketed entities in jars
This commit is contained in:
parent
f0b2a8a550
commit
2784627adc
8 changed files with 474 additions and 76 deletions
src/main
java/com/minelittlepony/unicopia
block
client/render
mixin
util
resources
|
@ -2,18 +2,38 @@ package com.minelittlepony.unicopia.block;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.IntStream;
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import com.minelittlepony.unicopia.mixin.MixinEntityBucketItem;
|
||||||
|
import com.minelittlepony.unicopia.util.NbtSerialisable;
|
||||||
|
|
||||||
import net.minecraft.block.BlockEntityProvider;
|
import net.minecraft.block.BlockEntityProvider;
|
||||||
import net.minecraft.block.BlockRenderType;
|
import net.minecraft.block.BlockRenderType;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.block.Blocks;
|
||||||
import net.minecraft.block.InventoryProvider;
|
import net.minecraft.block.InventoryProvider;
|
||||||
import net.minecraft.block.entity.BlockEntity;
|
import net.minecraft.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.entity.Bucketable;
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.entity.EntityType;
|
||||||
import net.minecraft.entity.player.PlayerEntity;
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
import net.minecraft.inventory.SidedInventory;
|
import net.minecraft.inventory.SidedInventory;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.item.Items;
|
||||||
|
import net.minecraft.nbt.NbtCompound;
|
||||||
|
import net.minecraft.nbt.NbtElement;
|
||||||
|
import net.minecraft.network.listener.ClientPlayPacketListener;
|
||||||
|
import net.minecraft.network.packet.Packet;
|
||||||
|
import net.minecraft.network.packet.s2c.play.BlockEntityUpdateS2CPacket;
|
||||||
|
import net.minecraft.registry.Registries;
|
||||||
|
import net.minecraft.server.world.ServerWorld;
|
||||||
import net.minecraft.util.ActionResult;
|
import net.minecraft.util.ActionResult;
|
||||||
import net.minecraft.util.Hand;
|
import net.minecraft.util.Hand;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
import net.minecraft.util.TypedActionResult;
|
||||||
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.math.Direction;
|
import net.minecraft.util.math.Direction;
|
||||||
|
@ -36,14 +56,7 @@ public class ItemJarBlock extends JarBlock implements BlockEntityProvider, Inven
|
||||||
if (hand == Hand.OFF_HAND) {
|
if (hand == Hand.OFF_HAND) {
|
||||||
return ActionResult.PASS;
|
return ActionResult.PASS;
|
||||||
}
|
}
|
||||||
return world.getBlockEntity(pos, UBlockEntities.ITEM_JAR).map(data -> {
|
return world.getBlockEntity(pos, UBlockEntities.ITEM_JAR).map(data -> data.interact(player, hand)).orElse(ActionResult.PASS);
|
||||||
ItemStack stack = player.getStackInHand(hand);
|
|
||||||
if (stack.isEmpty()) {
|
|
||||||
return data.removeItem(world, pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
return data.insertItem(world, pos, player.isCreative() ? stack.copyWithCount(1) : stack.split(1));
|
|
||||||
}).orElse(ActionResult.PASS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
|
@ -51,9 +64,7 @@ public class ItemJarBlock extends JarBlock implements BlockEntityProvider, Inven
|
||||||
public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) {
|
public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) {
|
||||||
if (!moved && !state.isOf(newState.getBlock())) {
|
if (!moved && !state.isOf(newState.getBlock())) {
|
||||||
world.getBlockEntity(pos, UBlockEntities.ITEM_JAR).ifPresent(data -> {
|
world.getBlockEntity(pos, UBlockEntities.ITEM_JAR).ifPresent(data -> {
|
||||||
data.getStacks().forEach(stack -> {
|
data.getContents().onDestroyed();
|
||||||
dropStack(world, pos, stack);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
super.onStateReplaced(state, world, pos, newState, moved);
|
super.onStateReplaced(state, world, pos, newState, moved);
|
||||||
|
@ -66,7 +77,10 @@ public class ItemJarBlock extends JarBlock implements BlockEntityProvider, Inven
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getComparatorOutput(BlockState state, World world, BlockPos pos) {
|
public int getComparatorOutput(BlockState state, World world, BlockPos pos) {
|
||||||
return world.getBlockEntity(pos, UBlockEntities.ITEM_JAR).map(data -> Math.min(16, data.getStacks().size())).orElse(0);
|
return world.getBlockEntity(pos, UBlockEntities.ITEM_JAR)
|
||||||
|
.map(TileData::getItems)
|
||||||
|
.map(data -> Math.min(16, data.getStacks().size()))
|
||||||
|
.orElse(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
|
@ -85,34 +99,210 @@ public class ItemJarBlock extends JarBlock implements BlockEntityProvider, Inven
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SidedInventory getInventory(BlockState state, WorldAccess world, BlockPos pos) {
|
public SidedInventory getInventory(BlockState state, WorldAccess world, BlockPos pos) {
|
||||||
return world.getBlockEntity(pos, UBlockEntities.ITEM_JAR).orElse(null);
|
return world.getBlockEntity(pos, UBlockEntities.ITEM_JAR).map(TileData::getItems).orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TileData extends BlockEntity implements SidedInventory {
|
public static class TileData extends BlockEntity {
|
||||||
private static final int[] SLOTS = IntStream.range(0, 16).toArray();
|
|
||||||
private final List<ItemStack> stacks = new ArrayList<>();
|
private JarContents contents = new ItemsJarContents(this);
|
||||||
|
|
||||||
public TileData(BlockPos pos, BlockState state) {
|
public TileData(BlockPos pos, BlockState state) {
|
||||||
super(UBlockEntities.ITEM_JAR, pos, state);
|
super(UBlockEntities.ITEM_JAR, pos, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ActionResult insertItem(World world, BlockPos pos, ItemStack stack) {
|
public ActionResult interact(PlayerEntity player, Hand hand) {
|
||||||
if (stacks.size() >= size()) {
|
TypedActionResult<JarContents> result = contents.interact(player, hand);
|
||||||
return ActionResult.FAIL;
|
contents = result.getValue();
|
||||||
}
|
return result.getResult();
|
||||||
stacks.add(stack);
|
|
||||||
markDirty();
|
|
||||||
|
|
||||||
return ActionResult.SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ActionResult removeItem(World world, BlockPos pos) {
|
public JarContents getContents() {
|
||||||
|
return contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public ItemsJarContents getItems() {
|
||||||
|
return getContents() instanceof ItemsJarContents c ? c : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public EntityJarContents getEntity() {
|
||||||
|
return getContents() instanceof EntityJarContents c ? c : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Packet<ClientPlayPacketListener> toUpdatePacket() {
|
||||||
|
return BlockEntityUpdateS2CPacket.create(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NbtCompound toInitialChunkDataNbt() {
|
||||||
|
return createNbt();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void markDirty() {
|
||||||
|
super.markDirty();
|
||||||
|
if (getWorld() instanceof ServerWorld sw) {
|
||||||
|
sw.getChunkManager().markForUpdate(getPos());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readNbt(NbtCompound nbt) {
|
||||||
|
if (nbt.contains("items", NbtElement.COMPOUND_TYPE)) {
|
||||||
|
contents = new ItemsJarContents(this);
|
||||||
|
contents.fromNBT(nbt.getCompound("items"));
|
||||||
|
} else if (nbt.contains("entity", NbtElement.COMPOUND_TYPE)) {
|
||||||
|
contents = new EntityJarContents(this);
|
||||||
|
contents.fromNBT(nbt.getCompound("entity"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void writeNbt(NbtCompound nbt) {
|
||||||
|
var items = getItems();
|
||||||
|
if (items != null) {
|
||||||
|
nbt.put("items", items.toNBT());
|
||||||
|
} else if (getEntity() != null) {
|
||||||
|
nbt.put("entity", getEntity().toNBT());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public interface JarContents extends NbtSerialisable {
|
||||||
|
TypedActionResult<JarContents> interact(PlayerEntity player, Hand hand);
|
||||||
|
|
||||||
|
void onDestroyed();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class EntityJarContents implements JarContents {
|
||||||
|
@Nullable
|
||||||
|
private EntityType<?> entityType;
|
||||||
|
@Nullable
|
||||||
|
private Entity renderEntity;
|
||||||
|
|
||||||
|
private final TileData tile;
|
||||||
|
|
||||||
|
public EntityJarContents(TileData tile) {
|
||||||
|
this(tile, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public EntityJarContents(TileData tile, EntityType<?> entityType) {
|
||||||
|
this.tile = tile;
|
||||||
|
this.entityType = entityType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Entity getOrCreateEntity() {
|
||||||
|
if (entityType == null && tile.getWorld() != null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (renderEntity == null || renderEntity.getType() != entityType) {
|
||||||
|
renderEntity = entityType.create(tile.getWorld());
|
||||||
|
}
|
||||||
|
return renderEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypedActionResult<JarContents> interact(PlayerEntity player, Hand hand) {
|
||||||
|
ItemStack stack = player.getStackInHand(hand);
|
||||||
|
if (stack.isOf(Items.BUCKET)) {
|
||||||
|
if (getOrCreateEntity() instanceof Bucketable bucketable) {
|
||||||
|
if (!player.isCreative()) {
|
||||||
|
stack.decrement(1);
|
||||||
|
if (stack.isEmpty()) {
|
||||||
|
player.setStackInHand(hand, bucketable.getBucketItem());
|
||||||
|
} else {
|
||||||
|
player.giveItemStack(bucketable.getBucketItem());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
player.playSound(bucketable.getBucketFillSound(), 1, 1);
|
||||||
|
}
|
||||||
|
tile.markDirty();
|
||||||
|
return TypedActionResult.success(new ItemsJarContents(tile));
|
||||||
|
}
|
||||||
|
return TypedActionResult.pass(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroyed() {
|
||||||
|
tile.getWorld().setBlockState(tile.getPos(), Blocks.WATER.getDefaultState());
|
||||||
|
Entity entity = getOrCreateEntity();
|
||||||
|
if (entity != null) {
|
||||||
|
entity.refreshPositionAfterTeleport(tile.getPos().toCenterPos());
|
||||||
|
tile.getWorld().spawnEntity(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void toNBT(NbtCompound compound) {
|
||||||
|
compound.putString("entity", EntityType.getId(entityType).toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fromNBT(NbtCompound compound) {
|
||||||
|
entityType = Registries.ENTITY_TYPE.getOrEmpty(Identifier.tryParse(compound.getString("entity"))).orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ItemsJarContents implements JarContents, SidedInventory {
|
||||||
|
private static final int[] SLOTS = IntStream.range(0, 16).toArray();
|
||||||
|
|
||||||
|
private final TileData tile;
|
||||||
|
private List<ItemStack> stacks = new ArrayList<>();
|
||||||
|
|
||||||
|
public ItemsJarContents(TileData tile) {
|
||||||
|
this.tile = tile;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypedActionResult<JarContents> interact(PlayerEntity player, Hand hand) {
|
||||||
|
ItemStack handStack = player.getStackInHand(hand);
|
||||||
|
|
||||||
|
if (handStack.isEmpty()) {
|
||||||
if (stacks.isEmpty()) {
|
if (stacks.isEmpty()) {
|
||||||
return ActionResult.FAIL;
|
return TypedActionResult.fail(this);
|
||||||
}
|
}
|
||||||
dropStack(world, pos, stacks.remove(0));
|
dropStack(tile.getWorld(), tile.getPos(), stacks.remove(0));
|
||||||
markDirty();
|
markDirty();
|
||||||
return ActionResult.SUCCESS;
|
return TypedActionResult.success(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stacks.isEmpty()) {
|
||||||
|
if (handStack.getItem() instanceof MixinEntityBucketItem bucket) {
|
||||||
|
if (!player.isCreative()) {
|
||||||
|
handStack.decrement(1);
|
||||||
|
if (handStack.isEmpty()) {
|
||||||
|
player.setStackInHand(hand, Items.BUCKET.getDefaultStack());
|
||||||
|
} else {
|
||||||
|
player.giveItemStack(Items.BUCKET.getDefaultStack());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
player.playSound(bucket.getEmptyingSound(), 1, 1);
|
||||||
|
markDirty();
|
||||||
|
return TypedActionResult.success(new EntityJarContents(tile, bucket.getEntityType()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stacks.size() >= size()) {
|
||||||
|
return TypedActionResult.fail(this);
|
||||||
|
}
|
||||||
|
stacks.add(player.isCreative() ? handStack.copyWithCount(1) : handStack.split(1));
|
||||||
|
markDirty();
|
||||||
|
|
||||||
|
return TypedActionResult.success(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroyed() {
|
||||||
|
stacks.forEach(stack -> {
|
||||||
|
dropStack(tile.getWorld(), tile.getPos(), stack);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ItemStack> getStacks() {
|
public List<ItemStack> getStacks() {
|
||||||
|
@ -137,6 +327,9 @@ public class ItemJarBlock extends JarBlock implements BlockEntityProvider, Inven
|
||||||
@Override
|
@Override
|
||||||
public ItemStack removeStack(int slot, int amount) {
|
public ItemStack removeStack(int slot, int amount) {
|
||||||
if (slot < 0 || slot >= stacks.size()) {
|
if (slot < 0 || slot >= stacks.size()) {
|
||||||
|
return ItemStack.EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ItemStack stack = stacks.get(slot);
|
ItemStack stack = stacks.get(slot);
|
||||||
ItemStack removed = stack.split(1);
|
ItemStack removed = stack.split(1);
|
||||||
|
@ -148,40 +341,28 @@ public class ItemJarBlock extends JarBlock implements BlockEntityProvider, Inven
|
||||||
markDirty();
|
markDirty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ItemStack.EMPTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ItemStack removeStack(int slot) {
|
public ItemStack removeStack(int slot) {
|
||||||
if (slot < 0 || slot >= stacks.size()) {
|
if (slot < 0 || slot >= stacks.size()) {
|
||||||
|
return ItemStack.EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return stacks.remove(slot);
|
return stacks.remove(slot);
|
||||||
} finally {
|
} finally {
|
||||||
markDirty();
|
markDirty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ItemStack.EMPTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setStack(int slot, ItemStack stack) {
|
public void setStack(int slot, ItemStack stack) {
|
||||||
if (slot >= stacks.size()) {
|
if (slot >= stacks.size()) {
|
||||||
if (stacks.size() >= size()) {
|
|
||||||
dropStack(getWorld(), getPos(), stack);
|
|
||||||
} else {
|
|
||||||
stacks.add(stack);
|
stacks.add(stack);
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
ItemStack existing = stacks.get(slot);
|
stacks.set(slot, stack);
|
||||||
if (!ItemStack.canCombine(existing, stack)) {
|
|
||||||
dropStack(getWorld(), getPos(), stack);
|
|
||||||
} else {
|
|
||||||
existing.setCount(existing.getCount() + stack.split(Math.max(0, existing.getMaxCount() - existing.getCount())).getCount());
|
|
||||||
if (!stack.isEmpty()) {
|
|
||||||
dropStack(getWorld(), getPos(), stack);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
markDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -202,15 +383,29 @@ public class ItemJarBlock extends JarBlock implements BlockEntityProvider, Inven
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canInsert(int slot, ItemStack stack, Direction dir) {
|
public boolean canInsert(int slot, ItemStack stack, Direction dir) {
|
||||||
return (slot >= 0 && slot < size()) && (slot >= stacks.size() || (
|
return slot >= 0 && slot < size() && slot >= stacks.size();
|
||||||
ItemStack.canCombine(stacks.get(slot), stack)
|
|
||||||
&& (stacks.get(slot).getCount() + stack.getCount()) <= Math.min(stacks.get(slot).getMaxCount(), stack.getMaxCount())
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canExtract(int slot, ItemStack stack, Direction dir) {
|
public boolean canExtract(int slot, ItemStack stack, Direction dir) {
|
||||||
return true;
|
return slot >= 0 && slot < size() && slot < stacks.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void toNBT(NbtCompound compound) {
|
||||||
|
compound.put("items", NbtSerialisable.ITEM_STACK.writeAll(stacks));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fromNBT(NbtCompound compound) {
|
||||||
|
stacks = NbtSerialisable.ITEM_STACK.readAll(compound.getList("items", NbtElement.COMPOUND_TYPE))
|
||||||
|
.limit(size())
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void markDirty() {
|
||||||
|
tile.markDirty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,10 +11,17 @@ import net.minecraft.block.AbstractGlassBlock;
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.block.ShapeContext;
|
import net.minecraft.block.ShapeContext;
|
||||||
|
import net.minecraft.block.Waterloggable;
|
||||||
import net.minecraft.block.entity.BlockEntity;
|
import net.minecraft.block.entity.BlockEntity;
|
||||||
import net.minecraft.enchantment.EnchantmentHelper;
|
import net.minecraft.enchantment.EnchantmentHelper;
|
||||||
import net.minecraft.entity.player.PlayerEntity;
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
|
import net.minecraft.fluid.FluidState;
|
||||||
|
import net.minecraft.fluid.Fluids;
|
||||||
|
import net.minecraft.item.ItemPlacementContext;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.state.StateManager;
|
||||||
|
import net.minecraft.state.property.BooleanProperty;
|
||||||
|
import net.minecraft.state.property.Properties;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.math.Direction;
|
import net.minecraft.util.math.Direction;
|
||||||
import net.minecraft.util.math.random.Random;
|
import net.minecraft.util.math.random.Random;
|
||||||
|
@ -22,17 +29,25 @@ 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.minecraft.world.WorldAccess;
|
||||||
import net.minecraft.world.explosion.Explosion;
|
import net.minecraft.world.explosion.Explosion;
|
||||||
|
|
||||||
public class JarBlock extends AbstractGlassBlock {
|
public class JarBlock extends AbstractGlassBlock implements Waterloggable {
|
||||||
private static final VoxelShape SHAPE = VoxelShapes.union(
|
private static final VoxelShape SHAPE = VoxelShapes.union(
|
||||||
Block.createCuboidShape(4, 0, 4, 12, 12, 12),
|
Block.createCuboidShape(4, 0, 4, 12, 12, 12),
|
||||||
Block.createCuboidShape(6, 12, 6, 10, 16, 10),
|
Block.createCuboidShape(6, 12, 6, 10, 16, 10),
|
||||||
Block.createCuboidShape(5, 13, 5, 11, 14, 11)
|
Block.createCuboidShape(5, 13, 5, 11, 14, 11)
|
||||||
);
|
);
|
||||||
|
private static final BooleanProperty WATERLOGGED = Properties.WATERLOGGED;
|
||||||
|
|
||||||
public JarBlock(Settings settings) {
|
public JarBlock(Settings settings) {
|
||||||
super(settings);
|
super(settings);
|
||||||
|
setDefaultState(getDefaultState().with(WATERLOGGED, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
||||||
|
builder.add(WATERLOGGED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -40,9 +55,26 @@ public class JarBlock extends AbstractGlassBlock {
|
||||||
return SHAPE;
|
return SHAPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
@Override
|
@Override
|
||||||
public boolean isSideInvisible(BlockState state, BlockState stateFrom, Direction direction) {
|
public BlockState getStateForNeighborUpdate(BlockState state, Direction direction, BlockState neighborState, WorldAccess world, BlockPos pos, BlockPos neighborPos) {
|
||||||
return super.isSideInvisible(state, stateFrom, direction);
|
if (state.get(WATERLOGGED)) {
|
||||||
|
world.scheduleFluidTick(pos, Fluids.WATER, Fluids.WATER.getTickRate(world));
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.getStateForNeighborUpdate(state, direction, neighborState, world, pos, neighborPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public BlockState getPlacementState(ItemPlacementContext ctx) {
|
||||||
|
return getDefaultState().with(WATERLOGGED, ctx.getWorld().getFluidState(ctx.getBlockPos()).getFluid() == Fluids.WATER);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
@Override
|
||||||
|
public FluidState getFluidState(BlockState state) {
|
||||||
|
return state.get(WATERLOGGED) ? Fluids.WATER.getStill(false) : super.getFluidState(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -5,10 +5,16 @@ import org.joml.Vector3f;
|
||||||
import org.joml.Vector4f;
|
import org.joml.Vector4f;
|
||||||
|
|
||||||
import net.minecraft.client.render.BufferBuilder;
|
import net.minecraft.client.render.BufferBuilder;
|
||||||
|
import net.minecraft.client.render.RenderLayer;
|
||||||
import net.minecraft.client.render.Tessellator;
|
import net.minecraft.client.render.Tessellator;
|
||||||
|
import net.minecraft.client.render.VertexConsumer;
|
||||||
|
import net.minecraft.client.render.VertexConsumerProvider;
|
||||||
import net.minecraft.client.render.VertexFormat;
|
import net.minecraft.client.render.VertexFormat;
|
||||||
import net.minecraft.client.render.VertexFormats;
|
import net.minecraft.client.render.VertexFormats;
|
||||||
|
import net.minecraft.client.texture.Sprite;
|
||||||
import net.minecraft.client.util.math.MatrixStack;
|
import net.minecraft.client.util.math.MatrixStack;
|
||||||
|
import net.minecraft.util.math.ColorHelper;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
|
||||||
public class RenderUtil {
|
public class RenderUtil {
|
||||||
public static final Vector4f TEMP_VECTOR = new Vector4f();
|
public static final Vector4f TEMP_VECTOR = new Vector4f();
|
||||||
|
@ -25,6 +31,72 @@ public class RenderUtil {
|
||||||
new Vertex(1, 0, 0, 1, 1),
|
new Vertex(1, 0, 0, 1, 1),
|
||||||
new Vertex(0, 0, 0, 0, 1)
|
new Vertex(0, 0, 0, 0, 1)
|
||||||
};
|
};
|
||||||
|
private static final Vertex[][] CUBE_VERTICES = {
|
||||||
|
new Vertex[] { // down
|
||||||
|
new Vertex(0, 0, 0, 0, 0),
|
||||||
|
new Vertex(1, 0, 0, 1, 0),
|
||||||
|
new Vertex(1, 0, 1, 1, 1),
|
||||||
|
new Vertex(0, 0, 1, 0, 1)
|
||||||
|
},
|
||||||
|
new Vertex[] { //up
|
||||||
|
new Vertex(0, 1, 0, 0, 0),
|
||||||
|
new Vertex(0, 1, 1, 0, 1),
|
||||||
|
new Vertex(1, 1, 1, 1, 1),
|
||||||
|
new Vertex(1, 1, 0, 1, 0)
|
||||||
|
},
|
||||||
|
new Vertex[] { //north
|
||||||
|
new Vertex(0, 0, 0, 0, 0),
|
||||||
|
new Vertex(0, 1, 0, 0, 1),
|
||||||
|
new Vertex(1, 1, 0, 1, 1),
|
||||||
|
new Vertex(1, 0, 0, 1, 0)
|
||||||
|
},
|
||||||
|
new Vertex[] { //south
|
||||||
|
new Vertex(0, 0, 1, 0, 0),
|
||||||
|
new Vertex(1, 0, 1, 1, 0),
|
||||||
|
new Vertex(1, 1, 1, 1, 1),
|
||||||
|
new Vertex(0, 1, 1, 0, 1)
|
||||||
|
},
|
||||||
|
new Vertex[] { //west
|
||||||
|
new Vertex(0, 0, 0, 0, 0),
|
||||||
|
new Vertex(0, 0, 1, 1, 0),
|
||||||
|
new Vertex(0, 1, 1, 1, 1),
|
||||||
|
new Vertex(0, 1, 0, 0, 1)
|
||||||
|
},
|
||||||
|
new Vertex[] { //east
|
||||||
|
new Vertex(1, 0, 0, 0, 0),
|
||||||
|
new Vertex(1, 1, 0, 1, 0),
|
||||||
|
new Vertex(1, 1, 1, 1, 1),
|
||||||
|
new Vertex(1, 0, 1, 0, 1)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static void renderSpriteCubeFaces(MatrixStack matrices, VertexConsumerProvider provider, Sprite sprite,
|
||||||
|
float width, float height, float length,
|
||||||
|
int color, int light, int overlay,
|
||||||
|
Direction... directions) {
|
||||||
|
float r = ColorHelper.Abgr.getRed(color),
|
||||||
|
g = ColorHelper.Abgr.getGreen(color),
|
||||||
|
b = ColorHelper.Abgr.getBlue(color),
|
||||||
|
a = ColorHelper.Abgr.getAlpha(color);
|
||||||
|
float u0 = sprite.getMinU(), uDelta = sprite.getMaxU() - u0;
|
||||||
|
float v0 = sprite.getMinV(), vDelta = sprite.getMaxV() - v0;
|
||||||
|
RenderLayer layer = RenderLayer.getEntitySolid(sprite.getAtlasId());
|
||||||
|
VertexConsumer buffer = provider.getBuffer(layer);
|
||||||
|
Matrix4f position = matrices.peek().getPositionMatrix();
|
||||||
|
for (Direction direction : directions) {
|
||||||
|
for (Vertex vertex : CUBE_VERTICES[direction.ordinal()]) {
|
||||||
|
Vector4f pos = position.transform(TEMP_VECTOR.set(vertex.position(), 1).mul(width, height, length, 1));
|
||||||
|
buffer.vertex(
|
||||||
|
pos.x, pos.y, pos.z,
|
||||||
|
r, g, b, a,
|
||||||
|
u0 + vertex.texture().x * uDelta,
|
||||||
|
v0 + vertex.texture().y * vDelta,
|
||||||
|
overlay, light,
|
||||||
|
direction.getOffsetX(), direction.getOffsetY(), direction.getOffsetZ()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void renderFace(MatrixStack matrices, Tessellator te, BufferBuilder buffer, float r, float g, float b, float a, int light) {
|
public static void renderFace(MatrixStack matrices, Tessellator te, BufferBuilder buffer, float r, float g, float b, float a, int light) {
|
||||||
renderFace(matrices, te, buffer, r, g, b, a, light, 1, 1);
|
renderFace(matrices, te, buffer, r, g, b, a, light, 1, 1);
|
||||||
|
|
|
@ -1,29 +1,61 @@
|
||||||
package com.minelittlepony.unicopia.client.render.entity;
|
package com.minelittlepony.unicopia.client.render.entity;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import com.minelittlepony.unicopia.block.ItemJarBlock;
|
import com.minelittlepony.unicopia.block.ItemJarBlock;
|
||||||
|
import com.minelittlepony.unicopia.block.ItemJarBlock.EntityJarContents;
|
||||||
|
import com.minelittlepony.unicopia.block.ItemJarBlock.ItemsJarContents;
|
||||||
|
import com.minelittlepony.unicopia.client.render.RenderUtil;
|
||||||
|
import com.minelittlepony.unicopia.util.PosHelper;
|
||||||
|
|
||||||
|
import net.minecraft.block.Blocks;
|
||||||
import net.minecraft.client.MinecraftClient;
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.client.color.world.BiomeColors;
|
||||||
import net.minecraft.client.render.VertexConsumerProvider;
|
import net.minecraft.client.render.VertexConsumerProvider;
|
||||||
import net.minecraft.client.render.block.entity.BlockEntityRenderer;
|
import net.minecraft.client.render.block.entity.BlockEntityRenderer;
|
||||||
import net.minecraft.client.render.block.entity.BlockEntityRendererFactory;
|
import net.minecraft.client.render.block.entity.BlockEntityRendererFactory;
|
||||||
|
import net.minecraft.client.render.entity.EntityRenderDispatcher;
|
||||||
|
import net.minecraft.client.render.item.ItemRenderer;
|
||||||
import net.minecraft.client.render.model.json.ModelTransformationMode;
|
import net.minecraft.client.render.model.json.ModelTransformationMode;
|
||||||
|
import net.minecraft.client.texture.Sprite;
|
||||||
import net.minecraft.client.util.math.MatrixStack;
|
import net.minecraft.client.util.math.MatrixStack;
|
||||||
|
import net.minecraft.command.argument.EntityAnchorArgumentType.EntityAnchor;
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.MathHelper;
|
||||||
import net.minecraft.util.math.RotationAxis;
|
import net.minecraft.util.math.RotationAxis;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
import net.minecraft.util.math.random.Random;
|
import net.minecraft.util.math.random.Random;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
public class ItemJarBlockEntityRenderer implements BlockEntityRenderer<ItemJarBlock.TileData> {
|
public class ItemJarBlockEntityRenderer implements BlockEntityRenderer<ItemJarBlock.TileData> {
|
||||||
|
|
||||||
|
private final ItemRenderer itemRenderer;
|
||||||
|
private final EntityRenderDispatcher dispatcher;
|
||||||
|
|
||||||
|
private final Sprite waterSprite;
|
||||||
|
|
||||||
public ItemJarBlockEntityRenderer(BlockEntityRendererFactory.Context ctx) {
|
public ItemJarBlockEntityRenderer(BlockEntityRendererFactory.Context ctx) {
|
||||||
|
itemRenderer = ctx.getItemRenderer();
|
||||||
|
dispatcher = ctx.getEntityRenderDispatcher();
|
||||||
|
waterSprite = MinecraftClient.getInstance().getBakedModelManager().getBlockModels().getModel(Blocks.WATER.getDefaultState()).getParticleSprite();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render(ItemJarBlock.TileData entity, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertices, int light, int overlay) {
|
public void render(ItemJarBlock.TileData data, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertices, int light, int overlay) {
|
||||||
|
|
||||||
List<ItemStack> stacks = entity.getStacks();
|
ItemsJarContents items = data.getItems();
|
||||||
|
if (items != null) {
|
||||||
|
renderItemStacks(data, items, tickDelta, matrices, vertices, light, overlay);
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityJarContents entity = data.getEntity();
|
||||||
|
if (entity != null) {
|
||||||
|
renderEntity(data, entity, tickDelta, matrices, vertices, light, overlay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderItemStacks(ItemJarBlock.TileData data, ItemsJarContents items, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertices, int light, int overlay) {
|
||||||
float itemScale = 0.35F;
|
float itemScale = 0.35F;
|
||||||
|
|
||||||
matrices.push();
|
matrices.push();
|
||||||
|
@ -31,19 +63,66 @@ public class ItemJarBlockEntityRenderer implements BlockEntityRenderer<ItemJarBl
|
||||||
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(90));
|
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(90));
|
||||||
matrices.scale(itemScale, itemScale, itemScale);
|
matrices.scale(itemScale, itemScale, itemScale);
|
||||||
|
|
||||||
Random rng = Random.create(entity.getPos().asLong());
|
Random rng = Random.create(data.getPos().asLong());
|
||||||
|
|
||||||
float y = 0;
|
float y = 0;
|
||||||
for (ItemStack stack : stacks) {
|
for (ItemStack stack : items.getStacks()) {
|
||||||
matrices.push();
|
matrices.push();
|
||||||
|
|
||||||
matrices.translate((rng.nextFloat() - 0.5F) * 0.5F, (rng.nextFloat() - 0.5F) * 0.8F, -0.05 + y);
|
matrices.translate((rng.nextFloat() - 0.5F) * 0.5F, (rng.nextFloat() - 0.5F) * 0.8F, -0.05 + y);
|
||||||
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees((rng.nextFloat() * 360) - 180));
|
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees((rng.nextFloat() * 360) - 180));
|
||||||
matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees((rng.nextFloat() * 360) - 180));
|
matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees((rng.nextFloat() * 360) - 180));
|
||||||
y -= 0.1F;
|
y -= 0.1F;
|
||||||
MinecraftClient.getInstance().getItemRenderer().renderItem(stack, ModelTransformationMode.FIXED, light, overlay, matrices, vertices, entity.getWorld(), 0);
|
itemRenderer.renderItem(stack, ModelTransformationMode.FIXED, light, overlay, matrices, vertices, data.getWorld(), 0);
|
||||||
matrices.pop();
|
matrices.pop();
|
||||||
}
|
}
|
||||||
matrices.pop();
|
matrices.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void renderEntity(ItemJarBlock.TileData data, EntityJarContents entity, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertices, int light, int overlay) {
|
||||||
|
Entity e = entity.getOrCreateEntity();
|
||||||
|
if (e != null) {
|
||||||
|
|
||||||
|
|
||||||
|
PlayerEntity player = MinecraftClient.getInstance().player;
|
||||||
|
int age = player == null ? 0 : player.age;
|
||||||
|
|
||||||
|
float fullTick = age + tickDelta;
|
||||||
|
|
||||||
|
float size = Math.max(e.getWidth(), e.getHeight());
|
||||||
|
float desiredSize = 0.25F;
|
||||||
|
float scale = desiredSize / size;
|
||||||
|
float eyePos = (e.getEyeHeight(e.getPose())) * scale;
|
||||||
|
|
||||||
|
float yaw = 0;
|
||||||
|
if (player != null) {
|
||||||
|
Vec3d center = data.getPos().toCenterPos();
|
||||||
|
Vec3d observerPos = MinecraftClient.getInstance().gameRenderer.getCamera().getPos();
|
||||||
|
e.setPosition(center);
|
||||||
|
e.lookAt(EntityAnchor.FEET, observerPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
matrices.push();
|
||||||
|
matrices.translate(0.5, 0.48 + MathHelper.sin(fullTick / 19F) * 0.02F - eyePos, 0.5);
|
||||||
|
matrices.scale(scale, scale, scale);
|
||||||
|
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(10 * MathHelper.sin(fullTick / 19F)));
|
||||||
|
dispatcher.render(e, 0, 0, 0, yaw * MathHelper.RADIANS_PER_DEGREE, tickDelta, matrices, vertices, light);
|
||||||
|
matrices.pop();
|
||||||
|
}
|
||||||
|
renderFluid(data.getWorld(), data.getPos(), tickDelta, matrices, vertices, light, overlay);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderFluid(World world, BlockPos pos, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertices, int light, int overlay) {
|
||||||
|
matrices.push();
|
||||||
|
matrices.translate(0.3F, 0, 0.3F);
|
||||||
|
RenderUtil.renderSpriteCubeFaces(
|
||||||
|
matrices,
|
||||||
|
vertices,
|
||||||
|
waterSprite,
|
||||||
|
0.4F, 0.4F, 0.4F,
|
||||||
|
BiomeColors.getWaterColor(world, pos),
|
||||||
|
light, overlay, PosHelper.ALL
|
||||||
|
);
|
||||||
|
matrices.pop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
package com.minelittlepony.unicopia.mixin;
|
||||||
|
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||||
|
|
||||||
|
import net.minecraft.entity.EntityType;
|
||||||
|
import net.minecraft.item.EntityBucketItem;
|
||||||
|
import net.minecraft.sound.SoundEvent;
|
||||||
|
|
||||||
|
@Mixin(EntityBucketItem.class)
|
||||||
|
public interface MixinEntityBucketItem {
|
||||||
|
@Accessor
|
||||||
|
EntityType<?> getEntityType();
|
||||||
|
@Accessor
|
||||||
|
SoundEvent getEmptyingSound();
|
||||||
|
}
|
|
@ -8,12 +8,14 @@ import java.util.stream.Stream;
|
||||||
import com.mojang.datafixers.util.Pair;
|
import com.mojang.datafixers.util.Pair;
|
||||||
import com.mojang.serialization.Codec;
|
import com.mojang.serialization.Codec;
|
||||||
|
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.nbt.*;
|
import net.minecraft.nbt.*;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.math.Vec3d;
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
|
||||||
public interface NbtSerialisable {
|
public interface NbtSerialisable {
|
||||||
Serializer<BlockPos> BLOCK_POS = Serializer.of(NbtHelper::toBlockPos, NbtHelper::fromBlockPos);
|
Serializer<BlockPos> BLOCK_POS = Serializer.of(NbtHelper::toBlockPos, NbtHelper::fromBlockPos);
|
||||||
|
Serializer<ItemStack> ITEM_STACK = Serializer.of(ItemStack::fromNbt, stack -> stack.writeNbt(new NbtCompound()));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called to save this to nbt to persist state on file or to transmit over the network
|
* Called to save this to nbt to persist state on file or to transmit over the network
|
||||||
|
@ -44,6 +46,7 @@ public interface NbtSerialisable {
|
||||||
}
|
}
|
||||||
|
|
||||||
static Vec3d readVector(NbtList list) {
|
static Vec3d readVector(NbtList list) {
|
||||||
|
|
||||||
return new Vec3d(list.getDouble(0), list.getDouble(1), list.getDouble(2));
|
return new Vec3d(list.getDouble(0), list.getDouble(1), list.getDouble(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ import net.minecraft.world.BlockView;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
public interface PosHelper {
|
public interface PosHelper {
|
||||||
|
Direction[] ALL = Direction.values();
|
||||||
Direction[] HORIZONTAL = Arrays.stream(Direction.values()).filter(d -> d.getAxis().isHorizontal()).toArray(Direction[]::new);
|
Direction[] HORIZONTAL = Arrays.stream(Direction.values()).filter(d -> d.getAxis().isHorizontal()).toArray(Direction[]::new);
|
||||||
|
|
||||||
static Vec3d offset(Vec3d a, Vec3i b) {
|
static Vec3d offset(Vec3d a, Vec3i b) {
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
"MixinEnchantmentHelper",
|
"MixinEnchantmentHelper",
|
||||||
"MixinFallLocation",
|
"MixinFallLocation",
|
||||||
"MixinEntity",
|
"MixinEntity",
|
||||||
|
"MixinEntityBucketItem",
|
||||||
"MixinEntityView",
|
"MixinEntityView",
|
||||||
"MixinEntityShapeContext",
|
"MixinEntityShapeContext",
|
||||||
"MixinFallingBlock",
|
"MixinFallingBlock",
|
||||||
|
|
Loading…
Add table
Reference in a new issue