Jump to content

How can I get the location of the master block in a multiblock? [SOLVED]


TheEpicTekkit

Recommended Posts

Im really sorry to bother you again for like the fourth day in a row, but this has to be the strangest thing so far.

 

Im still working on my distillation chamber multiblock structure, and in testing if I can return the master block of the whole structure, the one that contains all the inventoris contents, I put in the onBlockActivated method this:

        @Override
public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int side, float hitX, float hitY, float hitZ) {
	TileEntityDistillationChamberGag tileEntity = (TileEntityDistillationChamberGag)world.getTileEntity(x, y, z);

	System.out.println("X: " + x + ", Y: " + y + ", Z: " + z + ".");

	//TileEntityDistillationChamberGag tileEntity1 = (TileEntityDistillationChamberGag)world.getTileEntity(x, y, z);

	if (!world.isRemote) {
		System.out.println("Master located at: X " + tileEntity.masterPosX + ", Y: " + tileEntity.masterPosY + ", Z: " + tileEntity.masterPosZ);
		return true;
	}
	return false;
}

Now the first system.out.println is the coordinates of the block you are clicking on, and the second one after the if (!world.isRemote) should return the coordinates of the master block. But instead it crashes, and in the crash report it says:

java.lang.ClassCastException: net.theepictekkit.generator.common.tileentity.TileEntityDistillationChamberFrame cannot be cast to net.theepictekkit.generator.common.tileentity.TileEntityDistillationChamberGag
at net.theepictekkit.generator.common.blocks.advanced.multiblock.BlockDistillationChamberWall.onBlockActivated(BlockDistillationChamberWall.java:26)

 

And line 26 is:

TileEntityDistillationChamberGag tileEntity = (TileEntityDistillationChamberGag)world.getTileEntity(x, y, z);

now for some reason the x, y, z is returning the coords of the master block, but only in this line of code, as in the first system.out.println uses the same x, y, z coords and returns the coords of the block being clicked.

 

And from what I understand, this is trying to cast the master: (TileEntityDistillationChamberFrame) to itself: (TileEntityDistillationChamberGag) and it shouldnt be doing that because the x, y, z coords shouldnt return the master block, and in no other place have I referenced the master block (yet).

 

Am I doing something wrong in how I am trying to get the master block from the gag blocks? if so, what is the correct way to do this?

 

Thanks for any help.

I ask complicated questions, and apparently like to write really long detailed posts. But I also help others when I can.

Link to comment
Share on other sites

How can I make the gag blocks search for the master block in a certain area? because I had an idea where instead of the gag blocks having a tileentity that references the master tileentity, I can make it search for the master when it is activated, and open the masters gui in my guiHandler.

 

Is this the correct way to do this? or is there a better way?

I ask complicated questions, and apparently like to write really long detailed posts. But I also help others when I can.

Link to comment
Share on other sites

change this

System.out.println("Master located at: X " + tileEntity.masterPosX + ", Y: " + tileEntity.masterPosY + ", Z: " + tileEntity.masterPosZ);

to

System.out.println("Master located at: X " + tileEntity.xCoord+ ", Y: " + tileEntity.yCoord+ ", Z: " + tileEntity.zCoord);

or

System.out.println("Master located at: X " + DistillationChamberGag .xCoord+ ", Y: " + DistillationChamberGag .yCoord+ ", Z: " + DistillationChamberGag .zCoord);

Link to comment
Share on other sites

change this

System.out.println("Master located at: X " + tileEntity.masterPosX + ", Y: " + tileEntity.masterPosY + ", Z: " + tileEntity.masterPosZ);

to

System.out.println("Master located at: X " + tileEntity.xCoord+ ", Y: " + tileEntity.yCoord+ ", Z: " + tileEntity.zCoord);

or

System.out.println("Master located at: X " + DistillationChamberGag .xCoord+ ", Y: " + DistillationChamberGag .yCoord+ ", Z: " + DistillationChamberGag .zCoord);

 

