Fix chests crashing users when it goes to sync the top stacks to the client for rendering due to a nbt overflow. (Switched to getNBTShareTag that was added to forge and is used by Refined Storage for it's Storage Blocks) Closes #91

This commit is contained in:
alexbegt 2017-05-26 20:58:28 -04:00
parent 276859566e
commit 767528115e
7 changed files with 191 additions and 90 deletions

View File

@ -33,7 +33,7 @@ repositories {
} }
dependencies { dependencies {
deobfCompile "mezz.jei:jei_1.10.2:3.7.6.232" deobfCompile "mezz.jei:jei_1.10.2:3.14.7.+"
} }
// This is our group. I'm cpw.mods // This is our group. I'm cpw.mods
@ -43,8 +43,8 @@ archivesBaseName = "ironchest"
// Setup the forge minecraft plugin data. Specify the preferred forge/minecraft version here // Setup the forge minecraft plugin data. Specify the preferred forge/minecraft version here
minecraft { minecraft {
version = "1.10.2-12.18.1.2014" version = "1.10.2-12.18.3.2297"
mappings = "snapshot_20160715" mappings = "snapshot_20161116"
runDir = "run" runDir = "run"
} }

View File

@ -28,6 +28,11 @@ public class CommonProxy implements IGuiHandler
return null; return null;
} }
public World getClientWorld()
{
return null;
}
@Override @Override
public Object getServerGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) public Object getServerGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z)
{ {

View File

@ -37,7 +37,7 @@ public class ContainerIronChest extends Container
@Override @Override
public boolean canInteractWith(EntityPlayer player) public boolean canInteractWith(EntityPlayer player)
{ {
return this.chest.isUseableByPlayer(player); return this.chest.isUsableByPlayer(player);
} }
@Override @Override

View File

@ -12,14 +12,18 @@ package cpw.mods.ironchest;
import java.util.Properties; import java.util.Properties;
import cpw.mods.ironchest.network.MessageCrystalChestSync;
import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventHandler; import net.minecraftforge.fml.common.Mod.EventHandler;
import net.minecraftforge.fml.common.Mod.Instance; import net.minecraftforge.fml.common.Mod.Instance;
import net.minecraftforge.fml.common.SidedProxy; import net.minecraftforge.fml.common.SidedProxy;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.network.NetworkRegistry; import net.minecraftforge.fml.common.network.NetworkRegistry;
import net.minecraftforge.fml.common.network.simpleimpl.SimpleNetworkWrapper;
import net.minecraftforge.fml.common.registry.GameRegistry; import net.minecraftforge.fml.common.registry.GameRegistry;
import net.minecraftforge.fml.relauncher.Side;
@Mod(modid = IronChest.MOD_ID, name = "Iron Chests", dependencies = "required-after:Forge@[12.17.0.1909,)", acceptedMinecraftVersions = "[1.9.4, 1.11)") @Mod(modid = IronChest.MOD_ID, name = "Iron Chests", dependencies = "required-after:Forge@[12.17.0.1909,)", acceptedMinecraftVersions = "[1.9.4, 1.11)")
public class IronChest public class IronChest
@ -35,6 +39,8 @@ public class IronChest
public static BlockIronChest ironChestBlock; public static BlockIronChest ironChestBlock;
public static ItemIronChest ironChestItemBlock; public static ItemIronChest ironChestItemBlock;
public static final SimpleNetworkWrapper packetHandler = NetworkRegistry.INSTANCE.newSimpleChannel(MOD_ID);
@EventHandler @EventHandler
public void preInit(FMLPreInitializationEvent event) public void preInit(FMLPreInitializationEvent event)
{ {
@ -46,7 +52,6 @@ public class IronChest
String minor = properties.getProperty("IronChest.build.minor.number"); String minor = properties.getProperty("IronChest.build.minor.number");
String rev = properties.getProperty("IronChest.build.revision.number"); String rev = properties.getProperty("IronChest.build.revision.number");
String build = properties.getProperty("IronChest.build.number"); String build = properties.getProperty("IronChest.build.number");
// String mcversion = properties.getProperty("IronChest.build.mcversion");
event.getModMetadata().version = String.format("%s.%s.%s build %s", major, minor, rev, build); event.getModMetadata().version = String.format("%s.%s.%s build %s", major, minor, rev, build);
} }
@ -65,4 +70,11 @@ public class IronChest
proxy.registerRenderInformation(); proxy.registerRenderInformation();
MinecraftForge.EVENT_BUS.register(new OcelotsSitOnChestsHandler()); MinecraftForge.EVENT_BUS.register(new OcelotsSitOnChestsHandler());
} }
@EventHandler
public void init(FMLInitializationEvent event)
{
int messageId = 0;
packetHandler.registerMessage(MessageCrystalChestSync.Handler.class, MessageCrystalChestSync.class, messageId++, Side.CLIENT);
}
} }

