Jump to content

[SOLVED] [1.7.10] Chunkloading Block


Pancake

Recommended Posts

I know, this problem has come up plenty of times on this forum, but I've read almost all of the threads about it here and on external forums, and I've looked into several source codes from other mods. Nothing helped me to make implement it into my own mod.

 

The problem is this: I'm trying to access a TileEntity somewhere in the world. That TileEntity CAN be far away, outside of player-loaded chunks. So I've been thinking, and my only solution is to make the block a chunkloader.

 

All the other threads about this subject I've read either tell me to:

- go check source code for ChickenChunks (which is too complicated to be able to ... the elements I need for a simple chunkloader)

OR

- try to explain the code, giving single lines which aren't helping because I have no idea where to put them. (In the mod main class? in the block class? in the TileEntity? A new class?)

 

I know Java, so reading/writing code isn't the problem. It's the fact that I don't have a complete overview of whatever Forge is doing in the background that messes me up.

 

So what I'd like is a person who can give me an overview of what classes I need to implement/extend in what classes, and what methods should be implemented/overriden and what should be in them to be able to keep a chunk loaded while the game is running. Ofcourse, what needs to be in the methods can be in pseudo-code, I'll understand.

 

Thanks in advance,

Pancake :3

Link to comment
Share on other sites

~ Decided to bump, since i tried more stuff, and I think i'm getting close... for the fourth time. ;) ~

 

All of the thigns below here are graciously copied and distilled from the code for a buildcraft quarry.

 

I added the following lines of code to my constructor of my TileEntity (TileEntityMainframeUnit) which extends TileEntity and implements LoadingCallback

 

ticket = ForgeChunkManager.requestTicket(Singularity.instance,worldObj,Type.NORMAL);
ticket.getModData().setInteger("locationX",xCoord);
ticket.getModData().setInteger("locationY",yCoord);
ticket.getModData().setInteger("locationZ",zCoord);
ForgeChunkManager.forceChunk(ticket,new ChunkCoordIntPair(xCoord>>4,zCoord>>4));
ForgeChunkManager.setForcedChunkLoadingCallback(Singularity.instance,this);

 

ticket is a private field.

 

I have overriden the following method

 

@Override
public void ticketsLoaded(List<Ticket> tickets, World world) {
for(Ticket t : tickets){
	int locationX = ticket.getModData().getInteger("locationX");
	int locationY = ticket.getModData().getInteger("locationY");
	int locationZ = ticket.getModData().getInteger("locationZ");
	TileEntityMainframeCore entity = (TileEntityMainframeCore)world.getTileEntity(locationX, locationY, locationZ);
	entity.forceChunkLoading(ticket);
}
}

 

where the method forceChunkLoading is the following:

 

public void forceChunkLoading(Ticket ticket) {
if (this.ticket == null) {
	this.ticket = ticket;
}
ChunkCoordIntPair chunk = new ChunkCoordIntPair(xCoord >> 4, zCoord >> 4);
ForgeChunkManager.forceChunk(ticket,chunk);
}

 

i'm getting the following error upon placing a BlockMainFrame(which has a TileEntityMainFrame):

 

The mod Singularity has attempted to request a ticket without a listener in place

 

Doesn't refferencing my mod instance take care of the listeners? I must be confused...

 

Thanks in advance,

Pancake.

Link to comment
Share on other sites

Well, after watching at the source code for the buildcraft quarry block and the corresponding tile entity, I fixed my errors.

I requested a ticket before my mod was registered, and I registered my mod everytime a new TileEntity was created.

I created a new class which implements OrderedLoadingCallback, and I implemented the two ticketsLoaded methods.

 

 

public class MainframeChunkloadCallback implements OrderedLoadingCallback{

@Override
public void ticketsLoaded(List<Ticket> tickets, World world) {
	for (Ticket ticket : tickets) {
		int coreX = ticket.getModData().getInteger("coreX");
		int coreY = ticket.getModData().getInteger("coreY");
		int coreZ = ticket.getModData().getInteger("coreZ");
		TileEntityMainframeCore entity = (TileEntityMainframeCore) world.getTileEntity(coreX, coreY, coreZ);
		entity.forceChunkLoading(ticket);
	}
}

@Override
public List<Ticket> ticketsLoaded(List<Ticket> tickets, World world, int maxTicketCount) {
	List<Ticket> validTickets = new ArrayList();
	for (Ticket ticket : tickets) {
		int coreX = ticket.getModData().getInteger("coreX");
		int coreY = ticket.getModData().getInteger("coreY");
		int coreZ = ticket.getModData().getInteger("coreZ");
		Block block = world.getBlock(coreX, coreY, coreZ);
		if (block == Singularity.BlockMainframeCore)
			validTickets.add(ticket);
	}
	return validTickets;
}
}

 

 

