Hello there.
So I've been working on this 'TE base' class that allows for 'easier' creation of TEs.. However, I ran into some issue with the TE's storage tank / energy not updating until I re-logged. (Also for some reason dissipating liquid next to it seems to update it, but no other updates.). Also, another one of my TEs share each others storage, which is very odd.
I've been looking for a fix for a few hours now.. and have not came upon one, so I decided to post it here:
Here is the base class:
public abstract class TileEntityBase extends TileEntity implements ITickable{
public final String name;
public boolean isRedstonePowered;
public boolean isPulseMode;
public boolean stopFromDropping;
protected int ticksElapsed;
protected TileEntity[] tilesAround = new TileEntity[6];
protected boolean hasSavedDataOnChangeOrWorldStart;
public TileEntityBase(String name){
this.name = name;
}
public static void init(){
ModUtil.LOGGER.info("Registering TileEntities...");
register(TileEntityMobSoulEater.class);
register(TileEntityItemTeleporter.class);
register(TileEntityItemLimiter.class);
register(TileEntityMobLimiter.class);
register(TileEntityBiomeizer.class);
register(TileEntityHomeostaticGenerator.class);
}
private static void register(Class<? extends TileEntityBase> tileClass){
try{
String name = ModUtil.MOD_ID+":"+tileClass.newInstance().name;
GameRegistry.registerTileEntity(tileClass, name);
}
catch(Exception e){
ModUtil.LOGGER.fatal("Registering a TileEntity failed!", e);
}
}
@Override
public final NBTTagCompound writeToNBT(NBTTagCompound compound){
this.writeSyncableNBT(compound, NBTType.SAVE_TILE);
return compound;
}
@Override
public final void readFromNBT(NBTTagCompound compound){
this.readSyncableNBT(compound, NBTType.SAVE_TILE);
}
@Override
public final SPacketUpdateTileEntity getUpdatePacket(){
NBTTagCompound compound = new NBTTagCompound();
this.writeSyncableNBT(compound, NBTType.SYNC);
return new SPacketUpdateTileEntity(this.pos, -1, compound);
}
@Override
public final void onDataPacket(NetworkManager net, SPacketUpdateTileEntity pkt){
this.readSyncableNBT(pkt.getNbtCompound(), NBTType.SYNC);
}
@Override
public final NBTTagCompound getUpdateTag(){
NBTTagCompound compound = new NBTTagCompound();
this.writeSyncableNBT(compound, NBTType.SYNC);
return compound;
}
@Override
public final void handleUpdateTag(NBTTagCompound compound){
this.readSyncableNBT(compound, NBTType.SYNC);
}
public final void sendUpdate(){
if(this.world != null && !this.world.isRemote){
NBTTagCompound compound = new NBTTagCompound();
this.writeSyncableNBT(compound, NBTType.SYNC);
NBTTagCompound data = new NBTTagCompound();
data.setTag("Data", compound);
data.setInteger("X", this.pos.getX());
data.setInteger("Y", this.pos.getY());
data.setInteger("Z", this.pos.getZ());
PacketHandler.theNetwork.sendToAllAround(new PacketServerToClient(data, PacketHandler.TILE_ENTITY_HANDLER), new NetworkRegistry.TargetPoint(this.world.provider.getDimension(), this.getPos().getX(), this.getPos().getY(), this.getPos().getZ(), 64));
}
}
public void writeSyncableNBT(NBTTagCompound compound, NBTType type){
if(type != NBTType.SAVE_BLOCK){
super.writeToNBT(compound);
}
if(type == NBTType.SAVE_TILE){
compound.setBoolean("Redstone", this.isRedstonePowered);
compound.setInteger("TicksElapsed", this.ticksElapsed);
compound.setBoolean("StopDrop", this.stopFromDropping);
}
if(this.isRedstoneToggle() && (type != NBTType.SAVE_BLOCK || this.isPulseMode)){
compound.setBoolean("IsPulseMode", this.isPulseMode);
}
}
public void readSyncableNBT(NBTTagCompound compound, NBTType type){
if(type != NBTType.SAVE_BLOCK){
super.readFromNBT(compound);
}
if(type == NBTType.SAVE_TILE){
this.isRedstonePowered = compound.getBoolean("Redstone");
this.ticksElapsed = compound.getInteger("TicksElapsed");
this.stopFromDropping = compound.getBoolean("StopDrop");
}
if(this.isRedstoneToggle()){
this.isPulseMode = compound.getBoolean("IsPulseMode");
}
}
@Override
public boolean shouldRefresh(World world, BlockPos pos, IBlockState oldState, IBlockState newState){
return !oldState.getBlock().isAssociatedBlock(newState.getBlock());
}
public String getDisplayedName(){
return StringUtil.localize("container."+ModUtil.MOD_ID+"."+this.name+".name");
}
@Override
public ITextComponent getDisplayName(){
return new TextComponentString(this.getDisplayedName());
}
@Override
public final void update(){
this.updateEntity();
}
public int getComparatorStrength(){
return 0;
}
public void updateEntity(){
this.ticksElapsed++;
if(!this.world.isRemote){
if(this instanceof ISharingEnergyProvider){
ISharingEnergyProvider provider = (ISharingEnergyProvider)this;
if(provider.doesShareEnergy()){
int total = provider.getEnergyToSplitShare();
if(total > 0){
EnumFacing[] sides = provider.getEnergyShareSides();
int amount = total/sides.length;
if(amount <= 0){
amount = total;
}
for(EnumFacing side : sides){
TileEntity tile = this.tilesAround[side.ordinal()];
if(tile != null && provider.canShareTo(tile)){
WorldUtil.doEnergyInteraction(this, tile, side, amount);
}
}
}
}
}
if(this instanceof ISharingFluidProvider){
ISharingFluidProvider handler = (ISharingFluidProvider)this;
if(handler.doesShareFluid()){
int total = handler.getMaxFluidAmountToSplitShare();
if(total > 0){
EnumFacing[] sides = handler.getFluidShareSides();
int amount = total/sides.length;
if(amount <= 0){
amount = total;
}
for(EnumFacing side : sides){
TileEntity tile = this.tilesAround[side.ordinal()];
if(tile != null){
WorldUtil.doFluidInteraction(this, tile, side, amount);
}
}
}
}
}
if(!this.hasSavedDataOnChangeOrWorldStart){
if(this.shouldSaveDataOnChangeOrWorldStart()){
this.saveDataOnChangeOrWorldStart();
}
this.hasSavedDataOnChangeOrWorldStart = true;
}
}
}
public void saveDataOnChangeOrWorldStart(){
for(EnumFacing side : EnumFacing.values()){
this.tilesAround[side.ordinal()] = this.world.getTileEntity(this.pos.offset(side));
}
}
public boolean shouldSaveDataOnChangeOrWorldStart(){
return this instanceof ISharingEnergyProvider || this instanceof ISharingFluidProvider;
}
public void setRedstonePowered(boolean powered){
this.isRedstonePowered = powered;
this.markDirty();
}
public boolean canPlayerUse(EntityPlayer player){
return player.getDistanceSq(this.getPos().getX()+0.5D, this.pos.getY()+0.5D, this.pos.getZ()+0.5D) <= 64 && !this.isInvalid() && this.world.getTileEntity(this.pos) == this;
}
protected boolean sendUpdateWithInterval(){
if(this.ticksElapsed%ConfigIntValues.TILE_ENTITY_UPDATE_INTERVAL.getValue() == 0){
this.sendUpdate();
return true;
}
else{
return false;
}
}
@Override
public boolean hasCapability(Capability<?> capability, EnumFacing facing){
return this.getCapability(capability, facing) != null;
}
@Override
public <T> T getCapability(Capability<T> capability, EnumFacing facing){
if(capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY){
IItemHandler handler = this.getItemHandler(facing);
if(handler != null){
return (T)handler;
}
}
else if(capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY){
IFluidHandler tank = this.getFluidHandler(facing);
if(tank != null){
return (T)tank;
}
}
else if(capability == CapabilityEnergy.ENERGY){
IEnergyStorage storage = this.getEnergyStorage(facing);
if(storage != null){
return (T)storage;
}
}
return super.getCapability(capability, facing);
}
public IFluidHandler getFluidHandler(EnumFacing facing){
return null;
}
public IEnergyStorage getEnergyStorage(EnumFacing facing){
return null;
}
public IItemHandler getItemHandler(EnumFacing facing){
return null;
}
public boolean isRedstoneToggle(){
return false;
}
public void activateOnPulse(){
}
public boolean respondsToPulses(){
return this.isRedstoneToggle() && this.isPulseMode;
}
public enum NBTType{
SAVE_TILE,
SYNC,
SAVE_BLOCK
}
}
and here is the TE that doesnt update properly:
public class TileEntityHomeostaticGenerator extends TileEntityBase implements ISharingEnergyProvider, ISharingFluidProvider {
public final CustomEnergyStorage storage = new CustomEnergyStorage(150000, 0, 120);
public final FluidTank tankLava = new FluidTank(8*Util.BUCKET);
public final FluidTank tankWater = new FluidTank(8*Util.BUCKET);
private final FluidHandlerFluidMap handlerMap;
public final int DRAIN_PER_TICK = 5;
private static final int BASE_PRODUCE = 30;
private int lastEnergy;
private int lastLavaTank;
private int lastWaterTank;
public TileEntityHomeostaticGenerator() {
super("homeostaticGenerator");
this.handlerMap = new FluidHandlerFluidMap();
this.handlerMap.addHandler(FluidRegistry.WATER, this.tankWater);
this.handlerMap.addHandler(FluidRegistry.LAVA, this.tankLava);
}
@Override
public void writeSyncableNBT(NBTTagCompound compound, NBTType type){
this.storage.writeToNBT(compound);
this.tankWater.writeToNBT(compound);
this.tankLava.writeToNBT(compound);
super.writeSyncableNBT(compound, type);
}
@Override
public void readSyncableNBT(NBTTagCompound compound, NBTType type){
this.storage.readFromNBT(compound);
this.tankWater.readFromNBT(compound);
this.tankLava.readFromNBT(compound);
super.readSyncableNBT(compound, type);
}
@Override
public void updateEntity() {
super.updateEntity();
if(!world.isRemote) {
boolean canProcess;
if(tankWater.getFluidAmount() != 0 && tankLava.getFluidAmount() != 0) {
canProcess=true;
}else {
canProcess=false;
}
if(canProcess) {
this.tankLava.drainInternal(new FluidStack(FluidRegistry.LAVA, DRAIN_PER_TICK), true);
this.tankWater.drainInternal(new FluidStack(FluidRegistry.WATER, DRAIN_PER_TICK), true);
this.storage.receiveEnergyInternal(BASE_PRODUCE, false);
}
if(storage.getEnergyStored() != this.lastEnergy || tankWater.getFluidAmount() != this.lastWaterTank || tankLava.getFluidAmount() != this.lastLavaTank && this.sendUpdateWithInterval()) {
this.lastEnergy = storage.getEnergyStored();
this.lastLavaTank = tankLava.getFluidAmount();
this.lastWaterTank = tankWater.getFluidAmount();
}
}
}
@Override
public int getEnergyToSplitShare(){
return this.storage.getEnergyStored();
}
@Override
public boolean doesShareEnergy(){
return true;
}
@Override
public EnumFacing[] getEnergyShareSides(){
return EnumFacing.values();
}
@Override
public boolean canShareTo(TileEntity tile){
return true;
}
@Override
public IEnergyStorage getEnergyStorage(EnumFacing facing){
return this.storage;
}
@Override
public IFluidHandler getFluidHandler(EnumFacing facing){
return handlerMap;
}
@Override
public int getMaxFluidAmountToSplitShare(){
return 0;
}
@Override
public boolean doesShareFluid(){
return false;
}
@Override
public EnumFacing[] getFluidShareSides(){
return null;
}
}
Here is the TE that 'saves' its energy among all of itself:
public class TileEntityBiomeizer extends TileEntityBase implements IEnergyDisplay, ISharingEnergyProvider
{
public static final int UKNOWN_BIOME_AVERAGE = 10;
public static CustomEnergyStorage storage = new CustomEnergyStorage(250000, 0, 5000);
public TileEntityBiomeizer() {
super("biomeizer");
}
@Override
public void updateEntity() {
super.updateEntity();
if(!world.isRemote) {
this.storage.receiveEnergyInternal(this.getEnergyFromBiome(this.getLocalBiome()), false);
}
}
public int getEnergyFromBiome(Biome biome) {
if(BiomeUtility.isVaildBiome(biome)) {
float temp = biome.getTemperature();
boolean canRain = biome.canRain();
float heightVariation = biome.getHeightVariation();
boolean isHumid = biome.isHighHumidity();
return energyAmount(temp,canRain,heightVariation,isHumid);
}
return 0;
}
public int energyAmount(float temp, boolean canRain, float heightVar, boolean isHighHumid) {
int energyToReturn = 0;
if(1.95-temp >= 0) {
energyToReturn+=2;
}else {
energyToReturn+=1;
}
if(canRain) {
energyToReturn+=2;
}
if(.4-heightVar >= 0) {
energyToReturn+=5;
}else {
energyToReturn+=2;
}
if(isHighHumid) {
energyToReturn+=5;
}
return energyToReturn;
}
public Biome getLocalBiome() {
return this.world.getBiome(this.getPos());
}
@Override
public int getEnergyToSplitShare(){
return this.storage.getEnergyStored();
}
@Override
public boolean doesShareEnergy(){
return true;
}
@Override
public EnumFacing[] getEnergyShareSides(){
return EnumFacing.values();
}
@Override
public boolean canShareTo(TileEntity tile){
return true;
}
@Override
public CustomEnergyStorage getEnergyStorage(){
return this.storage;
}
@Override
public boolean needsHoldShift() {
return false;
}
}
And the 'CustomEnergyStorage' class:
import net.minecraft.nbt.NBTTagCompound;
import net.minecraftforge.energy.EnergyStorage;
public class CustomEnergyStorage extends EnergyStorage{
public CustomEnergyStorage(int capacity, int maxReceive, int maxExtract){
super(capacity, maxReceive, maxExtract);
}
public int extractEnergyInternal(int maxExtract, boolean simulate){
int before = this.maxExtract;
this.maxExtract = Integer.MAX_VALUE;
int toReturn = this.extractEnergy(maxExtract, simulate);
this.maxExtract = before;
return toReturn;
}
public int receiveEnergyInternal(int maxReceive, boolean simulate){
int before = this.maxReceive;
this.maxReceive = Integer.MAX_VALUE;
int toReturn = this.receiveEnergy(maxReceive, simulate);
this.maxReceive = before;
return toReturn;
}
@Override
public int receiveEnergy(int maxReceive, boolean simulate){
if(!this.canReceive()){
return 0;
}
int energy = this.getEnergyStored();
int energyReceived = Math.min(this.capacity-energy, Math.min(this.maxReceive, maxReceive));
if(!simulate){
this.setEnergyStored(energy+energyReceived);
}
return energyReceived;
}
@Override
public int extractEnergy(int maxExtract, boolean simulate){
if(!this.canExtract()){
return 0;
}
int energy = this.getEnergyStored();
int energyExtracted = Math.min(energy, Math.min(this.maxExtract, maxExtract));
if(!simulate){
this.setEnergyStored(energy-energyExtracted);
}
return energyExtracted;
}
public void readFromNBT(NBTTagCompound compound){
this.setEnergyStored(compound.getInteger("Energy"));
}
public void writeToNBT(NBTTagCompound compound){
compound.setInteger("Energy", this.getEnergyStored());
}
public void setEnergyStored(int energy){
this.energy = energy;
}
}
Also, I do indeed send my packets correctly.
Thanks for your time.