The Meaning of Life, the Universe, and Everything.
Join Date:
7/2/2014
Posts:
55
Minecraft:
BinaryAura
Member Details
No, CommandStamina is for a Command. I fixed that problem. The server launches now. Now I cannot connect to the server from a client. I keep getting an invalid session. I also moved this to it's own thread.
In step 5 of your tutorial you say that I have to put "NBTTagCompound playerData = proxy.getEntityData(((EntityPlayer) event.entity).username);" into the EntityJoinWorldEvent. There is no .username, so I used .getCommandSenderName().
I don't have the class "proxy" either, but I have "CommonProxy", with the method ".getEntityData" as you said earlier in step 5, so I just assumed you meant CommonProxy.
Here's the method ".getEntityData" according to step 5.
/**
* Removes the compound from the map and returns the NBT tag stored for name or null if none exists
*/
public static NBTTagCompound getEntityData(String name)
{
return extendedEntityData.remove(name);
}
It returns an NBTTagCompound, so it should be the same type, right?
So sorry if I'm too stupid to understand that, but as far as I can see this, it would make sense :/
By the way I love your tutorial!
Oops, sorry, you are right - I missed the closing ')' on the end of your method call :$ Hm... well, in your LivingDeathEvent, it looks like you are saving the data twice, though I don't think that's the problem. You may want to take a look at the full demo mod; here is my EntityJoinWorldEvent. You can see how I consolidated all of that code into the ExtendedPlayer class with the loadProxyData and saveProxyData methods.
From the wiki page you linked us to and told us to copy-paste:
"This is a poor example of using Netty. It can cause memory leaks. It doesn't separate handlers from codecs properly. It reimplements functionality existant in FML for months. If you are using this, consider switching to using FMLIndexedMessageToMessageCodec, or better yet, use the simpleimpl Message functionality.
(...)
I know, I just haven't had time to update entirely yet. The old Netty tutorial code works just fine for those who are still using it (all my mods still use it...), and now that SimpleNetworkWrapper finally works, using that is a piece of cake (though I'm working on something a bit more interesting, if I can get it to work properly).
So anyway, all the code presented here is still fully functional, including the outdated network code, though you should update that to the SimpleNetworkWrapper if you can. If you can't do that by yourself, then you'll just have to wait until I get time to update the tutorial, sorry.
Would a LivingUpdateEvent where I add one to an int, let's say timer, and do something case it equals x, then reset it to 0, be the best way to make sure something, in this case regaining some mana, every number seconds.
Just an example to make it simple to understand (I know I would have to make sure event.entity is instanceof entityPlayer, get the properties for that player, etc, etc, but for sake of simplicity, I made it simple to read and understand):
Yes, that would be fine. I put the timer inside of my ExtendedPlayer class and call an update method each tick from my living update event handler, just because I like to keep as much of the mana code in one place as I can.
Ideally, though, if you are only dealing with EntityPlayer in your event code you would use the PlayerTickEvent instead of LivingUpdateEvent; LivingUpdateEvent is posted for every EntityLivingBase that exists in the game, so you are checking all of those entities if they are a player every tick, whereas PlayerTickEvent is only posted for players.
You are setting the value on the client side, and then sends a new packet to the same client.. You are also castin the client player to server player. Make a new packet which sends information to the server to run that method, but on the server. And then sync it back to t client
I've been using this tutorial since 1.5.something, and it's always worked fine. However, with my version of 1.7.2, the extended stuff is not persisting through death or log outs on servers... Any idea what's wrong? Brace yourselves, code pastes are coming.
ExtendedPlayer (important bits)
public class ExtendedPlayer implements IExtendedEntityProperties
{
publicfinalstatic String EXT_PROP_NAME = "ExtendedPlayer";
public static final void register(EntityPlayer player)
{
player.registerExtendedProperties(ExtendedPlayer.EXT_PROP_NAME, new ExtendedPlayer(player));
}
public static final ExtendedPlayer get(EntityPlayer player)
{
return (ExtendedPlayer) player.getExtendedProperties(EXT_PROP_NAME);
}
private static String getSaveKey(EntityPlayer player)
{
return player.getCommandSenderName() + ":" + EXT_PROP_NAME;
}
public static void saveProxyData(EntityPlayer player)
{
ExtendedPlayer playerData = ExtendedPlayer.get(player);
NBTTagCompound savedData = new NBTTagCompound();
playerData.saveNBTData(savedData);
CommonProxy.storeEntityData(getSaveKey(player), savedData);
}
public static final void loadProxyData(EntityPlayer player)
{
ExtendedPlayer playerData = ExtendedPlayer.get(player);
NBTTagCompound savedData = CommonProxy.getEntityData(getSaveKey(player));
if (savedData != null) { playerData.loadNBTData(savedData); }
if(player instanceof EntityPlayerMP)
BleachMod.network.sendTo(new ClientSyncMessage(player), (EntityPlayerMP) player);
}
@Override
public void loadNBTData(NBTTagCompound nbt)
{
etc...
}
}
Event Handler
public class BleachEvents
{
public static CommonProxy proxy = new CommonProxy();
Random rand = new Random();
@SubscribeEvent
public void onEntityConstructing(EntityConstructing event)
{
if (event.entity instanceof EntityPlayer &&
event.entity.getExtendedProperties(ExtendedPlayer.EXT_PROP_NAME) == null)
{
ExtendedPlayer.register(((EntityPlayer) event.entity));
}
}
@SubscribeEvent
public void onEntityJoinWorld(EntityJoinWorldEvent event)
{
if(!event.entity.worldObj.isRemote)
{
if(event.entity instanceof EntityPlayerMP)
ExtendedPlayer.loadProxyData((EntityPlayer) event.entity);
}
if(event.entity instanceof EntityPlayerMP)
{
EntityPlayer player = ((EntityPlayer)event.entity);
ExtendedPlayer props = (ExtendedPlayer) player.getExtendedProperties(ExtendedPlayer.EXT_PROP_NAME);
if(props.getFaction() == 0 && !player.inventory.hasItem(BleachItems.factionSelect))
{
player.inventory.addItemStackToInventory(new ItemStack(BleachItems.factionSelect, 1));
if(!player.worldObj.isRemote)
props.replenishEnergy(1);
}
}
if(event.entity instanceof EntityWhole || event.entity instanceof EntityDecoy)
{
event.entity.setCurrentItemOrArmor(2, new ItemStack(Armor.SoulChain, 1));
}
}
//On Death
@SubscribeEvent
public void onLivingDeathEvent(LivingDeathEvent event)
{
if(event.entity instanceof EntityPlayerMP && !event.entity.worldObj.isRemote)
{
EntityPlayerMP player = ((EntityPlayerMP)event.entity);
ExtendedPlayer.saveProxyData(player);
if(player.inventory.hasItem(BleachItems.zanpakuto))
{
}
}
}
}
CommonProxy
public class CommonProxy implements IGuiHandler
{
private static HashMap<String, NBTTagCompound> extendedEntityData = new HashMap<String, NBTTagCompound>();
public void initRenderers()
{
}
public int addArmor(String string)
{
return 0;
}
@Override
public Object getServerGuiElement(int guiId, EntityPlayer player, World world, int x, int y, int z)
{
returnnull;
}
@Override
public Object getClientGuiElement(int guiId, EntityPlayer player, World world, int x, int y, int z)
{
returnnull;
}
public static void storeEntityData(String name, NBTTagCompound compound)
{
extendedEntityData.put(name, compound);
}
public static NBTTagCompound getEntityData(String name)
{
returnextendedEntityData.remove(name);
}
}
ClientSyncMessage
package littlebreadloaf.bleach.network;
import io.netty.buffer.ByteBuf;
import littlebreadloaf.bleach.BleachMod;
import littlebreadloaf.bleach.events.ExtendedPlayer;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
import cpw.mods.fml.common.network.ByteBufUtils;
import cpw.mods.fml.common.network.simpleimpl.IMessage;
import cpw.mods.fml.common.network.simpleimpl.IMessageHandler;
import cpw.mods.fml.common.network.simpleimpl.MessageContext;
import cpw.mods.fml.relauncher.Side;
public class ClientSyncMessage implements IMessage
{
private NBTTagCompound data;
public ClientSyncMessage(){}
public ClientSyncMessage(EntityPlayer player)
{
this.data = new NBTTagCompound();
ExtendedPlayer.get(player).saveNBTData(data);
}
@Override
public void fromBytes(ByteBuf buf)
{
data = ByteBufUtils.readTag(buf);
}
@Override
public void toBytes(ByteBuf buf)
{
ByteBufUtils.writeTag(buf, data);
}
public static class Handler implements IMessageHandler<ClientSyncMessage, IMessage>
{
@Override
public IMessage onMessage(ClientSyncMessage message, MessageContext ctx)
{
if(ctx.side == Side.CLIENT)
{
EntityPlayer player = Minecraft.getMinecraft().thePlayer; // I know, don't use this. But if I use ANY other method of getting the player, it crashes the game. If there's a better way, this might be my problem...
ExtendedPlayer props = ExtendedPlayer.get(player);
if(player != null)
{
if(props != null)
{
ExtendedPlayer.get(player).loadNBTData(message.data);
}
}
}
return null;
}
}
}
ServerSyncMessage
package littlebreadloaf.bleach.network;
import littlebreadloaf.bleach.events.ExtendedPlayer;
import io.netty.buffer.ByteBuf;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
import cpw.mods.fml.common.network.ByteBufUtils;
import cpw.mods.fml.common.network.simpleimpl.IMessage;
import cpw.mods.fml.common.network.simpleimpl.IMessageHandler;
import cpw.mods.fml.common.network.simpleimpl.MessageContext;
public class ServerSyncMessage implements IMessage
{
private NBTTagCompound data;
public ServerSyncMessage(){}
public ServerSyncMessage(EntityPlayer player)
{
this.data = new NBTTagCompound();
ExtendedPlayer.get(player).saveNBTData(data);
}
@Override
public void fromBytes(ByteBuf buf)
{
data = ByteBufUtils.readTag(buf);
}
@Override
public void toBytes(ByteBuf buf)
{
ByteBufUtils.writeTag(buf, data);
}
public static class Handler implements IMessageHandler<ServerSyncMessage, IMessage>
{
@Override
public IMessage onMessage(ServerSyncMessage message, MessageContext ctx)
{
ExtendedPlayer.get(ctx.getServerHandler().playerEntity).loadNBTData(message.data);
return null;
}
}
}
Packet Handling has no bearing on saving/loading of custom NBT for extended player properties, at least not for death. For logout I don't see how it'd be any different.
@SubscribeEvent
public void onEntityConstructing(EntityConstructing event) {
if (event.entity instanceof EntityPlayer && MinecraftEmpiresPlayer.get((EntityPlayer) event.entity) == null)
MinecraftEmpiresPlayer.register((EntityPlayer) event.entity);
if (event.entity instanceof EntityPlayer && event.entity.getExtendedProperties(MinecraftEmpiresPlayer.EXT_PROP_NAME) == null) {
event.entity.registerExtendedProperties(MinecraftEmpiresPlayer.EXT_PROP_NAME, new MinecraftEmpiresPlayer((EntityPlayerMP) event.entity));
}
}
...I'm pretty sure that is all I had to do to get saveNBTData/loadNBTData working perfectly, saving whenever Minecraft saves the standard player data. I've not done extensive dedicated server testing but it did work when I first put it in and tested it.
EDIT: I used to use EntityPlayerMP but I've since learned that it's wrong to force the requirement of an extended class.
I've been using this tutorial since 1.5.something, and it's always worked fine. However, with my version of 1.7.2, the extended stuff is not persisting through death or log outs on servers... Any idea what's wrong? Brace yourselves, code pastes are coming.
Any help would be wonderful.
Thanks,
LittleBreadLoaf
Your events and properties code looks fine, so I suspect the problem is in your network. Make sure you register ALL messages on BOTH sides, as the server needs to be able to send the messages, and then add a method to your proxy class to return the player from message context and use that so that Minecraft.getMinecraft() doesn't crash your server - I know, it's only sent to the client, but it will still crash your game. See this thread.
Quote from CosmicDan»
EDIT: I used to use EntityPlayerMP but I've since learned that it's wrong to force the requirement of an extended class.
It's not at all wrong to do so, but you need to understand why and how to use it. Whenever you are going to cast to a specific type, you want to make sure that whatever object you have is really that type; in this case, we needed an EntityPlayerMP (i.e. the server player) to send a packet from the server, so we check for that. It's only a problem when you use a more specific type than necessary for no reason, and even then, it depends on how exactly you are using it. In general, always use the most generic class that makes sense, but sometimes it makes more sense or is actually required to use a specific type.
It's not at all wrong to do so, but you need to understand why and how to use it. Whenever you are going to cast to a specific type, you want to make sure that whatever object you have is really that type; in this case, we needed an EntityPlayerMP (i.e. the server player) to send a packet from the server, so we check for that. It's only a problem when you use a more specific type than necessary for no reason, and even then, it depends on how exactly you are using it. In general, always use the most generic class that makes sense, but sometimes it makes more sense or is actually required to use a specific type.
Oh yeah of course. What I mean in this case was that I didn't realize EntityClientPlayerMP would also need to access the extended player properties. Seems very obvious now I know I do still use EntityPlayerMP type in some method args, simply because they are indeed specific to server-side tasks - like you said, one example being a helper method for sending a packet to a client, or another helper method that updates a specific player property from a world tick event.
An aside, it's nice to know that I can use the same IMessage (and nested IMessageHandler class) for both client and server, registering the same thing on both sides and just doing a side check in onMessage. I also see even moreso now why proxies are essential/great.
Your events and properties code looks fine, so I suspect the problem is in your network. Make sure you register ALL messages on BOTH sides, as the server needs to be able to send the messages, and then add a method to your proxy class to return the player from message context and use that so that Minecraft.getMinecraft() doesn't crash your server - I know, it's only sent to the client, but it will still crash your game. See this thread.
Ok, I changed that, not sure if it works on servers yet because I haven't gotten around to testing it yet. But what still happens is this:
Regular log outs are fine, they save the data. However, if you die and say "Return to Title Screen", then the next time you log in and respawn, it resets all the data, even in singleplayer. Is this a problem with the way my code is set up? Or is it something that happens with all ExtendedEntity stuff?
I think this might be by design, at least in single player. I'm thining this because it asks if you're sure you want to quit, i.e. implying that it won't "save" this player's death, if so then that'd also mean the extended player data isn't saved.
If this is true, maybe you can force a player save on worldunload event or playerlogout.
To be honest, I'm not sure how it works when you quit to title screen instead of respawning. I'll have to play around with it, but I would guess that it must save the player's data, and by extension the IEEP data as well, otherwise you would lose all the items, xp, etc... but I guess your items are lost anyway in Minecraft, so who knows.
Worst case scenario: always make sure to respawn before you quit
To be honest, I'm not sure how it works when you quit to title screen instead of respawning. I'll have to play around with it, but I would guess that it must save the player's data, and by extension the IEEP data as well, otherwise you would lose all the items, xp, etc... but I guess your items are lost anyway in Minecraft, so who knows.
Worst case scenario: always make sure to respawn before you quit
Well really, what player data is there to save? You just died and lost all your items, and XP I believe... There's no real reason for it to save anything, and no event (I don't think) that we can save IEEP data during...
What is actually happening though? I though the player data is saved when the world is I.e. every pause in SSP and every x minutes in SMP. When you quit to title screen, have you checked NBT before relogging in to see that the data is actually erased? Failing to save shouldnt wipe everything (unless its hardcore?) But just revert to last save. Again, if this is what actually happens - I still don't know.
If you quit to title or desktop instead of respawning, I can confirm that the storage is highly unreliable - it seems to get removed from the proxy AND lost from the entity's NBT (the latter being expected, although stupid, behavior).
I was using this to, among other things, count player deaths, with the number of deaths subtracting from the player's stats and so on. I quickly realized that quitting after death then reloading the game later, would reset the saved information (I imagine it has something to do with the proxy only acting as only a halfway house for the information in between death and respawn, with no enforcement of persistence).
I had trouble figuring out a different solution that would work (a lot of what Minecraft does seems terribly irrational and inefficient to me, which really doesn't help). I did have a fiddle with a few persistent world data things and stuff, but I concluded that with my limited knowledge of Forge and MCP inner workings, it was going to be more reliable to simply store the data in my own file in the world folder, and I haven't had a single problem with it since.
EDIT: IM A DIAMOND MINER!
Rollback Post to RevisionRollBack
I believe in the Invisible Pink Unicorn, bless her Invisible Pinkness.
The storage in CommonProxy or elsewhere may only be available during a game session and is probably removed when you exit to main menu - its purpose is just to store the data between death and respawn within a session. However, I had assumed the player / world data would be saved to NBT when you quit (in which case the extended properties would also be saved without a problem). If this is not the case, then we may be able to force the player to save to NBT during LivingDeathEvent; whether this would have any bizarre side effects remains to be seen, but I suspect it should work fine.
Ok, so I've found out that on servers, it just deletes the saved player data on death. However, if you log out and log back in, then it keeps your data. (Regular log out, not the weird death/logout from above).
Please please please is there any way to fix this
Rollback Post to RevisionRollBack
Bleach Mod
To post a comment, please login or register a new account.
-
View User Profile
-
View Posts
-
Send Message
Curse PremiumRead that carefully. NBTTagCompound = getCommandSenderName()... those are most definitely not the same type.
-
View User Profile
-
View Posts
-
Send Message
Curse PremiumOops, sorry, you are right - I missed the closing ')' on the end of your method call :$ Hm... well, in your LivingDeathEvent, it looks like you are saving the data twice, though I don't think that's the problem. You may want to take a look at the full demo mod; here is my EntityJoinWorldEvent. You can see how I consolidated all of that code into the ExtendedPlayer class with the loadProxyData and saveProxyData methods.
I know, I just haven't had time to update entirely yet. The old Netty tutorial code works just fine for those who are still using it (all my mods still use it...), and now that SimpleNetworkWrapper finally works, using that is a piece of cake (though I'm working on something a bit more interesting, if I can get it to work properly).
So anyway, all the code presented here is still fully functional, including the outdated network code, though you should update that to the SimpleNetworkWrapper if you can. If you can't do that by yourself, then you'll just have to wait until I get time to update the tutorial, sorry.
-
View User Profile
-
View Posts
-
Send Message
Curse PremiumYes, that would be fine. I put the timer inside of my ExtendedPlayer class and call an update method each tick from my living update event handler, just because I like to keep as much of the mana code in one place as I can.
Ideally, though, if you are only dealing with EntityPlayer in your event code you would use the PlayerTickEvent instead of LivingUpdateEvent; LivingUpdateEvent is posted for every EntityLivingBase that exists in the game, so you are checking all of those entities if they are a player every tick, whereas PlayerTickEvent is only posted for players.
Art by me: [email protected]
-
View User Profile
-
View Posts
-
Send Message
Curse PremiumI've been using this tutorial since 1.5.something, and it's always worked fine. However, with my version of 1.7.2, the extended stuff is not persisting through death or log outs on servers... Any idea what's wrong? Brace yourselves, code pastes are coming.
ExtendedPlayer (important bits)
public class ExtendedPlayer implements IExtendedEntityProperties { publicfinalstatic String EXT_PROP_NAME = "ExtendedPlayer"; public static final void register(EntityPlayer player) { player.registerExtendedProperties(ExtendedPlayer.EXT_PROP_NAME, new ExtendedPlayer(player)); } public static final ExtendedPlayer get(EntityPlayer player) { return (ExtendedPlayer) player.getExtendedProperties(EXT_PROP_NAME); } private static String getSaveKey(EntityPlayer player) { return player.getCommandSenderName() + ":" + EXT_PROP_NAME; } public static void saveProxyData(EntityPlayer player) { ExtendedPlayer playerData = ExtendedPlayer.get(player); NBTTagCompound savedData = new NBTTagCompound(); playerData.saveNBTData(savedData); CommonProxy.storeEntityData(getSaveKey(player), savedData); } public static final void loadProxyData(EntityPlayer player) { ExtendedPlayer playerData = ExtendedPlayer.get(player); NBTTagCompound savedData = CommonProxy.getEntityData(getSaveKey(player)); if (savedData != null) { playerData.loadNBTData(savedData); } if(player instanceof EntityPlayerMP) BleachMod.network.sendTo(new ClientSyncMessage(player), (EntityPlayerMP) player); } @Override public void loadNBTData(NBTTagCompound nbt) { etc... } }Event Handler
public class BleachEvents { public static CommonProxy proxy = new CommonProxy(); Random rand = new Random(); @SubscribeEvent public void onEntityConstructing(EntityConstructing event) { if (event.entity instanceof EntityPlayer && event.entity.getExtendedProperties(ExtendedPlayer.EXT_PROP_NAME) == null) { ExtendedPlayer.register(((EntityPlayer) event.entity)); } } @SubscribeEvent public void onEntityJoinWorld(EntityJoinWorldEvent event) { if(!event.entity.worldObj.isRemote) { if(event.entity instanceof EntityPlayerMP) ExtendedPlayer.loadProxyData((EntityPlayer) event.entity); } if(event.entity instanceof EntityPlayerMP) { EntityPlayer player = ((EntityPlayer)event.entity); ExtendedPlayer props = (ExtendedPlayer) player.getExtendedProperties(ExtendedPlayer.EXT_PROP_NAME); if(props.getFaction() == 0 && !player.inventory.hasItem(BleachItems.factionSelect)) { player.inventory.addItemStackToInventory(new ItemStack(BleachItems.factionSelect, 1)); if(!player.worldObj.isRemote) props.replenishEnergy(1); } } if(event.entity instanceof EntityWhole || event.entity instanceof EntityDecoy) { event.entity.setCurrentItemOrArmor(2, new ItemStack(Armor.SoulChain, 1)); } } //On Death @SubscribeEvent public void onLivingDeathEvent(LivingDeathEvent event) { if(event.entity instanceof EntityPlayerMP && !event.entity.worldObj.isRemote) { EntityPlayerMP player = ((EntityPlayerMP)event.entity); ExtendedPlayer.saveProxyData(player); if(player.inventory.hasItem(BleachItems.zanpakuto)) { } } } }CommonProxy
public class CommonProxy implements IGuiHandler { private static HashMap<String, NBTTagCompound> extendedEntityData = new HashMap<String, NBTTagCompound>(); public void initRenderers() { } public int addArmor(String string) { return 0; } @Override public Object getServerGuiElement(int guiId, EntityPlayer player, World world, int x, int y, int z) { returnnull; } @Override public Object getClientGuiElement(int guiId, EntityPlayer player, World world, int x, int y, int z) { returnnull; } public static void storeEntityData(String name, NBTTagCompound compound) { extendedEntityData.put(name, compound); } public static NBTTagCompound getEntityData(String name) { returnextendedEntityData.remove(name); } }ClientSyncMessage
package littlebreadloaf.bleach.network; import io.netty.buffer.ByteBuf; import littlebreadloaf.bleach.BleachMod; import littlebreadloaf.bleach.events.ExtendedPlayer; import net.minecraft.client.Minecraft; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.nbt.NBTTagCompound; import cpw.mods.fml.common.network.ByteBufUtils; import cpw.mods.fml.common.network.simpleimpl.IMessage; import cpw.mods.fml.common.network.simpleimpl.IMessageHandler; import cpw.mods.fml.common.network.simpleimpl.MessageContext; import cpw.mods.fml.relauncher.Side; public class ClientSyncMessage implements IMessage { private NBTTagCompound data; public ClientSyncMessage(){} public ClientSyncMessage(EntityPlayer player) { this.data = new NBTTagCompound(); ExtendedPlayer.get(player).saveNBTData(data); } @Override public void fromBytes(ByteBuf buf) { data = ByteBufUtils.readTag(buf); } @Override public void toBytes(ByteBuf buf) { ByteBufUtils.writeTag(buf, data); } public static class Handler implements IMessageHandler<ClientSyncMessage, IMessage> { @Override public IMessage onMessage(ClientSyncMessage message, MessageContext ctx) { if(ctx.side == Side.CLIENT) { EntityPlayer player = Minecraft.getMinecraft().thePlayer; // I know, don't use this. But if I use ANY other method of getting the player, it crashes the game. If there's a better way, this might be my problem... ExtendedPlayer props = ExtendedPlayer.get(player); if(player != null) { if(props != null) { ExtendedPlayer.get(player).loadNBTData(message.data); } } } return null; } } }ServerSyncMessage
package littlebreadloaf.bleach.network; import littlebreadloaf.bleach.events.ExtendedPlayer; import io.netty.buffer.ByteBuf; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.nbt.NBTTagCompound; import cpw.mods.fml.common.network.ByteBufUtils; import cpw.mods.fml.common.network.simpleimpl.IMessage; import cpw.mods.fml.common.network.simpleimpl.IMessageHandler; import cpw.mods.fml.common.network.simpleimpl.MessageContext; public class ServerSyncMessage implements IMessage { private NBTTagCompound data; public ServerSyncMessage(){} public ServerSyncMessage(EntityPlayer player) { this.data = new NBTTagCompound(); ExtendedPlayer.get(player).saveNBTData(data); } @Override public void fromBytes(ByteBuf buf) { data = ByteBufUtils.readTag(buf); } @Override public void toBytes(ByteBuf buf) { ByteBufUtils.writeTag(buf, data); } public static class Handler implements IMessageHandler<ServerSyncMessage, IMessage> { @Override public IMessage onMessage(ServerSyncMessage message, MessageContext ctx) { ExtendedPlayer.get(ctx.getServerHandler().playerEntity).loadNBTData(message.data); return null; } } }Registering the Messages
in ClientProxy
in Main Mod File preInit
network = NetworkRegistry.INSTANCE.newSimpleChannel("BleachChannel"); BleachMod.network.registerMessage(ServerSyncMessage.Handler.class, ServerSyncMessage.class, 0, Side.SERVER);Any help would be wonderful.
Thanks,
LittleBreadLoaf
Bleach Mod
@SubscribeEvent public void onEntityConstructing(EntityConstructing event) { if (event.entity instanceof EntityPlayer && MinecraftEmpiresPlayer.get((EntityPlayer) event.entity) == null) MinecraftEmpiresPlayer.register((EntityPlayer) event.entity); if (event.entity instanceof EntityPlayer && event.entity.getExtendedProperties(MinecraftEmpiresPlayer.EXT_PROP_NAME) == null) { event.entity.registerExtendedProperties(MinecraftEmpiresPlayer.EXT_PROP_NAME, new MinecraftEmpiresPlayer((EntityPlayerMP) event.entity)); } }...I'm pretty sure that is all I had to do to get saveNBTData/loadNBTData working perfectly, saving whenever Minecraft saves the standard player data. I've not done extensive dedicated server testing but it did work when I first put it in and tested it.
EDIT: I used to use EntityPlayerMP but I've since learned that it's wrong to force the requirement of an extended class.
-
View User Profile
-
View Posts
-
Send Message
Curse PremiumYour events and properties code looks fine, so I suspect the problem is in your network. Make sure you register ALL messages on BOTH sides, as the server needs to be able to send the messages, and then add a method to your proxy class to return the player from message context and use that so that Minecraft.getMinecraft() doesn't crash your server - I know, it's only sent to the client, but it will still crash your game. See this thread.
It's not at all wrong to do so, but you need to understand why and how to use it. Whenever you are going to cast to a specific type, you want to make sure that whatever object you have is really that type; in this case, we needed an EntityPlayerMP (i.e. the server player) to send a packet from the server, so we check for that. It's only a problem when you use a more specific type than necessary for no reason, and even then, it depends on how exactly you are using it. In general, always use the most generic class that makes sense, but sometimes it makes more sense or is actually required to use a specific type.
Oh yeah of course. What I mean in this case was that I didn't realize EntityClientPlayerMP would also need to access the extended player properties. Seems very obvious now I know
An aside, it's nice to know that I can use the same IMessage (and nested IMessageHandler class) for both client and server, registering the same thing on both sides and just doing a side check in onMessage. I also see even moreso now why proxies are essential/great.
Ok, I changed that, not sure if it works on servers yet because I haven't gotten around to testing it yet. But what still happens is this:
Regular log outs are fine, they save the data. However, if you die and say "Return to Title Screen", then the next time you log in and respawn, it resets all the data, even in singleplayer. Is this a problem with the way my code is set up? Or is it something that happens with all ExtendedEntity stuff?
Thanks for the help,
LittleBreadLoaf
Bleach Mod
If this is true, maybe you can force a player save on worldunload event or playerlogout.
-
View User Profile
-
View Posts
-
Send Message
Curse PremiumWorst case scenario: always make sure to respawn before you quit
Well really, what player data is there to save? You just died and lost all your items, and XP I believe... There's no real reason for it to save anything, and no event (I don't think) that we can save IEEP data during...
Bleach Mod
I was using this to, among other things, count player deaths, with the number of deaths subtracting from the player's stats and so on. I quickly realized that quitting after death then reloading the game later, would reset the saved information (I imagine it has something to do with the proxy only acting as only a halfway house for the information in between death and respawn, with no enforcement of persistence).
I had trouble figuring out a different solution that would work (a lot of what Minecraft does seems terribly irrational and inefficient to me, which really doesn't help). I did have a fiddle with a few persistent world data things and stuff, but I concluded that with my limited knowledge of Forge and MCP inner workings, it was going to be more reliable to simply store the data in my own file in the world folder, and I haven't had a single problem with it since.
EDIT: IM A DIAMOND MINER!
I believe in the Invisible Pink Unicorn, bless her Invisible Pinkness.
-
View User Profile
-
View Posts
-
Send Message
Curse PremiumPlease please please is there any way to fix this
Bleach Mod