Jump to content

Recommended Posts

Posted

Hi, I have a working gui code, a TileEntity, Gui Handler, Gui Class, and Container, for a custom block. But instead of opening the gui with a block, I want to open the gui by pressing a keyboard key.  If its possible, can I assign that particular input key to the  same  input the player assigned towards the inventory? (Overwriting Inventory Screen) Do you render the gui the same as if it was a block (I Couldnt get this to work) or is there different code to open a gui for inventory?

 

In Summary: How do you render a custom gui from the input handler?  How do you assign that particular input to that of your game settings for inventory?

 

Edit: Cleaned Up Post

Posted

I didn't get the part about "overwriting the inventory gui" but as for "can I open the gui by pressing a keyboard key", see this http://www.minecraftforge.net/wiki/Upgrading_To_Forge_for_1.3.1#Key_Bindings. It's called "updating to 1.3.1" but it's the same for 1.4 and 1.5

 

The only part I felt not documented well is the

 

@Override
        public EnumSet<TickType> ticks() {
                return EnumSet.of(TickType.CLIENT);

 

Part. Basically, it's what ticks do you want to be notified about. Which is basically just client (your key handler only needs to listen on the client side). If you return null, you won't get any notifications (key presses).

Posted

Thanks for that link. What I was trying to say earlier was: How can you set the inputKey to the inputKey the User Specified as his/her Inventory Key? My Custom Gui would overwrite the Vanilla inventory with my own, but the following code

while (this.gameSettings.keyBindInventory.isPressed()) {
		this.displayGuiScreen(new GuiInventory(this.thePlayer)); 

does not work, specifically the

gameSettings.keyBindInventory.isPressed()

Posted

I'm getting a nullpointer when I render my gui from the key. Here is my keyHandler code:

static EntityPlayer player;
static World world;
int x;
int y;
int z;

public TileEntity createNewTileEntity(World world) {
	return new TileEntityInventory();
}

static KeyBinding myBinding = new KeyBinding("MyBind", Keyboard.KEY_R);

public ExcelteorKeyHandler() {
	// the first value is an array of KeyBindings, the second is whether or
	// not the call
	// keyDown should repeat as long as the key is down
	super(new KeyBinding[] { myBinding }, new boolean[] { false });
}

@Override
public String getLabel() {
	return "mykeybindings";
}

@Override
public void keyDown(EnumSet<TickType> types, KeyBinding kb,
		boolean tickEnd, boolean isRepeat) {
	TileEntity tileEntity = world.getBlockTileEntity(x, y, z);
	if (tileEntity == null) {
		return;
	}
	player.openGui(Main.instance, 0, world, x, y, z);

}

@Override
public void keyUp(EnumSet<TickType> types, KeyBinding kb, boolean tickEnd) {
	// do whatever
}

@Override
public EnumSet<TickType> ticks() {
	return EnumSet.of(TickType.CLIENT);
	// I am unsure if any different TickTypes have any different effects.
}

The Null Pointer Is From the Two Lines

TileEntity tileEntity = world.getBlockTileEntity(x, y, z);

player.openGui(Main.instance, 0, world, x, y, z);

Posted

This is my current IIventory.class file:

 public class IInventory implements IExtendedEntityProperties {

private ItemStack[] inv;

@Override
public void saveNBTData(NBTTagCompound compound) {

	NBTTagList itemList = new NBTTagList();
	for (int i = 0; i < inv.length; i++) {
		ItemStack stack = inv[i];
		if (stack != null) {
			NBTTagCompound tag = new NBTTagCompound();
			tag.setByte("Slot", (byte) i);
			stack.writeToNBT(tag);
			itemList.appendTag(tag);
		}
	}
	compound.setTag("Inventory", itemList);

}

@Override
public void loadNBTData(NBTTagCompound compound) {

	NBTTagList tagList = compound.getTagList("Inventory");
	for (int i = 0; i < tagList.tagCount(); i++) {
		NBTTagCompound tag = (NBTTagCompound) tagList.tagAt(i);
		byte slot = tag.getByte("Slot");
		if (slot >= 0 && slot < inv.length) {
			inv[slot] = ItemStack.loadItemStackFromNBT(tag);
		}
	}

}

@Override
public void init(Entity entity, World world) {

} 

But I am confused about

subscribe to the event EntityEvent.EntityConstructing
and
EntityConstructing event check if the entity is a player and if so register a new instance of your Data class to it. (entity.registerExtendedProperties).
Also, this particular code
 (YourDataClass)player.getExtendedProperties(Your_Identifier) 

would go under the keyDown event, right?

Posted

Ok I've changed the Inventory Event Class. I've added  this code to my main File:

MinecraftForge.EVENT_BUS.register(new EventCustomInventory()); 

 

Now, I have updated my previous misnamed class into implementing IInventory and updating the code:

 public class EventCustomInventory implements IExtendedEntityProperties, IInventory {

private ItemStack[] inv;

public EventCustomInventory() {
	inv = new ItemStack[9];
}

@Override
public void saveNBTData(NBTTagCompound compound) {

	NBTTagList itemList = new NBTTagList();
	for (int i = 0; i < inv.length; i++) {
		ItemStack stack = inv[i];
		if (stack != null) {
			NBTTagCompound tag = new NBTTagCompound();
			tag.setByte("Slot", (byte) i);
			stack.writeToNBT(tag);
			itemList.appendTag(tag);
		}
	}
	compound.setTag("Inventory", itemList);

}

@Override
public void loadNBTData(NBTTagCompound compound) {

	NBTTagList tagList = compound.getTagList("Inventory");
	for (int i = 0; i < tagList.tagCount(); i++) {
		NBTTagCompound tag = (NBTTagCompound) tagList.tagAt(i);
		byte slot = tag.getByte("Slot");
		if (slot >= 0 && slot < inv.length) {
			inv[slot] = ItemStack.loadItemStackFromNBT(tag);
		}
	}

}

@Override
public void init(Entity entity, World world) {

}

@Override
public int getSizeInventory() {
	return inv.length;
}

@Override
public ItemStack getStackInSlot(int slot) {
	return inv[slot];
}

@Override
public ItemStack decrStackSize(int slot, int amt) {
	ItemStack stack = getStackInSlot(slot);
	if (stack != null) {
		if (stack.stackSize <= amt) {
			setInventorySlotContents(slot, null);
		} else {
			stack = stack.splitStack(amt);
			if (stack.stackSize == 0) {
				setInventorySlotContents(slot, null);
			}
		}
	}
	return stack;
}

@Override
public ItemStack getStackInSlotOnClosing(int slot) {
	ItemStack stack = getStackInSlot(slot);
	if (stack != null) {
		setInventorySlotContents(slot, null);
	}
	return stack;
}

@Override
public void setInventorySlotContents(int slot, ItemStack stack) {
	inv[slot] = stack;
	if (stack != null && stack.stackSize > getInventoryStackLimit()) {
		stack.stackSize = getInventoryStackLimit();
	}

}

@Override
public String getInvName() {
	return "main.custominventory";
}

@Override
public boolean isInvNameLocalized() {
	return false;
}

@Override
public int getInventoryStackLimit() {
	return 64;
}

@Override
public void onInventoryChanged() {

}

@Override
public boolean isUseableByPlayer(EntityPlayer entityplayer) {
	// TODO Auto-generated method stub
	return false;
}

@Override
public void openChest() {

}

@Override
public void closeChest() {

}

@Override
public boolean isStackValidForSlot(int i, ItemStack itemstack) {
	return false;
} 

Now, I have some trouble actually making it open. Under my main class, I have the code

 @ForgeSubscribe
public void EntityEvent(EntityConstructing event, EntityPlayer player) {
	if (event.entity == player) {
		event.entity.registerExtendedProperties("main.custominventory",
				new EventCustomInventory());
		("idk what to put here!")player.getExtendedProperties("main.custominventory");
	}
} 

I am not sure if that is correct at all, most likely far off from what it should be. It is just me trying to do my best.  I am still confused what to do for

 (YourDataClass)player.getExtendedProperties(Your_Identifier) 

Also, how would i incorporate the actual gui render class (GuiExcelteorInventory) and open it (packets T_T) ?

Posted

I'l try to work on the packet system in a bit. But, I have updated my code to whats needed. Currently in my GuiHandler, I have

// returns an instance of the Container you made earlier
@Override
public Object getServerGuiElement(int id, EntityPlayer player, World world,
		int x, int y, int z) {
	EventCustomInventory eCI = (EventCustomInventory)player.getExtendedProperties("main.custominventory");
	return new ContainerInventory(player.inventory, (EventCustomInventory) eCI);
}

// returns an instance of the Gui you made earlier
@Override
public Object getClientGuiElement(int id, EntityPlayer player, World world,
		int x, int y, int z) {

	EventCustomInventory eCI = (EventCustomInventory)player.getExtendedProperties("main.custominventory");
	return new GuiExcelteorInventory(player.inventory, (EventCustomInventory) eCI);

} 

 

That should be correct. Now, I'm having trouble with checking the entity is a player. Under my @Init I have my register lines (should be correct)

NetworkRegistry.instance().registerGuiHandler(this, new GuiHandler());
	KeyBindingRegistry.registerKeyBinding(new ExcelteorKeyHandler());
	MinecraftForge.EVENT_BUS.register(this); 

Outside of that method, I have

 @ForgeSubscribe
public void EntityEvent(EntityConstructing event) {
	//EntityPlayer player = (EntityPlayer) player.isCreatureType(EnumCreatureType.creature, true);
//	if (event.entity == player) {
	//	player.registerExtendedProperties("main.custominventory", new EventCustomInventory());
	//}
//}

I tried playing around with it for a while, but could not find a working solution. How would I properly check if the entity is a player? (I know that the player.registerExtendedProperties must be EntityPlayer player)

Posted

I can tell you that I've read java tutorials before. I can read them as many times as I want, but they will mean nothing to me unless I actually get the experience up front. Some people learn from experience rather than reading a book. Most can only learn from example...Anyway, I really have no idea what to do for that and a few other things. Again, I have no idea how to do check the instance (all of the following is competely off):

@ForgeSubscribe
public void EntityEvent(EntityConstructing event) {
	EntityPlayer player = (EntityPlayer) event.entity;
	if (event instanceof player) {
		player.registerExtendedProperties("main.custominventory", new EventCustomInventory());
	}
} 

Second, the actual open Gui Code after receiving the packet:

@Override
public void onPacketData(INetworkManager manager,
		Packet250CustomPayload packet, Player player) {

	if (packet.channel.equals("Excelteor")) {
		openGui(packet);
	}
}

private void openGui(Packet250CustomPayload packet) {

} 

 

Lastly (and this should do it), writing the packet to send:

@Override
public void keyDown(EnumSet<TickType> types, KeyBinding kb,
		boolean tickEnd, boolean isRepeat) {

	ByteArrayOutputStream bos = new ByteArrayOutputStream(;
	DataOutputStream outputStream = new DataOutputStream(bos);

	Packet250CustomPayload packet = new Packet250CustomPayload();
	packet.channel = "Excelteor";
	packet.data = bos.toByteArray();
	packet.length = bos.size();

	Side side = FMLCommonHandler.instance().getEffectiveSide();
	if (side == Side.SERVER) {
		// We are on the server side.
		EntityPlayerMP player = (EntityPlayerMP) playerEntity;
	} else if (side == Side.CLIENT) {
		// We are on the client side.
		EntityClientPlayerMP player = (EntityClientPlayerMP) playerEntity;
		player.sendQueue.addToSendQueue(packet);
	} else {

	}
} 

Any help greatly appreciated :/

Posted

Almost there :P

Is this any better for the first?:

@ForgeSubscribe
public void EntityEvent(EntityConstructing event) {
	if (event instanceof EntityEvent) {
		EntityPlayer player = (EntityPlayer) event.entity;
		player.registerExtendedProperties("main.custominventory",
				new EventCustomInventory());
	}
} 

Second, I Left the openGui part empty because I do not know what to put in, so I'l need some further help there:

@Override
public void onPacketData(INetworkManager manager,
   Packet250CustomPayload packet, Player player) {

  if (packet.channel.equals("Excelteor")) {
   openGui(packet);
  }
}

private void openGui(Packet250CustomPayload packet) {
  
}

You need to actually open the GUI, not just do nothing

 

Lastly, for the third I now have this:

 @Override
public void keyDown(EnumSet<TickType> types, KeyBinding kb,
		boolean tickEnd, boolean isRepeat) {

	Packet250CustomPayload packet = new Packet250CustomPayload();
                packet.channel = "Excelteor";
	PacketDispatcher.sendPacketToServer(packet);
}

Thanks in advance for the help :P

Posted

Made some adjustments.

1. Instanceof code:

 @ForgeSubscribe
public void EntityEvent(EntityConstructing event) {
	if (event.entity instanceof EntityPlayer) {
		EntityPlayer player = Minecraft.getMinecraft().thePlayer;
		player.registerExtendedProperties("main.custominventory",
				new EventCustomInventory());
	}
}

 

2. Packet Handler Part:

 private void openGui(Packet250CustomPayload packet) {
	EntityPlayer player = Minecraft.getMinecraft().thePlayer;
	World world = Minecraft.getMinecraft().theWorld;
	player.openGui(Main.instance, 0, world, 0, 0, 0);

}

 

3. Key Handler Part:

 @Override
public void keyDown(EnumSet<TickType> types, KeyBinding kb,
		boolean tickEnd, boolean isRepeat) {

	if (tickEnd) {
		Packet250CustomPayload packet = new Packet250CustomPayload();
		packet.channel = "Excelteor";
		PacketDispatcher.sendPacketToServer(packet);
	}
} 

 

Thanks for all the help so far!

After this, it somewhat works. Unless i open the actual inventory gui first, my custom one crashes. I think it is because the world is null. How would I fix that?  In Addition: If I wanted to assign the "key down" to "Minecraft.gameSettings.keyBindInventory" how would I go about doing that? (Did not work when i replaced it with the KeyBoard key)

Posted

All fixed :) Last few Questions, though.....

Would this be ok for the keyHandler?

 static KeyBinding inventoryBinding = Minecraft.getMinecraft().gameSettings.keyBindInventory;

public ExcelteorKeyHandler() {
	super(new KeyBinding[] { inventoryBinding }, new boolean[] { false });
}

 

And Second: If I press the same key while in the screen, it will open again. If I press the key while in another gui, it will open the inventory. So, how would I check if the current screen is null?

Posted

Typing in chat

 

Check if the ingame has focus.

Don't ask for support per PM! They'll get ignored! | If a post helped you, click the "Thank You" button at the top right corner of said post! |

mah twitter

This thread makes me sad because people just post copy-paste-ready code when it's obvious that the OP has little to no programming experience. This is not how learning works.

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.