Jump to content

[1.7.10][SOLVED] GUI + Player Inventory Interaction


Arkoonius

Recommended Posts

Hello all. I would like some help with my GUI. Tutorials I see are mostly just plain code for copy/pasting and I have no idea whether if my issue is specific or not to do that. I want the player to be able to open up a GUI and click on buttons or icons to craft items. This crafting consists of checking the players inventory if it contains the necessary components, destroying them if everything exists, and directly adding the result item to the players inventory. As an example. The player clicks on the "Iron Sword" button on the GUI. The GUI checks the player's inventory that it contains a stick and 2 iron ingots. If the checks return true, a stick and 2 iron ingots are removed from the player's inventory, and the player is given an iron sword as a result.

 

The issues I'm having isn't within the drawing of the GUI, but the actual changes in the player's inventory. In order for what I want to work, I have to do things server-side as well, else everything doesn't work and gets out of sync. I have no idea how to do this, and I'm sure packet handling is required. Could any please explain, in detail, what I have to do? I would normal say "please point me in the right direction," but giving a simple link to another's tutorial, as I've experienced in the past.

 

This GUI is opened by right clicking on a specific block, but it will have no inventory of sorts (e.g. a chest) or even slots (e.g. villager trading). Just simple buttons, textures, and texts.

Link to comment
Share on other sites

The GUI checks the player's inventory that it contains a stick and 2 iron ingots

You are approaching this from wrong direction. Gui is on client side and remember that client can let the gui know exactly what it wants (hacking). So you really need to do that on server side and I would do this like this way:

 

