Jump to content

Recommended Posts

Posted

Hi, I'm currently working on a project and got into a small problem. I try to change a value that is saved in the player using the ExtendedEntityProperties stuff, inside a gui. The only I am having is that the way I am doing it, I only change the values on the client side which makes a lot of problems. So I was wondering how I can fix this problem, is there something missing in my packet or something or do I need a new one?

 

Here is all the classes I am using for it:

 

Mod class:

 

  Reveal hidden contents

 

 

ItemTalisman class:

 

  Reveal hidden contents

 

 

GuiReligion class:

 

  Reveal hidden contents

 

 

PacketPipeline class:

 

  Reveal hidden contents

 

 

SyncPlayerPropsPacket class:

 

  Reveal hidden contents

 

 

CultureEventHandler class:

 

  Reveal hidden contents

 

 

CommonProxy class:

 

  Reveal hidden contents

 

 

ExtendedPlayer class:

 

  Reveal hidden contents

 

Posted

First, you're not using extended properties properly. Second, this code will register your Entity data with a null player. Reverse to == to != and it should fix one problem.

public void onEntityConstructing(EntityConstructing event) {
	if (event.entity instanceof EntityPlayer) {
		if (ExtendedPlayer.get((EntityPlayer) event.entity) == null)
		ExtendedPlayer.register((EntityPlayer) event.entity);
	}
}

 

Advice, the init() method is called when entity is created to set the initial properties for the entity. Yours does nothing. (maybe not critical, as the defaults are 0... in the case of objects it another story).

loadNBTData() and saveNBTData() are called on entity spawn (player spawn in this case), and on entity despawn. This is where the data in the ExtendedEntity itself is loaded and saved.

 

DataWatcher is nice only to the extent that it lets you know if the data has changed and communicates it to the other side immediately. However, you need to keep a valid copy in the data fields of this object. (So, when the datawatcher changes, you grab the data and update).

 

Beyond that, I have not looked closely enough to give you an absolute fix. I'll keep looking, though.

Posted
  On 3/18/2014 at 7:54 AM, sequituri said:

First, you're not using extended properties properly. Second, this code will register your Entity data with a null player. Reverse to == to != and it should fix one problem.

public void onEntityConstructing(EntityConstructing event) {
	if (event.entity instanceof EntityPlayer) {
		if (ExtendedPlayer.get((EntityPlayer) event.entity) == null)
		ExtendedPlayer.register((EntityPlayer) event.entity);
	}
}

 

Advice, the init() method is called when entity is created to set the initial properties for the entity. Yours does nothing. (maybe not critical, as the defaults are 0... in the case of objects it another story).

loadNBTData() and saveNBTData() are called on entity spawn (player spawn in this case), and on entity despawn. This is where the data in the ExtendedEntity itself is loaded and saved.

 

DataWatcher is nice only to the extent that it lets you know if the data has changed and communicates it to the other side immediately. However, you need to keep a valid copy in the data fields of this object. (So, when the datawatcher changes, you grab the data and update).

 

Beyond that, I have not looked closely enough to give you an absolute fix. I'll keep looking, though.

No, I am pretty sure what that code does is, if the player haven't been registered yet then register it. Other than that thank you for replying and helping me out. (btw if I use != it just crashes when the player joins the world)
Posted
  On 3/18/2014 at 11:44 AM, Chibill said:

Dude you have it as == the guy just said make it != and you say I can't make it == it crashes.

No, what I meant to say is that when I have it as "!=" it crashes when I open the world. I get a nullpointer exception when using "!=".

 

Crashlog:

 

  Reveal hidden contents

 

 

My real problems (I think) is that my values never really gets synced (client -> server or server -> client). This also make it so that when I open a new world, the gui says that I have the religion from the previous world (even if I create a new one) as well as when I close down minecraft and open it again it is reset to "None" instead of the religion name (where "None" is my default value in the ExtendedPlayer class).

Posted

Don't listen to what that guy said about registration - he obviously has no clue. Anyway, what you're doing wrong is you're setting the values client side, but your packet is set up to only sync data from the server TO the client, not the other way around. Easy fix is just allow your packet to be handled server side as well, reading everything from some bundled NBT that you send, but I do NOT recommend that.

 

Instead, what you should do is send a packet directly from the GUI to the server, saying "button x was pressed, do something", and then parse through the button ids server side setting the data as you need. This will avoid the issue of possible bad packets from the client overwriting your server side data, and you should then be able to synchronize right away with your normal packet. I prefer to have dedicated packets for various things, rather than sending the entire properties data every single time, but that's up to you.

Posted
  On 3/24/2014 at 9:55 AM, coolAlias said:

Don't listen to what that guy said about registration - he obviously has no clue. Anyway, what you're doing wrong is you're setting the values client side, but your packet is set up to only sync data from the server TO the client, not the other way around. Easy fix is just allow your packet to be handled server side as well, reading everything from some bundled NBT that you send, but I do NOT recommend that.

 

