Jump to content

[1.7.10] Calculations Server Side Only?


HalestormXV

Recommended Posts

Outstanding. Yeah I register everything in one MainClass and utilize functions to register other classes all at once. I plan to change to a more universal style once I do another mod. I won't change it now though because I am so deep into it that it doesn't pay.

 

So using the if check worked wonderfully and the server boots up without a problem.

 

I think I have one other issue. I bound my HotKey packet "openInventory"  to a keypress that is supposed to be attached to an item.

 

It is basically a backpack. What it does is really simple since I just wanted to learn how packets work. By pressing the "Y" key you open a custom inventory which works flawlessly. However on a server if you press the Y key and you are not holding the Backpack item the client crashes with a Fatal Exeception. Here is the Exception the server spits out:

http://pastebin.com/WDh4rMXR

 

So once again it is a Fatal Exception, not a crash. This only happens on a server which to my understanding means it is packet related. Now to be quite honest I really don't know which class is causing this, although whatever it is shouldn't be attempting to open that inventory to begin with unless that Backpack is somewhere in your inventory. Now I know I likely didn't tell the code this since I am just learning. Ultimately if the backpack isn't anywhere in your inventory and you press the Y key, nothing should happen. But I don't know where I would put that check or how to make that check as the key pressing occurs in the KeyHandler, and there is nothing in there to get the player.

 

And I truly am most appreciative of all the help I am getting. It is amazing how far I have come from the start of this thread to now at the time of this post. Tackling the packets has been quite fun, and I am enjoying all the knowledge and tips very much, so thank you.

Link to comment
Share on other sites

  • Replies 62
  • Created
  • Last Reply

Top Posters In This Topic

Fatal Exception is a crash.  Specifically you have a Null Pointer:

 

java.lang.NullPointerException
    at com.halestormxv.inventory.InventoryKeyPouch.<init>(InventoryKeyPouch.java:34) ~[inventoryKeyPouch.class:?]

 

On line 34 of your InventoryKeyPouch class, something is null.

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

Fatal Exception is a crash.  Specifically you have a Null Pointer:

 

java.lang.NullPointerException
    at com.halestormxv.inventory.InventoryKeyPouch.<init>(InventoryKeyPouch.java:34) ~[inventoryKeyPouch.class:?]

 

On line 34 of your InventoryKeyPouch class, something is null.

 

Yeah, your right lol. I made that post at 2:30 in the morning :P I guess what i meant was that the client doesn't shutdown, it just boots you from the server and the server just throws that error. Here is the class: http://pastebin.com/NMkgK7TY  I followed coolAlias's tut (also at 2:30 in the morning) so perhaps I missed something when making my changes?

 

It appears that the error gets thrown right as it tries to create a Compound/read from it. What makes this odd is that it seems to happen when items are in the inventory and you press the shortcutkey o_O So something is wrong in that class somewhere or in my packet? Perhaps it tried to read the NBT that was non-existent and skipped over the check where if it doesn't exist to set it? It appears the only time it happens is if there are items in the inventory and then you use the hotkey to open the bag. Otherwise when you open it with a right click there is no issue with or without items in it.

 

Perhaps I have to have the packet read from the NBT as well and not just attempt to open the GUI? Since in my mind trying to open the GUI via packet and you don't let the packet know that there is NBT data in there it might throw that null? Where as when you simply right click it knows there is NBT in there? Here is the packet: http://pastebin.com/MXDpVYAU

=============

=============

@UberAffe: That makes sense. How would I go about doing that exactly? I know how we check using the worldRemote, but how would i check if the item is serverside and in the player's inventory? I know typically for items i use the onUpdate to add "permanent" buffs while it is in the inventory.

Link to comment
Share on other sites

It looks like you are passing NULL rather than a valid ItemStack to your IInventory constructor. Show your IGuiHandler class.

 

Also, you don't need to pass the player's position when opening a GUI unless you need them for some reason; those last 3 parameters are usually used for Block-based GUIs to pass the BlockPos coordinates.

 

As for checking things on the server side, that's what you do when you handle your packet - recall it was sent from the client to the server and you should know or be able to check which side you are on when you receive it.

 

Then, just loop through the player's inventory and check each slot for your special inventory item. If you find it, go ahead and open the inventory, otherwise don't. Simple as that.

Link to comment
Share on other sites

I linked the old packet in the above post accidentally (I since changed it).

This is the correct one I am using: http://pastebin.com/MXDpVYAU

And here is the implementation of IGuiHandler: http://pastebin.com/p1meeccz

That is where I handle all my GUIs, and yes I am returning null as that is what I did for all the GUIs. I suppose I am supposed to be returning the itemstack?

 

 

Here is the Inventory which implements IInventory: http://pastebin.com/G52kbWkK

 

And with respect to the looping of the inventory I can essentially do that within the packet correct? Ideally I am only executing this:

player.openGui(MainRegistry.modInstance, message.id, player.worldObj, (int) player.posX, (int) player.posY, (int) player.posZ);

if that particular inventory item is in the player's inventory, so essentially I can just write the check over there? And if we don't have the item in the inventory we will never send that player.openGui

Link to comment
Share on other sites

Yeah, your right lol. I made that post at 2:30 in the morning :P I guess what i meant was that the client doesn't shutdown, it just boots you from the server and the server just throws that error.

 

The server thread crashed but the client thread did not.  That shuts down the SSP world and boots the client connection.

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

No.

 

If the client thread "stops" or crashes, the whole thing comes down and you are returned to Eclipse.

 

The server thread crashed but the client thread did not.  That shuts down the SSP world and boots the client connection.

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

Okay, so your problem is that your IGuiHandler code expects the player to be holding the backpack, but you are opening it from a key press so that is not necessarily true. The player might not be holding anything - i.e. NULL - but still have the backpack somewhere in their inventory.

 

So you have 2 options:

 

1. Restrict opening of the backpack to when it is in the player's hand by checking that condition when receiving the packet server side. This makes it pointless to use a key press, however, as the player may as well just right-click use the item and open the GUI from there.

 

2. Loop through the player's inventory again to find the backpack ItemStack instance so you can use it to create the inventory. To avoid looping, you could pass the inventory slot index of the backpack from your packet:

for (i = 0; i < player.inventory.size(); ++i) {
  if (inventory[i] is backpack item) {
    player.openGui(MainRegistry.modInstance, message.id, player.worldObj, i, 0, 0);
  }
}

In your IGuiHandler, 'x' will now contain the slot index, so you can easily retrieve the ItemStack you need.

Link to comment
Share on other sites

Alright, I totally didn't understand that post or at least I don't think I understood it the way it was supposed to be understood. Sorry about that.

 

In other words, in my OpenGuiPacketAlt: http://pastebin.com/VChbFb8G

I am going to create a loop check (I am opting for option 2) in the public IMessage handleServerMessage? It is basically going to go like this?

 

public static class Handler extends AbstractServerMessageHandler<OpenGuiPacketAlt> 
{
	@Override
	public IMessage handleServerMessage(EntityPlayer player, OpenGuiPacketAlt message, MessageContext ctx)
	{
		for (int slot = 0; slot < player.inventory.getSizeInventory(); slot++)
		{
			if (player.inventory.getStackInSlot(slot).getItem() == CelestialCraft_items.keyPouch)
			{
				System.out.println("Congratulations you finally created a frigen packet that works!");
				player.openGui(MainRegistry.modInstance, message.id, player.worldObj, slot, 0, 0);
			}	
		}	
		return null;
	}
}

 

 

That would be the first part? Or is this check going into my GUI handler? I think that is where I am getting confused. Like I get it. My GUI handler is using that getItemHeld() (is that even needed?) and that is why the Hotkey works if you have the item in your hand. But if you aren't holding it is crashes because it is looking for the backpack and nothing is there (being held). So I  understand that part but I guess I am just confused as to where I am lopping the inventory and then passing my slotID indicating that the item is indeed somewhere in the inventory.

 

Or would it go something like run that loop in the GUIhandler, collect the slot and then use that slotID in the:

return new GuiCelestialKeyPouch((ContainerCelestialKeypouch) new ContainerCelestialKeypouch(player, player.inventory, new InventoryKeyPouch(player.getHeldItem())));

of the GUIhander instead of the player.getHeldItem

Link to comment
Share on other sites

You're passing the slot index so that you can retrieve the ItemStack from the inventory rather than using player.getHeldItem(), since you're not requiring the item to be held.

 

So replace 'player.getHeldItem()' with:

ItemStack stack = player.inventory.getStackInSlot(x); // where 'x' is a method parameter passed via IGuiHandler
// maybe check again if the stack is correct, just to be safe
// then pass it into your inventory constructor when returning the GUI or Container, e.g.:
return new GuiCelestialKeyPouch((ContainerCelestialKeypouch) new ContainerCelestialKeypouch(player, player.inventory, new InventoryKeyPouch(stack)));

Link to comment
Share on other sites

You're passing the slot index so that you can retrieve the ItemStack from the inventory rather than using player.getHeldItem(), since you're not requiring the item to be held.

 

So replace 'player.getHeldItem()' with:

ItemStack stack = player.inventory.getStackInSlot(x); // where 'x' is a method parameter passed via IGuiHandler
// maybe check again if the stack is correct, just to be safe
// then pass it into your inventory constructor when returning the GUI or Container, e.g.:
return new GuiCelestialKeyPouch((ContainerCelestialKeypouch) new ContainerCelestialKeypouch(player, player.inventory, new InventoryKeyPouch(stack)));

 

Ahhh, I see, i didn't think i could pass the InventoryKeyPouch(stack) like that. Sneaky and genius at the same time lol. So basically what is happening in my packet I create the loop like so:

public static class Handler extends AbstractServerMessageHandler<OpenGuiPacketAlt> 
{
	@Override
	public IMessage handleServerMessage(EntityPlayer player, OpenGuiPacketAlt message, MessageContext ctx)
	{
		for (int slot = 0; slot < player.inventory.getSizeInventory(); slot++)
		{
			if (player.inventory.getStackInSlot(slot) != null)
			{
				if (player.inventory.getStackInSlot(slot).getItem() == CelestialCraft_items.keyPouch)
				{
					System.out.println("Congratulations you finally created a frigen packet that works!");
					player.openGui(MainRegistry.modInstance, message.id, player.worldObj, slot, 0, 0);
				}
			}
		}	
		return null;
	}
}

 

So what this essentially doing is taking the X variable that is required by the openGUI method and just storing the SlotID in it, instead of an X coord. I was TOTALLY restricting myself thinking that the X HAD to be a coord or a 0, when really it is just an integer in the code language. Once we dispatch this packet the SlotID is stored with it so it gets passed with it in there. Then all we are simply doing in the GUI handler is saying to fetch the slotID or the "X" (since it is going to be the same that we passed via the packet) Thanks uber for the nullCheck tip.

 

Brilliant! And of course upon looking at it like that and coding it as such. Guess what, it works lol.

 

Here is the new OpenGUIPacket code: http://pastebin.com/FPKGukRD

Here is the GUI Handler Code: http://pastebin.com/U0QKijJG  (specifically line 44, 45, 72 and 73 handle the backpack)

Here is the InventoryKeyPouch class: http://pastebin.com/uzF6B9a7

 

I only have what appears to be one more issue. A new error has cropped up with my changes. The game will now crash if I right-click to open the bag with it selected. However if I press Y with the bag selected it will open fine. I imagine this is a simple error on my part that can be easily fixed? Hopefully. Help? lol

 

Here is the new error: http://pastebin.com/gcsedduq

 

Thank you again for all the help to everyone!!

Link to comment
Share on other sites

That's the same error, but caused because when you right click, you aren't sending a packet and thus not sending the slot index (well, hopefully you're sending '0').

 

You can fix the issue by sending player.inventory.currentItem, or you can also do a check for the player's held item in the IGuiHandler code and use that if it is correct, or you can pass a 'flag' such as -1 as the slot index when right-clicked which you can check for to know that you need to use the held item instead of the inventory slot.

Link to comment
Share on other sites

Nailed it! Thank you so much everyone! I have 2 remaining issues that seems to have popped up lol. (Please don't hate me, I am literally learning so damn much from this it is incredible lol). I do however know what is causing it I think.

 

But first here is the new code: (btw I keep posting the new code so others can learn from this as many of you who know me I like to learn and share what i learn)

 

GUI Handler: http://pastebin.com/wcrb2v8L

Packet: http://pastebin.com/RNumzySi

 

The first issue is now that I don't crash anymore, I realize however that if I have the item currently equipped and right click it the inventory is not stored and it is (the container) empty. However if I press Y while having the bag equipped I see the inventory inside it. Is this a sync issue or is this because I am calling a "new instance" of the container with my check?

=====================

Now the last remaining issue I think has to do with Shift Clicking. What it appears is going on is when you have the inventory open and you shift click items into it (you are only allowed a certain type of item, and that part is working fine) it leave a "ghost" duplicate of the item in your inventory and puts the real one in the bag. The ghost duplicate item can't be picked up, dragged, or anything. It just sits there in the inventory. If you try to right click the item it disappears. This only happens when shift clicking the item into the bag. If you actually click and drag it into the bag it doesn't leave any "ghost" items or anything like that.

 

Here is the inventory: http://pastebin.com/g9Em0XVc

Here is the container class: http://pastebin.com/6mPtXky0

 

What I am curious about is this what that "desync" issue is that you guys said might occur? Or is this just something wrong in the Shift+Click code?

 

Once again, coolAlias and Uber your both awesome and thank you for helping me out with this. Please know that I am not just "getting help" your both genuinely teaching me about this and I am learning and I am willing to keep working at it. Just like I did with the packets. At the start of this thread I didn't know a damn thing about them lol.

 

 

Link to comment
Share on other sites

The shift-click ghost issue is one I have noticed occurs when you limit the stack size of your inventory slot to 1 - is this perhaps the case with your inventory?

 

If so, the issue isn't your code, it's Mojang's, but you can fix it by overriding #mergeItemStack in your Container class and using the code found in that link. That implementation I wrote myself almost 2 years ago now, but I've seen others do it slightly differently since then that you may want to look at also, or if you want a challenge you can avoid looking at my or anyone else's code and see if you can't figure out what's wrong with Mojang's implementation on your own ;)

Link to comment
Share on other sites

Thanks I will have a look. I just edited my post to add another issue that just creeped up.

 

now that I don't crash anymore, I realize however that if I have the item currently equipped and right click it the inventory is not stored and it is (the container) empty. However if I press Y while having the bag equipped I see the inventory inside it. Is this a sync issue or is this because I am calling a "new instance" of the container with my check?

 

If that is the case, how can I make sure I am calling the same container/inventory?

Link to comment
Share on other sites

Here is the item code: http://pastebin.com/xPDRG7dq

 

And yes I limited my stack size to 1 to answer your prior question, and I am actually using that link you posted as the Shift+click code. Most of what I learn is from your tutorials lol and I piece through each part. This item actually happens to be based off your tutorial.

 

Should I do the same slot check i did in the GUI handler here and maybe that will resolve it?

 

EDIT: Figured it out I think. I changed the line in the item code to this:

player.openGui(MainRegistry.instance, CelestialCraft_items.guiIDKeyPouch, world, player.inventory.currentItem, 0, 0);

 

Because in the item code it was opening a "new" gui and not using the parameters I passed when the NBT data was written I guess when I pressed Y? So by changing it to the currentItem it made sure it was the EXACT same as when you are pressing the Y key?

 

Or am I totally wrong lol. But it seems to work now? Unless that is because shut down the client and logged back in and it read the data?

 

Link to comment
Share on other sites

No, but since you're passing '0', chances are you are getting a non-null but incorrect ItemStack in that slot in your IGuiHandler, so you either need to pass player.inventory.currentItem OR actually do a real check in your IGuiHandler (which would be safer anyway) - note that you can and should do both.

// in IGuiHandler
ItemStack stack = player.inventory.getStackInSlot(x);
if (stack != null && stack.getItem() instanceof YourBackPackItem) {
  // okay to return GUI or Container element
} else {
// do nothing - invalid item
}

Link to comment
Share on other sites

Understood, I see I made my edit (i just reedited it now to change the color) right before your post. I had it working in the edited version but I just changed it to your suggestion and it works as well.

 

However I am curious, for my own knowledge sake and for proper coding practice, what do you mean by "safer?"

Link to comment
Share on other sites

However I am curious, for my own knowledge sake and for proper coding practice, what do you mean by "safer?"

Your previous code was this:

ItemStack stack = player.inventory.getStackInSlot(x);
if (stack != null) {
  return element with new inventory(stack)
}

Well, all you know is that the stack is not null - what if it's a stack of chicken meat? Or dirt? It could be anything, but your inventory constructor is expecting a specific class of Items, specifically YourBackpackItem, and if it gets anything else, you are probably going to crash.

Link to comment
Share on other sites

Ahhh, alright I see. That makes sense. I didn't think of it like that. Awesome. I think all that remains is the "ghost items" with the SHIFT+CLICK and the fact that when I open the inventory with the "Y" key and pick up an item in my inventory I can't place the item back down in any inventory slots and have to drop the item and re-pick it back up. Yet when I right click the item open, it works fine, however the ghost item still persists no matter how I open the inventory.

 

Here is the ContainerClass: http://pastebin.com/ziQuBPUg  (with the override)

Here is the Inventory Class: http://pastebin.com/Ltvir5FJ

And I took your advice in the tutorial and created a custom slot as I want only my keys to be storeable in that bag and not the actual bag itself: http://pastebin.com/tsw3tnH4

Link to comment
Share on other sites

Since it only occurs when you use a key press and not when using onItemRightClick, you can rule out your GUI and Container classes as the culprit. Show your key handler code - are you by chance opening the gui from there before or after sending the packet? Are you sending your packet?

 

Speaking of your packet... your if statements are really weird, specifically '... && i != player.inventory.currentItem)' and then the next one that checks the opposite.

 

First of all, why even check that? Does it matter if it is the held item or not? Just send the slot index to your IGuiHandler and it won't care in the slightest if it's the currentItem slot or not.

 

Second, and irrelevant (for your specific case) after you follow the above advice, but the way your if statements are written, you are checking 2 if statements every iteration through the loop. That is poor coding style. You generally want to do as few operations as possible, so always ask yourself "which is more likely?"

 

Is 'i' more likely to be equal to currentItem, or not? Check the most likely condition first, and use an 'else if' for the following conditions:

if (i != currentItem) {
  // this will happen 35 out of 36 times, and always if the item is not in the hot bar
} else if (i == currentItem) {
  // will only happen if the item is in the hotbar and i < 9
}

Furthermore, those 2 conditions are exact opposites, so you don't need 'else if', just 'else'.

 

Long story short, you need to take some time to go over Java basics so you can write better code. I recommend Oracle's tutorials - if you follow all of them diligently, you will have increased your Java skills 10 to 100-fold.

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.