Fix Bucket rendering and add sound (#2865)

* Adjust generated quads from texture to take texture size into account #2858

*  Fix universal bucket not passing through when rightclicking on a non-block
Add proper sound events when picking up modded fluids #2821

* Have FluidUtil execute properly on both sides and sync as expected. Add default sounds to interacting with tanks

* Save sound for filling/emptying in the fluid
This commit is contained in:
boni authored and LexManos committed 2016-05-16 13:20:31 -07:00
1 parent 87b0f7db99
commit 5d5c005aae
4 files changed
+210 -248

No files matched your search

@@ -47,6 +47,8 @@ public final class ItemTextureQuadConverter
{
int w = template.getIconWidth();
int h = template.getIconHeight();
float wScale = 16f / (float)w;
float hScale = 16f / (float)h;
int[] data = template.getFrameTextureData(0)[0];
List<UnpackedBakedQuad> quads = Lists.newArrayList();
@@ -90,7 +92,12 @@ public final class ItemTextureQuadConverter
}
// create the quad
quads.add(genQuad(format, transform, start, y, x, endY, z, sprite, facing, color));
quads.add(genQuad(format, transform,
(float)start * wScale,
(float)y * hScale,
(float)x * wScale,
(float)endY * hScale,
z, sprite, facing, color));
// update Y if all the rows match. no need to rescan
if (endY - y > 1)
@@ -114,6 +121,8 @@ public final class ItemTextureQuadConverter
{
int w = template.getIconWidth();
int h = template.getIconHeight();
float wScale = 16f / (float)w;
float hScale = 16f / (float)h;
int[] data = template.getFrameTextureData(0)[0];
List<UnpackedBakedQuad> quads = Lists.newArrayList();
@@ -157,7 +166,12 @@ public final class ItemTextureQuadConverter
}
// create the quad
quads.add(genQuad(format, transform, x, start, endX, y, z, sprite, facing, color));
quads.add(genQuad(format, transform,
(float)x * wScale,
(float)start * hScale,
(float)endX * wScale,
(float)y * hScale,
z, sprite, facing, color));
// update X if all the columns match. no need to rescan
if (endX - x > 1)
@@ -181,6 +195,7 @@ public final class ItemTextureQuadConverter
/**
* Generates a Front/Back quad for an itemmodel. Therefore only supports facing NORTH and SOUTH.
* Coordinates are [0,16] to match the usual coordinates used in TextureAtlasSprites
*/
public static UnpackedBakedQuad genQuad(VertexFormat format, TRSRTransformation transform, float x1, float y1, float x2, float y2, float z, TextureAtlasSprite sprite, EnumFacing facing, int color)
{
@@ -2,6 +2,9 @@ package net.minecraftforge.fluids;
import java.util.Locale;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.init.SoundEvents;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.translation.I18n;
import net.minecraft.util.ResourceLocation;
@@ -36,6 +39,9 @@ public class Fluid
protected final ResourceLocation still;
protected final ResourceLocation flowing;
private SoundEvent fillSound;
private SoundEvent emptySound;
/**
* The light level emitted by this fluid.
*
@@ -158,6 +164,18 @@ public class Fluid
return this;
}
public Fluid setFillSound(SoundEvent fillSound)
{
this.fillSound = fillSound;
return this;
}
public Fluid setEmptySound(SoundEvent emptySound)
{
this.emptySound = emptySound;
return this;
}
public final String getName()
{
return this.fluidName;
@@ -244,6 +262,40 @@ public class Fluid
return flowing;
}
public SoundEvent getFillSound()
{
if(fillSound == null)
{
if(getBlock() != null && getBlock().getDefaultState().getMaterial() == Material.lava)
{
fillSound = SoundEvents.item_bucket_fill_lava;
}
else
{
fillSound = SoundEvents.item_bucket_fill;
}
}
return fillSound;
}
public SoundEvent getEmptySound()
{
if(emptySound == null)
{
if(getBlock() != null && getBlock().getDefaultState().getMaterial() == Material.lava)
{
emptySound = SoundEvents.item_bucket_empty_lava;
}
else
{
emptySound = SoundEvents.item_bucket_empty;
}
}
return emptySound;
}
/* Stack-based Accessors */
public int getLuminosity(FluidStack stack){ return getLuminosity(); }
public int getDensity(FluidStack stack){ return getDensity(); }
@@ -254,6 +306,8 @@ public class Fluid
public int getColor(FluidStack stack){ return getColor(); }
public ResourceLocation getStill(FluidStack stack) { return getStill(); }
public ResourceLocation getFlowing(FluidStack stack) { return getFlowing(); }
public SoundEvent getFillSound(FluidStack stack) { return getFillSound(); }
public SoundEvent getEmptySound(FluidStack stack) { return getEmptySound(); }
/* World-based Accessors */
public int getLuminosity(World world, BlockPos pos){ return getLuminosity(); }
@@ -265,5 +319,7 @@ public class Fluid
public int getColor(World world, BlockPos pos){ return getColor(); }
public ResourceLocation getStill(World world, BlockPos pos) { return getStill(); }
public ResourceLocation getFlowing(World world, BlockPos pos) { return getFlowing(); }
public SoundEvent getFillSound(World world, BlockPos pos) { return getFillSound(); }
public SoundEvent getEmptySound(World world, BlockPos pos) { return getEmptySound(); }
}
@@ -1,26 +1,17 @@
package net.minecraftforge.fluids;
import net.minecraft.crash.CrashReport;
import net.minecraft.crash.CrashReportCategory;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.init.SoundEvents;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ReportedException;
import net.minecraft.util.SoundCategory;
import net.minecraft.world.World;
import net.minecraft.util.SoundEvent;
import net.minecraftforge.common.ForgeModContainer;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemHandlerHelper;
import net.minecraftforge.items.wrapper.PlayerMainInvWrapper;
import java.util.concurrent.Callable;
public class FluidUtil
{
@@ -31,7 +22,7 @@ public class FluidUtil
/** Returns true if interaction was successful. */
public static boolean interactWithTank(ItemStack stack, EntityPlayer player, IFluidHandler tank, EnumFacing side)
{
if (stack == null || player.worldObj.isRemote)
if (stack == null)
{
return true;
}
@@ -40,8 +31,8 @@ public class FluidUtil
// regular bucket?
int slot = player.inventory.currentItem;
if ((result = FluidUtil.tryFillBucket(stack, tank, side)) != null ||
(result = FluidUtil.tryEmptyBucket(stack, tank, side)) != null)
if ((result = FluidUtil.tryFillBucket(stack, tank, side, player)) != null ||
(result = FluidUtil.tryEmptyBucket(stack, tank, side, player)) != null)
{
// "use up" the input item if the player is not in creative
if (!player.capabilities.isCreativeMode)
@@ -60,7 +51,9 @@ public class FluidUtil
else
{
// copy of the original item for creative mode
ItemStack original = stack; // needed for how minecraft manages inventory with interaction
ItemStack copy = stack.copy();
stack = stack.copy(); // needed so we don't affect itemstacks outside of this function
boolean changedBucket = false;
// convert to fluidcontainer-bucket if it's a regular empty bucket
if (ItemStack.areItemsEqual(stack, FluidContainerRegistry.EMPTY_BUCKET) && FluidRegistry.isUniversalBucketEnabled())
@@ -74,6 +67,7 @@ public class FluidUtil
if (FluidUtil.tryFillFluidContainerItem(stack, tank, side, player) ||
FluidUtil.tryEmptyFluidContainerItem(stack, tank, side, player))
{
original.stackSize--; // this tells the player that the item he held was "used up" and the inventory syncing will then play the correct animation
if (player.capabilities.isCreativeMode)
{
// reset the stack that got modified
@@ -117,6 +111,12 @@ public class FluidUtil
return false;
}
@Deprecated
public static ItemStack tryFillBucket(ItemStack bucket, IFluidHandler tank, EnumFacing side)
{
return tryFillBucket(bucket, tank, side, null);
}
/**
* Fill an empty bucket from the given tank. Uses the FluidContainerRegistry.
*
@@ -125,7 +125,7 @@ public class FluidUtil
* @param side Side to access the tank from
* @return The filled bucket or null if the liquid couldn't be taken from the tank.
*/
public static ItemStack tryFillBucket(ItemStack bucket, IFluidHandler tank, EnumFacing side)
public static ItemStack tryFillBucket(ItemStack bucket, IFluidHandler tank, EnumFacing side, EntityPlayer player)
{
FluidTankInfo[] info = tank.getTankInfo(side);
// check for fluid in the tank
@@ -144,6 +144,13 @@ public class FluidUtil
FluidStack liquid = tank.drain(side, FluidContainerRegistry.getContainerCapacity(inTank, bucket), false);
if (liquid != null && liquid.amount > 0)
{
// play sound
if(player != null)
{
SoundEvent soundevent = liquid.getFluid().getFillSound(liquid);
player.playSound(soundevent, 1f, 1f);
}
// success, return filled bucket
tank.drain(side, FluidContainerRegistry.getContainerCapacity(liquid, bucket), true);
return FluidContainerRegistry.fillFluidContainer(liquid, bucket);
@@ -152,15 +159,22 @@ public class FluidUtil
return null;
}
@Deprecated
public static ItemStack tryEmptyBucket(ItemStack bucket, IFluidHandler tank, EnumFacing side)
{
return tryEmptyBucket(bucket, tank, side, null);
}
/**
* Takes a filled bucket and tries to empty it into the given tank. Uses the FluidContainerRegistry.
*
* @param bucket The filled bucket
* @param tank The tank to fill with the bucket
* @param side Side to access the tank from
* @param player
* @return The empty bucket if successful, null if the tank couldn't be filled.
*/
public static ItemStack tryEmptyBucket(ItemStack bucket, IFluidHandler tank, EnumFacing side)
public static ItemStack tryEmptyBucket(ItemStack bucket, IFluidHandler tank, EnumFacing side, EntityPlayer player)
{
// not a filled bucket
if (!FluidContainerRegistry.isFilledContainer(bucket))
@@ -177,6 +191,12 @@ public class FluidUtil
// not everything?
if (amount == liquid.amount)
{
// play sound
if(player != null)
{
SoundEvent soundevent = liquid.getFluid().getEmptySound(liquid);
player.playSound(soundevent, 1f, 1f);
}
// success, fully filled it into the tank, return empty bucket
tank.fill(side, liquid, true);
return FluidContainerRegistry.drainFluidContainer(bucket);
@@ -263,18 +283,21 @@ public class FluidUtil
return false;
}
// check if we can give the itemstack to the inventory
ItemStack remainder = ItemHandlerHelper.insertItemStacked(inventory, toFill, true);
if (remainder != null && player == null)
if(player == null || !player.worldObj.isRemote)
{
// couldn't add to the inventory and don't have a player to drop the item at
return false;
}
remainder = ItemHandlerHelper.insertItemStacked(inventory, toFill, false);
// give it to the player or drop it at his feet
if (remainder != null && player != null)
{
ItemHandlerHelper.giveItemToPlayer(player, remainder);
// check if we can give the itemstack to the inventory
ItemStack remainder = ItemHandlerHelper.insertItemStacked(inventory, toFill, true);
if (remainder != null && player == null)
{
// couldn't add to the inventory and don't have a player to drop the item at
return false;
}
remainder = ItemHandlerHelper.insertItemStacked(inventory, toFill, false);
// give it to the player or drop it at his feet
if (remainder != null && player != null)
{
ItemHandlerHelper.giveItemToPlayer(player, remainder);
}
}
// the result has been given to the player, drain the tank since everything is ok
@@ -300,6 +323,13 @@ public class FluidUtil
tank.drain(side, filled, true);
}
// play sound
if(player != null)
{
SoundEvent soundevent = liquid.getFluid().getFillSound(liquid);
player.playSound(soundevent, 1f, 1f);
}
return true;
}
@@ -356,18 +386,21 @@ public class FluidUtil
toEmpty.stackSize = 1;
drained = fluidContainer.drain(toEmpty, filled, true); // modifies the container!
// try adding the drained container to the inventory
ItemStack remainder = ItemHandlerHelper.insertItemStacked(inventory, toEmpty, true);
if (remainder != null && player == null)
if(player == null || !player.worldObj.isRemote)
{
// couldn't add to the inventory and don't have a player to drop the item at
return false;
}
remainder = ItemHandlerHelper.insertItemStacked(inventory, toEmpty, false);
// give it to the player or drop it at his feet
if (remainder != null && player != null)
{
ItemHandlerHelper.giveItemToPlayer(player, remainder);
// try adding the drained container to the inventory
ItemStack remainder = ItemHandlerHelper.insertItemStacked(inventory, toEmpty, true);
if (remainder != null && player == null)
{
// couldn't add to the inventory and don't have a player to drop the item at
return false;
}
remainder = ItemHandlerHelper.insertItemStacked(inventory, toEmpty, false);
// give it to the player or drop it at his feet
if (remainder != null && player != null)
{
ItemHandlerHelper.giveItemToPlayer(player, remainder);
}
}
// the result has been given to the player, fill the tank since everything is ok
@@ -383,6 +416,13 @@ public class FluidUtil
drained = fluidContainer.drain(container, filled, true); // modifies the container!
tank.fill(side, drained, true);
}
// play sound
if(player != null)
{
SoundEvent soundevent = drained.getFluid().getEmptySound(drained);
player.playSound(soundevent, 1f, 1f);
}
return true;
}
}
@@ -391,175 +431,4 @@ public class FluidUtil
return false;
}
private static boolean insertItemInto(ItemStack stack, IInventory inventory, World world, BlockPos pos, boolean isCreative)
{
if (stack == null)
{
return false;
}
// add it to the inventory
if (inventory != null && addItemStackToInventory(stack, inventory, isCreative))
{
if (world != null && pos != null)
{
world.playSound(null, pos.getX(), pos.getY(), pos.getZ(), SoundEvents.entity_item_pickup, SoundCategory.PLAYERS, 0.2F, ((world.rand.nextFloat() - world.rand.nextFloat()) * 0.7F + 1.0F) * 2.0F);
}
return true;
}
else if (world != null && pos != null)
{
double d0 = pos.getY() + 0.5d;
EntityItem entityitem = new EntityItem(world, pos.getX(), d0, pos.getZ(), stack);
entityitem.setPickupDelay(40);
entityitem.motionX = 0;
//entityitem.motionY = 0;
entityitem.motionZ = 0;
if (!world.isRemote)
{
world.spawnEntityInWorld(entityitem);
}
return true;
}
return false;
}
// generalized copy of InventoryPlayer.addItemStackToInventory without regarding itemstack sizes > 1
private static boolean addItemStackToInventory(final ItemStack itemstack, IInventory inventory, boolean isCreative)
{
if (itemstack != null && itemstack.stackSize == 1 && itemstack.getItem() != null)
{
try
{
int sizeInventory = inventory.getSizeInventory();
// player inventory requires hardcoding because we don't want to add to the armor slots
if (inventory instanceof InventoryPlayer)
{
sizeInventory -= 4;
}
if (itemstack.isItemDamaged())
{
int j = 0;
for (; j < sizeInventory; ++j)
{
if (inventory.getStackInSlot(j) == null)
{
break;
}
}
// found empty slot
if (j < sizeInventory)
{
ItemStack copy = ItemStack.copyItemStack(itemstack);
copy.animationsToGo = 5;
inventory.setInventorySlotContents(j, copy);
itemstack.stackSize = 0;
return true;
}
else if (isCreative)
{
itemstack.stackSize = 0;
return true;
}
else
{
return false;
}
}
else
{
int origSize = itemstack.stackSize;
// go through the inventory and try to fill up already existing items
for (int i = 0; i < sizeInventory; i++)
{
ItemStack slot = inventory.getStackInSlot(i);
if (slot != null && slot.getItem() == itemstack.getItem() &&
slot.isStackable() && slot.stackSize < slot.getMaxStackSize() &&
slot.stackSize < inventory.getInventoryStackLimit() &&
(!slot.getHasSubtypes() || slot.getMetadata() == itemstack.getMetadata()) &&
ItemStack.areItemStackTagsEqual(slot, itemstack))
{
// stackable
int dif = itemstack.stackSize;
if (dif > slot.getMaxStackSize() - slot.stackSize)
{
dif = slot.getMaxStackSize() - slot.stackSize;
}
if (dif > inventory.getInventoryStackLimit())
{
dif = inventory.getInventoryStackLimit();
}
slot.stackSize += dif;
slot.animationsToGo = 5;
itemstack.stackSize -= dif;
inventory.setInventorySlotContents(i, slot);
if (itemstack.stackSize <= 0)
{
break;
}
}
}
if (itemstack.stackSize > 0)
{
// find empty slot
for (int i = 0; i < sizeInventory; i++)
{
if (inventory.getStackInSlot(i) == null)
{
ItemStack slot = ItemStack.copyItemStack(itemstack);
if (slot.stackSize > inventory.getInventoryStackLimit())
{
slot.stackSize = inventory.getInventoryStackLimit();
}
slot.animationsToGo = 5;
inventory.setInventorySlotContents(i, slot);
itemstack.stackSize -= slot.stackSize;
}
if (itemstack.stackSize <= 0)
{
break;
}
}
}
if (itemstack.stackSize > 0 && isCreative)
{
itemstack.stackSize = 0;
return true;
}
else
{
return itemstack.stackSize < origSize;
}
}
}
catch (Throwable throwable)
{
CrashReport crashreport = CrashReport.makeCrashReport(throwable, "Adding item to inventory");
CrashReportCategory crashreportcategory = crashreport.makeCategory("Item being added");
crashreportcategory.addCrashSection("Item ID", Item.getIdFromItem(itemstack.getItem()));
crashreportcategory.addCrashSection("Item data", itemstack.getMetadata());
crashreportcategory.addCrashSectionCallable("Item name", new Callable<String>()
{
public String call() throws Exception
{
return itemstack.getDisplayName();
}
});
throw new ReportedException(crashreport);
}
}
else
{
return false;
}
}
}
@@ -11,14 +11,10 @@ import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.stats.StatList;
import net.minecraft.util.*;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.text.translation.I18n;
import net.minecraft.util.ActionResult;
import net.minecraft.util.EnumActionResult;
import net.minecraft.util.EnumHand;
import net.minecraft.util.EnumParticleTypes;
import net.minecraft.util.SoundCategory;
import net.minecraft.world.World;
import net.minecraftforge.event.entity.player.FillBucketEvent;
import net.minecraftforge.fml.common.eventhandler.Event;
@@ -112,39 +108,42 @@ public class UniversalBucket extends Item implements IFluidContainerItem
// clicked on a block?
RayTraceResult mop = this.getMovingObjectPositionFromPlayer(world, player, false);
if (mop != null && mop.typeOfHit == RayTraceResult.Type.BLOCK)
if(mop == null || mop.typeOfHit != RayTraceResult.Type.BLOCK)
{
BlockPos clickPos = mop.getBlockPos();
// can we place liquid there?
if (world.isBlockModifiable(player, clickPos))
return ActionResult.newResult(EnumActionResult.PASS, itemstack);
}
BlockPos clickPos = mop.getBlockPos();
// can we place liquid there?
if (world.isBlockModifiable(player, clickPos))
{
// the block adjacent to the side we clicked on
BlockPos targetPos = clickPos.offset(mop.sideHit);
// can the player place there?
if (player.canPlayerEdit(targetPos, mop.sideHit, itemstack))
{
// the block adjacent to the side we clicked on
BlockPos targetPos = clickPos.offset(mop.sideHit);
// can the player place there?
if (player.canPlayerEdit(targetPos, mop.sideHit, itemstack))
// try placing liquid
if (this.tryPlaceFluid(player, player.getEntityWorld(), fluidStack.getFluid().getBlock(), targetPos)
&& !player.capabilities.isCreativeMode)
{
// try placing liquid
if (this.tryPlaceFluid(fluidStack.getFluid().getBlock(), world, targetPos)
&& !player.capabilities.isCreativeMode)
// success!
player.addStat(StatList.func_188057_b(this));
itemstack.stackSize--;
ItemStack emptyStack = getEmpty() != null ? getEmpty().copy() : new ItemStack(this);
// check whether we replace the item or add the empty one to the inventory
if (itemstack.stackSize <= 0)
{
// success!
player.addStat(StatList.func_188057_b(this));
itemstack.stackSize--;
ItemStack emptyStack = getEmpty() != null ? getEmpty().copy() : new ItemStack(this);
// check whether we replace the item or add the empty one to the inventory
if (itemstack.stackSize <= 0)
{
return ActionResult.newResult(EnumActionResult.SUCCESS, emptyStack);
}
else
{
// add empty bucket to player inventory
ItemHandlerHelper.giveItemToPlayer(player, emptyStack);
return ActionResult.newResult(EnumActionResult.SUCCESS, itemstack);
}
return ActionResult.newResult(EnumActionResult.SUCCESS, emptyStack);
}
else
{
// add empty bucket to player inventory
ItemHandlerHelper.giveItemToPlayer(player, emptyStack);
return ActionResult.newResult(EnumActionResult.SUCCESS, itemstack);
}
}
}
@@ -154,13 +153,23 @@ public class UniversalBucket extends Item implements IFluidContainerItem
return ActionResult.newResult(EnumActionResult.FAIL, itemstack);
}
// compatibility
@Deprecated
public boolean tryPlaceFluid(Block block, World worldIn, BlockPos pos)
{
return tryPlaceFluid(null, worldIn, block, pos);
}
private boolean tryPlaceFluid(EntityPlayer player, World worldIn, Block block, BlockPos pos)
{
if (block == null)
{
return false;
}
if(worldIn == null && player != null)
{
worldIn = player.getEntityWorld();
}
Material material = worldIn.getBlockState(pos).getMaterial();
boolean isSolid = material.isSolid();
@@ -194,7 +203,16 @@ public class UniversalBucket extends Item implements IFluidContainerItem
worldIn.destroyBlock(pos, true);
}
worldIn.setBlockState(pos, block.getDefaultState(), 3);
if(player != null && block instanceof IFluidBlock)
{
Fluid fluid = ((IFluidBlock) block).getFluid();
if(fluid != null)
{
worldIn.setBlockState(pos, block.getDefaultState(), 3);
SoundEvent soundevent = fluid.getEmptySound(worldIn, pos);
worldIn.playSound(player, pos, soundevent, SoundCategory.BLOCKS, 1.0F, 1.0F);
}
}
}
return true;
}
@@ -247,6 +265,10 @@ public class UniversalBucket extends Item implements IFluidContainerItem
// set it as the result
event.setResult(Event.Result.ALLOW);
event.setFilledBucket(filledBucket);
// sound!
SoundEvent soundevent = drained.getFluid().getFillSound(drained);
event.getEntityPlayer().playSound(soundevent, 1.0F, 1.0F);
}
else
{