Instead, what you should do is send a packet directly from the GUI to the server, saying "button x was pressed, do something", and then parse through the button ids server side setting the data as you need. This will avoid the issue of possible bad packets from the client overwriting your server side data, and you should then be able to synchronize right away with your normal packet. I prefer to have dedicated packets for various things, rather than sending the entire properties data every single time, but that's up to you.

So let me see if I got you right, you mean that I create a new packet that instead of sending from server side sends info from server to client instead? And that this new packet should be sent whenever one of the buttons are pressed?

 

If that is correct do you know of any tutorial on sending data from server to client or the other way around? I wanna learn the new netty system in and out, so that I can use this for future projects and problems as well.

Posted

I mean you need to send a packet from the client to the server, but you can do it both ways using the exact same packet since you seem to have followed the same network tutorial I did :P

 

// on the server side, this is how you send a packet to a single player:
dispatcher.sendTo(new YourPacket(somedata), (EntityPlayerMP) player);

// on the client side, this is how you send a packet from the player to the server
// the handling on the server side is for the same player that sent it
dispatcher.sendToServer(new YourPacket(somedata));

Note that those are both using the exact same packet, and you have two methods in the AbstractPacket class that you need to implement if you want it to work both ways:

/**
     * Handle a packet on the client side. Note this occurs after decoding has completed.
     *
     * @param player the player reference
     */
    public abstract void handleClientSide(EntityPlayer player);

    /**
     * Handle a packet on the server side. Note this occurs after decoding has completed.
     *
     * @param player the player reference
     */
    public abstract void handleServerSide(EntityPlayer player);

Posted

BTW, I found example code somewhere (can't remember where tho) and used similar code.

 

[spoiler=ChannelHandler]

public class ChannelHandler extends FMLIndexedMessageToMessageCodec<IPacket> {
public ChannelHandler() {
	this.addDiscriminator(0, PacketWormhole.class);
	this.addDiscriminator(1, PacketDHDEnterGlyph.class);
}

public static EnumMap<Side, FMLEmbeddedChannel> channels;

public static void initChannels() {
	channels = NetworkRegistry.INSTANCE.newChannel("SpaceDistortion", new ChannelHandler());
}

@SideOnly(Side.CLIENT)
/**
 * Sends a packet from the client to the server
 * @param packet An IPacket to send
 */
public static void clientSendPacket(IPacket packet) {
	FMLEmbeddedChannel channel = ChannelHandler.channels.get(Side.CLIENT);
	channel.attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.TOSERVER);
	channel.writeOutbound(packet);
}

@SideOnly(Side.SERVER)
/**
 * Sends a packet from the server to a given client
 * @param packet An IPacket to send
 * @param player A player to send it to
 */
public static void serverSentPacket(IPacket packet, EntityPlayer player) {
	FMLEmbeddedChannel channel = ChannelHandler.channels.get(Side.SERVER);
	channel.attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.PLAYER);
	channel.attr(FMLOutboundHandler.FML_MESSAGETARGETARGS).set(player);
	channel.writeOutbound(packet);
}

/**
 * Sends a packet from the server to all clients
 * @param packet An IPacket to send
 */
@SideOnly(Side.SERVER)
public static void serverSendPacketAllClients(IPacket packet) {
	FMLEmbeddedChannel channel = ChannelHandler.channels.get(Side.SERVER);
	channel.attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.ALL);
	channel.writeOutbound(packet);
}

@Override
public void encodeInto(ChannelHandlerContext context, IPacket packet, ByteBuf data) throws Exception {
	packet.writeBytes(data);
}

@Override
public void decodeInto(ChannelHandlerContext context, ByteBuf data, IPacket packet) {
	// read the packet
	packet.readBytes(data);

	// handle the packet by calling IPacket#onReceive
	Side side = FMLCommonHandler.instance().getEffectiveSide();
	EntityPlayer player;
	switch (side) {
		case CLIENT:
			player = Minecraft.getMinecraft().thePlayer;
			packet.onReceive(player, side);
		case SERVER:
			INetHandler net = context.channel().attr(NetworkRegistry.NET_HANDLER).get();
			player = ((NetHandlerPlayServer) net).playerEntity;
			packet.onReceive(player, side);
	}
}

 

 

[spoiler=IPacket]

public interface IPacket {
public void readBytes(ByteBuf bytes);
public void writeBytes(ByteBuf bytes);
public void onReceive(EntityPlayer player, Side side);
}

[/code]

 

You probably don't need the entire class, but I hope this helps. Especially look at clientSendPacket, serverSendPacket, and serverSendPacketAllClients.

I like to make mods, just like you. Here's one worth checking out

Posted

Ok, it seems I can't work this out by myself even after the information you gave me (server/client stuff really confuses me and this is my first time handling nbttag stuff).

 

My current bugs is, when I open a world after quiting the game, it prints out correct information in the console (I made it so that when I use the method loadNBTData in the ExtendedPlayer.class it will print the religion and culture) but when I look inside my gui everything is reset back to the standard values. Though when I open a different world without leaving the game, it still has the information from the earlier world.

 

So I ask how I can make it save for only the world he is currently in, and that it will save and load correctly even after I restart the game.

 

Here is my current code:

 