That wont work because tileEntity.xCoord, yCoord etc is the coordinates of the gag tileentity, but in the gag tileentity there are 3 integers, masterPosX, masterPosY, and masterPosZ. These should return the location of the master block. Now im not sure if I am referencing the master correctly in the tileentitygag here is what I did:

 

 

public class TileEntityDistillationChamberGag extends TileEntity implements ISidedInventory{

private TileEntityDistillationChamberFrame tileEntityMain;
private boolean hasMaster = true;
private boolean isMaster = false;

public int masterPosX = tileEntityMain.xCoord;
public int masterPosY = tileEntityMain.yCoord;
public int masterPosZ = tileEntityMain.zCoord;

...Irrelevant code...

 

 

Im pretty sure it is wrong because when it is part of the multiblock it returns x: 0, y: 0, z: 0. And when it is not part of the multiblock, it crashes the game with a nullPointerException.

 

Is the way I am getting the master block correct? I have a strong feeling that it is not, but I cant figure out how to properly do so.

 

Also sorry for the late reply, I was out of the house for a bit.

I ask complicated questions, and apparently like to write really long detailed posts. But I also help others when I can.

Link to comment
Share on other sites

but how do I set a non static variable from another class? (I am kind of new to java, and for the record, I have attempted this before in this mod, and havnt had much luck, so it would be great if I could get a detailed explanation  on how to do this).

I ask complicated questions, and apparently like to write really long detailed posts. But I also help others when I can.

Link to comment
Share on other sites

But it is actually referencing the class that is the problem, I dont know how to properly do this. Before when I have tried to reference other classes, I have had crashes saying things like classCastException, class1 can not be cast to class2, or nullPointerException etc.

 

I knew that the variable needed to be public for other classes to access it, I pretty much make everything public, unless I know that it needs to be protected or private.

I ask complicated questions, and apparently like to write really long detailed posts. But I also help others when I can.

Link to comment
Share on other sites

When you create the class, you could pass in the reference in the constructor and then assign it to a property. You could also create a method in the class that accepts the reference and does something with it. There are numerous ways to pass along reference to instances.

 

ClassCastExceptions arise when one tries to cast an instance of an ObjectA to ObjectB when ObjectA doesn't extend or implement ObjectB. For example if you have an ArrayList, a ClassCastExceptions will be thrown when you try to cast this to a Map. A good way to prevent this is to check before you cast:

 

if (ObjectA instanceof ObjectB) { /** Do your stuff **/ }

 

NullPointers arise when one uses a variable or a property while it hasn't been assigned yet. So if you create a variable like `String foo;` or `String foo = null;` and you start calling methods on it like foo.equalsIgnoreCase("bar") it throws an exception because foo is used as a string while it's a null. When you come across this a lot, try assigning values in your constructors more or make sure a value has been set before using it:

 

if (foo != null) { /** Do your stuff **/ }

 

Hope this helps.

Link to comment
Share on other sites

Thanks! now alot more things make sense.

 

When you say I could pass the reference in the constructor, do you mean like this?

        private TileEntityDistillationChamberFrame tileEntityMain;

public int masterPosX;
public int masterPosY;
public int masterPosZ;

public TileEntityDistillationChamberGag(TileEntityDistillationChamberFrame main) {
	this.tileEntityMain = main;

	if (tileEntityMain != null) {
		this.masterPosX = tileEntityMain.masterPosX;
		this.masterPosY = tileEntityMain.masterPosY;
		this.masterPosZ = tileEntityMain.masterPosZ;
	} else {
		this.masterPosX = 1;
		this.masterPosY = 1;
		this.masterPosZ = 1; //So that it isn't null and causes a crash when right clicked
		this.hasMaster = false;
	}
}

 

And then change the createNewTileEntity method in the block class from:

        @Override
public TileEntity createNewTileEntity(World world, int par2) {
	return new TileEntityDistillationChamberGag();
}

to:

        @Override
public TileEntity createNewTileEntity(World world, int par2) {
	return new TileEntityDistillationChamberGag(new TileEntityDistillationChamberFrame());
}

 

But how would this work if there was multiple of these structures in the world? I feel like I am missing something to make sure that it is part of 'this' multiblock structure.

I ask complicated questions, and apparently like to write really long detailed posts. But I also help others when I can.

Link to comment
Share on other sites

Im also looking on github for the way forestry has done their multifarms. I cant actually find where they have done this though. I have their page on github up, and I have looked through all their packages, but cant find the multifarm code. This will also be useful for me to see how the inventory can store liquids, because I want to have a gui that can store liquids (I have an idea on how to do this, but I dont think that it would be compatible with things like fluiducts, or waterproof pipes, I want to see how they make it compatible)

I ask complicated questions, and apparently like to write really long detailed posts. But I also help others when I can.

Link to comment
Share on other sites

Update:

This code has fixed all the crash problems when the block is activated, but it now only returns 0, 0, 0 for the coords of the master... what am I doing wrong? because if this were to open a gui, I would get a nullPointerException because the block at 0, 0, 0 doesnt have a gui.

I ask complicated questions, and apparently like to write really long detailed posts. But I also help others when I can.

Link to comment
Share on other sites

Thanks! now alot more things make sense.

 

When you say I could pass the reference in the constructor, do you mean like this?

        private TileEntityDistillationChamberFrame tileEntityMain;

public int masterPosX;
public int masterPosY;
public int masterPosZ;

public TileEntityDistillationChamberGag(TileEntityDistillationChamberFrame main) {
	this.tileEntityMain = main;

	if (tileEntityMain != null) {
		this.masterPosX = tileEntityMain.masterPosX;
		this.masterPosY = tileEntityMain.masterPosY;
		this.masterPosZ = tileEntityMain.masterPosZ;
	} else {
		this.masterPosX = 1;
		this.masterPosY = 1;
		this.masterPosZ = 1; //So that it isn't null and causes a crash when right clicked
		this.hasMaster = false;
	}
}

 

And then change the createNewTileEntity method in the block class from:

        @Override
public TileEntity createNewTileEntity(World world, int par2) {
	return new TileEntityDistillationChamberGag();
}

to:

        @Override
public TileEntity createNewTileEntity(World world, int par2) {
	return new TileEntityDistillationChamberGag(new TileEntityDistillationChamberFrame());
}

 

But how would this work if there was multiple of these structures in the world? I feel like I am missing something to make sure that it is part of 'this' multiblock structure.

 

You don't need those parameters, this is the fixed code:

 

        @Override
public TileEntity createNewTileEntity() {
	return new TileEntityDistillationChamberGag();
}

 

        @Override
public TileEntity createNewTileEntity() {
	return new TileEntityDistillationChamberGag(new TileEntityDistillationChamberFrame());
}

Link to comment
Share on other sites

I do need something there though, because otherwise it gives an error saying 'add arguments to match TileEntityDistillationChamberGag(TileEntityDistillationChamberFrame)' because there is a constructor in the tileentity to reference the master.

I ask complicated questions, and apparently like to write really long detailed posts. But I also help others when I can.

Link to comment
Share on other sites

Could you place in your onBlockActivated method of your master block a check

TileEnitity te = world.getTileEntity(x, y, z)

if(!world.isRemote){

  if (muiltiblockStructure()){

      open gui

  }

}

 

Then create a method called boolean multiBlockStructure().  Set the tile block there as meta zero.  Create the mutliblock around it uing for loops or just setBlock(x, y, z, gagBlock, meta, flag).. Gag block can be normal block or a vanilla block.  Return true if the structure is correct.

This way only one tile entity at X, Y, and Z.

 

Link to comment
Share on other sites

I got it working finally :)

 