I added the following code to my main mod class.

 

 

@EventHandler
    public void postInit(FMLInitializationEvent event)
    {
    	ForgeChunkManager.setForcedChunkLoadingCallback(instance, new MainframeChunkloadCallback());
    }

 

 

And this is now my TileEntity. (I left out the other methods which don't have to do anything with this solution)

 

 

private int[] location;
private HashSet<int[]> moduleLocations;
private Ticket ticket;
private boolean triedToAssignTicket;

public TileEntityMainframeCore(){
location = null;
moduleLocations = new HashSet();
triedToAssignTicket = false;
}

@Override
public void invalidate() {
ForgeChunkManager.releaseTicket(ticket);
super.invalidate();
}

public void forceChunkLoading(Ticket ticket) {
if (this.ticket == null)
	this.ticket = ticket;
ChunkCoordIntPair chunk = new ChunkCoordIntPair(xCoord >> 4, zCoord >> 4);
ForgeChunkManager.forceChunk(ticket,chunk);
}

@Override
public void updateEntity() {
super.updateEntity();
if(!triedToAssignTicket && !worldObj.isRemote){
	triedToAssignTicket = true;
	System.out.println("huehuehue");
	if(ticket==null)
		ticket = ForgeChunkManager.requestTicket(Singularity.instance,worldObj,Type.NORMAL);
	if(ticket==null)
		System.out.println("Ticket could not be reserved for MainframeCore @ ("+xCoord+","+yCoord+","+zCoord+")");
	else {
		ticket.getModData().setInteger("coreX",xCoord);
		ticket.getModData().setInteger("coreY",yCoord);
		ticket.getModData().setInteger("coreZ",zCoord);
		ForgeChunkManager.forceChunk(ticket,new ChunkCoordIntPair(xCoord>>4,zCoord>>4));
	}
}
}

 

 

Now my chunk stays loaded on the serverside. I'm pretty happy with this solution, and i'm glad I could share it with those that don't have the patience I've had for the last two days.

 

I had to request a ticket in the updateEntity method, because the worldObj is still null when constructing the TileEntity object, and you need it to request a ticket.

 

EDIT: fixed 2 mistakes in my code. Thanks Draco. :3

Link to comment
Share on other sites

I noticed something:

 

			ticket.getModData().setInteger("coreX",xCoord);//set X to X
		ticket.getModData().setInteger("coreX",yCoord);//set X to Y
		ticket.getModData().setInteger("coreX",zCoord);//set X to Z

 

Uh?

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.

Link to comment
Share on other sites

I noticed something:

 

			ticket.getModData().setInteger("coreX",xCoord);//set X to X
		ticket.getModData().setInteger("coreX",yCoord);//set X to Y
		ticket.getModData().setInteger("coreX",zCoord);//set X to Z

 

Uh?

 

Buildcraft did that in it's code, because it requests those integers in the class  that implements LoadingCallback, to get the TileEntity, upon which it calls the function forceChunkLoading(). It stores the ticket in the TileEntity, so it doesn't make a new one.

 

Check my code in the TileEntity in the method updateEntity to see why I need the ticket in the TileEntity. I couldn't get the worldObj in the constructor, so I had to get it somewhere else. The first time the method runs, the game hasn't tried to make a ticket yet, so it tries. if it isn't null, then it means it was already loaded upon entering the world, and there's no need for it to make a new one. See why I need the ticket in the TileEntity? :3

 

If there's an easier way, do tell me, because I figured this all out from someone else's code, I might be doing alot of unnecessary steps.

 

EDITEDITEDIT: Omg. I just saw my mistake. I copied something, and didn't bother to change the X to Y and Z... My bad! :D

Link to comment
Share on other sites

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.