>>> For the 1.7.+ the method is no longer needed because of the update, it synchronizes automatically?
No, it does not synchronize automatically: in 1.6.4, many people built packets using PacketCustomPayload250 or whatever it was called, so there needed to be a semi-logical place for all the code to build the packet, which is what the 'sync()' method was doing.
Now, however, packets are as they should be - they handle their own reading and writing inside each packet class, and you just send whatever packet you need whenever you need to update.
So instead of calling the properties 'sync()' method, now you just send the update packet directly.
Run -> Run Configurations -> Select your Run Configuration -> Arguments -> Add '--username [email protected] --password YourPassword' - then you will log in with your real Minecraft name and skin every time.
For anyone still using this tutorial, please keep in mind that you need to update the network code to use SimpleNetworkWrapper - the PacketPipeline code is outdated.
Hey everyone, here is a much better way of persisting your data through death / the End. I will update the main post eventually, but the forum editor and I still don't see eye to eye. In the meantime, I will post the updated 'Step 5' here, and you can see the exact changes I made on Github.
Step 5: Getting your custom data to persist through player death
When the player dies or travels from the End, the current player instance is actually destroyed and a copy of that player is spawned. This means that a new instance of our extended properties is created for the new player, as well, but unlike the original player data, there is no mechanism that will copy our data to the new instance. Thankfully, there is the PlayerEvent.Clone event, which fires under just this circumstance with both the old player instance and the new, giving us what we need to copy, aka persist, our data.
The implementation can be as simple as writing the old data to NBT and 'loading' the new properties from that NBT:
@SubscribeEvent
public void onClonePlayer(PlayerEvent.Clone event) {
NBTTagCompound compound = new NBTTagCompound();
ExtendedPlayer.get(event.original).saveNBTData(compound);
ExtendedPlayer.get(event.entityPlayer).loadNBTData(compound);
}
That is pretty easy, though we can improve efficiency by avoiding the costly disk reads and writes resulting from the use of NBT. To do so, we simply implement a 'copy' method for our properties that sets the fields more directly:
/**
* Copies additional player data from the given ExtendedPlayer instance
* Avoids NBT disk I/O overhead when cloning a player after respawn
*/
public void copy(ExtendedPlayer props) {
this.player.getDataWatcher().updateObject(MANA_WATCHER, props.getCurrentMana());
this.maxMana = props.maxMana;
this.manaRegenTimer = props.manaRegenTimer;
}
Using our new 'copy' method, our Clone event now looks like this:
@SubscribeEvent
public void onClonePlayer(PlayerEvent.Clone event) {
ExtendedPlayer.get(event.entityPlayer).copy(ExtendedPlayer.get(event.original));
}
That's all it takes to have our data persisted when the player is destroyed and reborn, though the client will not be aware of any of our data yet. If there is any data that we will need on the client, we must still sync our extended property data when the player joins the world:
@SubscribeEvent
public void onEntityJoinWorld(EntityJoinWorldEvent event) {
if (event.entity instanceof EntityPlayer && !event.entity.worldObj.isRemote) {
PacketDispatcher.sendTo(new SyncPlayerPropsMessage((EntityPlayer) event.entity), (EntityPlayerMP) event.entity);
}
}
Recall that the SyncPlayerPropsMessage writes the entire properties to NBT and sends it to the client, which is the lazy way of syncing our data. It is always better to send only what you will actually need on the client, but for the sake of this tutorial, I have chosen the more expedient solution.
Make your own SharedMonsterAttribute(s) and then add modifiers using Item#getAttributeModifiers(ItemStack) - so long as you are wearing or holding the item (in vanilla slots, at least), the attributes will be calculated appropriately.
If that is not an option, then you need to use the player's update tick to check if the armor is worn or not and add/remove the stats each time the armor slot changes. You cannot use the armor's update tick because it will not tick when removed.
If anyone wants to update to 1.8, all of the event handler code is the same, EXCEPT that you need to remove EVERY SINGLE import with 'cpw.mods.fml' in it and replace it with 'net.minecraftforge.fml...'. See my demo mod on github (textures not currently working, sorry).
Note that you have to change them in EVERY file, notably your event handling classes and anywhere you may have had @SideOnly (e.g. GUIs, key handlers, rendering, etc.).
Actually, I'm not so sure about what I posted originally (see below), at least as far as 1.8 is concerned. In 1.7 and prior, EntityJoinWorldEvent is the correct place to send synchronization packets, but in 1.8 the client player is sometimes null that event fires the first time the player joins the world (i.e. on log-in).
Another note: PlayerEvent.Clone works great for cloning the player's server side data after death, but sending a packet from there will go to the OLD client player, and once the player is 'reborn', the new client player's data will not be correct - solved if you send your update packets from EntityJoinWorldEvent. Of course, this is only an issue if you have anything you need to be known by the client and are not using DataWatcher for it.
Original Post
Another note: for sending the initial synchronization packet to the player when they join the world, we should really be using PlayerLoggedInEvent instead of EntityJoinWorldEvent - it is more specific and should guarantee that the client player exists to receive the packet.
Only difference is that the PlayerLoggedInEvent is on the FML bus.
Code snippet
// Registration
FMLCommonHandler.instance().bus().register(new YourEventHandler());
// The event; checking if the player is an instance of EntityPlayerMP will ensure the packet can be sent from server to client
// without any problems; no need to check world.isRemote in addition to that, since EntityPlayerMP only exists on the server
@SubscribeEvent
public void onPlayerLogIn(PlayerLoggedInEvent event) {
if (event.player instanceof EntityPlayerMP) {
PacketDispatcher.sendTo(new SyncPlayerPropsMessage(event.player), (EntityPlayerMP) event.player);
}
}
WHY can't I find MinecraftForge.EVENT_BUS and LivingUpdateEvent ?? Libraries have changed ?! I can't import MinecraftForge and LivingUpdateEvent, please help me !!!!
Changed from what? Are you updating to 1.8 from 1.7? Nothing really changed except for FML packages are now in net.minecraftforge rather than cpw.mods. Use Eclipse and press ctrl-shift-o to automatically import what you need.
The Meaning of Life, the Universe, and Everything.
Location:
New York
Join Date:
6/3/2012
Posts:
50
Minecraft:
VikingGoth
Member Details
I'm modding in 1.7.10, and I know I need to use an event because i'm adding in a weapon enchant. is there a way to detect if the mob you've stricken with a weapon with a specific enchant is killed? and if so, how? I'm assuming that I would use AttackEntityEvent... oh. it contains a Entity target. so, i'd just have to check to see how much damage is done to it, and if it kills it, run a method to do what I want? how would I implement this, being that mobs don't die immediately from a code standpoint?
I'm modding in 1.7.10, and I know I need to use an event because i'm adding in a weapon enchant. is there a way to detect if the mob you've stricken with a weapon with a specific enchant is killed? and if so, how? I'm assuming that I would use AttackEntityEvent... oh. it contains a Entity target. so, i'd just have to check to see how much damage is done to it, and if it kills it, run a method to do what I want? how would I implement this, being that mobs don't die immediately from a code standpoint?
There is LivingDeathEvent for this very reason, and it contains the source of the damage from which you can get the entity, check if it is EntityLivingBase or EntityPlayer, then get the held itemstack and check for your enchantment.
Already done and I had the same problem, maybe I failed with gradlew ... ?
Open a command prompt in your project's working directory and run 'gradlew --refresh-dependencies setupDecompWorkspace', then 'gradlew eclipse'. If you still do not have the forgeSrc in your referenced libraries, you need to add it manually by right-clicking in the package explore and going to 'build path' -> 'configure build path'. The source file should be in '$users/.gradle/caches/net/minecraft/minecraftforge/forge' or thereabouts.
The Meaning of Life, the Universe, and Everything.
Location:
New York
Join Date:
6/3/2012
Posts:
50
Minecraft:
VikingGoth
Member Details
I figured out that I shoulda been using the LivingDeathEvent and I now have it working correctly with a sword I added, but am a little stuck on the enchantment checking
Hey coolAlias, i am currently developing my minecraft reallife mod and i want to save a NAME to the EntityPlayer that still exists when Minecraft was closed, can you help me?
Hey coolAlias, i am currently developing my minecraft reallife mod and i want to save a NAME to the EntityPlayer that still exists when Minecraft was closed, can you help me?
Hey coolAlias, i am currently developing my minecraft reallife mod and i want to save a NAME to the EntityPlayer that still exists when Minecraft was closed, can you help me?
Use extended properties to save the name. It will persist for that player in that world save even if you close Minecraft. Just follow the tutorial.
I don't think what you want is possible, at least not without storing the data online and retrieving it each time the player logs in. That is well beyond the scope of this tutorial, sorry.
Use extended properties to save the name. It will persist for that player in that world save even if you close Minecraft. Just follow the tutorial.
I don't think what you want is possible, at least not without storing the data online and retrieving it each time the player logs in. That is well beyond the scope of this tutorial, sorry.
I did, but the problem is, that the eclipse username of the player changes each time you open minecraft, so i cant test it.
Not doing mc modding that much anymore because I am making a full blown game that does not have limitations that mc has. (rip Magiology for now)
I may come back if MC fixes it's rendering pipeline.
-
View User Profile
-
View Posts
-
Send Message
Curse PremiumNo, it does not synchronize automatically: in 1.6.4, many people built packets using PacketCustomPayload250 or whatever it was called, so there needed to be a semi-logical place for all the code to build the packet, which is what the 'sync()' method was doing.
Now, however, packets are as they should be - they handle their own reading and writing inside each packet class, and you just send whatever packet you need whenever you need to update.
So instead of calling the properties 'sync()' method, now you just send the update packet directly.
-
View User Profile
-
View Posts
-
Send Message
Curse Premium-
View User Profile
-
View Posts
-
Send Message
Curse Premium-
View User Profile
-
View Posts
-
Send Message
Curse PremiumStep 5: Getting your custom data to persist through player death
When the player dies or travels from the End, the current player instance is actually destroyed and a copy of that player is spawned. This means that a new instance of our extended properties is created for the new player, as well, but unlike the original player data, there is no mechanism that will copy our data to the new instance. Thankfully, there is the PlayerEvent.Clone event, which fires under just this circumstance with both the old player instance and the new, giving us what we need to copy, aka persist, our data.
The implementation can be as simple as writing the old data to NBT and 'loading' the new properties from that NBT:
@SubscribeEvent public void onClonePlayer(PlayerEvent.Clone event) { NBTTagCompound compound = new NBTTagCompound(); ExtendedPlayer.get(event.original).saveNBTData(compound); ExtendedPlayer.get(event.entityPlayer).loadNBTData(compound); }That is pretty easy, though we can improve efficiency by avoiding the costly disk reads and writes resulting from the use of NBT. To do so, we simply implement a 'copy' method for our properties that sets the fields more directly:
/** * Copies additional player data from the given ExtendedPlayer instance * Avoids NBT disk I/O overhead when cloning a player after respawn */ public void copy(ExtendedPlayer props) { this.player.getDataWatcher().updateObject(MANA_WATCHER, props.getCurrentMana()); this.maxMana = props.maxMana; this.manaRegenTimer = props.manaRegenTimer; }Using our new 'copy' method, our Clone event now looks like this:
@SubscribeEvent public void onClonePlayer(PlayerEvent.Clone event) { ExtendedPlayer.get(event.entityPlayer).copy(ExtendedPlayer.get(event.original)); }That's all it takes to have our data persisted when the player is destroyed and reborn, though the client will not be aware of any of our data yet. If there is any data that we will need on the client, we must still sync our extended property data when the player joins the world:
@SubscribeEvent public void onEntityJoinWorld(EntityJoinWorldEvent event) { if (event.entity instanceof EntityPlayer && !event.entity.worldObj.isRemote) { PacketDispatcher.sendTo(new SyncPlayerPropsMessage((EntityPlayer) event.entity), (EntityPlayerMP) event.entity); } }Recall that the SyncPlayerPropsMessage writes the entire properties to NBT and sends it to the client, which is the lazy way of syncing our data. It is always better to send only what you will actually need on the client, but for the sake of this tutorial, I have chosen the more expedient solution.
-
View User Profile
-
View Posts
-
Send Message
Curse PremiumIf that is not an option, then you need to use the player's update tick to check if the armor is worn or not and add/remove the stats each time the armor slot changes. You cannot use the armor's update tick because it will not tick when removed.
-
View User Profile
-
View Posts
-
Send Message
Curse PremiumExample import revision:
Note that you have to change them in EVERY file, notably your event handling classes and anywhere you may have had @SideOnly (e.g. GUIs, key handlers, rendering, etc.).
参照你的教程写的,请帮忙看看
-
View User Profile
-
View Posts
-
Send Message
Curse PremiumAnother note: PlayerEvent.Clone works great for cloning the player's server side data after death, but sending a packet from there will go to the OLD client player, and once the player is 'reborn', the new client player's data will not be correct - solved if you send your update packets from EntityJoinWorldEvent. Of course, this is only an issue if you have anything you need to be known by the client and are not using DataWatcher for it.
Original Post
Only difference is that the PlayerLoggedInEvent is on the FML bus.
Code snippet
// Registration FMLCommonHandler.instance().bus().register(new YourEventHandler()); // The event; checking if the player is an instance of EntityPlayerMP will ensure the packet can be sent from server to client // without any problems; no need to check world.isRemote in addition to that, since EntityPlayerMP only exists on the server @SubscribeEvent public void onPlayerLogIn(PlayerLoggedInEvent event) { if (event.player instanceof EntityPlayerMP) { PacketDispatcher.sendTo(new SyncPlayerPropsMessage(event.player), (EntityPlayerMP) event.player); } }-
View User Profile
-
View Posts
-
Send Message
Curse PremiumChanged from what? Are you updating to 1.8 from 1.7? Nothing really changed except for FML packages are now in net.minecraftforge rather than cpw.mods. Use Eclipse and press ctrl-shift-o to automatically import what you need.
Just press Ctrl+Shift+o if you are in Eclipse
Not doing mc modding that much anymore because I am making a full blown game that does not have limitations that mc has. (rip Magiology for now)
I may come back if MC fixes it's rendering pipeline.
Not doing mc modding that much anymore because I am making a full blown game that does not have limitations that mc has. (rip Magiology for now)
I may come back if MC fixes it's rendering pipeline.
-
View User Profile
-
View Posts
-
Send Message
Curse PremiumThere is LivingDeathEvent for this very reason, and it contains the source of the damage from which you can get the entity, check if it is EntityLivingBase or EntityPlayer, then get the held itemstack and check for your enchantment.
Open a command prompt in your project's working directory and run 'gradlew --refresh-dependencies setupDecompWorkspace', then 'gradlew eclipse'. If you still do not have the forgeSrc in your referenced libraries, you need to add it manually by right-clicking in the package explore and going to 'build path' -> 'configure build path'. The source file should be in '$users/.gradle/caches/net/minecraft/minecraftforge/forge' or thereabouts.
boolean hasMyEnchant = false;
NBTTagList enchList = item.getNBTTagList("ench", 10);
for (blah enchlist.tagcount blah)
{
if(enchlist.getTagAt(i).getShort? getInt? getByte? ("id") == myMod.myEnch.effectID)
{
hasMyEnchant = true;
break;
{
}
if(hasMyEnchant) nowDoThing();
That look like a good way to do it? what getter should I use to get the ID or does it not matter?
-
View User Profile
-
View Posts
-
Send Message
Curse Premium- YouTube - -Twitter - - Facebook - -Website-
That is the same thing that I want!
Not doing mc modding that much anymore because I am making a full blown game that does not have limitations that mc has. (rip Magiology for now)
I may come back if MC fixes it's rendering pipeline.
-
View User Profile
-
View Posts
-
Send Message
Curse PremiumCool! Have you received any tutorial or so yet?
- YouTube - -Twitter - - Facebook - -Website-
-
View User Profile
-
View Posts
-
Send Message
Curse PremiumUse extended properties to save the name. It will persist for that player in that world save even if you close Minecraft. Just follow the tutorial.
I don't think what you want is possible, at least not without storing the data online and retrieving it each time the player logs in. That is well beyond the scope of this tutorial, sorry.
-
View User Profile
-
View Posts
-
Send Message
Curse PremiumI did, but the problem is, that the eclipse username of the player changes each time you open minecraft, so i cant test it.
- YouTube - -Twitter - - Facebook - -Website-