I havn't found any crash bugs (yet) and the inventory is accessable from any block in the structure, and the inventory is the same, it has the same contents no matter what block you click, and is only accessible when the structure is formed.

 

For anyone that wants to see how I have done it, here is my code:

 

 

The onBlockActivated method in the block class of the gag blocks:

        @Override
public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int side, float hitX, float hitY, float hitZ) {
	TileEntityDistillationChamberGag DistillationChamberGag = (TileEntityDistillationChamberGag)world.getTileEntity(x, y, z);

	Block master = BlockHandler.distillationChamber;

	int masterX;
	int masterY;
	int masterZ;

	TileEntityDistillationChamberFrame tileEntityMaster = null;

	for (int i = x-2; i < x+3; i++) { //x
		for (int k = z-2; k < z+3; k++) {//z
			for (int j = y-10; j < y+10; j++) {//y
				if (world.getBlock(i, j, k) == master) {
					masterX = i;
					masterY = j;
					masterZ = k;
					tileEntityMaster = (TileEntityDistillationChamberFrame) world.getTileEntity(i, j, k);

					if (!world.isRemote) {
						if (tileEntityMaster != null && tileEntityMaster.checkMultiBlockForm()) {
							System.out.println("Located master At: X:" + masterX + ", Y: " + masterY + ", Z: " + masterZ + " and structure is successfully formed!");
							FMLNetworkHandler.openGui(player, Generator.instance, Generator.guiIdDistillationChamber, world, i, j, k);
							return true;
						}
					}
				} else {
					masterX = 0;
					masterY = 0;
					masterZ = 0;
				}
			}
		}
	}
	return false;
}

There isn't any other methods related to synchronising the inventories in this class, only registering textures.