View File

@ -15,6 +15,7 @@ import java.util.Comparator;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import cpw.mods.ironchest.network.MessageCrystalChestSync;
import net.minecraft.block.state.IBlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayer;
@ -34,6 +35,7 @@ import net.minecraft.util.ITickable;
import net.minecraft.util.SoundCategory; import net.minecraft.util.SoundCategory;
import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.AxisAlignedBB;
import net.minecraftforge.common.util.Constants; import net.minecraftforge.common.util.Constants;
import net.minecraftforge.fml.common.network.NetworkRegistry.TargetPoint;
public class TileEntityIronChest extends TileEntityLockableLoot implements ITickable, IInventory public class TileEntityIronChest extends TileEntityLockableLoot implements ITickable, IInventory
{ {
@ -114,7 +116,7 @@ public class TileEntityIronChest extends TileEntityLockableLoot implements ITick
if (this.hasWorldObj()) if (this.hasWorldObj())
{ {
IBlockState state = this.worldObj.getBlockState(this.pos); IBlockState state = this.world.getBlockState(this.pos);
if (state.getBlock() == IronChest.ironChestBlock) if (state.getBlock() == IronChest.ironChestBlock)
{ {
@ -145,7 +147,7 @@ public class TileEntityIronChest extends TileEntityLockableLoot implements ITick
protected void sortTopStacks() protected void sortTopStacks()
{ {
if (!this.getType().isTransparent() || (this.worldObj != null && this.worldObj.isRemote)) if (!this.getType().isTransparent() || (this.world != null && this.world.isRemote))
{ {
return; return;
} }
@ -194,11 +196,11 @@ public class TileEntityIronChest extends TileEntityLockableLoot implements ITick
this.topStacks[i] = null; this.topStacks[i] = null;
} }
if (this.worldObj != null) if (this.world != null)
{ {
IBlockState iblockstate = this.worldObj.getBlockState(this.pos); IBlockState iblockstate = this.world.getBlockState(this.pos);
this.worldObj.notifyBlockUpdate(this.pos, iblockstate, iblockstate, 3); this.world.notifyBlockUpdate(this.pos, iblockstate, iblockstate, 3);
} }
return; return;
@ -247,12 +249,14 @@ public class TileEntityIronChest extends TileEntityLockableLoot implements ITick
this.topStacks[i] = null; this.topStacks[i] = null;
} }
if (this.worldObj != null) if (this.world != null)
{ {
IBlockState iblockstate = this.worldObj.getBlockState(this.pos); IBlockState iblockstate = this.world.getBlockState(this.pos);
this.worldObj.notifyBlockUpdate(this.pos, iblockstate, iblockstate, 3); this.world.notifyBlockUpdate(this.pos, iblockstate, iblockstate, 3);
} }
sendTopStacksPacket();
} }
@Override @Override
@ -380,14 +384,14 @@ public class TileEntityIronChest extends TileEntityLockableLoot implements ITick
} }
@Override @Override
public boolean isUseableByPlayer(EntityPlayer player) public boolean isUsableByPlayer(EntityPlayer player)
{ {
if (this.worldObj == null) if (this.world == null)
{ {
return true; return true;
} }
if (this.worldObj.getTileEntity(this.pos) != this) if (this.world.getTileEntity(this.pos) != this)
{ {
return false; return false;
} }
@ -400,7 +404,7 @@ public class TileEntityIronChest extends TileEntityLockableLoot implements ITick
{ {
// Resynchronizes clients with the server state // Resynchronizes clients with the server state
//@formatter:off //@formatter:off
if (this.worldObj != null && !this.worldObj.isRemote && this.numPlayersUsing != 0 && (this.ticksSinceSync + this.pos.getX() + this.pos.getY() + this.pos.getZ()) % 200 == 0) if (this.world != null && !this.world.isRemote && this.numPlayersUsing != 0 && (this.ticksSinceSync + this.pos.getX() + this.pos.getY() + this.pos.getZ()) % 200 == 0)
//@formatter:on //@formatter:on
{ {
this.numPlayersUsing = 0; this.numPlayersUsing = 0;
@ -408,7 +412,7 @@ public class TileEntityIronChest extends TileEntityLockableLoot implements ITick
float f = 5.0F; float f = 5.0F;
//@formatter:off //@formatter:off
for (EntityPlayer player : this.worldObj.getEntitiesWithinAABB(EntityPlayer.class, new AxisAlignedBB(this.pos.getX() - f, this.pos.getY() - f, this.pos.getZ() - f, this.pos.getX() + 1 + f, this.pos.getY() + 1 + f, this.pos.getZ() + 1 + f))) for (EntityPlayer player : this.world.getEntitiesWithinAABB(EntityPlayer.class, new AxisAlignedBB(this.pos.getX() - f, this.pos.getY() - f, this.pos.getZ() - f, this.pos.getX() + 1 + f, this.pos.getY() + 1 + f, this.pos.getZ() + 1 + f)))
//@formatter:on //@formatter:on
{ {
if (player.openContainer instanceof ContainerIronChest) if (player.openContainer instanceof ContainerIronChest)
@ -418,12 +422,12 @@ public class TileEntityIronChest extends TileEntityLockableLoot implements ITick
} }
} }
if (this.worldObj != null && !this.worldObj.isRemote && this.ticksSinceSync < 0) if (this.world != null && !this.world.isRemote && this.ticksSinceSync < 0)
{ {
this.worldObj.addBlockEvent(this.pos, IronChest.ironChestBlock, 3, ((this.numPlayersUsing << 3) & 0xF8) | (this.facing.ordinal() & 0x7)); this.world.addBlockEvent(this.pos, IronChest.ironChestBlock, 3, ((this.numPlayersUsing << 3) & 0xF8) | (this.facing.ordinal() & 0x7));
} }
if (!this.worldObj.isRemote && this.inventoryTouched) if (!this.world.isRemote && this.inventoryTouched)
{ {
this.inventoryTouched = false; this.inventoryTouched = false;
@ -442,7 +446,7 @@ public class TileEntityIronChest extends TileEntityLockableLoot implements ITick
double y = this.pos.getY() + 0.5D; double y = this.pos.getY() + 0.5D;
double z = this.pos.getZ() + 0.5D; double z = this.pos.getZ() + 0.5D;
this.worldObj.playSound(null, x, y, z, SoundEvents.BLOCK_CHEST_OPEN, SoundCategory.BLOCKS, 0.5F, this.worldObj.rand.nextFloat() * 0.1F + 0.9F); this.world.playSound(null, x, y, z, SoundEvents.BLOCK_CHEST_OPEN, SoundCategory.BLOCKS, 0.5F, this.world.rand.nextFloat() * 0.1F + 0.9F);
} }
if (this.numPlayersUsing == 0 && this.lidAngle > 0.0F || this.numPlayersUsing > 0 && this.lidAngle < 1.0F) if (this.numPlayersUsing == 0 && this.lidAngle > 0.0F || this.numPlayersUsing > 0 && this.lidAngle < 1.0F)
@ -471,7 +475,7 @@ public class TileEntityIronChest extends TileEntityLockableLoot implements ITick
double y = this.pos.getY() + 0.5D; double y = this.pos.getY() + 0.5D;
double z = this.pos.getZ() + 0.5D; double z = this.pos.getZ() + 0.5D;
this.worldObj.playSound(null, x, y, z, SoundEvents.BLOCK_CHEST_CLOSE, SoundCategory.BLOCKS, 0.5F, this.worldObj.rand.nextFloat() * 0.1F + 0.9F); this.world.playSound(null, x, y, z, SoundEvents.BLOCK_CHEST_CLOSE, SoundCategory.BLOCKS, 0.5F, this.world.rand.nextFloat() * 0.1F + 0.9F);
} }
if (this.lidAngle < 0.0F) if (this.lidAngle < 0.0F)
@ -506,7 +510,7 @@ public class TileEntityIronChest extends TileEntityLockableLoot implements ITick
{ {
if (!player.isSpectator()) if (!player.isSpectator())
{ {
if (this.worldObj == null) if (this.world == null)
{ {
return; return;
} }
@ -518,9 +522,9 @@ public class TileEntityIronChest extends TileEntityLockableLoot implements ITick
++this.numPlayersUsing; ++this.numPlayersUsing;
this.worldObj.addBlockEvent(this.pos, IronChest.ironChestBlock, 1, this.numPlayersUsing); this.world.addBlockEvent(this.pos, IronChest.ironChestBlock, 1, this.numPlayersUsing);
this.worldObj.notifyNeighborsOfStateChange(this.pos, IronChest.ironChestBlock); this.world.notifyNeighborsOfStateChange(this.pos, IronChest.ironChestBlock);
this.worldObj.notifyNeighborsOfStateChange(this.pos.down(), IronChest.ironChestBlock); this.world.notifyNeighborsOfStateChange(this.pos.down(), IronChest.ironChestBlock);
} }
} }
@ -529,16 +533,16 @@ public class TileEntityIronChest extends TileEntityLockableLoot implements ITick
{ {
if (!player.isSpectator()) if (!player.isSpectator())
{ {
if (this.worldObj == null) if (this.world == null)
{ {
return; return;
} }
--this.numPlayersUsing; --this.numPlayersUsing;
this.worldObj.addBlockEvent(this.pos, IronChest.ironChestBlock, 1, this.numPlayersUsing); this.world.addBlockEvent(this.pos, IronChest.ironChestBlock, 1, this.numPlayersUsing);
this.worldObj.notifyNeighborsOfStateChange(this.pos, IronChest.ironChestBlock); this.world.notifyNeighborsOfStateChange(this.pos, IronChest.ironChestBlock);
this.worldObj.notifyNeighborsOfStateChange(this.pos.down(), IronChest.ironChestBlock); this.world.notifyNeighborsOfStateChange(this.pos.down(), IronChest.ironChestBlock);
} }
} }
@ -559,29 +563,6 @@ public class TileEntityIronChest extends TileEntityLockableLoot implements ITick
compound.setByte("facing", (byte) this.facing.ordinal()); compound.setByte("facing", (byte) this.facing.ordinal());
ItemStack[] stacks = this.buildItemStackDataList();
if (stacks != null)
{
NBTTagList itemList = new NBTTagList();
for (int slot = 0; slot < stacks.length; slot++)
{
if (stacks[slot] != null)
{
NBTTagCompound item = new NBTTagCompound();
item.setByte("Slot", (byte) slot);
stacks[slot].writeToNBT(item);
itemList.appendTag(item);
}
}
compound.setTag("stacks", itemList);
}
return new SPacketUpdateTileEntity(this.pos, 0, compound); return new SPacketUpdateTileEntity(this.pos, 0, compound);
} }
@ -593,41 +574,6 @@ public class TileEntityIronChest extends TileEntityLockableLoot implements ITick
NBTTagCompound compound = pkt.getNbtCompound(); NBTTagCompound compound = pkt.getNbtCompound();
this.facing = EnumFacing.VALUES[compound.getByte("facing")]; this.facing = EnumFacing.VALUES[compound.getByte("facing")];
NBTTagList itemList = compound.getTagList("stacks", Constants.NBT.TAG_COMPOUND);
ItemStack[] stacks = new ItemStack[this.topStacks.length];
for (int item = 0; item < stacks.length; item++)
{
NBTTagCompound itemStack = itemList.getCompoundTagAt(item);
int slot = itemStack.getByte("Slot") & 255;
if (slot >= 0 && slot < stacks.length)
{
stacks[slot] = ItemStack.loadItemStackFromNBT(itemStack);
}
}
if (this.getType().isTransparent() && stacks != null)
{
int pos = 0;
for (int i = 0; i < this.topStacks.length; i++)
{
if (stacks[pos] != null)
{
this.topStacks[i] = stacks[pos];
}
else
{
this.topStacks[i] = null;
}
pos++;
}
}
} }
} }
@ -678,7 +624,7 @@ public class TileEntityIronChest extends TileEntityLockableLoot implements ITick
{ {
this.setFacing(this.facing.rotateY()); this.setFacing(this.facing.rotateY());
this.worldObj.addBlockEvent(this.pos, IronChest.ironChestBlock, 2, this.facing.ordinal()); this.world.addBlockEvent(this.pos, IronChest.ironChestBlock, 2, this.facing.ordinal());
} }
public void wasPlaced(EntityLivingBase entityliving, ItemStack stack) public void wasPlaced(EntityLivingBase entityliving, ItemStack stack)
@ -742,4 +688,17 @@ public class TileEntityIronChest extends TileEntityLockableLoot implements ITick
{ {
return this.writeToNBT(new NBTTagCompound()); return this.writeToNBT(new NBTTagCompound());
} }
protected void sendTopStacksPacket()
{
ItemStack[] stacks = this.buildItemStackDataList();
//@formatter:off
IronChest.packetHandler.sendToAllAround(new MessageCrystalChestSync(this, stacks), new TargetPoint(world.provider.getDimension(), getPos().getX(), getPos().getY(), getPos().getZ(), 32));
//@formatter:on
}
public void receiveMessageFromServer(ItemStack[] topStacks)
{
this.topStacks = topStacks;
}
} }