Mod class:

 

  Reveal hidden contents

 

 

GuiReligion.class:

 

  Reveal hidden contents

 

 

ItemTalisman.class:

 

  Reveal hidden contents

 

 

ExtendedPlayer.class:

 

  Reveal hidden contents

 

 

CultureEventHandler.class:

 

  Reveal hidden contents

 

 

SyncPlayerPropsPacket.class:

 

  Reveal hidden contents

 

 

CommonProxy.class:

 

  Reveal hidden contents

 

 

AbstractPacket.class:

 

  Reveal hidden contents

 

 

ClientProxy.class:

 

  Reveal hidden contents

 

Posted

1. You don't need to send a synchronization packet to the server when loading your properties - they just loaded on the server.

 

2. You are using DataWatcher for your variables, so you don't need to send a packet at all - that's done automatically when you update the value, ON THE SERVER SIDE. Send a packet from your GUI to the server, rather than trying to set the data from the GUI:

switch (button.id) {
case 0:
// BIG NOOOOOO!!! This is on the client! Send a packet with the information you need and set the data there
ItemTalisman.pantheon = PantheonReference.NO_RELIGION;
ExtendedPlayer.get(player).setPantheon(PantheonReference.pantheons[PantheonReference.NO_RELIGION]);
// etc.

// Should be:
yourDispatcher.sendToServer(new UpdateReligion(newReligion));
// and in your UpdateReligion packet, in the handle server side method, you would then do
// what you were doing in your GUI:
handleServerSide(args) { // <- obviously don't copy that
ExtendedPlayer.get(player).setPantheon(packet.religion);
}

 

So your GUI code would look like this:

public void actionPerformed(GuiButton button) {
YourReligionObject newReligion = PantheonReference.NO_RELIGION;
switch (button.id) {
// don't need case 0 anymore, that's the default
case 1:
newReligion = PantheonReference.GREEK;
break;
case 2:
newReligion = PantheonReference.NORSE;
break;
.
.
. etc.
}
PantheonCraft.packetPipeline.sendToServer(new UpdateReligionPacket(newReligion));
}

UpdateReligionPacket writes the religion to the buffer, reads it back in, and then uses that religion to set both the ItemTalisman and ExtendedProperties data, on the SERVER.

Posted

For some reason this is giving me null and 0 all the time. I even tried using lists but that doesn't work either.

package com.xetosphere.pantheon.network.packet;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.ChatComponentText;

import com.xetosphere.pantheon.entity.ExtendedPlayer;
import com.xetosphere.pantheon.network.AbstractPacket;

import cpw.mods.fml.common.network.ByteBufUtils;

public class UpdateReligionPacket extends AbstractPacket {

private NBTTagCompound data;
private String religion;
private int religionId;

public UpdateReligionPacket() {
}

public UpdateReligionPacket(String religion, int religionId) {

	data = new NBTTagCompound();
	setReligion(religion);
	setReligionId(religionId);
}

public void setReligion(String religion) {

	this.religion = religion;
}

public void setReligionId(int religionId) {

	this.religionId = religionId;
}

public String getReligion() {

	return religion;
}

public int getReligionId() {

	return religionId;
}

@Override
public void encodeInto(ChannelHandlerContext ctx, ByteBuf buffer) {

	ByteBufUtils.writeTag(buffer, data);
}

@Override
public void decodeInto(ChannelHandlerContext ctx, ByteBuf buffer) {

	data = ByteBufUtils.readTag(buffer);
}

@Override
public void handleClientSide(EntityPlayer player) {

}

@Override
public void handleServerSide(EntityPlayer player) {

	System.out.println(getReligion() + ", " + getReligionId());
	ExtendedPlayer.get(player).setPantheon(getReligion());
	ExtendedPlayer.get(player).setPantheonId(getReligionId());
	if (!player.worldObj.isRemote) player.addChatComponentMessage(new ChatComponentText("You set your pantheon to: " + ExtendedPlayer.get(player).getPantheon()));
	System.out.println("[XETOPC] Pantheon = " + ExtendedPlayer.get(player).getPantheon());
	System.out.println("[XETOPC] PantheonId = " + ExtendedPlayer.get(player).getPantheonId());
}

}

 

Posted
  On 3/25/2014 at 11:15 AM, AppliedOnce said:

For some reason this is giving me null and 0 all the time. I even tried using lists but that doesn't work either.

You never add any data to the NBTTagCompound, which you don't even need since you can write the int and String directly to the output stream, and read them back in. You don't need getter and setter methods because you will never be (should never be) trying to access your variables outside of this class.

Posted
  On 3/25/2014 at 11:18 AM, coolAlias said:

  Quote

For some reason this is giving me null and 0 all the time. I even tried using lists but that doesn't work either.

You never add any data to the NBTTagCompound, which you don't even need since you can write the int and String directly to the output stream, and read them back in. You don't need getter and setter methods because you will never be (should never be) trying to access your variables outside of this class.

Thank you, I forgot I could use the NBTTagCompound to store the values (I am very stupid sometimes). Everything works as it should now, I really appreciate your help.

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.