Здравствуйте! Пишу небольшой аддон, в котором есть один блок с ГУИ, в верхний слот которого кладутся фильтры для воды. Через некоторое время фильтры ломаются и попадают в нижний слот. Проблема состоит в том, что периодически происходит следующая проблема. Если оставить наполовину сломанный фильтр в ГУИ( у фильтров есть прочность) и перезайти в мир или перезапустить игру, то прочность у фильтра самопроизвольно восстанавливается. Иногда до конца, иногда нет. И если один фильтр сломался и попал в нижний слот, а в верхний был помещен новый, целый, то при перезаходе сломанный фильтр с нижнего слота исчезает вообще. Предполагаю, что проблема с NBT, пытался переписать. Но не помогло. Проблема то есть, то нет. Не понимаю условия её появления, из за этого сложно отладить. Вот код всех нужных классов
Код:
public class CleanMachineTile extends TileBuildCraft implements ISidedInventory,IPipeConnection,IFluidHandler,IRedstoneEngineReceiver {
private String inventoryTitle="CleanserInventory";
private int slotsCount;
private ItemStack[] inventoryContents;
private List field_70480_d;
private boolean hasCustomInventoryName;
private boolean powerRedEnable;
private Tank tankWater;
private Tank tankCleanWater;
private TankManager<Tank> tankManager;
private int tempVolumeCleanWater=0;
private int damageFilter=0;
private double rateProduction=1;
private double rateEnergyCost=1;
public CleanMachineTile(String inventoryTitle, boolean hasCustomInventoryName)
{
this.inventoryTitle = inventoryTitle;
this.hasCustomInventoryName = hasCustomInventoryName;
init();
}
public CleanMachineTile(){
init();
}
private void init(){
if(this.inventoryContents==null) {
this.inventoryContents = new ItemStack[Constants.SlotCount];
}
this.slotsCount = Constants.SlotCount;
tankWater=new Tank("tank", Constants.CapacityDirtWater, this);
tankCleanWater=new Tank("tank2",Constants.CapacityClearWater,this);
tankManager=new TankManager<>();
this.tankManager.add(tankWater);
this.tankManager.add(tankCleanWater);
this.setBattery(new RFBattery(Constants.CapacityEnergy, Constants.MaxReceiveEnergy, 0));
}
@Override
public int[] getAccessibleSlotsFromSide(int p_94128_1_) {
return new int[0];
}
@Override
public boolean canInsertItem(int p_102007_1_, ItemStack p_102007_2_, int p_102007_3_) {
return this.isItemValidForSlot(p_102007_1_, p_102007_2_);
}
@Override
public boolean canExtractItem(int p_102008_1_, ItemStack p_102008_2_, int p_102008_3_) {
return false;
}
@Override
public int getSizeInventory()
{
return this.slotsCount;
}
@Override
public ItemStack getStackInSlot(int index) {
if(this.inventoryContents!=null){
return index >= 0 && index < this.inventoryContents.length ? this.inventoryContents[index] : null;
}else
return null;
}
@Override
public void updateEntity() {
super.updateEntity();
//Если соблюдены условия, раз в секунду очищать воду
if (!worldObj.isRemote) {
if (checkCondition()) {
if (new Date().getTime() % 1000 < 50) {
clearWater();
getBattery().setEnergy(getBattery().getEnergyStored()-(int)(Constants.CountEnergyForOneCleaning*rateEnergyCost));
calculateRate();
}
}
worldObj.markBlockForUpdate(xCoord,yCoord,zCoord);
updateContainingBlockInfo();
}
}
//Рассчитываем коэффициенты эффективност и затрат энергии в зависимости от количества запасенной энергии
// (а косвенно от количество приходящей энергии - для поддержания запаса)
private void calculateRate(){
if(getBattery().getEnergyStored()<Constants.CapacityEnergy/3){
rateProduction=1;
rateEnergyCost=1;
}else if(getBattery().getEnergyStored()>=Constants.CapacityEnergy/3&&getBattery().getEnergyStored()<Constants.CapacityEnergy*2/3){
rateProduction=1.5;
rateEnergyCost=1.5;
}else if(getBattery().getEnergyStored()>=Constants.CapacityEnergy*2/3&&getBattery().getEnergyStored()<=Constants.CapacityEnergy){
rateProduction=2.5;
rateEnergyCost=5;
}
}
@Override
public ItemStack decrStackSize(int numberSlot, int p_70298_2_) {
if (this.inventoryContents[numberSlot] != null){
ItemStack itemstack;
if (this.inventoryContents[numberSlot].stackSize <= p_70298_2_){
itemstack = this.inventoryContents[numberSlot];
this.inventoryContents[numberSlot] = null;
this.markDirty();
return itemstack;
}
else{
itemstack = this.inventoryContents[numberSlot].splitStack(p_70298_2_);
if(this.inventoryContents[numberSlot].stackSize == 0){
this.inventoryContents[numberSlot] = null;
}
this.markDirty();
return itemstack;
}
}else{
return null;
}
}
@Override
public ItemStack getStackInSlotOnClosing(int indexSlot) {
if (this.inventoryContents[indexSlot] != null){
ItemStack itemstack = this.inventoryContents[indexSlot];
this.inventoryContents[indexSlot] = null;
return itemstack;
}else{
return null;
}
}
@SideOnly(Side.CLIENT)
@Override
public void setInventorySlotContents(int index, ItemStack stack) {
if(this.inventoryContents!=null){
this.inventoryContents[index] = stack;
if(stack!=null&&stack.getItem()==ItemLoader.filter){
damageFilter = stack.getItemDamage();
}
if(index==0){
if (stack != null && stack.stackSize > this.getInventoryStackLimit()){
stack.stackSize = this.getInventoryStackLimit();
}
}else if(index==1){
if (stack != null && stack.stackSize > 64) {
stack.stackSize = 64;
}
}
this.markDirty();
}
}
@Override
public String getInventoryName(){
return this.hasCustomInventoryName() ? this.inventoryTitle : "CleanserInventory";
}
@Override
public boolean hasCustomInventoryName()
{
return this.hasCustomInventoryName;
}
@Override
public int getInventoryStackLimit() {
return 1;
}
@Override
public boolean isUseableByPlayer(EntityPlayer player)
{
return true;
}
@Override
public void openInventory() {}
@Override
public void closeInventory() {}
@Override
public boolean isItemValidForSlot(int p_94041_1_, ItemStack stack) {
if(stack!=null){
return (stack.getItem() == ItemLoader.filter);
} else return false;
}
@Override
public void readFromNBT(NBTTagCompound data) {
super.readFromNBT(data);
NBTTagList tagList = data.getTagList("Data", 10);
inventoryContents = new ItemStack[Constants.SlotCount];
if(data.hasKey("CleanserInventory", 8)){
this.inventoryTitle = data.getString("CleanserInventory");
}
//Последний тег под дополнительные данные, а все до него - под предметы
for(int i = 0; i < tagList.tagCount()-1; i++){
NBTTagCompound tagCompound = tagList.getCompoundTagAt(i);
int j = tagCompound.getByte("Slot") & 255;
setInventorySlotContents(j,ItemStack.loadItemStackFromNBT(tagCompound));
System.out.println("READ: "+ItemStack.loadItemStackFromNBT(tagCompound));
}
//Подгружаем дополнительные данные
NBTTagCompound tagCompound = tagList.getCompoundTagAt(tagList.tagCount()-1);
powerRedEnable = tagCompound.getBoolean("redPowerEnable");
tankWater.fill(new FluidStack(FluidRegistry.WATER,tagCompound.getInteger("waterAmount")),true);
tankCleanWater.fill(new FluidStack(CoreMod.cleanWaterFluid,tagCompound.getInteger("clearWaterAmount")),true);
tankWater.readFromNBT(data);
tankCleanWater.readFromNBT(data);
}
@Override
public void writeToNBT(NBTTagCompound data) {
super.writeToNBT(data);
NBTTagList tagList = new NBTTagList();
NBTTagCompound tagCompound;
for(int i = 0; i < this.inventoryContents.length; i++){
if (getStackInSlot(i)!= null) {
tagCompound = new NBTTagCompound();
tagCompound.setByte("Slot", (byte) i);//Номер слота
tagCompound=getStackInSlot(i).writeToNBT(tagCompound);//Сам предмет
System.out.println("WRITE: "+getStackInSlot(i));
tagList.appendTag(tagCompound);
}
}
tagCompound = new NBTTagCompound();//Тег для дополнительных данных
tagCompound.setBoolean("redPowerEnable", powerRedEnable);
tagCompound.setInteger("waterAmount",tankWater.getFluidAmount());
tagCompound.setInteger("clearWaterAmount",tankCleanWater.getFluidAmount());
tagList.appendTag(tagCompound);
data.setTag("Data", tagList);
if(this.hasCustomInventoryName()) {
data.setString("CleanserInventory", this.inventoryTitle);
}
tankWater.writeToNBT(data);
tankCleanWater.writeToNBT(data);
}
@Override
public ConnectOverride overridePipeConnection(IPipeTile.PipeType pipeType, ForgeDirection forgeDirection) {
if(pipeType!=IPipeTile.PipeType.ITEM) {
return ConnectOverride.CONNECT;
}else {
return ConnectOverride.DISCONNECT;
}
}
//Нужен ли?
@Override
public void markDirty(){
if (this.field_70480_d != null){
for (int i = 0; i < this.field_70480_d.size(); ++i){
((IInventory)this.field_70480_d.get(i)).markDirty();
}
}
}
public boolean isPowerRedEnable() {
return powerRedEnable;
}
public void setPowerRedEnable(boolean powerRedEnable) {
this.powerRedEnable = powerRedEnable;
}
@Override
public int fill(ForgeDirection from, FluidStack resource, boolean doFill) {
worldObj.markBlockForUpdate(xCoord,yCoord,zCoord);
if(resource!= null && resource.getFluid()!= null) {
if(resource.getFluid()==FluidRegistry.WATER) {
return tankWater.fill(resource, doFill);
} else if(resource.getFluid()==CoreMod.cleanWaterFluid){
return tankCleanWater.fill(resource, doFill);
}else
return 0;
}else
return 0;
}
@Override
public FluidStack drain(ForgeDirection from, FluidStack resource, boolean doDrain) {
if(resource==null){
return null;
}
if(tankCleanWater.getFluid()!=null) {
//Слив из аппарата в трубу?
worldObj.markBlockForUpdate(xCoord,yCoord,zCoord);
return tankCleanWater.drain(resource.amount,doDrain);
}else return null;
}
@Override
public FluidStack drain(ForgeDirection from, int maxDrain, boolean doDrain) {
worldObj.markBlockForUpdate(xCoord,yCoord,zCoord);
return tankCleanWater.drain(maxDrain,doDrain);
}
@Override
public boolean canFill(ForgeDirection from, Fluid fluid) {
return fluid==FluidRegistry.WATER;
}
@Override
public boolean canDrain(ForgeDirection from, Fluid fluid) {
return fluid==CoreMod.cleanWaterFluid;
}
@Override
public FluidTankInfo[] getTankInfo(ForgeDirection from) {
return this.tankManager.getTankInfo(from);
}
public void litterFilter(int damage,ItemStack[] inventory){
if(inventory[0].getItem()==ItemLoader.filter) {
if (damage >= 5) {
ItemStack dirtyFilter = new ItemStack(ItemLoader.dirtyFilter);
if (inventory[1]!=null) {
inventory[0]=null;
++inventory[1].stackSize;
}else {
inventory[0]=null;
inventory[1] = dirtyFilter;
}
}
}
}
public boolean checkCondition(){
if(inventoryContents[0] != null &&(inventoryContents[0].getItem().equals(ItemLoader.filter)||
inventoryContents[0].getItem().equals(ItemLoader.charcoalFilter))&&checkSlotDirtyFilters(inventoryContents[1])){
//Если хватает энергии и бак с чистой водой не заполнен
if(getBattery().getEnergyStored()>Constants.CountEnergyForOneCleaning&&getTankCleanWater().getFluidAmount()<getTankCleanWater().getCapacity()) {
return tankWater.getFluid() != null && powerRedEnable;
}else return false;
}else return false;
}
//Проверяем, что слот для загрязненных фильтров не заполнен
private boolean checkSlotDirtyFilters(ItemStack slot) {
return slot == null || slot.stackSize < 64;
}
public void clearWater() {
tempVolumeCleanWater+=Constants.VolumeCWaterAtATime;
if (tempVolumeCleanWater >= Constants.CountClearWaterForFilter) {
damageFilter++;
inventoryContents[0].setItemDamage(damageFilter);
tempVolumeCleanWater = 0;
litterFilter(damageFilter, inventoryContents);
}
tankWater.drain((int)(Constants.CountWaterAbsorbing * rateProduction), true);
tankCleanWater.fill(new FluidStack(CoreMod.cleanWaterFluid, (int)(Constants.VolumeCWaterAtATime * rateProduction)), true);
}
@Override
public Packet getDescriptionPacket() {
worldObj.markBlockForUpdate(xCoord,yCoord,zCoord);
NBTTagCompound nbt = new NBTTagCompound();
nbt.setInteger("countWater",tankWater.getFluidAmount());
writeToNBT(nbt);
return new S35PacketUpdateTileEntity(xCoord, yCoord, zCoord, 0, nbt);
}
@Override
public void onDataPacket(NetworkManager net, S35PacketUpdateTileEntity packet) {
worldObj.markBlockForUpdate(xCoord,yCoord,zCoord);
readFromNBT(packet.func_148857_g());
}
@Override
public boolean canConnectRedstoneEngine(ForgeDirection forgeDirection) {
return true;
}
public Tank getTankWater() {
return tankWater;
}
public Tank getTankCleanWater() {
return tankCleanWater;
}
//Нужны ли эти методы??
public void func_110134_a(IInvBasic p_110134_1_)
{
if (this.field_70480_d == null)
{
this.field_70480_d = new ArrayList();
}
this.field_70480_d.add(p_110134_1_);
}
public void func_110132_b(IInvBasic p_110132_1_)
{
this.field_70480_d.remove(p_110132_1_);
}
public void func_110133_a(String p_110133_1_)
{
this.hasCustomInventoryName = true;
this.inventoryTitle = p_110133_1_;
}
}
Код:
public class CleanMachineContainer extends BuildCraftContainer {
public CleanMachineTile machineTile;
public CleanMachineContainer(InventoryPlayer player, CleanMachineTile tile){
super(Constants.SlotCount);
machineTile=tile;
this.addSlotToContainer(new MachineSlot(tile,0,59,24,new ItemStack[]{new ItemStack(ItemLoader.filter)},1));
this.addSlotToContainer(new MachineSlot(tile,1,59,58,null,64));
int i;
for (i = 0; i < 3; ++i)
{
for (int j = 0; j < 9; ++j)
{
this.addSlotToContainer(new Slot(player, j + i * 9 + 9, 8 + j * 18, 84 + i * 18));
}
}
for (i = 0; i < 9; ++i)
{
this.addSlotToContainer(new Slot(player, i, 8 + i * 18, 142));
}
}
@Override
public boolean canInteractWith(EntityPlayer player) {
return machineTile.isUseableByPlayer(player);
}
Код:
@Mod(modid = MODID)
public class CoreMod {
public static final String MODID = "cleanwatermod";
public static Block cleanMachine;
public static Fluid cleanWaterFluid;
public static Block cleanWaterBlock;
@Mod.Instance(MODID)
public static CoreMod INSTANCE;
@Mod.EventHandler
public void preInit(FMLPreInitializationEvent event)
{
cleanMachine = (new CleanMachine(Material.iron,this));
GameRegistry.registerBlock(cleanMachine, "cleanMachine");
LanguageRegistry.addName(cleanMachine,"Очистное сооружение");
cleanWaterFluid = new Fluid("CleanWaterFluid");
FluidRegistry.registerFluid(cleanWaterFluid);
FluidContainerRegistry.registerFluidContainer(cleanWaterFluid,new ItemStack(ItemLoader.freshWaterBucket),
new ItemStack(Items.bucket));
cleanWaterBlock = new FreshWaterFluid(cleanWaterFluid, Material.water);
GameRegistry.registerBlock(cleanWaterBlock, "cleanWaterBlock");
LanguageRegistry.addName(cleanWaterBlock, "Чистая вода");
GameRegistry.registerTileEntity(CleanMachineTile.class,MODID+":CleanMachineTile");
FreshBucketHandler.INSTANCE.buckets.put(cleanWaterBlock, ItemLoader.freshWaterBucket);
ItemLoader.freshWaterBucket.setTextureName(CoreMod.MODID+":cleanwaterbucket");
}
@Mod.EventHandler
public void Init(FMLInitializationEvent event){
NetworkRegistry.INSTANCE.registerGuiHandler(this,new CleanMachineGuiHandler());
}
@Mod.EventHandler
public void postInit(FMLPostInitializationEvent event){
MinecraftForge.EVENT_BUS.register(FreshBucketHandler.INSTANCE);
}
}
Код:
public class CleanMachine extends BlockContainer implements ITileEntityProvider {
private final Random random = new Random();
private IIcon[] iconSide = new IIcon[6];
private static CoreMod instance;
public CleanMachine(Material material, CoreMod instanceMod)
{
super(material);
setCreativeTab(ThirstMod.thirstCreativeTab);
setBlockName(CoreMod.MODID + "." + "cleanMachine");
setHardness(2.0F);
setResistance(10.0F);
setHarvestLevel("pickaxe",3);
setStepSound(Block.soundTypeMetal);
setBlockTextureName(CoreMod.MODID+":cleanser");
instance = instanceMod;
}
@Override
public IIcon getIcon(int side, int meta) {
return this.iconSide[side];
}
@Override
public void registerBlockIcons(IIconRegister reg) {
for (int a=0;a<6;a++){
iconSide[a]=reg.registerIcon(this.textureName+"/cleanser"+"_"+a);
}
}
@Override
public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player,
int par1, float par2, float par3, float par4) {
if (!player.isSneaking()) {
player.openGui(instance, Constants.GuiIDCleanMachine, world, x, y, z);
return true;
} else {
return false;
}
}
@Override
public Item getItemDropped(int p_149650_1_, Random p_149650_2_, int p_149650_3_) {
return Item.getItemFromBlock(CoreMod.cleanMachine);
}
@Override
public TileEntity createNewTileEntity(World p_149915_1_, int p_149915_2_) {
return new CleanMachineTile("CleanserInventory", true);
}
@Override
public void breakBlock(World world, int x, int y, int z, Block block, int p_149749_6_) {
CleanMachineTile entity = (CleanMachineTile) world.getTileEntity(x, y, z);
if (entity != null) {
ItemStack itemStack = entity.getStackInSlot(0);
if (itemStack != null) {
float f = this.random.nextFloat() * 0.8F + 0.1F;
float f1 = this.random.nextFloat() * 0.8F + 0.1F;
float f2 = this.random.nextFloat() * 0.8F + 0.1F;
while (itemStack.stackSize > 0) {
int j1 = this.random.nextInt(21) + 10;
if (j1 > itemStack.stackSize) {
j1 = itemStack.stackSize;
}
itemStack.stackSize -= j1;
EntityItem entityItem = new EntityItem(world, (double) ((float) x + f), (double) ((float) y + f1),
(double) ((float) z + f2), new ItemStack(itemStack.getItem(), j1, itemStack.getItemDamage()));
if (itemStack.hasTagCompound()) {
entityItem.getEntityItem().setTagCompound((NBTTagCompound) itemStack.getTagCompound().copy());
}
float f3 = 0.05F;
entityItem.motionX = (double) ((float) this.random.nextGaussian() * f3);
entityItem.motionY = (double) ((float) this.random.nextGaussian() * f3 + 0.2F);
entityItem.motionZ = (double) ((float) this.random.nextGaussian() * f3);
world.spawnEntityInWorld(entityItem);
}
}
world.func_147453_f(x, y, z, block);
}
}
@SideOnly(Side.CLIENT)
@Override
public void onNeighborBlockChange(World world, int x, int y, int z, Block block){
if(!world.isRemote) {
CleanMachineTile tile=(CleanMachineTile)world.getTileEntity(x,y,z);
if (tile.isPowerRedEnable() && !world.isBlockIndirectlyGettingPowered(x, y, z))
{
tile.setPowerRedEnable(false);
}
else if (!tile.isPowerRedEnable() && world.isBlockIndirectlyGettingPowered(x, y, z))
{
tile.setPowerRedEnable(true);
}
}
}
}