Jump to content

[Solved][1.7.10] IEEP Persistence


Izzy Axel

Recommended Posts

The issue is, my IEEP doesn't carry over across reconstructions such as travelling to a dimension, what's the preferred method of making this data persistent, or is there an issue with my IEEP?  Death I think I do want stored mana to be lost on, but you shouldn't have the mana you've collected vanish when you travel to a dimension. <__<

 

 

IEEP

Link to comment
Share on other sites

Will this work?

 

 

public class ManaPersistence
{
public void persistMana(PlayerEvent.Clone event)
{
	if(!event.wasDeath)
	{
		EntityPlayer playerOrig = event.original;
		EntityPlayer playerNew = event.entityPlayer;


		AAExtendedPlayer propsOrig = (AAExtendedPlayer)playerOrig.getExtendedProperties(AAExtendedPlayer.EEPName);
		AAExtendedPlayer propsNew = (AAExtendedPlayer)playerNew.getExtendedProperties(AAExtendedPlayer.EEPName);


		propsNew = propsOrig;
	}
}
}

 

 

Unfortunately I cant easily test this until I solve the other issue I'm having, which is getting the IEEP variables for mana to set correctly.  I have a keybind that when held should refill mana, currently I just have it giving it quickly and for free to test.  I have a GUI element that reflects changes made to the mana variables in the IEEP.  I send a packet to the server from the keybinding class with the client's entity ID, then I've tried checking and adding mana using IEEP in the packet handler and in proxies, and a few other ways, but nothing's worked, the GUI doesn't update and no mana is given/stored in IEEP.  Any idea what I'm doing wrong?  I also tried slowing the player down via the packet/proxy serverside, like the effect when you draw a bow, and that results in 1 tick bursts of slowness every 10ish ticks...this is really confusing.

Link to comment
Share on other sites

Bro, do you even reference?

 

Will this work?

AAExtendedPlayer propsOrig = (AAExtendedPlayer)playerOrig.getExtendedProperties(AAExtendedPlayer.EEPName);
AAExtendedPlayer propsNew = (AAExtendedPlayer)playerNew.getExtendedProperties(AAExtendedPlayer.EEPName);
propsNew = propsOrig;

 

I can honestly say, while I've seen a lot of Java mistakes here, this one is genuinely new.

It should be: newPlayer.setIEEP(oldPlayer.getIEEP());

 

As to second part:

The logic is fairly simple:

Each server and cleint holds its own EntityPlayer (call them: MP and SP). Each of those players have their own IEEPs assigned (it's even possible to have one-sided IEEP).

Now - updates should ALWAYS travel from server to client one. Most of packets that way will look like:

Server changes value -> Packet with update is sent to client. You can split them into 2 groups:

1. Direct packet to owner of data (you send data from MP IEEP to SP IEEP).

* Packet contains ONLY data.

* Receiving client reads data and applies it derectly onto Minecraft#thePlayer (himself).

2. "Signed" packet to few clients (you send data from MP IEEP to multiple SP receivers).

* Packet contains data AND entityID.

* Receiving client reads "entityID", gets entity from its client world and update that entity's data.

 

How +/- it should look with your mana:

1. Click Key.

2. Send packet to server (can be empty or with some Id of key).

3. Senrver knows who sent data -> do security checks.

4. Change value in MP IEEP ---(Assume you have setter method)---> MP IEEP sends update packet to client or clients (like described above).

5. Done.

 

1.7.10 is no longer supported by forge, you are on your own.

Link to comment
Share on other sites

Also, after the player respawns, the client side IEEP will be out of sync unless you send a packet to fill in its data, but you can't do that from the Clone event, you have to do it when the player joins the world via EntityJoinWorldEvent or the Player RespawnEvent (I think that's what it's called...).

 

Check [ur=http://www.minecraftforum.net/forums/mapping-and-modding/mapping-and-modding-tutorials/1571567-forge-1-6-4-1-8-eventhandler-and?comment=2l]here[/url] for more information.

Link to comment
Share on other sites

~

 

 

Yes, I know that's wrong.

 

So I'm doing...

 

@SubscribeEvent
public void syncPersistenceToClient(EntityJoinWorldEvent event)
{
   if(!event.world.isRemote && event.entity instanceof EntityPlayer)
   {
      EntityPlayer player = (EntityPlayer)event.entity;
      ArcaneArtificing.snw.sendToAll(new MessageSyncManaPersistence(player.getEntityId()));
   }
}

 

 

 

Do I need to send each mana's value individually to set on the client side, and set them there?

 

 

Edit: Ok there's another problem, apparently I'm trying to load EntityClientPlayerMP on the server, stacktrace points to the registration of the mana client sync packet, which gets sent at the end of the handler for the packet that manipulates the mana on the server, so...can I not chain packets like that?

 

 

Everything

Link to comment
Share on other sites

Server changes value -> Packet with update is sent to client. You can split them into 2 groups:

1. Direct packet to owner of data (you send data from MP IEEP to SP IEEP).

* Packet contains ONLY data.

* Receiving client reads data and applies it derectly onto Minecraft#thePlayer (himself).

 

2. "Signed" packet to few clients (you send data from MP IEEP to multiple SP receivers).

* Packet contains data AND entityID.

* Receiving client reads "entityID", gets entity from its client world and update that entity's data.

 

You kinda picked to send "Signed" one and then you apply data onto #thePlayer.

 

Signed case (can also be used for non-players):

@Override
public IMessage onMessage(MessageSyncManaRegen message, MessageContext ctx)
{
Entity e = Main.proxy.getClientWorld().getEntityByID(message.entityId);
if (e instanceof EntityPlayer)
{
	AAExtendedPlayer props = (AExtendedPlayer) ((EntityPlayer) e).getExtendedProperties(AAExtendedPlayer.EEPName);
	props.addMana(new Mana(ManaType.W, message.w));
	props.addMana(new Mana(ManaType.U, message.u));
	props.addMana(new Mana(ManaType.B, message.b));
	props.addMana(new Mana(ManaType.G, message.g));
	props.addMana(new Mana(ManaType.R, message.r));
}
return null;
}

 

Unsigned packet (remove "entityId"):

@Override
public IMessage onMessage(MessageSyncManaRegen message, MessageContext ctx)
{
AAExtendedPlayer props = (AExtendedPlayer) (Main.proxy.getClientPlayer()).getExtendedProperties(AAExtendedPlayer.EEPName);
props.addMana(new Mana(ManaType.W, message.w));
props.addMana(new Mana(ManaType.U, message.u));
props.addMana(new Mana(ManaType.B, message.b));
props.addMana(new Mana(ManaType.G, message.g));
props.addMana(new Mana(ManaType.R, message.r));
return null;
}

 

Now - the methods should be placed in your client proxy and should return Minecraft.getMinecrraft()#thePlayer or #theWorld.

 

1.7.10 is no longer supported by forge, you are on your own.

Link to comment
Share on other sites

How +/- it should look with your mana:

1. Click Key.

2. Send packet to server (can be empty or with some Id of key).

3. Senrver knows who sent data -> do security checks.

4. Change value in MP IEEP ---(Assume you have setter method)---> MP IEEP sends update packet to client or clients (like described above).

5. Done.

 

I can't tell you more without seeing all code, from registration and packet to calls and handling. Also your IEEP can be messed up.

1.7.10 is no longer supported by forge, you are on your own.

Link to comment
Share on other sites

Ok...I had to delete the playerdata or make a new world on SSP, and delete the playerdata on SMP; the old IEEP values were interfering. So now everything works. Thanks!

 

 

EDIT: wait crap no there's still one more issue; persistence over exiting/rejoining.  At least with simply exiting an SSP world and going back in when one type is halfway down, upon entering the world again, it resets to full. Seems like maybe I need to sync NBT on a player logout event?

 

 

Fixed

Link to comment
Share on other sites

Just when you think it's done...

 

 

So, there's definitely an issue with this method of carrying IEEP over death, namely that it doesn't work right; everything gets reset, because of how the IEEP is getting copied.  The identifier used to register it already exists during death reconstruction so the new one gets renamed, and therefore the new IEEP is not used, the old is wiped, and I'm left trying to read from the old one.  I hope I'm wrong, but it's looking there's going to be reflection going on to directly alter the protected HashMap for the IEEP, since there are no other methods for setting IEEP.

 

event handler

public class ManaPersistence
{
   public static ManaPersistence INSTANCE = new ManaPersistence();


   @SubscribeEvent
   public void persistMana(PlayerEvent.Clone event)
   {
      EntityPlayer playerOrig = event.original;
      EntityPlayer playerNew = event.entityPlayer;
      AAExtendedPlayer propsOrig = (AAExtendedPlayer)playerOrig.getExtendedProperties(AAExtendedPlayer.EEPName);
      playerNew.registerExtendedProperties(AAExtendedPlayer.EEPName, propsOrig);
   }


   @SubscribeEvent
   public void syncPersistenceToClient(EntityJoinWorldEvent event)
   {
      if(!event.world.isRemote && event.entity instanceof EntityPlayer)
      {
         EntityPlayer player = (EntityPlayer)event.entity;
         AAExtendedPlayer props = (AAExtendedPlayer)player.getExtendedProperties(AAExtendedPlayer.EEPName);
         ArcaneArtificing.snw.sendToAll(new MessageSyncMana(player.getEntityId(), props.getWhiteMana(), props.getBlueMana(), props.getBlackMana(), props.getGreenMana(), props.getRedMana(), props.hasLearnedAboutmana()));
      }
   }


   @SubscribeEvent
   public void syncOnDisconnect(cpw.mods.fml.common.gameevent.PlayerEvent.PlayerLoggedOutEvent event)
   {
      if(!event.player.worldObj.isRemote)
      {
         AAExtendedPlayer props = (AAExtendedPlayer)event.player.getExtendedProperties(AAExtendedPlayer.EEPName);
         ArcaneArtificing.snw.sendToAll(new MessageSyncMana(event.player.getEntityId(), props.getWhiteMana(), props.getBlueMana(), props.getBlackMana(), props.getGreenMana(), props.getRedMana(), props.hasLearnedAboutmana()));
      }
   }
}

Link to comment
Share on other sites

1st of all - when code is used a lot, you make helpers for it:

public static AAExtendedPlayer get(EntityPlayer player) { return player.getExtendedProperties(AAExtendedPlayer.EEPName); }

 

And now you just call AAExtendedPlayer.get(player);

 

2nd:

Like "get" is totally different than "set", same rule applies to "register"!

"register" != "set".

 

Again - make helper method in AAExtendedPlayer:

public void copy(AAExtendedPlayer ieep)
{
    this.mana = ieep.getMana();
    this.soething = ieep.getSomething();
    ...
}

 

Now:

   @SubscribeEvent
   public void persistMana(PlayerEvent.Clone event)
   {
      EntityPlayer playerOrig = event.original;
      EntityPlayer playerNew = event.entityPlayer;
      AAExtendedPlaye.get(playerNew).copy(AAExtendedPlaye.get(playerOrig));
   }

 

Registration should happen almost always only in entity's construction event.

 

New player is created -> IEEP is registered -> old data is copied to new IEEP -> old entity is discarded -> new one is spawned -> JoinedWorldEvent calls sync methods and updates stuff from new IEEP.

1.7.10 is no longer supported by forge, you are on your own.

Link to comment
Share on other sites

Ok, that works, but after the player dies, the HUD element doesn't update to the new IEEP, it acts like the player hasn't learned about mana yet, (one of the values in the IEEP) and therefore doesn't display the HUD element.  Relogging fixes it.  I'm not sure if I should tie the showing of the HUD to the achievement that is setting the IEEP variable for it, or the way I've been doing with IEEP; achievements seem to get reset a lot...

 

 

HUD

Event Handler

IEEP

Link to comment
Share on other sites

Can't really say. I recommend debugging with Syso. Place sysos in:

* Construction

* JoinedWorld

* Clone

* Packet - on encode and receive.

and make them print (client and server) properties.

 

If manas are synced after death and as you say - "has learned about mana" is not - there might be some small mistake in packeting.

If none of properties get synced,  then debugging will lead to mistake.

 

You can also post full repo if you want.

1.7.10 is no longer supported by forge, you are on your own.

Link to comment
Share on other sites

 

Arcane Artificing

 

I'm sending all the important IEEP properties/the ones that should be synced through death and reconstruction to the client, including hasLearnedAboutMana.  The HUD works fine across reconstructions via dimensional travel but when a player dies, that doesn't get synced for some reason, even though I'm sending the same sync packet as every other situation :/  I checked by printing the value in the HUD class, and after death it changes to false.

Link to comment
Share on other sites

Unless you are doing some fancy rendering for other players based on these IEEP values, this is entirely unnecessary - you're handling the message client side, so the only possible player is the client player, i.e. Minecraft.getMinecraft().thePlayer.

 

Where are you sending the sync message from?

 

Also, all of these and the other similar fields should be static and all uppercase, since you are defining constants. The reason they should be static is you don't need a unique instance of each of those values for every player IEEP - they are always the same, so you only need one of each, i.e. static.

Link to comment
Share on other sites

Alright, I'll make those changes.

 

 

I'm sending them from mana.ManaHandler#provideMana, mana.ManaPersistence#syncPersistenceToClient and syncPersistenceOnRespawn (which didn't help so I'll probably remove it), achievements.AchievementListener#achievementGet, main.handlers.AAEventHandler#onJoin, main.messages.MessageRegenMana.RegenManaHandler#onMessage, and main.messages.MessageRegainMana.RegainManaHandler#onMessage

Link to comment
Share on other sites

That's a LOT of places, which is a big clue your design is poor. Sync from one place and one place only, but don't send more than you need to.

 

Sync ALL data that you need on the client side (for rendering such as in a GUI) when the player joins the world. Easiest is EntityJoinWorldEvent. This takes care of things such as changing dimensions and respawning.

 

Sync current / max mana from the only logical place to do so, i.e. the method you use to set it. You ARE using a setter, right? And that is the only way you ever change your mana values, right? Right?!?! This takes care of when the player consumes or regains mana through the normal course of play.

 

Again, only send what you need, so when the mana changes, only send the mana value, not the entire IEEP. This means make a separate packet for when you just want to sync mana.

 

Also, you don't need to make a separate 'Handler' class for every single event you handle - every one of those adds an entry to the list of handlers Forge must iterate through. You can if you really want to, but you can also put them all in the same class. If it starts getting unwieldy, group them by macro category (e.g. combat, entity, item, or whatever).

Link to comment
Share on other sites

I have getters and setters for everything in the IEEP.  I'm sending a sync packet anywhere where the mana values are changed, after the change is made.  I know about the handlers thing, I haven't gotten around to cleaning that up, that's what I made the AAEventHandler class for today. :P  The sync packet at the moment syncs mana values, hasLearnendAboutMana, and hasReceivedJournal, tied to the HUD being shown for that player, and not re-giving the journal item to the player every time they join the world.  Also, the change you mentioned about not getting the entity from the ID in the sync packet, replacing that with Minecraft#thePlayer will cause an EntityClientPlayerMP loaded on invalid side SERVER crash, not quite sure why.

Link to comment
Share on other sites

You can avoid the crash by using your proxy:

EntityPlayer player =  Main.proxy.getPlayerEntity(ctx);

// Common / Server Proxy:
public EntityPlayer getPlayerEntity(MessageContext ctx) {
return ctx.getServerHandler().playerEntity;
}

// Client Proxy:
@Override
public EntityPlayer getPlayerEntity(MessageContext ctx) {
return (ctx.side.isClient() ? mc.thePlayer : super.getPlayerEntity(ctx));
}

 

If you are changing mana values from that many places, you are generally doing something wrong. Consolidate those into one setter, if you can. Have different types of mana? No problem, add an argument to the method:

public void setMana(EnumManaType type, int amount) {
switch (type) {
case BLUE: this.blueMana = amount; break;
case RED: this.redMana = amount; break;
}
network.sendPacketTo(new SyncManaPacket(type, amount), this.player);
}

That's just pseudo-code, but you get the idea. If you ever find yourself doing the same thing in more than one place (e.g. sending the same sync packet), that's a big hint that you need to centralize that shit.

Link to comment
Share on other sites

Oh, I see what you mean, I already have functions to add and subtract mana, so I should just send the packets from those functions instead of from the items that use them.  That won't affect the HUD issue I don't think though.

 

Adding a PlayerRespawnEvent handler and syncing there fixed it.  It's required to sync client IEEP when the player joins world, and when they respawn, one or the other leads to problems.

Link to comment
Share on other sites

Ok one more question, with the method of sending the sync packet to only the client who needs it (I assume this would be the preferred method, especially since if there's a problem with it, only one client will crash, instead of everyone you're sending it to), how do you get a valid reference to that player's EntityPlayerMP?  That's one thing I've never known/or figured out. :P

Link to comment
Share on other sites

Ok one more question, with the method of sending the sync packet to only the client who needs it (I assume this would be the preferred method, especially since if there's a problem with it, only one client will crash, instead of everyone you're sending it to), how do you get a valid reference to that player's EntityPlayerMP?  That's one thing I've never known/or figured out. :P

 

On the server side, every

EntityPlayer

is an instance of

EntityPlayerMP

(or a subclass of it).

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.

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.



×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.