Posted September 29, 20168 yr Hi, Im learning modding at the moment and im at a point where i try to create a solar panel creating the new "forge energy" Overall everything works like it should, but i have a few questions and problems which i want to ask :=) But first the code i use at the moment: First the TileEntityEnergyBase class. This is my base class for all my TileEntities using Energy. It extends TileEntity and implements IEnergyStorage. It also exposes the Energy Capability and writes and reads the energy value to/from NBT. public class TileEntityEnergyBase extends TileEntity implements IEnergyStorage { protected int energy; protected int capacity; protected int maxReceive; protected int maxExtract; public TileEntityEnergyBase() { } public TileEntityEnergyBase(int capacity) { this(capacity, capacity, capacity); } public TileEntityEnergyBase(int capacity, int maxTransfer) { this(capacity, maxTransfer, maxTransfer); } public TileEntityEnergyBase(int capacity, int maxReceive, int maxExtract) { this.capacity = capacity; this.maxReceive = maxReceive; this.maxExtract = maxExtract; } //------Start IEnergyStorage-----// @Override public int receiveEnergy(int maxReceive, boolean simulate) { if (!canReceive()) return 0; int energyReceived = Math.min(capacity - energy, Math.min(this.maxReceive, maxReceive)); if (!simulate) energy += energyReceived; return energyReceived; } @Override public int extractEnergy(int maxExtract, boolean simulate) { if (!canExtract()) return 0; int energyExtracted = Math.min(energy, Math.min(this.maxExtract, maxExtract)); if (!simulate) energy -= energyExtracted; return energyExtracted; } @Override public int getEnergyStored() { return energy; } @Override public int getMaxEnergyStored() { return capacity; } @Override public boolean canExtract() { return this.maxExtract > 0; } @Override public boolean canReceive() { return this.maxReceive > 0; } //------End IEnergyStorage-----// //Energy Capability Stuff @Override public boolean hasCapability(Capability<?> capability, EnumFacing facing) { if(capability == CapabilityEnergy.ENERGY) { return true; } return super.hasCapability(capability, facing); } @Override public <T> T getCapability(Capability<T> capability, EnumFacing facing) { if(capability == CapabilityEnergy.ENERGY) { return (T) this; } return super.getCapability(capability, facing); } //Read and Write Energy from/to NBT (on world load/world unload --> persistent data) @Override public void readFromNBT(NBTTagCompound compound) { super.readFromNBT(compound); if(compound.hasKey("energy")) { this.energy = compound.getInteger("energy"); } } @Override public NBTTagCompound writeToNBT(NBTTagCompound compound) { super.writeToNBT(compound); compound.setInteger("energy", energy); return compound; } } Next up is my TileEntitySolarPanel class. (Block Class/ Jsons/ and so on all working): It extends my TileEntityEnergyBase class above and implements ITickable for update() Note, the update() Method just gives it 2 Energy per Tick when the capacity is not reached and tries to give energy to TEs on the bottom 10 e/t. public class TileEntitySolarPanel extends TileEntityEnergyBase implements ITickable { public TileEntitySolarPanel() { } public TileEntitySolarPanel(int capacity, int maxReceive, int maxExtract) { super(capacity, maxReceive, maxExtract); } //------Start ITickable-----// @Override public void update() { System.out.println(energy); if(energy < capacity) { energy += 2; } if(!(energy < 10)) { TileEntity tile = worldObj.getTileEntity(getPos().down()); if(tile != null && tile.hasCapability(CapabilityEnergy.ENERGY, EnumFacing.UP)) { tile.getCapability(CapabilityEnergy.ENERGY, EnumFacing.UP).receiveEnergy(10, false); energy -= 10; } } } //------End ITickable-----// } The TileEntitySolarPanel gets created by the BlockSolarPanel with the following parameters: //----START ITileEntityProvider---// @Override public TileEntity createNewTileEntity(World worldIn, int meta) { return new TileEntitySolarPanel(1000, 0, 10); } //----END ITileEntityProvider---// So on to my questions: 1. My TileEntities get created with parameters for capacity and transfer, but it seems like i always need 1 constructor without parameters so the TE can be restored on world load, is this correct? If so, do i have to store the capacity and transfer ints also in NBT and not only the current energy? 2. Syncing. Everything works fine when i sysout the energy. When i close and reload the world it seems like there are 2 TEs for the Block, 1 with the old energy value and 1 new one startig from 0 again. syout looks like this: (164 old value) 164 0 2 4 6 8 10 12 14 16 164 164 164 18 20 164 22 24 164 164 26 164 28 164 30 164 32 164 I think i need to sync something between client and server here? 3. How to check if it is day? My solar panel should produce 2 e/t while its daytime, but the method worldObj.isDaytime() returns: false true false true false true while it is night. How should i check for day time? Thats it for now, thanks in advance
September 29, 20168 yr The whole point of the capability system is that you don't implement interfaces on your TileEntity / Entity / Item . Instead, you store one or more instances of the interface ( IEnergyStorage ) and override the ICapabilityProvider methods to return them. EnergyStorage is the default implementation of IEnergyStorage , use or extend this unless you need a completely different implementation. You only need to sync data to the client if it's required for rendering. All game logic is controlled by the server. World#isDaytime will only return a valid result on the server because the World#skylightSubtracted field that it uses is only updated from WorldServer . Whenever you print something to the log, it should tell you whether it was done from the client or server thread. Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.
September 29, 20168 yr Whenever you print something to the log, it should tell you whether it was done from the client or server thread. Unless you print out a pure number. System.out.println(someInt) will print "4" while System.out.println(someInt + " energy") will print "[time] [client] [package and class name:line#]: 4 energy" Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable. If you think this is the case, JUST REPORT ME. Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice. Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked. DO NOT PM ME WITH PROBLEMS. No help will be given.
September 29, 20168 yr Author The whole point of the capability system is that you don't implement interfaces on your TileEntity / Entity / Item . Instead, you store one or more instances of the interface ( IEnergyStorage ) and override the ICapabilityProvider methods to return them. EnergyStorage is the default implementation of IEnergyStorage , use or extend this unless you need a completely different implementation. ah, i completely missed this while thinking about it. So i just create a new EnergyStorage object(i want to use teh default implementation) save it in the TileEntity and return this field at getCapability right? You only need to sync data to the client if it's required for rendering. All game logic is controlled by the server. I need to figure out why the TE has 2 different values for energy after world loading then... World#isDaytime will only return a valid result on the server because the World#skylightSubtracted field that it uses is only updated from WorldServer . Whenever you print something to the log, it should tell you whether it was done from the client or server thread. That makes sense, thanks!
September 29, 20168 yr The whole point of the capability system is that you don't implement interfaces on your TileEntity / Entity / Item . Instead, you store one or more instances of the interface ( IEnergyStorage ) and override the ICapabilityProvider methods to return them. EnergyStorage is the default implementation of IEnergyStorage , use or extend this unless you need a completely different implementation. ah, i completely missed this while thinking about it. So i just create a new EnergyStorage object(i want to use teh default implementation) save it in the TileEntity and return this field at getCapability right? Yes. You only need to sync data to the client if it's required for rendering. All game logic is controlled by the server. I need to figure out why the TE has 2 different values for energy after world loading then... Is one on the client and one on the server? Only the server reads the TileEntity from NBT. Whenever you print something to the log, it should tell you whether it was done from the client or server thread. Unless you print out a pure number. System.out.println(someInt) will print "4" while System.out.println(someInt + " energy") will print "[time] [client] [package and class name:line#]: 4 energy" Ah, I wasn't aware of that. I always use a log4j Logger when writing something to the console/log, which I would also recommend the OP does. Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.
September 29, 20168 yr Author Is one on the client and one on the server? Only the server reads the TileEntity from NBT. Im relatively new to TEs so how can a TE be on the client and how can i prevent it? Ah, I wasn't aware of that. I always use a log4j Logger when writing something to the console/log, which I would also recommend the OP does. Well for just testing stuff a sysout + strg + enter is the easiest or what am i missing?
September 29, 20168 yr Author Another question: When i store an EnergyStorage object i can only add Energy via storage#receiveEnergy But how do i implement a way the TE produces Energy but cant receive energy from "outside", cables for example?
September 29, 20168 yr Ah, I wasn't aware of that. I always use a log4j Logger when writing something to the console/log, which I would also recommend the OP does. I often forget as I'm accustomed to using basic trace statements for debugging. I have converted over to using the logger, generally, though. Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable. If you think this is the case, JUST REPORT ME. Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice. Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked. DO NOT PM ME WITH PROBLEMS. No help will be given.
September 29, 20168 yr Is one on the client and one on the server? Only the server reads the TileEntity from NBT. Im relatively new to TEs so how can a TE be on the client and how can i prevent it? The server and client both have their own instance of the TileEntity , this is normal and not something to be prevented. The client won't have any of the data that you write to NBT unless you sync it. The client doesn't need to have this data unless it's required for rendering purposes. Ah, I wasn't aware of that. I always use a log4j Logger when writing something to the console/log, which I would also recommend the OP does. Well for just testing stuff a sysout + strg + enter is the easiest or what am i missing? You can get a Logger named with your mod ID by calling FMLPreInitializationEvent#getModLog . You should store this in a field somewhere and use it whenever you want to write something to the log. You can also use your IDE's debugger to pause execution at certain points and inspect the values of fields and local variables. Another question: When i store an EnergyStorage object i can only add Energy via storage#receiveEnergy But how do i implement a way the TE produces Energy but cant receive energy from "outside", cables for example? You'll probably want to create a class that extends EnergyStorage , overrides EnergyStorage#canReceive to return false and has a copy of the EnergyStorage#receiveEnergy method with a different name and/or signature (so it doesn't implement the interface method) that ignores EnergyStorage#canReceive . External cables will use the interface method, your internal code can use the method you created. Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.
September 29, 20168 yr Author The server and client both have their own instance of the TileEntity , this is normal and not something to be prevented. The client won't have any of the data that you write to NBT unless you sync it. The client doesn't need to have this data unless it's required for rendering purposes. SO the client version of the TE will always start the values again from 0, becuase only the server variant loads the data from nbt. And it is no problem that there are 2 different values as long i dont do client side things with the value?
September 29, 20168 yr The server and client both have their own instance of the TileEntity , this is normal and not something to be prevented. The client won't have any of the data that you write to NBT unless you sync it. The client doesn't need to have this data unless it's required for rendering purposes. SO the client version of the TE will always start the values again from 0, becuase only the server variant loads the data from nbt. And it is no problem that there are 2 different values as long i dont do client side things with the value? Yes. Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.
September 29, 20168 yr Author Thank you very much, that explains that. I will look into snyching after i implemented my own EnergyStorage to draw the actual energy in teh gui
September 29, 20168 yr Author Can someone link me to examples/tutorials for Server/Client TE syncing? I havent done that at all til now and i guess i need it because i want to add an energy bar to the gui and the gui is client stuff
September 29, 20168 yr Can someone link me to examples/tutorials for Server/Client TE syncing? I havent done that at all til now and i guess i need it because i want to add an energy bar to the gui and the gui is client stuff For syncing values used in a GUI, you should cache any synced values in the Container and override Container#detectAndSendChanges to check the current values, send them to the client if they're different to the cached values and then cache the current values. This can be done using vanilla packets or your own custom packets. Use IContainerListener#sendProgressBarUpdate to send a pair of int s (e.g. the ID of the energy storage and the current energy in it) to the client-side Container , which will then have Container#updateProgressBar called with them as arguments. Look at ContainerFurnace for an example of this. For syncing values used to render the block, you need to send them in the TileEntity 's update tag and packet. This document explains these in more detail. Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.