View File

@ -15,6 +15,7 @@ import cpw.mods.ironchest.CommonProxy;
import cpw.mods.ironchest.IronChest; import cpw.mods.ironchest.IronChest;
import cpw.mods.ironchest.IronChestType; import cpw.mods.ironchest.IronChestType;
import cpw.mods.ironchest.TileEntityIronChest; import cpw.mods.ironchest.TileEntityIronChest;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.block.model.ModelResourceLocation; import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item; import net.minecraft.item.Item;
@ -55,6 +56,12 @@ public class ClientProxy extends CommonProxy
} }
} }
@Override
public World getClientWorld()
{
return Minecraft.getMinecraft().world;
}
@Override @Override
public Object getClientGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) public Object getClientGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z)
{ {

View File

@ -0,0 +1,118 @@
package cpw.mods.ironchest.network;
import cpw.mods.ironchest.IronChest;
import cpw.mods.ironchest.TileEntityIronChest;
import io.netty.buffer.ByteBuf;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.fml.common.network.ByteBufUtils;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
public class MessageCrystalChestSync implements IMessage
{
int dimension;
BlockPos pos;
private ItemStack[] topStacks;
public MessageCrystalChestSync(TileEntityIronChest tile, ItemStack[] stack)
{
this.dimension = tile.getWorld().provider.getDimension();
this.pos = tile.getPos();
this.topStacks = stack;
}
public MessageCrystalChestSync()
{
}
@Override
public void fromBytes(ByteBuf buf)
{
this.dimension = buf.readInt();
this.pos = new BlockPos(buf.readInt(), buf.readInt(), buf.readInt());
int size = buf.readInt();
this.topStacks = new ItemStack[size];
int stackListSize = buf.readInt();
for (int i = 0; i < stackListSize; i++)
{
if (i < stackListSize)
{
this.topStacks[i] = readItemStack(buf);
}
else
{
this.topStacks[i] = null;
}
}
}
@Override
public void toBytes(ByteBuf buf)
{
buf.writeInt(this.dimension);
buf.writeInt(this.pos.getX());
buf.writeInt(this.pos.getY());
buf.writeInt(this.pos.getZ());
buf.writeInt(topStacks.length);
int stackListSize = 0;
for (ItemStack stack : topStacks)
{
if (stack != null)
{
stackListSize++;
}
}
buf.writeInt(stackListSize);
for (ItemStack stack : topStacks)
{
if (stack != null)
{
writeItemStack(buf, stack);
}
}
}
public static void writeItemStack(ByteBuf buf, ItemStack stack)
{
buf.writeInt(Item.getIdFromItem(stack.getItem()));
buf.writeInt(stack.stackSize);
buf.writeInt(stack.getItemDamage());
ByteBufUtils.writeTag(buf, stack.getItem().getNBTShareTag(stack));
}
public static ItemStack readItemStack(ByteBuf buf)
{
ItemStack stack = new ItemStack(Item.getItemById(buf.readInt()), buf.readInt(), buf.readInt());
stack.setTagCompound(ByteBufUtils.readTag(buf));
return stack;
}
public static class Handler implements IMessageHandler<MessageCrystalChestSync, IMessage>
{
@Override
public IMessage onMessage(MessageCrystalChestSync message, MessageContext ctx)
{
World world = IronChest.proxy.getClientWorld();
if (world != null)
{
TileEntity tile = world.getTileEntity(message.pos);
if (tile instanceof TileEntityIronChest)
((TileEntityIronChest) tile).receiveMessageFromServer(message.topStacks);
}
return null;
}
}
}