To be honest, all the work of synchronising the inventories is done here in the onBlockActivated method. There is a nested for loop (i, j, and k (x, y, and z) this searches a 5x5x10 area for the master block (5x5x10 because that is the size of my structure, and I want the furthest blocks in the structure to be able to find the master too).

 

If it can't find the master, it just skips everything up to the else statement, that else statement is just there to avoid a nullPointerException by actually initializing the masterX, masterY, masterZ variables with 0.

 

If on the other hand, it does find a master block, it initializes the masterX, masterY, and masterZ variables with the location of the master block, then it initializes the tileentity as the master blocks tileentity.

 

        masterX = i;
masterY = j;
masterZ = k;
tileEntityMaster = (TileEntityDistillationChamberFrame) world.getTileEntity(i, j, k);

 

After that, it goes onto double check if the tileentity is not null, and checks if the structure is formed. and if both of those are true, then it opens the inventory at the location of the master block.

if (tileEntityMaster != null && tileEntityMaster.checkMultiBlockForm()) {
System.out.println("Located master At: X:" + masterX + ", Y: " + masterY + ", Z: " + masterZ + " and structure is successfully formed!");
FMLNetworkHandler.openGui(player, Generator.instance, Generator.guiIdDistillationChamber, world, i, j, k);
return true;
}

The System.out.println is from when I was testing this worked.

 

Works perfectly now.

 

 

I ask complicated questions, and apparently like to write really long detailed posts. But I also help others when I can.

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.



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • Hi! If you have your forge installation file not in the system disc on PC (D, E etc.), drag it to disk C and try to start again. In my case it solved the problem.
    • KILAT77 : Waspada Situs Scam dengan Withdraw Yang Tidak Dibayar Di era digital saat ini, banyak orang yang mencari keberuntungan melalui situs perjudian online. Namun, dibalik gemerlap janji-janji manis kemenangan, ada bahaya yang mengintai. Salah satu situs yang patut diwaspadai adalah KILAT77. Situs ini mendapat reputasi buruk karena banyak laporan dari pengguna yang mengklaim bahwa mereka tidak bisa menarik dana kemenangan mereka. Dalam artikel ini, kita akan membahas mengapa ROTER88 dianggap sebagai situs scam dan bagaimana Anda bisa melindungi diri dari penipuan serupa. Pengalaman Pengguna: Penarikan Tidak Dibayar Beberapa pengguna telah melaporkan pengalaman buruk mereka dengan KILAT77. Mereka mengaku bahwa setelah memenangkan sejumlah uang dan mencoba menariknya, proses penarikan mereka ditolak tanpa alasan yang jelas. Bahkan, beberapa pengguna melaporkan bahwa akun mereka tiba-tiba diblokir setelah mencoba melakukan penarikan, sehingga mereka kehilangan akses ke dana mereka sama sekali.
    • It is a dupe mod issue Remove Rubidium - you are already using Embeddium which is a fork of Rubidium
    • I made a block entity in forge 1.20.1, I want to prevent hopper from taking input slot item, i tried to override the extractItem method, it prevented hopper from taking input slot item, but the player also unable to take/change the item in input slot unless the slot is empty. public class FluidSeparatorBlockEntity extends BlockEntity implements MenuProvider { private static final int INPUT_SLOT = 0; private final CustomItemHandler itemHandler = new CustomItemHandler(3){ @Override protected void onContentsChanged(int slot) { setChanged(); } @Override public boolean isItemValid(int slot, @NotNull ItemStack stack) { return slot == INPUT_SLOT; } @Override public @NotNull ItemStack extractItem(int slot, int amount, boolean simulate) { if (slot == INPUT_SLOT) { return ItemStack.EMPTY; } return super.extractItem(slot, amount, simulate); } }; private LazyOptional<IItemHandler> lazyItemHandler = LazyOptional.empty(); protected final ContainerData data; private int progress = 0; private int maxProgress = 78; public FluidSeparatorBlockEntity(BlockPos pPos, BlockState pBlockState) { super(ModBlockEntities.FLUID_SEPARATOR_BE.get(), pPos, pBlockState); this.data = new ContainerData() { @Override public int get(int pIndex) { return switch (pIndex) { case 0 -> FluidSeparatorBlockEntity.this.progress; case 1, 2 -> FluidSeparatorBlockEntity.this.maxProgress; default -> 0; }; } @Override public void set(int pIndex, int pValue) { switch (pIndex) { case 0 -> FluidSeparatorBlockEntity.this.progress = pValue; case 1, 2 -> FluidSeparatorBlockEntity.this.maxProgress = pValue; } } @Override public int getCount() { return 3; } }; } @Override public @NotNull <T> LazyOptional<T> getCapability(@NotNull Capability<T> cap, @Nullable Direction side) { if(cap == ForgeCapabilities.ITEM_HANDLER) { return lazyItemHandler.cast(); } return super.getCapability(cap, side); } @Override public void onLoad() { super.onLoad(); lazyItemHandler = LazyOptional.of(() -> itemHandler); } @Override public void invalidateCaps() { super.invalidateCaps(); lazyItemHandler.invalidate(); } public void drops() { SimpleContainer inventory = new SimpleContainer(itemHandler.getSlots()); for(int i = 0; i < itemHandler.getSlots(); i++) { inventory.setItem(i, itemHandler.getStackInSlot(i)); } Containers.dropContents(this.level, this.worldPosition, inventory); } @Override public Component getDisplayName() { return Component.translatable("block.chemmaster.fluid_separator"); } @Nullable @Override public AbstractContainerMenu createMenu(int pContainerId, Inventory pPlayerInventory, Player pPlayer) { return new FluidSeparatorMenu(pContainerId, pPlayerInventory, this, this.data); } @Override protected void saveAdditional(CompoundTag pTag) { pTag.put("inventory", itemHandler.serializeNBT()); pTag.putInt("fluid_separator.progress", progress); super.saveAdditional(pTag); } @Override public void load(CompoundTag pTag) { super.load(pTag); itemHandler.deserializeNBT(pTag.getCompound("inventory")); progress = pTag.getInt("fluid_separator.progress"); } public void tick(Level pLevel, BlockPos pPos, BlockState pState) { ItemStack inputStack = this.itemHandler.getStackInSlot(INPUT_SLOT); if (inputStack.getCount() < 2) { resetProgress(); return; } if(hasRecipe()) { increaseCraftingProgress(); setChanged(pLevel, pPos, pState); if(hasProgressFinished()) { craftItem(); resetProgress(); } } else { resetProgress(); } } private void resetProgress() { progress = 0; } private void craftItem() { Optional<FluidSeparatingRecipe> recipe = getCurrentRecipe(); if (recipe.isPresent()) { List<ItemStack> results = recipe.get().getOutputs(); ItemStack inputStack = this.itemHandler.getStackInSlot(INPUT_SLOT); if (inputStack.getCount() < 2) { // If there are not enough items, do not proceed with crafting return; } // Extract the input item from the input slot this.itemHandler.internalExtractItem(INPUT_SLOT, 2, false); // Loop through each result item and find suitable output slots for (ItemStack result : results) { int outputSlot = findSuitableOutputSlot(result); if (outputSlot != -1) { this.itemHandler.setStackInSlot(outputSlot, new ItemStack(result.getItem(), this.itemHandler.getStackInSlot(outputSlot).getCount() + result.getCount())); } else { // Handle the case where no suitable output slot is found // This can be logging an error, throwing an exception, or any other handling logic System.err.println("No suitable output slot found for item: " + result); } } } } private int findSuitableOutputSlot(ItemStack result) { // Implement logic to find a suitable output slot for the given result // Return the slot index or -1 if no suitable slot is found for (int i = 0; i < this.itemHandler.getSlots(); i++) { // Ensure we do not place the output item in the input slot if (i == INPUT_SLOT) { continue; } ItemStack stackInSlot = this.itemHandler.getStackInSlot(i); if (stackInSlot.isEmpty() || (stackInSlot.getItem() == result.getItem() && stackInSlot.getCount() + result.getCount() <= stackInSlot.getMaxStackSize())) { return i; } } return -1; } private boolean hasRecipe() { Optional<FluidSeparatingRecipe> recipe = getCurrentRecipe(); if (recipe.isEmpty()) { return false; } List<ItemStack> results = recipe.get().getOutputs(); for (ItemStack result : results) { if (!canInsertAmountIntoOutputSlot(result) || !canInsertItemIntoOutputSlot(result.getItem())) { return false; } } return true; } private Optional<FluidSeparatingRecipe> getCurrentRecipe(){ SimpleContainer inventory = new SimpleContainer(this.itemHandler.getSlots()); for (int i = 0; i < itemHandler.getSlots(); i++) { inventory.setItem(i, this.itemHandler.getStackInSlot(i)); } return this.level.getRecipeManager().getRecipeFor(FluidSeparatingRecipe.Type.INSTANCE, inventory, level); } private boolean canInsertAmountIntoOutputSlot(ItemStack result) { for (int i = 1; i < this.itemHandler.getSlots(); i++) { ItemStack stackInSlot = this.itemHandler.getStackInSlot(i); if (stackInSlot.isEmpty() || (stackInSlot.getItem() == result.getItem() && stackInSlot.getCount() + result.getCount() <= stackInSlot.getMaxStackSize())) { return true; } } return false; } private boolean canInsertItemIntoOutputSlot(Item item) { for (int i = 1; i < this.itemHandler.getSlots(); i++) { ItemStack stackInSlot = this.itemHandler.getStackInSlot(i); if (stackInSlot.isEmpty() || stackInSlot.getItem() == item) { return true; } } return false; } private boolean hasProgressFinished() { return progress >= maxProgress; } private void increaseCraftingProgress() { progress++; } }  
  • Topics

×
×
  • Create New...

Important Information

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