- Player presses gui button -> onActionPerformed() get called. It sends request to server (can be your own packet or same way as item enchant is done so look for that. That request contains the name of requested item/block to craft.

 

- Server gets this requests and gets player from server side container (EntityPlayerMP#opencontainer)

- Server "scans" player inventory with for-loop and checks every slot of players inventory looking for items/blocks needed for requested crafting. Server knows needed items by getting it's recipe from GameRegistry (or was it somewhere else). It can find recipe by getting correct item for recipe with Item.getItemByName(requested item name)

- If the correct items have been found, server subtracts itemstacks on player inventory as needed.

- Now server sets requested item to slot, it can be slot in gui or in player inventory. If its in player inventory server finds first free slot with for-loop and is trying to find slot that is null. When its found then it can be set, and for cases that there is no free space left in player inventory, server can spawn item next to your block so player can pick it up.

Link to comment
Share on other sites

Just like you would do it on client side. You can set itemstacks and check player inventory on server-side same way as on client side, you just need to use server-side player (EntityPlayerMP).

The first thing you need to do is to let server know which button was pressed and this is where the packet is needed. So you need packet and handlers. There is great tutorial at http://www.minecraftforge.net/forum/index.php/topic,20135.0.html

 

When the packet is received by server, you can get EntityPlayerMP from MessageContext#getServerHandler().playerEntity and server-side container from player EntityPlayerMP#openContainer which is the container you have returned in your IGuiHandler#getServerGuiElement when player opened the gui.

Link to comment
Share on other sites

Just like you would do it on client side. You can set itemstacks and check player inventory on server-side same way as on client side, you just need to use server-side player (EntityPlayerMP).

The first thing you need to do is to let server know which button was pressed and this is where the packet is needed. So you need packet and handlers. There is great tutorial at http://www.minecraftforge.net/forum/index.php/topic,20135.0.html

 

When the packet is received by server, you can get EntityPlayerMP from MessageContext#getServerHandler().playerEntity and server-side container from player EntityPlayerMP#openContainer which is the container you have returned in your IGuiHandler#getServerGuiElement when player opened the gui.

 

Alright. So on button press send a packet to the server and when that is received I can make use of EntityPlayerMP. I can make sense to that, but I'm confused about after that as I have yet to work with containers. From what I understand by reading on the wiki (and please correct me if I'm interpreting this incorrectly), a Container allows interaction between player and TileEntity inventories via GUIs, and TileEntities are simply blocks that can hold extra data beyond just plain metadata (inventory and such). So what I'm thinking what needs to be done is connect the player's inventory with the TileEntity and that TileEntity with the container. Then from there I can mess around with the inventory as needed. But then again, isn't that all serverside? Unless this method has some auto-syncing in the background, I'm seeing this to cause sync issues between server and client player inventories.

Link to comment
Share on other sites

Here's how I think of Guis on a high level, which might help.

 

Most Guis have 2 parts: something that extends GuiContainer and something that extends Container. The GuiContainer is on the client side, so it should handle all of the drawing. The Container is on the server side, so it should handle all of the logic. These two components are "registered" using the getClientGuiElement/getServerGuiElement methods.

 

When you're instantiating your GuiContainer and Container, you should pass the tile entity to both of them, and also the player inventory if needed.

 

So it's more accurate to say that you "connect" the Container to both the player inventory and the tile entity. However, you don't connect the tile entity to the player inventory, since the Container acts like a "mediator" between the two. (For example, the Container can "take" something from the player's inventory and "put it into" the tile entity's inventory.)

 

Since the GuiContainer also has the reference to the player inventory and tile entity, it automatically knows whenever the player inventory or tile entity changes. (The client/server things are done under the hood, so it's sufficient to just say that it magically works.)

Link to comment
Share on other sites

Thanks for the help you two. I've managed to make some form of progress. Upon opening up the player's inventory, I'm able to give the player an item. Sorta... every time I bring up the GUI the game crashes and I'm left with a TickingMemoryException and NullPointerException within the console. Wiki and forge source documentation is unhelpful due to them being barren in terms of comments and relevant argument names. Though I DO have the item in my inventory when I start the game back up.

 

So how exactly do I properly make changes to the player's inventory within the Container?

Link to comment
Share on other sites

If you use Eclipse, you can set a breakpoint on the line of code where it crashes (look in your error log/stack trace for the exact line). Then you can run Minecraft in debug mode, and it'll pause right before executing that line. When it pauses, you can check the values of all variables by hovering over them.

 

I'm not 100% sure, but your null pointer probably isn't relevant to the actual problem. (It's more likely that you actually solved your problem, but a small mistake somewhere causes a null pointer which crashes the game.)

Link to comment
Share on other sites

Well, let's first ask this question: am I doing anything wrong in the first place?

 

Here's the relevant code:

[spoiler=TestGui.java]

public class TestGui extends GuiContainer
{

int bgWidth = 256;
int bgHeight = 145;

//calc positions to place gui in middle of screen
int guiXPos = 0;
int guiYPos = 0;

int buttonWidth = 40;
int buttonHeight = 20;

GuiButton btnBalls;

boolean mousedOver = false;

//for drawing buttons and other GUI elements, keep everything in one image file and work with it
//as if you would with a sprite sheet (see drawTexturedModalRect comment)

public TestGui(InventoryPlayer inv) 
{
	super(new TestGuiContainer(inv));
}

@Override
public void initGui()
{
	guiXPos = (width - bgWidth) / 2;
	guiYPos = (height - bgHeight) / 2;

	buttonList.clear();
	//add button                           id      xPos        yPos      width height text
	buttonList.add(btnBalls = new GuiButton(0, guiXPos + 10, guiYPos + 70, 40, 20, "Things"));

	super.initGui();
}

@Override
public void actionPerformed(GuiButton button)
{
	switch (button.id)
	{
	case 0:
		button.displayString = "Butts";
	}

	super.actionPerformed(button);
}

@Override
public void keyTyped(char what, int keyCode)
{
	switch (keyCode)
	{
	case Keyboard.KEY_E:
		mc.displayGuiScreen(null);
	}

	super.keyTyped(what, keyCode);
}

@Override
public void mouseClicked(int x, int y, int mouseButton)
{
	if (mouseOver(x, y, guiXPos + 10, guiYPos + 50, buttonHeight, buttonWidth))
	{
		mousedOver = true;
	}
	else mousedOver = false;

	super.mouseClicked(x, y, mouseButton);
}

public boolean mouseOver(int mouseX, int mouseY, int posX, int posY, int height, int width)
{
	if ((mouseX >= posX) & (mouseY >= posY))
	{
		if ((mouseX <= (posX + width)) & (mouseY <= (posY + height)))
		{
			return true;
		}
	}

	return false;
}

@Override
protected void drawGuiContainerBackgroundLayer(float arg0, int arg1, int arg2) 
{
	guiXPos = (width - bgWidth) / 2;
	guiYPos = (height - bgHeight) / 2;

	GL11.glColor4f(1.f, 1.f, 1.f, 1.f); //RGBA
	drawDefaultBackground();
	mc.renderEngine.bindTexture(new ResourceLocation("runeblock", "textures/gui/CraftingGuiBackground.png")); //bind GUI texture
	//drawing GUI background
	drawTexturedModalRect(guiXPos, guiYPos, 0, 0, bgWidth, bgHeight); //0s are starting position with texture to draw (think sprite sheets)

	if (!mousedOver) drawTexturedModalRect(guiXPos + 10, guiYPos + 50, 0, bgHeight, buttonWidth, buttonHeight);
	else drawTexturedModalRect(guiXPos + 10, guiYPos + 50, 0, bgHeight + buttonHeight, buttonWidth, buttonHeight);
}

@Override
protected void drawGuiContainerForegroundLayer(int arg1, int arg2)
{
	fontRendererObj.drawString("Things", guiXPos + 10, guiYPos + 10, 0x000000); //last arg is hex for color
}

}

 

 

[spoiler=TestGuiContainer.java]

public class TestGuiContainer extends Container
{
InventoryPlayer playerInv;

public TestGuiContainer(InventoryPlayer inv)
{
	inv.mainInventory[3] = new ItemStack(RBItems.runiteOre, 1);
}


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

 

 

Perhaps not relevant, but I'll include these as well.

[spoiler=GuiHandler.java]

public class GuiHandler implements IGuiHandler
{

@Override
public Object getClientGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) 
{
	switch (ID)
	{
	case 0: return new TestGui(player.inventory);
	}

	return null;
}

@Override
public Object getServerGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) 
{
	switch (ID)
	{
	case 0: return new TestGuiContainer(player.inventory);
	}

	return null;
}

}

 

 

And this is how I'm opening the GUI

[spoiler=GoldBar.java]

public class GoldBar extends Item
{
public GoldBar()
{
	setMaxStackSize(1);
	setCreativeTab(runeBlock.lib.ModInfo.runeBlockTab);
	setUnlocalizedName("goldBar");
	setTextureName("runeblock:GoldBar");
}

@Override
public boolean onItemUse(ItemStack itemStack, EntityPlayer player, World world, int x, int y, int z,
            int par7, float par8, float par9, float par10)
{
	player.openGui(RuneBlock.instance, 0, world, x, y, z);
	return false;
}	

}

 

Link to comment
Share on other sites

Here's the log starting from me joining the game.

 

[18:44:14] [server thread/INFO]: Player680 joined the game
[18:44:14] [server thread/INFO]: [runeBlock.network.ServerPacket:sendPacketToClient:46]: sending packet to client
[18:44:14] [Client thread/INFO]: [Client thread] Client side modded connection established
[18:44:14] [Client thread/INFO]: [runeBlock.network.ClientPacketHandler:onClientPacket:23]: packet received
[18:44:14] [server thread/INFO]: Saving and pausing game...
[18:44:14] [server thread/INFO]: Saving chunks for level 'New World'/Overworld
[18:44:14] [server thread/INFO]: Saving chunks for level 'New World'/Nether
[18:44:14] [server thread/INFO]: Saving chunks for level 'New World'/The End
[18:44:17] [server thread/ERROR]: Encountered an unexpected exception
net.minecraft.util.ReportedException: Ticking memory connection
at net.minecraft.network.NetworkSystem.networkTick(NetworkSystem.java:181) ~[NetworkSystem.class:?]
at net.minecraft.server.MinecraftServer.updateTimeLightAndEntities(MinecraftServer.java:659) ~[MinecraftServer.class:?]
at net.minecraft.server.MinecraftServer.tick(MinecraftServer.java:547) ~[MinecraftServer.class:?]
at net.minecraft.server.integrated.IntegratedServer.tick(IntegratedServer.java:111) ~[integratedServer.class:?]
at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:427) [MinecraftServer.class:?]
at net.minecraft.server.MinecraftServer$2.run(MinecraftServer.java:685) [MinecraftServer$2.class:?]
Caused by: java.lang.NullPointerException
at net.minecraft.network.NetHandlerPlayServer.processPlayerBlockPlacement(NetHandlerPlayServer.java:620) ~[NetHandlerPlayServer.class:?]
at net.minecraft.network.play.client.C08PacketPlayerBlockPlacement.processPacket(SourceFile:60) ~[C08PacketPlayerBlockPlacement.class:?]
at net.minecraft.network.play.client.C08PacketPlayerBlockPlacement.processPacket(SourceFile:9) ~[C08PacketPlayerBlockPlacement.class:?]
at net.minecraft.network.NetworkManager.processReceivedPackets(NetworkManager.java:212) ~[NetworkManager.class:?]
at net.minecraft.network.NetworkSystem.networkTick(NetworkSystem.java:165) ~[NetworkSystem.class:?]
... 5 more
[18:44:17] [server thread/ERROR]: This crash report has been saved to: C:\Users\Owner\Desktop\my mc mods\RuneBlock\eclipse\.\crash-reports\crash-2015-01-08_18.44.17-server.txt
[18:44:17] [server thread/INFO]: Stopping server
[18:44:17] [server thread/INFO]: Saving players
[18:44:17] [server thread/INFO]: Saving worlds
[18:44:17] [server thread/INFO]: Saving chunks for level 'New World'/Overworld
[18:44:17] [Client thread/INFO]: [net.minecraft.client.Minecraft:displayCrashReport:349]: ---- Minecraft Crash Report ----
// You're mean.

Time: 1/8/15 6:44 PM
Description: Ticking memory connection

java.lang.NullPointerException: Ticking memory connection
at net.minecraft.network.NetHandlerPlayServer.processPlayerBlockPlacement(NetHandlerPlayServer.java:620)
at net.minecraft.network.play.client.C08PacketPlayerBlockPlacement.processPacket(SourceFile:60)
at net.minecraft.network.play.client.C08PacketPlayerBlockPlacement.processPacket(SourceFile:9)
at net.minecraft.network.NetworkManager.processReceivedPackets(NetworkManager.java:212)
at net.minecraft.network.NetworkSystem.networkTick(NetworkSystem.java:165)
at net.minecraft.server.MinecraftServer.updateTimeLightAndEntities(MinecraftServer.java:659)
at net.minecraft.server.MinecraftServer.tick(MinecraftServer.java:547)
at net.minecraft.server.integrated.IntegratedServer.tick(IntegratedServer.java:111)
at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:427)
at net.minecraft.server.MinecraftServer$2.run(MinecraftServer.java:685)


