mirror of
https://github.com/Sollace/Unicopia.git
synced 2024-11-23 21:38:00 +01:00
Jars can now hold fluids
This commit is contained in:
parent
a81336ef88
commit
7d63797d4d
11 changed files with 772 additions and 346 deletions
|
@ -1,42 +1,34 @@
|
|||
package com.minelittlepony.unicopia.block;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.minelittlepony.unicopia.mixin.MixinEntityBucketItem;
|
||||
import com.minelittlepony.unicopia.util.NbtSerialisable;
|
||||
import com.minelittlepony.unicopia.block.jar.EntityJarContents;
|
||||
import com.minelittlepony.unicopia.block.jar.FluidOnlyJarContents;
|
||||
import com.minelittlepony.unicopia.block.jar.ItemsJarContents;
|
||||
import com.minelittlepony.unicopia.block.jar.FakeFluidJarContents;
|
||||
|
||||
import net.fabricmc.fabric.api.transfer.v1.fluid.FluidConstants;
|
||||
import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant;
|
||||
import net.minecraft.block.BlockEntityProvider;
|
||||
import net.minecraft.block.BlockRenderType;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.block.InventoryProvider;
|
||||
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.inventory.SidedInventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.item.ItemUsage;
|
||||
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.Hand;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.TypedActionResult;
|
||||
import net.minecraft.util.hit.BlockHitResult;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.WorldAccess;
|
||||
|
||||
|
@ -79,7 +71,7 @@ public class ItemJarBlock extends JarBlock implements BlockEntityProvider, Inven
|
|||
public int getComparatorOutput(BlockState state, World world, BlockPos pos) {
|
||||
return world.getBlockEntity(pos, UBlockEntities.ITEM_JAR)
|
||||
.map(TileData::getItems)
|
||||
.map(data -> Math.min(16, data.getStacks().size()))
|
||||
.map(data -> Math.min(16, data.stacks().size()))
|
||||
.orElse(0);
|
||||
}
|
||||
|
||||
|
@ -96,7 +88,7 @@ public class ItemJarBlock extends JarBlock implements BlockEntityProvider, Inven
|
|||
return new TileData(pos, state);
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public SidedInventory getInventory(BlockState state, WorldAccess world, BlockPos pos) {
|
||||
return world.getBlockEntity(pos, UBlockEntities.ITEM_JAR).map(TileData::getItems).orElse(null);
|
||||
|
@ -130,6 +122,16 @@ public class ItemJarBlock extends JarBlock implements BlockEntityProvider, Inven
|
|||
return getContents() instanceof EntityJarContents c ? c : null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public FluidJarContents getFluid() {
|
||||
return getContents() instanceof FluidJarContents c ? c : null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public FakeFluidJarContents getFakeFluid() {
|
||||
return getContents() instanceof FakeFluidJarContents c ? c : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Packet<ClientPlayPacketListener> toUpdatePacket() {
|
||||
return BlockEntityUpdateS2CPacket.create(this);
|
||||
|
@ -151,11 +153,13 @@ public class ItemJarBlock extends JarBlock implements BlockEntityProvider, Inven
|
|||
@Override
|
||||
public void readNbt(NbtCompound nbt) {
|
||||
if (nbt.contains("items", NbtElement.COMPOUND_TYPE)) {
|
||||
contents = new ItemsJarContents(this);
|
||||
contents.fromNBT(nbt.getCompound("items"));
|
||||
contents = new ItemsJarContents(this, nbt.getCompound("items"));
|
||||
} else if (nbt.contains("entity", NbtElement.COMPOUND_TYPE)) {
|
||||
contents = new EntityJarContents(this);
|
||||
contents.fromNBT(nbt.getCompound("entity"));
|
||||
contents = new EntityJarContents(this, nbt.getCompound("entity"));
|
||||
} else if (nbt.contains("fluid", NbtElement.COMPOUND_TYPE)) {
|
||||
contents = new FluidOnlyJarContents(this, nbt.getCompound("fluid"));
|
||||
} else if (nbt.contains("fakeFluid", NbtElement.COMPOUND_TYPE)) {
|
||||
contents = new FakeFluidJarContents(this, nbt.getCompound("fakeFluid"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -163,249 +167,34 @@ public class ItemJarBlock extends JarBlock implements BlockEntityProvider, Inven
|
|||
protected void writeNbt(NbtCompound nbt) {
|
||||
var items = getItems();
|
||||
if (items != null) {
|
||||
nbt.put("items", items.toNBT());
|
||||
nbt.put("items", items.toNBT(new NbtCompound()));
|
||||
} else if (getEntity() != null) {
|
||||
nbt.put("entity", getEntity().toNBT());
|
||||
nbt.put("entity", getEntity().toNBT(new NbtCompound()));
|
||||
} else if (getFluid() != null) {
|
||||
nbt.put("fluid", getFluid().toNBT(new NbtCompound()));
|
||||
} else if (getFakeFluid() != null) {
|
||||
nbt.put("fakeFluid", getFakeFluid().toNBT(new NbtCompound()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public interface JarContents extends NbtSerialisable {
|
||||
public interface JarContents {
|
||||
TypedActionResult<JarContents> interact(PlayerEntity player, Hand hand);
|
||||
|
||||
void onDestroyed();
|
||||
|
||||
NbtCompound toNBT(NbtCompound compound);
|
||||
|
||||
default void consumeAndSwap(PlayerEntity player, Hand hand, ItemStack output) {
|
||||
player.setStackInHand(hand, ItemUsage.exchangeStack(player.getStackInHand(hand), player, output.copy()));
|
||||
}
|
||||
}
|
||||
|
||||
public static class EntityJarContents implements JarContents {
|
||||
@Nullable
|
||||
private EntityType<?> entityType;
|
||||
@Nullable
|
||||
private Entity renderEntity;
|
||||
public interface FluidJarContents extends JarContents {
|
||||
FluidVariant fluid();
|
||||
|
||||
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()) {
|
||||
return TypedActionResult.fail(this);
|
||||
}
|
||||
dropStack(tile.getWorld(), tile.getPos(), stacks.remove(0));
|
||||
markDirty();
|
||||
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() {
|
||||
return stacks;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return 15;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return stacks.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getStack(int slot) {
|
||||
return slot < 0 || slot >= stacks.size() ? ItemStack.EMPTY : stacks.get(slot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack removeStack(int slot, int amount) {
|
||||
if (slot < 0 || slot >= stacks.size()) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
try {
|
||||
ItemStack stack = stacks.get(slot);
|
||||
ItemStack removed = stack.split(1);
|
||||
if (stack.isEmpty()) {
|
||||
stacks.remove(slot);
|
||||
}
|
||||
return removed;
|
||||
} finally {
|
||||
markDirty();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack removeStack(int slot) {
|
||||
if (slot < 0 || slot >= stacks.size()) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
try {
|
||||
return stacks.remove(slot);
|
||||
} finally {
|
||||
markDirty();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStack(int slot, ItemStack stack) {
|
||||
if (slot >= stacks.size()) {
|
||||
stacks.add(stack);
|
||||
} else {
|
||||
stacks.set(slot, stack);
|
||||
}
|
||||
markDirty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPlayerUse(PlayerEntity player) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
stacks.clear();
|
||||
markDirty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getAvailableSlots(Direction side) {
|
||||
return SLOTS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canInsert(int slot, ItemStack stack, Direction dir) {
|
||||
return slot >= 0 && slot < size() && slot >= stacks.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canExtract(int slot, ItemStack stack, Direction dir) {
|
||||
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();
|
||||
default long amount() {
|
||||
return FluidConstants.BUCKET;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
package com.minelittlepony.unicopia.block.jar;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.minelittlepony.unicopia.block.ItemJarBlock.FluidJarContents;
|
||||
import com.minelittlepony.unicopia.block.ItemJarBlock.JarContents;
|
||||
import com.minelittlepony.unicopia.block.ItemJarBlock.TileData;
|
||||
|
||||
import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.entity.Bucketable;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.fluid.Fluids;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.registry.Registries;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.TypedActionResult;
|
||||
|
||||
public record EntityJarContents (
|
||||
TileData tile,
|
||||
@Nullable EntityType<?> entityType,
|
||||
Supplier<@Nullable Entity> entity
|
||||
) implements FluidJarContents {
|
||||
public EntityJarContents(TileData tile, NbtCompound compound) {
|
||||
this(tile, Registries.ENTITY_TYPE.getOrEmpty(Identifier.tryParse(compound.getString("entity"))).orElse(null));
|
||||
}
|
||||
|
||||
public EntityJarContents(TileData tile) {
|
||||
this(tile, (EntityType<?>)null);
|
||||
}
|
||||
|
||||
public EntityJarContents(TileData tile, EntityType<?> entityType) {
|
||||
this(tile, entityType, Suppliers.memoize(() -> {
|
||||
return entityType == null ? null : entityType.create(tile.getWorld());
|
||||
}));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypedActionResult<JarContents> interact(PlayerEntity player, Hand hand) {
|
||||
ItemStack stack = player.getStackInHand(hand);
|
||||
if (stack.isOf(Items.BUCKET)) {
|
||||
if (entity().get() instanceof Bucketable bucketable) {
|
||||
consumeAndSwap(player, hand, 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 = entity().get();
|
||||
if (entity != null) {
|
||||
entity.refreshPositionAfterTeleport(tile.getPos().toCenterPos());
|
||||
tile.getWorld().spawnEntity(entity);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public NbtCompound toNBT(NbtCompound compound) {
|
||||
compound.putString("entity", EntityType.getId(entityType).toString());
|
||||
return compound;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FluidVariant fluid() {
|
||||
return FluidVariant.of(Fluids.WATER);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
package com.minelittlepony.unicopia.block.jar;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import com.minelittlepony.unicopia.USounds;
|
||||
import com.minelittlepony.unicopia.block.ItemJarBlock.JarContents;
|
||||
import com.minelittlepony.unicopia.block.ItemJarBlock.TileData;
|
||||
import com.minelittlepony.unicopia.util.FluidHelper;
|
||||
|
||||
import net.fabricmc.fabric.api.transfer.v1.fluid.FluidConstants;
|
||||
import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.fluid.Fluid;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.registry.Registries;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.TypedActionResult;
|
||||
|
||||
public record FakeFluidJarContents (
|
||||
TileData tile,
|
||||
String fluid,
|
||||
int color,
|
||||
Item empty,
|
||||
Item filled
|
||||
) implements JarContents {
|
||||
public FakeFluidJarContents(TileData tile, NbtCompound compound) {
|
||||
this(tile, compound.getString("fluid"), compound.getInt("color"),
|
||||
Registries.ITEM.get(new Identifier(compound.getString("empty"))),
|
||||
Registries.ITEM.get(new Identifier(compound.getString("filled"))));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypedActionResult<JarContents> interact(PlayerEntity player, Hand hand) {
|
||||
ItemStack stack = player.getStackInHand(hand);
|
||||
|
||||
tile.markDirty();
|
||||
return getRealFluid().map(FluidVariant::of).<TypedActionResult<JarContents>>map(fluid -> {
|
||||
long remainder = FluidHelper.deposit(stack, player, hand, fluid, FluidConstants.BUCKET);
|
||||
fluid.getFluid().getBucketFillSound().ifPresent(sound -> player.playSound(sound, 1, 1));
|
||||
if (remainder > 0) {
|
||||
return TypedActionResult.success(new FluidOnlyJarContents(tile, remainder, fluid));
|
||||
}
|
||||
return TypedActionResult.success(new ItemsJarContents(tile));
|
||||
}).orElseGet(() -> {
|
||||
if (!stack.isOf(empty)) {
|
||||
return TypedActionResult.pass(this);
|
||||
}
|
||||
consumeAndSwap(player, hand, filled.getDefaultStack());
|
||||
player.playSound("powder_snow".equalsIgnoreCase(fluid) ? USounds.Vanilla.ITEM_BUCKET_FILL_POWDER_SNOW : USounds.Vanilla.ITEM_BUCKET_FILL, 1, 1);
|
||||
return TypedActionResult.success(new ItemsJarContents(tile));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyed() {
|
||||
getRealFluid().ifPresent(fluid -> {
|
||||
tile.getWorld().setBlockState(tile.getPos(), FluidHelper.getFullFluidState(FluidVariant.of(fluid)).getBlockState());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public NbtCompound toNBT(NbtCompound compound) {
|
||||
compound.putString("fluid", fluid);
|
||||
compound.putInt("color", color);
|
||||
compound.putString("empty", Registries.ITEM.getId(empty).toString());
|
||||
compound.putString("filled", Registries.ITEM.getId(filled).toString());
|
||||
return compound;
|
||||
}
|
||||
|
||||
private Optional<Fluid> getRealFluid() {
|
||||
return Registries.FLUID.getIds().stream()
|
||||
.filter(id -> id.getPath().equalsIgnoreCase(fluid))
|
||||
.findFirst()
|
||||
.map(Registries.FLUID::get);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package com.minelittlepony.unicopia.block.jar;
|
||||
|
||||
import com.minelittlepony.unicopia.block.ItemJarBlock.FluidJarContents;
|
||||
import com.minelittlepony.unicopia.block.ItemJarBlock.JarContents;
|
||||
import com.minelittlepony.unicopia.block.ItemJarBlock.TileData;
|
||||
import com.minelittlepony.unicopia.util.FluidHelper;
|
||||
|
||||
import net.fabricmc.fabric.api.transfer.v1.fluid.FluidConstants;
|
||||
import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.TypedActionResult;
|
||||
|
||||
public record FluidOnlyJarContents (
|
||||
TileData tile,
|
||||
long amount,
|
||||
FluidVariant fluid
|
||||
) implements FluidJarContents {
|
||||
|
||||
public FluidOnlyJarContents(TileData tile, NbtCompound compound) {
|
||||
this(tile, compound.getLong("amount"), FluidVariant.fromNbt(compound.getCompound("fluid")));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypedActionResult<JarContents> interact(PlayerEntity player, Hand hand) {
|
||||
ItemStack stack = player.getStackInHand(hand);
|
||||
if (stack.isOf(Items.BUCKET)) {
|
||||
long remainder = FluidHelper.deposit(stack, player, hand, fluid, amount);
|
||||
tile.markDirty();
|
||||
fluid.getFluid().getBucketFillSound().ifPresent(sound -> player.playSound(sound, 1, 1));
|
||||
if (remainder > 0) {
|
||||
return TypedActionResult.success(new FluidOnlyJarContents(tile, remainder, fluid));
|
||||
}
|
||||
return TypedActionResult.success(new ItemsJarContents(tile));
|
||||
}
|
||||
return TypedActionResult.pass(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyed() {
|
||||
if (amount >= FluidConstants.BUCKET) {
|
||||
tile.getWorld().setBlockState(tile.getPos(), FluidHelper.getFullFluidState(fluid).getBlockState());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public NbtCompound toNBT(NbtCompound compound) {
|
||||
compound.put("fluid", fluid.toNbt());
|
||||
compound.putLong("amount", amount);
|
||||
return compound;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,208 @@
|
|||
package com.minelittlepony.unicopia.block.jar;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import com.minelittlepony.unicopia.USounds;
|
||||
import com.minelittlepony.unicopia.block.ItemJarBlock.JarContents;
|
||||
import com.minelittlepony.unicopia.block.ItemJarBlock.TileData;
|
||||
import com.minelittlepony.unicopia.item.UItems;
|
||||
import com.minelittlepony.unicopia.mixin.MixinEntityBucketItem;
|
||||
import com.minelittlepony.unicopia.util.FluidHelper;
|
||||
import com.minelittlepony.unicopia.util.NbtSerialisable;
|
||||
|
||||
import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.inventory.SidedInventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.nbt.NbtElement;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.Pair;
|
||||
import net.minecraft.util.TypedActionResult;
|
||||
import net.minecraft.util.math.Direction;
|
||||
|
||||
public record ItemsJarContents (
|
||||
TileData tile,
|
||||
List<ItemStack> stacks
|
||||
) implements JarContents, SidedInventory {
|
||||
private static final int[] SLOTS = IntStream.range(0, 16).toArray();
|
||||
|
||||
public ItemsJarContents(TileData tile) {
|
||||
this(tile, new ArrayList<>());
|
||||
}
|
||||
|
||||
public ItemsJarContents(TileData tile, NbtCompound compound) {
|
||||
this(tile, NbtSerialisable.ITEM_STACK.readAll(compound.getList("items", NbtElement.COMPOUND_TYPE))
|
||||
.limit(15)
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypedActionResult<JarContents> interact(PlayerEntity player, Hand hand) {
|
||||
ItemStack handStack = player.getStackInHand(hand);
|
||||
|
||||
if (handStack.isEmpty()) {
|
||||
if (stacks.isEmpty()) {
|
||||
return TypedActionResult.fail(this);
|
||||
}
|
||||
Block.dropStack(tile.getWorld(), tile.getPos(), stacks.remove(0));
|
||||
markDirty();
|
||||
return TypedActionResult.success(this);
|
||||
}
|
||||
|
||||
if (stacks.isEmpty()) {
|
||||
if (handStack.getItem() instanceof MixinEntityBucketItem bucket) {
|
||||
consumeAndSwap(player, hand, Items.BUCKET.getDefaultStack());
|
||||
player.playSound(bucket.getEmptyingSound(), 1, 1);
|
||||
markDirty();
|
||||
return TypedActionResult.success(new EntityJarContents(tile, bucket.getEntityType()));
|
||||
}
|
||||
|
||||
Pair<Long, FluidVariant> fluid = FluidHelper.extract(handStack, player, hand).orElse(null);
|
||||
if (fluid != null) {
|
||||
fluid.getRight().getFluid().getBucketFillSound().ifPresent(sound -> player.playSound(sound, 1, 1));
|
||||
markDirty();
|
||||
return TypedActionResult.success(new FluidOnlyJarContents(tile, fluid.getLeft(), fluid.getRight()));
|
||||
}
|
||||
|
||||
if (handStack.isOf(Items.MILK_BUCKET)) {
|
||||
consumeAndSwap(player, hand, handStack.getRecipeRemainder());
|
||||
player.playSound(USounds.Vanilla.ITEM_BUCKET_EMPTY, 1, 1);
|
||||
markDirty();
|
||||
return TypedActionResult.success(new FakeFluidJarContents(tile, "milk", 0xFFFFFFFF, Items.BUCKET, Items.MILK_BUCKET));
|
||||
}
|
||||
|
||||
if (handStack.isOf(Items.POWDER_SNOW_BUCKET)) {
|
||||
consumeAndSwap(player, hand, Items.BUCKET.getDefaultStack());
|
||||
player.playSound(USounds.Vanilla.ITEM_BUCKET_EMPTY_POWDER_SNOW, 1, 1);
|
||||
markDirty();
|
||||
return TypedActionResult.success(new FakeFluidJarContents(tile, "powder_snow", 0xFFFFFFFF, Items.BUCKET, Items.POWDER_SNOW_BUCKET));
|
||||
}
|
||||
|
||||
if (handStack.isOf(UItems.LOVE_BUCKET)) {
|
||||
consumeAndSwap(player, hand, handStack.getRecipeRemainder());
|
||||
player.playSound(USounds.Vanilla.ITEM_BUCKET_EMPTY, 1, 1);
|
||||
markDirty();
|
||||
return TypedActionResult.success(new FakeFluidJarContents(tile, "love", 0xFF3030, Items.BUCKET, UItems.LOVE_BUCKET));
|
||||
}
|
||||
|
||||
if (handStack.isOf(UItems.JUICE)) {
|
||||
consumeAndSwap(player, hand, handStack.getRecipeRemainder());
|
||||
player.playSound(USounds.Vanilla.ITEM_BUCKET_EMPTY, 1, 1);
|
||||
markDirty();
|
||||
return TypedActionResult.success(new FakeFluidJarContents(tile, "apple_juice", 0x30FF30, Items.GLASS_BOTTLE, UItems.JUICE));
|
||||
}
|
||||
}
|
||||
|
||||
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 -> Block.dropStack(tile.getWorld(), tile.getPos(), stack));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return 15;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return stacks.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getStack(int slot) {
|
||||
return slot < 0 || slot >= stacks.size() ? ItemStack.EMPTY : stacks.get(slot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack removeStack(int slot, int amount) {
|
||||
if (slot < 0 || slot >= stacks.size()) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
try {
|
||||
ItemStack stack = stacks.get(slot);
|
||||
ItemStack removed = stack.split(1);
|
||||
if (stack.isEmpty()) {
|
||||
stacks.remove(slot);
|
||||
}
|
||||
return removed;
|
||||
} finally {
|
||||
markDirty();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack removeStack(int slot) {
|
||||
if (slot < 0 || slot >= stacks.size()) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
try {
|
||||
return stacks.remove(slot);
|
||||
} finally {
|
||||
markDirty();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStack(int slot, ItemStack stack) {
|
||||
if (slot >= stacks.size()) {
|
||||
stacks.add(stack);
|
||||
} else {
|
||||
stacks.set(slot, stack);
|
||||
}
|
||||
markDirty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPlayerUse(PlayerEntity player) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
stacks.clear();
|
||||
markDirty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getAvailableSlots(Direction side) {
|
||||
return SLOTS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canInsert(int slot, ItemStack stack, Direction dir) {
|
||||
return slot >= 0 && slot < size() && slot >= stacks.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canExtract(int slot, ItemStack stack, Direction dir) {
|
||||
return slot >= 0 && slot < size() && slot < stacks.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NbtCompound toNBT(NbtCompound compound) {
|
||||
compound.put("items", NbtSerialisable.ITEM_STACK.writeAll(stacks));
|
||||
return compound;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markDirty() {
|
||||
tile.markDirty();
|
||||
}
|
||||
}
|
|
@ -5,20 +5,15 @@ import org.joml.Vector3f;
|
|||
import org.joml.Vector4f;
|
||||
|
||||
import net.minecraft.client.render.BufferBuilder;
|
||||
import net.minecraft.client.render.RenderLayer;
|
||||
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.VertexFormats;
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.util.math.ColorHelper;
|
||||
import net.minecraft.util.math.Direction;
|
||||
|
||||
public class RenderUtil {
|
||||
public static final Vector4f TEMP_VECTOR = new Vector4f();
|
||||
private static final Vector4f TEMP_UV_VECTOR = new Vector4f();
|
||||
public static final Vector4f TEMP_UV_VECTOR = new Vector4f();
|
||||
public static final Vector3f TEMP_NORMAL_VECTOR = new Vector3f();
|
||||
public static final Vertex[] UNIT_FACE = new Vertex[] {
|
||||
new Vertex(0, 0, 0, 1, 1),
|
||||
new Vertex(0, 1, 0, 1, 0),
|
||||
|
@ -31,72 +26,9 @@ public class RenderUtil {
|
|||
new Vertex(1, 0, 0, 1, 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) {
|
||||
renderFace(matrices, te, buffer, r, g, b, a, light, 1, 1);
|
||||
|
|
|
@ -1,14 +1,24 @@
|
|||
package com.minelittlepony.unicopia.client.render.entity;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.minelittlepony.common.util.Color;
|
||||
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.block.ItemJarBlock.FluidJarContents;
|
||||
import com.minelittlepony.unicopia.block.jar.ItemsJarContents;
|
||||
import com.minelittlepony.unicopia.block.jar.FakeFluidJarContents;
|
||||
import com.minelittlepony.unicopia.block.jar.EntityJarContents;
|
||||
import com.minelittlepony.unicopia.client.render.model.CubeModel;
|
||||
import com.minelittlepony.unicopia.util.FluidHelper;
|
||||
import com.minelittlepony.unicopia.util.PosHelper;
|
||||
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandler;
|
||||
import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandlerRegistry;
|
||||
import net.fabricmc.fabric.api.transfer.v1.fluid.FluidConstants;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.color.world.BiomeColors;
|
||||
import net.minecraft.client.render.RenderLayer;
|
||||
import net.minecraft.client.render.VertexConsumerProvider;
|
||||
import net.minecraft.client.render.block.entity.BlockEntityRenderer;
|
||||
import net.minecraft.client.render.block.entity.BlockEntityRendererFactory;
|
||||
|
@ -20,8 +30,12 @@ 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.fluid.Fluid;
|
||||
import net.minecraft.fluid.FluidState;
|
||||
import net.minecraft.fluid.Fluids;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.RotationAxis;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
@ -29,16 +43,13 @@ import net.minecraft.util.math.random.Random;
|
|||
import net.minecraft.world.World;
|
||||
|
||||
public class ItemJarBlockEntityRenderer implements BlockEntityRenderer<ItemJarBlock.TileData> {
|
||||
|
||||
private static final Direction[] GLASS_SIDES = Arrays.stream(PosHelper.ALL).filter(i -> i != Direction.UP).toArray(Direction[]::new);
|
||||
private final ItemRenderer itemRenderer;
|
||||
private final EntityRenderDispatcher dispatcher;
|
||||
|
||||
private final Sprite waterSprite;
|
||||
|
||||
public ItemJarBlockEntityRenderer(BlockEntityRendererFactory.Context ctx) {
|
||||
itemRenderer = ctx.getItemRenderer();
|
||||
dispatcher = ctx.getEntityRenderDispatcher();
|
||||
waterSprite = MinecraftClient.getInstance().getBakedModelManager().getBlockModels().getModel(Blocks.WATER.getDefaultState()).getParticleSprite();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -53,6 +64,16 @@ public class ItemJarBlockEntityRenderer implements BlockEntityRenderer<ItemJarBl
|
|||
if (entity != null) {
|
||||
renderEntity(data, entity, tickDelta, matrices, vertices, light, overlay);
|
||||
}
|
||||
|
||||
FluidJarContents fluid = data.getFluid();
|
||||
if (fluid != null) {
|
||||
renderFluid(data, fluid, tickDelta, matrices, vertices, light, overlay);
|
||||
}
|
||||
|
||||
FakeFluidJarContents milk = data.getFakeFluid();
|
||||
if (milk != null) {
|
||||
renderFluid(data, Fluids.WATER.getDefaultState(), milk.color(), FluidConstants.BUCKET, tickDelta, matrices, vertices, light, overlay);
|
||||
}
|
||||
}
|
||||
|
||||
private void renderItemStacks(ItemJarBlock.TileData data, ItemsJarContents items, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertices, int light, int overlay) {
|
||||
|
@ -66,7 +87,7 @@ public class ItemJarBlockEntityRenderer implements BlockEntityRenderer<ItemJarBl
|
|||
Random rng = Random.create(data.getPos().asLong());
|
||||
|
||||
float y = 0;
|
||||
for (ItemStack stack : items.getStacks()) {
|
||||
for (ItemStack stack : items.stacks()) {
|
||||
matrices.push();
|
||||
|
||||
matrices.translate((rng.nextFloat() - 0.5F) * 0.5F, (rng.nextFloat() - 0.5F) * 0.8F, -0.05 + y);
|
||||
|
@ -80,10 +101,9 @@ public class ItemJarBlockEntityRenderer implements BlockEntityRenderer<ItemJarBl
|
|||
}
|
||||
|
||||
private void renderEntity(ItemJarBlock.TileData data, EntityJarContents entity, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertices, int light, int overlay) {
|
||||
Entity e = entity.getOrCreateEntity();
|
||||
Entity e = entity.entity().get();
|
||||
if (e != null) {
|
||||
|
||||
|
||||
PlayerEntity player = MinecraftClient.getInstance().player;
|
||||
int age = player == null ? 0 : player.age;
|
||||
|
||||
|
@ -109,20 +129,57 @@ public class ItemJarBlockEntityRenderer implements BlockEntityRenderer<ItemJarBl
|
|||
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) {
|
||||
private void renderFluid(ItemJarBlock.TileData data, FluidJarContents fluid, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertices, int light, int overlay) {
|
||||
FluidState state = FluidHelper.getFullFluidState(fluid.fluid());
|
||||
int color = getFluidColor(data.getWorld(), data.getPos(), state);
|
||||
renderFluid(data, state, color, fluid.amount(), tickDelta, matrices, vertices, light, overlay);
|
||||
}
|
||||
|
||||
private void renderFluid(ItemJarBlock.TileData data, FluidState state, int color, long amount, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertices, int light, int overlay) {
|
||||
Sprite[] sprite = getFluidSprite(data.getWorld(), data.getPos(), state);
|
||||
matrices.push();
|
||||
matrices.translate(0.3F, 0, 0.3F);
|
||||
RenderUtil.renderSpriteCubeFaces(
|
||||
Sprite topSprite = sprite[0];
|
||||
float height = 0.6F * (amount / (float)FluidConstants.BUCKET);
|
||||
boolean opaque = Color.a(color) >= 1;
|
||||
CubeModel.render(
|
||||
matrices,
|
||||
vertices,
|
||||
waterSprite,
|
||||
0.4F, 0.4F, 0.4F,
|
||||
BiomeColors.getWaterColor(world, pos),
|
||||
light, overlay, PosHelper.ALL
|
||||
vertices.getBuffer(opaque ? RenderLayer.getEntitySolid(topSprite.getAtlasId()) : RenderLayer.getEntityTranslucent(topSprite.getAtlasId())),
|
||||
topSprite.getMinU(), topSprite.getMinV(),
|
||||
topSprite.getMaxU(), topSprite.getMaxV(),
|
||||
0.28F, 0.01F, 0.28F,
|
||||
0.73F, 0.01F + height, 0.73F,
|
||||
color,
|
||||
light, overlay, Direction.UP
|
||||
);
|
||||
Sprite sideSprite = sprite[sprite.length - 1];
|
||||
CubeModel.render(
|
||||
matrices,
|
||||
vertices.getBuffer(opaque ? RenderLayer.getEntitySolid(sideSprite.getAtlasId()) : RenderLayer.getEntityTranslucent(sideSprite.getAtlasId())),
|
||||
sideSprite.getMinU(), sideSprite.getMinV(),
|
||||
sideSprite.getMaxU(), sideSprite.getMaxV(),
|
||||
0.28F, 0.01F, 0.28F,
|
||||
0.73F, 0.01F + height, 0.73F,
|
||||
color,
|
||||
light, overlay, GLASS_SIDES
|
||||
);
|
||||
matrices.pop();
|
||||
}
|
||||
|
||||
private int getFluidColor(World world, BlockPos pos, FluidState state) {
|
||||
return getFluidHandler(state.getFluid()).getFluidColor(world, pos, state);
|
||||
}
|
||||
|
||||
private Sprite[] getFluidSprite(@Nullable World world, BlockPos pos, FluidState state) {
|
||||
return getFluidHandler(state.getFluid()).getFluidSprites(world, pos, state);
|
||||
}
|
||||
|
||||
private FluidRenderHandler getFluidHandler(Fluid fluid) {
|
||||
FluidRenderHandler handler = FluidRenderHandlerRegistry.INSTANCE.get(fluid);
|
||||
if (handler == null) {
|
||||
return FluidRenderHandlerRegistry.INSTANCE.get(Fluids.WATER);
|
||||
}
|
||||
return handler;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
package com.minelittlepony.unicopia.client.render.model;
|
||||
|
||||
import org.joml.Matrix3f;
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Vector2f;
|
||||
import org.joml.Vector3f;
|
||||
import org.joml.Vector4f;
|
||||
|
||||
import com.minelittlepony.common.util.Color;
|
||||
import com.minelittlepony.unicopia.client.render.RenderUtil;
|
||||
import com.minelittlepony.unicopia.client.render.RenderUtil.Vertex;
|
||||
|
||||
import net.minecraft.client.render.VertexConsumer;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.util.math.Direction;
|
||||
|
||||
public class CubeModel {
|
||||
private static final Vector2f TEMP_UV_VECTOR = new Vector2f();
|
||||
private static final Vertex[][] CUBE_VERTICES = {
|
||||
new Vertex[] {
|
||||
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[] {
|
||||
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[] {
|
||||
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[] {
|
||||
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[] {
|
||||
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[] {
|
||||
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 render(MatrixStack matrices, VertexConsumer buffer,
|
||||
float u0, float v0, float u1, float v1,
|
||||
float x0, float y0, float z0, float x1, float y1, float z1,
|
||||
int color, int light, int overlay,
|
||||
Direction... directions) {
|
||||
float r = Color.r(color), g = Color.g(color), b = Color.b(color);
|
||||
float du = u1 - u0, dv = v1 - v0;
|
||||
float dx = x1 - x0, dy = y1 - y0, dz = z1 - z0;
|
||||
Matrix4f position = matrices.peek().getPositionMatrix();
|
||||
Matrix3f normal = matrices.peek().getNormalMatrix();
|
||||
for (Direction direction : directions) {
|
||||
for (Vertex vertex : CUBE_VERTICES[direction.ordinal()]) {
|
||||
Vector4f pos = position.transform(RenderUtil.TEMP_VECTOR.set(vertex.position(), 1).mul(dx, dy, dz, 1).add(x0, y0, z0, 0));
|
||||
Vector2f tex = TEMP_UV_VECTOR.set(vertex.texture().x, vertex.texture().y).mul(du, dv).add(u0, v0);
|
||||
Vector3f norm = normal.transform(RenderUtil.TEMP_NORMAL_VECTOR.set(direction.getOffsetX(), direction.getOffsetY(), direction.getOffsetZ()));
|
||||
buffer.vertex(pos.x, pos.y, pos.z, r, g, b, 1, tex.x, tex.y, overlay, light, norm.x, norm.y, norm.z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
package com.minelittlepony.unicopia.datagen.providers.loot;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.minelittlepony.unicopia.block.PieBlock;
|
||||
import com.minelittlepony.unicopia.block.UBlocks;
|
||||
import com.minelittlepony.unicopia.datagen.providers.UModelProvider;
|
||||
import com.minelittlepony.unicopia.item.UItems;
|
||||
|
@ -14,14 +16,21 @@ import net.minecraft.block.Block;
|
|||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.block.enums.BedPart;
|
||||
import net.minecraft.enchantment.Enchantments;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.loot.LootPool;
|
||||
import net.minecraft.loot.LootTable;
|
||||
import net.minecraft.loot.condition.BlockStatePropertyLootCondition;
|
||||
import net.minecraft.loot.condition.LootConditionConsumingBuilder;
|
||||
import net.minecraft.loot.condition.TableBonusLootCondition;
|
||||
import net.minecraft.loot.entry.ItemEntry;
|
||||
import net.minecraft.loot.function.SetCountLootFunction;
|
||||
import net.minecraft.loot.provider.number.ConstantLootNumberProvider;
|
||||
import net.minecraft.loot.provider.number.UniformLootNumberProvider;
|
||||
import net.minecraft.predicate.StatePredicate;
|
||||
import net.minecraft.state.property.BooleanProperty;
|
||||
import net.minecraft.state.property.Property;
|
||||
import net.minecraft.util.StringIdentifiable;
|
||||
|
||||
public class UBlockLootTableProvider extends FabricBlockLootTableProvider {
|
||||
|
||||
|
@ -116,6 +125,7 @@ public class UBlockLootTableProvider extends FabricBlockLootTableProvider {
|
|||
addDrop(UBlocks.CLOUD_PILLAR, drops(UBlocks.CLOUD_PILLAR, UBlocks.CLOUD, ConstantLootNumberProvider.create(2)));
|
||||
|
||||
addDrop(UBlocks.FROSTED_OBSIDIAN, Blocks.OBSIDIAN);
|
||||
addDrop(UBlocks.APPLE_PIE, pieDrops(UBlocks.APPLE_PIE, UItems.APPLE_PIE, UItems.APPLE_PIE_HOOF));
|
||||
}
|
||||
|
||||
private LootTable.Builder fruitLeavesDrops(Block leaves) {
|
||||
|
@ -136,4 +146,23 @@ public class UBlockLootTableProvider extends FabricBlockLootTableProvider {
|
|||
);
|
||||
}
|
||||
|
||||
private LootTable.Builder pieDrops(Block block, Item drop, Item stomped) {
|
||||
return LootTable.builder().pool(LootPool.builder()
|
||||
.rolls(ConstantLootNumberProvider.create(1)).conditionally(WITH_SILK_TOUCH)
|
||||
.with(addStateCondition(block, PieBlock.STOMPED, false, applyExplosionDecay(block, ItemEntry.builder(drop))))
|
||||
.with(addStateCondition(block, PieBlock.STOMPED, true, applyExplosionDecay(block, ItemEntry.builder(stomped))))
|
||||
);
|
||||
}
|
||||
|
||||
public static <T extends LootConditionConsumingBuilder<T>, P extends Comparable<P> & StringIdentifiable> T addStateCondition(Block block,
|
||||
Property<P> property, P value,
|
||||
LootConditionConsumingBuilder<T> builder) {
|
||||
return builder.conditionally(BlockStatePropertyLootCondition.builder(block).properties(StatePredicate.Builder.create().exactMatch(property, value)));
|
||||
}
|
||||
|
||||
public static <T extends LootConditionConsumingBuilder<T>> T addStateCondition(Block block,
|
||||
BooleanProperty property, boolean value,
|
||||
LootConditionConsumingBuilder<T> builder) {
|
||||
return builder.conditionally(BlockStatePropertyLootCondition.builder(block).properties(StatePredicate.Builder.create().exactMatch(property, value)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
package com.minelittlepony.unicopia.util;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
import net.fabricmc.fabric.api.transfer.v1.context.ContainerItemContext;
|
||||
import net.fabricmc.fabric.api.transfer.v1.fluid.FluidConstants;
|
||||
import net.fabricmc.fabric.api.transfer.v1.fluid.FluidStorage;
|
||||
import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant;
|
||||
import net.fabricmc.fabric.api.transfer.v1.storage.Storage;
|
||||
import net.fabricmc.fabric.api.transfer.v1.storage.StorageView;
|
||||
import net.fabricmc.fabric.api.transfer.v1.transaction.Transaction;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.fluid.FluidState;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.Pair;
|
||||
|
||||
/**
|
||||
* Here be dragons
|
||||
*/
|
||||
public interface FluidHelper {
|
||||
static FluidState getFullFluidState(FluidVariant variant) {
|
||||
return PsyFluidHelper.getFullFluidState(variant);
|
||||
}
|
||||
|
||||
static Optional<Pair<Long, FluidVariant>> extract(ItemStack stack, PlayerEntity player, Hand hand) {
|
||||
return getAsContainer(stack, ContainerItemContext.forPlayerInteraction(player, hand))
|
||||
.filter(c -> !c.isResourceBlank())
|
||||
.map(container -> applyTransaction(t -> {
|
||||
FluidVariant type = container.getResource();
|
||||
long amountExtracted = container.extract(type, FluidConstants.BUCKET, t);
|
||||
if (amountExtracted > 0) {
|
||||
return new Pair<>(amountExtracted, type);
|
||||
}
|
||||
return null;
|
||||
}));
|
||||
}
|
||||
|
||||
static long deposit(ItemStack stack, PlayerEntity player, Hand hand, FluidVariant variant, long amount) {
|
||||
return amount - getAsStorage(stack, ContainerItemContext.forPlayerInteraction(player, hand))
|
||||
.map(storage -> applyTransaction(t -> storage.insert(variant, amount, t)))
|
||||
.orElse(0L);
|
||||
}
|
||||
|
||||
private static Optional<Storage<FluidVariant>> getAsStorage(ItemStack stack, ContainerItemContext context) {
|
||||
return Optional.ofNullable(FluidStorage.ITEM.find(stack, context));
|
||||
}
|
||||
|
||||
private static Optional<StorageView<FluidVariant>> getAsContainer(ItemStack stack, ContainerItemContext context) {
|
||||
return getAsStorage(stack, context).map(storage -> {
|
||||
Iterator<StorageView<FluidVariant>> iter = storage.iterator();
|
||||
return iter.hasNext() ? iter.next() : null;
|
||||
});
|
||||
}
|
||||
|
||||
private static <T> T applyTransaction(Function<Transaction, T> action) {
|
||||
try (@SuppressWarnings("deprecation") var transaction = Transaction.isOpen()
|
||||
? Transaction.getCurrentUnsafe().openNested()
|
||||
: Transaction.openOuter()) {
|
||||
try {
|
||||
return action.apply(transaction);
|
||||
} finally {
|
||||
transaction.commit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package com.minelittlepony.unicopia.util;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.google.common.base.Suppliers;
|
||||
|
||||
import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant;
|
||||
import net.minecraft.fluid.FluidState;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.registry.Registries;
|
||||
|
||||
final class PsyFluidHelper {
|
||||
private static final Supplier<Optional<Class<?>>> SIMPLE_FLUID_CLASS = Suppliers.memoize(() -> {
|
||||
try {
|
||||
return Optional.ofNullable(Class.forName("ivorius.psychedelicraft.fluid.SimpleFluid"));
|
||||
} catch (Throwable t) {
|
||||
return Optional.empty();
|
||||
}
|
||||
});
|
||||
private static final Function<FluidVariant, FluidState> FALLBACK_METHOD = fluid -> fluid.getFluid().getDefaultState();
|
||||
private static final Supplier<Function<FluidVariant, FluidState>> GET_FULL_FLUID_STATE = Suppliers.memoize(() -> SIMPLE_FLUID_CLASS.get().<Function<FluidVariant, FluidState>>map(type -> {
|
||||
try {
|
||||
final Method method = type.getDeclaredMethod("getFluidState", ItemStack.class);
|
||||
if (method != null) {
|
||||
return fluid -> {
|
||||
try {
|
||||
ItemStack stack = Items.STONE.getDefaultStack();
|
||||
NbtCompound fluidTag = stack.getOrCreateSubNbt("fluid");
|
||||
fluidTag.putString("id", Registries.FLUID.getId(fluid.getFluid()).toString());
|
||||
fluidTag.put("attributes", fluid.getNbt());
|
||||
return FluidState.class.cast(method.invoke(type.cast(fluid), stack));
|
||||
} catch (Throwable tt) {}
|
||||
return FALLBACK_METHOD.apply(fluid);
|
||||
};
|
||||
}
|
||||
} catch (Throwable t) {}
|
||||
return FALLBACK_METHOD;
|
||||
}).orElse(FALLBACK_METHOD));
|
||||
|
||||
static FluidState getFullFluidState(FluidVariant variant) {
|
||||
return SIMPLE_FLUID_CLASS.get()
|
||||
.filter(type -> type.isAssignableFrom(variant.getFluid().getClass()))
|
||||
.map(type -> GET_FULL_FLUID_STATE.get().apply(variant))
|
||||
.orElseGet(() -> variant.getFluid().getDefaultState());
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue