Posted November 7, 20168 yr I'm working with a system of: Press Keybinding to open "Player Class Menu" Select Class and/or Profession in GUI Press save Fire packet from client to server check to see if player has a class, no class allow free class change. Else check to see if they have enough gold to change. Send Response Packet to update client (server > client) Where it apparently is failing is I'm guessing the saving portion within the "requestPacket"(client > server) As the changes never stay, or save. [spoiler=gui code] package htd.rot.client.gui; import org.lwjgl.opengl.GL11; import htd.rot.Rot; import htd.rot.capability.attribute.CapAttribute; import htd.rot.capability.attribute.CapAttributeData; import htd.rot.capability.playerextra.CapPlayerExtra; import htd.rot.capability.playerextra.CapPlayerExtraData; import htd.rot.comms.packets.ClassRequestPacket; import htd.rot.comms.packets.ProfessionRequestPacket; import htd.rot.managers.PacketManager; import htd.rot.managers.PlayerCPTypeManager; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.inventory.GuiContainer; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.util.ResourceLocation; public class GuiClassSelection extends GuiContainer { public static final ResourceLocation texture = new ResourceLocation(Rot.MODID.toLowerCase(), "textures/gui/rotGui.png"); private EntityPlayer player; private int pad = 4; private int ch = 20; private int selectedClass = -1; private int selectedProfession = -1; public GuiClassSelection(EntityPlayer player) { super(new ContainerNull()); this.player = player; this.xSize = 176; this.ySize = 166; this.selectedClass = player.getCapability(CapPlayerExtra.CAPABILITY, null).currentClass; this.selectedProfession = player.getCapability(CapPlayerExtra.CAPABILITY, null).currentProfession; } /** Button Clicks **/ @Override protected void actionPerformed(GuiButton button) { switch (button.id) { case 0: // Class Forward this.selectedClass++; this.selectedClass = this.selectedClass == PlayerCPTypeManager.classes.length ? 0 : this.selectedClass; break; case 1: // Class Back this.selectedClass--; this.selectedClass = this.selectedClass < 0 ? PlayerCPTypeManager.classes.length - 1 : this.selectedClass; break; case 2: // Change Class PacketManager.INSTANCE.sendToServer(new ClassRequestPacket(selectedClass)); break; case 3: // Refresh Class PacketManager.INSTANCE.sendToServer(new ClassRequestPacket(0)); break; case 4: // Profession Forward this.selectedProfession++; this.selectedProfession = this.selectedProfession == PlayerCPTypeManager.professions.length ? 0 : this.selectedProfession; break; case 5: // Profession Back this.selectedProfession--; this.selectedProfession = this.selectedProfession < 0 ? PlayerCPTypeManager.professions.length - 1 : this.selectedProfession; break; case 6: // Change Profession PacketManager.INSTANCE.sendToServer(new ProfessionRequestPacket(selectedProfession)); break; case 7:// Refresh Profession PacketManager.INSTANCE.sendToServer(new ProfessionRequestPacket(0)); break; } } @Override protected void drawGuiContainerBackgroundLayer(float f, int i, int j) { /* * TextureManager manager = Minecraft.getMinecraft().renderEngine; * manager.bindTexture(manager.getResourceLocation(1)); //RENDER ITEMS * drawTexturedModelRectFromIcon(300, 300, * RotItems.itemGunpowderInfuser.getIconFromDamage(0), 16, 16); */ GL11.glColor4f(1F, 1F, 1F, 1F); Minecraft.getMinecraft().renderEngine.bindTexture(texture); drawTexturedModalRect(this.guiLeft, this.guiTop, 0, 0, this.xSize, this.ySize); this.buttonList.clear(); // Start with main control buttons CapPlayerExtraData playerExtra = player.getCapability(CapPlayerExtra.CAPABILITY, null); CapAttributeData attrs = player.getCapability(CapAttribute.CAPABILITY, null); int x1 = this.guiLeft + this.pad; int x2 = (this.guiLeft + this.xSize) - (8 + this.pad); int x3 = (x2 + x1) / 2; int textY = this.guiTop + this.pad; int textX = (this.guiLeft + this.xSize) + pad; this.buttonList.add(new GuiClassSelectionButton(0, x2, this.guiTop + this.pad, "", 1)); this.buttonList.add(new GuiClassSelectionButton(4, x2, this.guiTop + this.pad + (8 * 2), "", 1)); this.drawString(this.fontRendererObj, this.selectedClass != -1 ? PlayerCPTypeManager.classes[this.selectedClass].className : "None", x3, this.guiTop + this.pad + 5, 0xddeeee); this.drawString(this.fontRendererObj, this.selectedProfession != -1 ? PlayerCPTypeManager.professions[this.selectedProfession].professionName : "None", x3, this.guiTop + this.pad + 20, 0xddeeee); this.buttonList.add(new GuiClassSelectionButton(1, x2 - 8, this.guiTop + this.pad, "", 0)); this.buttonList.add(new GuiClassSelectionButton(2, x2 - 8, this.guiTop + this.pad + 8, "", 2)); this.buttonList.add(new GuiClassSelectionButton(3, x2, this.guiTop + this.pad + 8, "", 3)); this.buttonList.add(new GuiClassSelectionButton(5, x2 - 8, this.guiTop + this.pad + (8 * 2), "", 0)); this.buttonList.add(new GuiClassSelectionButton(6, x2 - 8, this.guiTop + this.pad + (8 * 3), "", 2)); this.buttonList.add(new GuiClassSelectionButton(7, x2, this.guiTop + this.pad + (8 * 3), "", 3)); this.drawString(this.fontRendererObj, "Current Class:", textX, textY, 0xdbdd15); textY += 15; this.drawString(this.fontRendererObj, playerExtra.currentClass == -1 ? "None" : PlayerCPTypeManager.classes[playerExtra.currentClass].className, textX, textY, 0xdbdd15); textY += 15; for (int index = 0; index < attrs.attributes.length;index++) { this.drawString(this.fontRendererObj, attrs.ATTRIBUTE_TAGS[index] + ": " + attrs.attributes[index], textX, textY, attrs.attributes[index] == 0 ? 0xFFFFFF : attrs.attributes[index] > 0 ? 0x00ff42 : 0xff0c00); textY += 15; } this.drawString(this.fontRendererObj, "Current Profession:", textX, textY, 0xdbdd15); textY += 15; this.drawString(this.fontRendererObj, playerExtra.currentProfession == -1 ? "None" : PlayerCPTypeManager.professions[playerExtra.currentClass].professionName, textX, textY, 0xdbdd15); // Visual information on location /* * this.drawString(fontRendererObj, "X: "+(xOffset+te.xCoord)+ * " offSet: "+xOffset, (startLeft + ((gridSizeX * 2) * cw)) + cw * 5, * (startTop + (gridSizeZ * ch) + 4) - ch, 0xFFFFFF); * this.drawString(fontRendererObj, "Y: "+(yOffset+te.yCoord)+ * " offSet: "+yOffset, (startLeft + ((gridSizeX * 2) * cw)) + cw * 5, * (startTop + (gridSizeZ * ch) + 4), 0xFFFFFF); * this.drawString(fontRendererObj, "Z: "+(zOffset+te.zCoord)+ * " offSet: "+zOffset, (startLeft + ((gridSizeX * 2) * cw)) + cw * 5, * (startTop + (gridSizeZ * ch) + 4) + ch, 0xFFFFFF); */ } /** Keyboard Clicks **/ @Override protected void keyTyped(char par1, int par2) { if ((par2 == 1) || (par2 == this.mc.gameSettings.keyBindInventory.getKeyCode())) { this.mc.thePlayer.closeScreen(); } } } [spoiler=request packet] package htd.rot.comms.packets; import htd.rot.capability.playerextra.CapPlayerExtra; import htd.rot.capability.playerextra.CapPlayerExtraData; import io.netty.buffer.ByteBuf; import net.minecraft.entity.player.EntityPlayer; import net.minecraftforge.fml.common.network.simpleimpl.IMessage; import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; public class ClassRequestPacket implements IMessage { public static class ClassRequestPacketHandler implements IMessageHandler<ClassRequestPacket, IMessage> { @Override public IMessage onMessage(ClassRequestPacket message, MessageContext ctx) { final int goldCost = 500; if (message.classID == -1) { return null; } EntityPlayer player = ctx.getServerHandler().playerEntity; CapPlayerExtraData props = player.getCapability(CapPlayerExtra.CAPABILITY, null); if (props.currentClass == -1) { props.currentClass = message.classID; return new ClassResponsePacket(props.currentClass,props.gold); } else { if (props.playerInfo[props.gold] >= goldCost) { props.playerInfo[props.gold] -= goldCost; props.currentClass = message.classID; return new ClassResponsePacket(props.currentClass,props.gold); } } return null; } } public int classID; public ClassRequestPacket() { } public ClassRequestPacket(int className) { this.classID = className; } @Override public void fromBytes(ByteBuf buf) { this.classID = buf.readInt(); } @Override public void toBytes(ByteBuf buf) { buf.writeInt(this.classID); } } [spoiler=response packet] package htd.rot.comms.packets; import htd.rot.capability.playerextra.CapPlayerExtra; import htd.rot.capability.playerextra.CapPlayerExtraData; import io.netty.buffer.ByteBuf; import net.minecraft.client.Minecraft; import net.minecraft.entity.player.EntityPlayer; import net.minecraftforge.fml.common.network.simpleimpl.IMessage; import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; public class ClassResponsePacket implements IMessage { public static class ClassResponsePacketHandler implements IMessageHandler<ClassResponsePacket, IMessage> { @Override public IMessage onMessage(ClassResponsePacket message, MessageContext ctx) { EntityPlayer player = Minecraft.getMinecraft().thePlayer; player.getCapability(CapPlayerExtra.CAPABILITY, null).currentClass = message.classID; player.getCapability(CapPlayerExtra.CAPABILITY, null).playerInfo[CapPlayerExtraData.gold] = message.gold; return null; } } public int classID, gold; public ClassResponsePacket() { } public ClassResponsePacket(int className, int gold) { this.classID = className; this.gold = gold; } @Override public void fromBytes(ByteBuf buf) { this.classID = buf.readInt(); this.gold = buf.readInt(); } @Override public void toBytes(ByteBuf buf) { buf.writeInt(this.classID); buf.writeInt(this.gold); } } I'm pulling most of my code from the old 1.8.2 era and trying to touch it up. And this is more or less the same format Oh the packet registery (for the sides, hopefully I have them correct, I do get some action if I use a Console.Out in the request so it's at least going somewhere) INSTANCE.registerMessage(CapAttributePacketHandler.class, CapAttributePacket.class, packetId++, Side.CLIENT); INSTANCE.registerMessage(CapPlayerExtraPacketHandler.class, CapPlayerExtraPacket.class, packetId++, Side.CLIENT); INSTANCE.registerMessage(CapPlayerUpdateRequestPacketHandler.class, CapPlayerUpdateRequestPacket.class, packetId++, Side.SERVER); INSTANCE.registerMessage(ClassGUIPacketHandler.class, ClassGUIPacket.class, packetId++, Side.SERVER); INSTANCE.registerMessage(ClassRequestPacketHandler.class, ClassRequestPacket.class, packetId++, Side.SERVER); INSTANCE.registerMessage(ClassResponsePacketHandler.class, ClassResponsePacket.class, packetId++, Side.CLIENT); INSTANCE.registerMessage(ProfessionRequestPacketHandler.class, ProfessionRequestPacket.class, packetId++, Side.SERVER); INSTANCE.registerMessage(ProfessionResponsePacketHandler.class, ProfessionResponsePacket.class, packetId++, Side.CLIENT); Currently updating my Mod to 1.10.2 https://bitbucket.org/hugo_the_dwarf/riseoftristram2016/src?at=master
November 7, 20168 yr Packet handlers are run on a separate thread, you must schedule a task to run on the main thread before you can safely interact with normal Minecraft classes. Forge's documentation explains this here. Apart from that, your code looks like it should work. Could you post the ICapabilityProvider you attach to players to provide your capability? Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.
November 7, 20168 yr Author [spoiler=CapPlayerExtraProvider] package htd.rot.capability.playerextra; import htd.rot.Rot; import net.minecraft.entity.EntityLivingBase; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.EnumFacing; import net.minecraft.util.ResourceLocation; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.ICapabilityProvider; import net.minecraftforge.common.capabilities.ICapabilitySerializable; public class CapPlayerExtraProvider implements ICapabilityProvider, ICapabilitySerializable<NBTTagCompound> { public static final ResourceLocation KEY = new ResourceLocation(Rot.MODID, "htd_playerextra"); private CapPlayerExtraData INSTANCE = new CapPlayerExtraData(); public CapPlayerExtraProvider(EntityLivingBase entity) { INSTANCE.setEntity(entity); } @Override public boolean hasCapability(Capability<?> capability, EnumFacing facing) { return capability == CapPlayerExtra.CAPABILITY; } @Override public <T> T getCapability(Capability<T> capability, EnumFacing facing) { if (capability == CapPlayerExtra.CAPABILITY)return (T)INSTANCE; return null; } @Override public NBTTagCompound serializeNBT() { return (NBTTagCompound)CapPlayerExtra.CAPABILITY.writeNBT(INSTANCE, null); } @Override public void deserializeNBT(NBTTagCompound nbt) { CapPlayerExtra.CAPABILITY.readNBT(INSTANCE, null, nbt); } } I know strangely if I have the Capability randomly assign values to values, and have a full data sync (so server and client are out of sync with different Random.nextInt() values) the client will be updated through the code in the playerTick and livingUpdate events with a simple just fire it off from the server to client (dataChanged() method). So would I have to rewrite some of my packet handlers to appear like this? @Override public IMessage onMessage(ClassGUIPacket message, MessageContext ctx) { // Open the gui on the server so we can actually do stuff. EntityPlayer player = ctx.getServerHandler().playerEntity; ctx.getServerHandler(). playerEntity. getServerWorld(). addScheduledTask( new Runnable() { public void run() { player.openGui(Rot.INSTANCE, GuiHandler.CLASS_GUI, player.worldObj, (int) player.posX, (int) player.posY, (int) player.posZ); } }); return null; } } Of course if I have a request/repsonse system would I add inside the runnable (task) a "PacketManager.INSTANCE.SendTo()" and just leave my returns as NULL? Currently updating my Mod to 1.10.2 https://bitbucket.org/hugo_the_dwarf/riseoftristram2016/src?at=master
November 7, 20168 yr Author OMG I'm just an idiot Was switching from an old way how I did things to a new way that I figure would be "easier" to manage the reading/writing of packet buffers and NBT Where I have 3 vars 2 of them are arrays One set to be a named Index One Array for Name/Keys Final Array for stored Data So in the given packet classes I have "props.currentClass" which is my index... It should have been "props.playerInfo[props.currentClass]" So now i'm changing the indexes to FINAL and making them all CAPS, and will be creating some getter/setter methods EDIT: Thanks for the help, but I still have the question of the New Runable(SendTo(message,player)) for my request packets to send the response. or any packet for that matter. Currently updating my Mod to 1.10.2 https://bitbucket.org/hugo_the_dwarf/riseoftristram2016/src?at=master
November 7, 20168 yr Yes, the return value of IMessageHandler#onMessage isn't that useful these days, since you need to do the actual processing asynchronously on the main thread. Just send the response message manually with your SimpleNetworkWrapper instance. Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.
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.