A detailed walkthrough of the error, its code path and all known details is as follows:
---------------------------------------------------------------------------------------

-- Head --
Stacktrace:
at net.minecraft.network.NetHandlerPlayServer.processPlayerBlockPlacement(NetHandlerPlayServer.java:620)
at net.minecraft.network.play.client.C08PacketPlayerBlockPlacement.processPacket(SourceFile:60)
at net.minecraft.network.play.client.C08PacketPlayerBlockPlacement.processPacket(SourceFile:9)
at net.minecraft.network.NetworkManager.processReceivedPackets(NetworkManager.java:212)

-- Ticking connection --
Details:
Connection: net.minecraft.network.NetworkManager@203ab1e1
Stacktrace:
at net.minecraft.network.NetworkSystem.networkTick(NetworkSystem.java:165)
at net.minecraft.server.MinecraftServer.updateTimeLightAndEntities(MinecraftServer.java:659)
at net.minecraft.server.MinecraftServer.tick(MinecraftServer.java:547)
at net.minecraft.server.integrated.IntegratedServer.tick(IntegratedServer.java:111)
at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:427)
at net.minecraft.server.MinecraftServer$2.run(MinecraftServer.java:685)

-- System Details --
Details:
Minecraft Version: 1.7.10
Operating System: Windows 7 (amd64) version 6.1
Java Version: 1.7.0_51, Oracle Corporation
Java VM Version: Java HotSpot(TM) 64-Bit Server VM (mixed mode), Oracle Corporation
Memory: 862425928 bytes (822 MB) / 1037959168 bytes (989 MB) up to 1037959168 bytes (989 MB)
JVM Flags: 3 total; -Xincgc -Xmx1024M -Xms1024M
AABB Pool Size: 0 (0 bytes; 0 MB) allocated, 0 (0 bytes; 0 MB) used
IntCache: cache: 0, tcache: 0, allocated: 0, tallocated: 0
FML: MCP v9.05 FML v7.10.85.1230 Minecraft Forge 10.13.2.1230 4 mods loaded, 4 mods active
mcp{9.05} [Minecraft Coder Pack] (minecraft.jar) Unloaded->Constructed->Pre-initialized->Initialized->Post-initialized->Available->Available->Available->Available
FML{7.10.85.1230} [Forge Mod Loader] (forgeBin-1.7.10-10.13.2.1230.jar) Unloaded->Constructed->Pre-initialized->Initialized->Post-initialized->Available->Available->Available->Available
Forge{10.13.2.1230} [Minecraft Forge] (forgeBin-1.7.10-10.13.2.1230.jar) Unloaded->Constructed->Pre-initialized->Initialized->Post-initialized->Available->Available->Available->Available
Ark_RuneBlock{v0.1} [RuneBlock] (bin) Unloaded->Constructed->Pre-initialized->Initialized->Post-initialized->Available->Available->Available->Available
Profiler Position: N/A (disabled)
Vec3 Pool Size: 0 (0 bytes; 0 MB) allocated, 0 (0 bytes; 0 MB) used
Player Count: 1 / 8; [EntityPlayerMP['Player680'/183, l='New World', x=286.37, y=4.00, z=-1259.41]]
Type: Integrated Server (map_client.txt)
Is Modded: Definitely; Client brand changed to 'fml,forge'
[18:44:17] [Client thread/INFO]: [net.minecraft.client.Minecraft:displayCrashReport:354]: #@!@# Game crashed! Crash report saved to: #@!@# .\crash-reports\crash-2015-01-08_18.44.17-server.txt
[18:44:17] [Client thread/INFO]: Waiting for the server to terminate/save.
[18:44:17] [server thread/INFO]: Saving chunks for level 'New World'/Nether
[18:44:17] [server thread/INFO]: Saving chunks for level 'New World'/The End
[18:44:17] [server thread/INFO]: Unloading dimension 0
[18:44:17] [server thread/INFO]: Unloading dimension -1
[18:44:17] [server thread/INFO]: Unloading dimension 1
[18:44:17] [server thread/INFO]: Applying holder lookups
[18:44:17] [server thread/INFO]: Holder lookups applied
[18:44:17] [server thread/INFO]: The state engine was in incorrect state SERVER_STOPPING and forced into state SERVER_STOPPED. Errors may have been discarded.
[18:44:17] [Client thread/INFO]: Server terminated.
AL lib: (EE) alc_cleanup: 1 device not closed

 

I tried debugging, but it doesn't crash during debug if I put a breakpoint on the the Container being instantiated and then stepping through the code line by line. Going into debug mode and having the code run it's course without any breakpoints still crashes the game, however.

Link to comment
Share on other sites

If you step through all the breakpoints, it should crash. You probably just didn't step through enough. If there's a breakpoint on a line, the program pauses before executing that line.

 

I would look here:

Caused by: java.lang.NullPointerException
at net.minecraft.network.NetHandlerPlayServer.processPlayerBlockPlacement(NetHandlerPlayServer.java:620) ~[NetHandlerPlayServer.class:?]

 

Go into the NetHandlerPlayServer class, and put breakpoints around line 620, on every line inside the

processPlayerBlockPlacement()

method.

Link to comment
Share on other sites

Alright. I figured out the issue and the GUI opens/closes without crashing as well as giving the player an item when opened.

 

Final thing: buttons. Making changes to the GUI client side when a button is pressed is easy enough, but how to detect a button press server side? Need to make a button press detectable by the container so that, upon button press, the container can handle giving the player an item. Packets are needed I'm sure, so I got started on that. Once I was nearly done for testing, I realized I had no idea how to "connect" the server side packet and the container.

Link to comment
Share on other sites

On the server when you receive the packet it gives you the player so you can get the container from player.openContainer.

 

Remember to use null checks

Could you elaborate more on those? I've never done this and trying to learn how to, so I'm going to need it more spelled out than the average guy.

 

Well. It doesn't seem I actually need access to the container. As soon as the packet is received (previously sent by clicking a button), I can just add items to the EntityPlayerMP's inventory no problem. EDIT:: Thought this was working, but the inventory gets unsync'd. Figured as much to begin with.

 

I asked about getting access to the container because I figured I would put whatever logic there to handle adding/removing items and just call the functions to do so from the container itself.

Link to comment
Share on other sites

Alright. I figured out the issue and the GUI opens/closes without crashing as well as giving the player an item when opened.

 

Final thing: buttons. Making changes to the GUI client side when a button is pressed is easy enough, but how to detect a button press server side? Need to make a button press detectable by the container so that, upon button press, the container can handle giving the player an item. Packets are needed I'm sure, so I got started on that. Once I was nearly done for testing, I realized I had no idea how to "connect" the server side packet and the container.

 

-> Server gets packet (that has pressed button ID for example)

-> Packet has MessageContext ctx, so ctx.getServerHandler().playerEntity gives you server-side player (EntityPlayerMP)

-> playerEntity.openContainer gives you container you have defined in your IGuiHandler (getClientGuiElement you returned GuiContainer for client-side and getServerGuiElement Container for server-side)

-> You can set ItemStack to player inventory by getting player's inventory either from Container (if you have passed InventoryPlayer as an argument when constructing Container for server in IGuiHandler, that would be easiest because InventoryPlayer has good methods for handling player's inventory) or from EntityPlayerMP#getInventory() (which returns inventory as ItemStack array).

Link to comment
Share on other sites

Alright. I figured out the issue and the GUI opens/closes without crashing as well as giving the player an item when opened.

 

Final thing: buttons. Making changes to the GUI client side when a button is pressed is easy enough, but how to detect a button press server side? Need to make a button press detectable by the container so that, upon button press, the container can handle giving the player an item. Packets are needed I'm sure, so I got started on that. Once I was nearly done for testing, I realized I had no idea how to "connect" the server side packet and the container.

 

-> Server gets packet (that has pressed button ID for example)

-> Packet has MessageContext ctx, so ctx.getServerHandler().playerEntity gives you server-side player (EntityPlayerMP)

-> playerEntity.openContainer gives you container you have defined in your IGuiHandler (getClientGuiElement you returned GuiContainer for client-side and getServerGuiElement Container for server-side)

-> You can set ItemStack to player inventory by getting player's inventory either from Container (if you have passed InventoryPlayer as an argument when constructing Container for server in IGuiHandler, that would be easiest because InventoryPlayer has good methods for handling player's inventory) or from EntityPlayerMP#getInventory() (which returns inventory as ItemStack array).

 

I am passing InventoryPlayer into the constructor, but I can't access it via player.openContainer.

public InventoryPlayer playerInv;

public TestGuiContainer(InventoryPlayer inv)
{
playerInv = inv;
}

Link to comment
Share on other sites

You should pass it into the constructor of your Container, not GuiContainer(which is on the client-side).

So in IGuiHandler#getServerGuiElement when you return new Container for server, you'll pass InventoryPlayer (I think you can get it from EntityPlayer#inventory) to your Container constructor.

 

 

Link to comment
Share on other sites

You should pass it into the constructor of your Container, not GuiContainer(which is on the client-side).

So in IGuiHandler#getServerGuiElement when you return new Container for server, you'll pass InventoryPlayer (I think you can get it from EntityPlayer#inventory) to your Container constructor.

 

Rofl, sorry. I get lazy with naming when I'm simply trying to figure things out. TestGuiContainer IS the container, while TestGui is the GuiContainer.

 

public class TestGuiContainer extends Container
{
public InventoryPlayer playerInv;

public TestGuiContainer(InventoryPlayer inv)
{
	playerInv = inv;
}

public void giveOre()
{
	for (int i = 0; i < playerInv.mainInventory.length; i++)
	{
		if (playerInv.mainInventory[i] == null) 
		{
			playerInv.mainInventory[i] = new ItemStack(RBItems.runiteOre, 1);
			break;
		}
	}
}

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

 

public class TestGui extends GuiContainer
{

int bgWidth = 256;
int bgHeight = 145;

//calc positions to place gui in middle of screen
int guiXPos = 0;
int guiYPos = 0;

int buttonWidth = 40;
int buttonHeight = 20;

GuiButton btnBalls;

boolean mousedOver = false;

//for drawing buttons and other GUI elements, keep everything in one image file and work with it
//as if you would with a sprite sheet (see drawTexturedModalRect comment)

public TestGui(InventoryPlayer inv) 
{
	super(new TestGuiContainer(inv));
}

@Override
public void initGui()
{
	guiXPos = (width - bgWidth) / 2;
	guiYPos = (height - bgHeight) / 2;

	buttonList.clear();
	//add button                           id      xPos        yPos      width height text
	buttonList.add(btnBalls = new GuiButton(0, guiXPos + 10, guiYPos + 70, 40, 20, "Things"));

	super.initGui();
}

@Override
public void actionPerformed(GuiButton button)
{
	switch (button.id)
	{
	case 0:
		button.displayString = "Butts";
		ClientPacket.createGuiPacket("gui");
	}

	super.actionPerformed(button);
}

@Override
public void keyTyped(char what, int keyCode)
{
	switch (keyCode)
	{
	case Keyboard.KEY_E:
		mc.displayGuiScreen(null);
	}

	super.keyTyped(what, keyCode);
}

@Override
public void mouseClicked(int x, int y, int mouseButton)
{
	if (mouseOver(x, y, guiXPos + 10, guiYPos + 50, buttonHeight, buttonWidth))
	{
		mousedOver = true;
	}
	else mousedOver = false;

	super.mouseClicked(x, y, mouseButton);
}

public boolean mouseOver(int mouseX, int mouseY, int posX, int posY, int height, int width)
{
	if ((mouseX >= posX) & (mouseY >= posY))
	{
		if ((mouseX <= (posX + width)) & (mouseY <= (posY + height)))
		{
			return true;
		}
	}

	return false;
}

@Override
protected void drawGuiContainerBackgroundLayer(float arg0, int arg1, int arg2) 
{
	guiXPos = (width - bgWidth) / 2;
	guiYPos = (height - bgHeight) / 2;

	GL11.glColor4f(1.f, 1.f, 1.f, 1.f); //RGBA
	drawDefaultBackground();
	mc.renderEngine.bindTexture(new ResourceLocation("runeblock", "textures/gui/CraftingGuiBackground.png")); //bind GUI texture
	//drawing GUI background
	drawTexturedModalRect(guiXPos, guiYPos, 0, 0, bgWidth, bgHeight); //0s are starting position with texture to draw (think sprite sheets)

	if (!mousedOver) drawTexturedModalRect(guiXPos + 10, guiYPos + 50, 0, bgHeight, buttonWidth, buttonHeight);
	else drawTexturedModalRect(guiXPos + 10, guiYPos + 50, 0, bgHeight + buttonHeight, buttonWidth, buttonHeight);
}

@Override
protected void drawGuiContainerForegroundLayer(int arg1, int arg2)
{
	fontRendererObj.drawString("Things", guiXPos + 10, guiYPos + 10, 0x000000); //last arg is hex for color
}

}

 

public class GuiHandler implements IGuiHandler
{

@Override
public Object getClientGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) 
{
	switch (ID)
	{
	case 0: return new TestGui(player.inventory);
	}

	return null;
}

@Override
public Object getServerGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) 
{
	switch (ID)
	{
	case 0: return new TestGuiContainer(player.inventory);
	}

	return null;
}

 

That's everything directly relevant to my GUI. Once I get this figured (with your help), I'll be making the class names less confusing along with actually putting comments within the code.

Link to comment
Share on other sites

ClientPacket.createGuiPacket("gui");

 

Does this method send a packet to the server, or does it just create one?

If not, this is where you'd want to send your packet to the server. You'd probably also want to include information about the player and tile entity in the packet too.

 

It does both. And no tile entities are used because, as far as I'm concerned, they aren't needed.

 

The packet is getting received and the player is getting the item, but the inventories between client and server are unsync'd. In order to see the results, I have to click on the slots to update my inventory on the client. I recorded a quick video to show it visually.

 

Link to comment
Share on other sites

I might be completely wrong and not understand what you're trying to do.

 

In your class that extends GuiContainer, you pass the InventoryPlayer in your constructor. Save it as a field and change the slots when you click on the button.

I'm not sure if the changes get synced between client and gui, but you could try... :3

Link to comment
Share on other sites

You could try IInventory#setInventorySlotContents(int, ItemStack) and then IInventory#markDirty

Not sure if that would do the trick and I cannot check from my own sources how I did that syncing right now, but I can check next time when I'm back. But anyway, let me know if it doesn't work.

Link to comment
Share on other sites

I might be completely wrong and not understand what you're trying to do.

 

In your class that extends GuiContainer, you pass the InventoryPlayer in your constructor. Save it as a field and change the slots when you click on the button.

I'm not sure if the changes get synced between client and gui, but you could try... :3

 

facepalm.jpg

 

Yep. That fixed it. Thanks everyone! I'll hopefully be able to take it from here, unless someone else has something they'd like to input to help me out.

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

    • Wow this looks a lot simpler than I thought it would be. Especially compared to the setup I had to do for capabilities. I'll look at all this and update if I have any issues ty
    • Me and a group of friends were trying to get a modpack to work so we can play together. It works for everyone else, except me. At first when I tried to import the modpack, it said "invalid file" but it didn't with anyone else's. The owner of the modpack resent it several times and I still kept getting the same issue, so I opened the modlist and downloaded every single mod by hand. I thought that it would resolve the issue, but instead, it started saying "Forge Modloader Installation Failed" after I created a new installation, so I tried to use a pre-existing modpack, made sure it was the same version "1.20.1, forge version 47.3.0" and swap the mods there, but it still had the same issue, and now none of my modpacks are working at all. They all keep saying that the modloader installation failed. None of us have any idea what to do as we aren't the techiest people. Any help is appreciated. Thank you!
    • I don't think there's any documentation on them yet, I mainly just looked at the Vanilla code when implementing mine. You can see a fairly simple example here: Registration: https://github.com/Choonster-Minecraft-Mods/TestMod3/blob/f3bea10d5f455fa0904056caafd8c844b6fd13ae/src/main/java/choonster/testmod3/init/ModDataComponents.java#L50-L58 Item Registration: https://github.com/Choonster-Minecraft-Mods/TestMod3/blob/f3bea10d5f455fa0904056caafd8c844b6fd13ae/src/main/java/choonster/testmod3/init/ModItems.java#L264-L266 Usage: https://github.com/Choonster-Minecraft-Mods/TestMod3/blob/f3bea10d5f455fa0904056caafd8c844b6fd13ae/src/main/java/choonster/testmod3/world/item/EntityCheckerItem.java
    • Okay, I'm glad I made a backup then. I'm confused as to where there is any information on how to work with Data Components. I don't see anything about it on the Forge docs or any tutorials on this in general unless I'm missing it somehow. I can see the DataComponents decompiled class file but I'm not sure how to work with it. Maybe it's beyond my technical expertise?
    • The situation is the same in 1.20.6. Data Components were introduced in 1.20.5/1.20.6 and Item Capabilities haven't been re-implemented since then.
  • Topics

×
×
  • Create New...

Important Information

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