Jump to content

Recommended Posts

Posted

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 :)

Posted

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.

Posted

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.

Posted

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!

Posted

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.

Posted

 

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?

Posted

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?

Posted

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.

Posted

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.

Posted

 

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?

Posted

 

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.

Posted

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 :)

Posted

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.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.