Petit problème Syncro ExtProp HashSet



  • Bonjour, bonjour,
    Je poste ce sujet pour vous demander de l'aide à propos d'un drôle de problème d'ExtProp et de synchro. Alors c'est bizarre mais quand je print la taille de mon HashSet, côté client elle est toujours égale à 0, et côté serveur, toujours à 1. Bref voici le code :
    ExtProp :

    
    import java.util.ArrayList;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Set;
    
    import net.minecraft.entity.Entity;
    import net.minecraft.entity.player.EntityPlayer;
    import net.minecraft.entity.player.EntityPlayerMP;
    import net.minecraft.nbt.NBTTagCompound;
    import net.minecraft.nbt.NBTTagList;
    import net.minecraft.nbt.NBTTagString;
    import net.minecraft.world.World;
    import net.minecraftforge.common.IExtendedEntityProperties;
    import net.minecraftforge.common.util.Constants;
    
    public class ExtendedEntityPropertiesPlayer implements IExtendedEntityProperties 
    {
    
    public final static String EXT_PROP_NAME = "ExtProp" + DICraftMod.MODID;
    private final EntityPlayer player;
    private boolean healthRegenState;
    private boolean strengthState;
    private boolean agilityState;
    private Set <string>handicaps;
    
    public ExtendedEntityPropertiesPlayer(EntityPlayer player)
    {
    this.player = player;
    healthRegenState = false;
    strengthState = false;
    agilityState = false;
    this.handicaps = new HashSet<string>();
    }
    
    @Override
    public void saveNBTData(NBTTagCompound compound) 
    {
    NBTTagCompound properties = new NBTTagCompound();
    properties.setBoolean("healthRegenState", this.healthRegenState);
    properties.setBoolean("strengthState", this.strengthState);
    properties.setBoolean("agilityState", this.agilityState);
    if(handicaps != null)
    {
    NBTTagList list = new NBTTagList();
    for(String current : this.handicaps)
    {
    list.appendTag(new NBTTagString(current));
    }
    properties.setTag("handicaps", list);
    }
    compound.setTag(EXT_PROP_NAME, properties);
    }
    
    @Override
    public void loadNBTData(NBTTagCompound compound) 
    {
    NBTTagCompound properties = (NBTTagCompound) compound.getTag(EXT_PROP_NAME);
    this.healthRegenState = properties.getBoolean("healthRegenState");
    this.strengthState = properties.getBoolean("strengthState");
    this.agilityState = properties.getBoolean("agilityState");
    NBTTagList list = properties.getTagList("handicaps", Constants.NBT.TAG_STRING);
    for(int i = 0; i < list.tagCount(); i++)
    {
    this.handicaps.add(list.getStringTagAt(i));
    }
    }
    
    @Override
    public void init(Entity entity, World world) 
    {
    
    }
    
    public static final void register(EntityPlayer player) 
    {
    player.registerExtendedProperties(ExtendedEntityPropertiesPlayer.EXT_PROP_NAME, new ExtendedEntityPropertiesPlayer(player));
    }
    
    public static final ExtendedEntityPropertiesPlayer get(EntityPlayer player) 
    {
    return (ExtendedEntityPropertiesPlayer) player.getExtendedProperties(EXT_PROP_NAME);
    }
    
    public final void sync() 
    {
    PacketGeneticModifierHealth packetModifVie = new PacketGeneticModifierHealth(this.healthRegenState);
    PacketGeneticModifierStrength packetModifAttack = new PacketGeneticModifierStrength(this.strengthState);
    PacketGeneticModifierAgility packetAgility = new PacketGeneticModifierAgility(this.agilityState);
    PacketUpdateHandicap packetHandicap = new PacketUpdateHandicap(this.handicaps);
    DICraftMod.network.sendToServer(packetModifVie);
    DICraftMod.network.sendToServer(packetModifAttack);
            DICraftMod.network.sendToServer(packetAgility);
            DICraftMod.network.sendToServer(packetHandicap);
    if (!player.worldObj.isRemote) 
    {
    EntityPlayerMP player1 = (EntityPlayerMP) player;
    DICraftMod.network.sendTo(packetModifVie, player1);
    DICraftMod.network.sendTo(packetModifAttack, player1);
    DICraftMod.network.sendTo(packetAgility, player1);
    DICraftMod.network.sendTo(packetHandicap, player1);
    }
    }
    
    private static String getSaveKey(EntityPlayer player) 
    {
    return player.getDisplayName() + ":" + EXT_PROP_NAME;
    }
    
    public static void saveProxyData(EntityPlayer player) 
    {
    ExtendedEntityPropertiesPlayer playerData = ExtendedEntityPropertiesPlayer.get(player);
    NBTTagCompound savedData = new NBTTagCompound();
    playerData.saveNBTData(savedData);
    CommonProxy.storeEntityData(getSaveKey(player), savedData);
    }
    
    public static void loadProxyData(EntityPlayer player) 
    {
    ExtendedEntityPropertiesPlayer playerData = ExtendedEntityPropertiesPlayer.get(player);
    NBTTagCompound savedData = CommonProxy.getEntityData(getSaveKey(player));
    if (savedData != null) 
    {
    playerData.loadNBTData(savedData);
    }
    playerData.sync();
    }
    
    public boolean getHealthRegenState() 
    {
    return healthRegenState;
    }
    
    public void changeHealthRegenStateInADN(boolean newHealthRegenState) 
    {
    this.healthRegenState = newHealthRegenState;
    this.sync();
    }
    
    public void changeHealthRegenStateInADNWithoutSync(boolean newHealthRegenState) 
    {
    this.healthRegenState = newHealthRegenState;
    }
    
    public boolean getStrengthState() 
    {
    return strengthState;
    }
    
    public void changeStrengthStateInADN(boolean newStrengthState) 
    {
    this.strengthState = newStrengthState;
    this.sync();
    }
    
    public void changeStrengthStateInADNWithoutSync(boolean newStrengthState) 
    {
    this.strengthState = newStrengthState;
    }
    
    public boolean getAgilityState() 
    {
    return agilityState;
    }
    
    public void changeAgilityStateInADN(boolean newAgilityState) 
    {
    this.agilityState = newAgilityState;
    this.sync();
    }
    
    public void changeAgilityStateInADNWithoutSync(boolean newAgilityState) 
    {
    this.agilityState = newAgilityState;
    }
    
    public void addHandicap(EnumPlayerHandicaps handicapToAdd)
    {
    this.handicaps.add(handicapToAdd.toString());
    this.sync();
    }
    
    public void removeHandicap(EnumPlayerHandicaps handicapToRemove)
    {
    this.handicaps.remove(handicapToRemove.toString());
    this.sync();
    }
    
    public Set <string>getHandicapsSet()
    {
    return handicaps;
    }
    
    public boolean hasSpecificHandicap(EnumPlayerHandicaps handicap)
    {
    return this.handicaps.contains(handicap.toString());
    }
    
    public void setNewHandicapsSet(Set <string>newOne)
    {
    this.handicaps = newOne;
    }
    
    public enum EnumPlayerHandicaps
    {
    KNOCKEDDOWN
    }
    }
    
    

    Mon packet :

    
    import java.util.ArrayList;
    import java.util.Set;
    
    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;
    import cpw.mods.fml.relauncher.SideOnly;
    import io.netty.buffer.ByteBuf;
    import net.minecraft.client.Minecraft;
    import net.minecraft.entity.player.EntityPlayer;
    
    public class PacketUpdateHandicap implements IMessage
    {
    private static Set <string>handicaps;
    
    public PacketUpdateHandicap()
    {
    }
    
    public PacketUpdateHandicap(Set <string>handicaps)
    {
    this.handicaps = handicaps;
    }
    
    @Override
    public void fromBytes(ByteBuf buf) 
    {
    for(String current : handicaps)
    {
    this.handicaps.add(ByteBufUtils.readUTF8String(buf));
    }
    }
    
    @Override
    public void toBytes(ByteBuf buf) 
    {
    for(String current : handicaps)
    {
    ByteBufUtils.writeUTF8String(buf, current);
    }
    }
    
    public static class ClientHandler implements IMessageHandler <packetupdatehandicap, imessage="">{
    @Override
    @SideOnly(Side.CLIENT)
    public IMessage onMessage(PacketUpdateHandicap message, MessageContext ctx) 
    {
    EntityPlayer player = Minecraft.getMinecraft().thePlayer;
    ExtendedEntityPropertiesPlayer props = ExtendedEntityPropertiesPlayer.get(player);
    props.setNewHandicapsSet(message.handicaps);
    return null;
    }
    }
    public static class CommonHandler implements IMessageHandler <packetupdatehandicap, imessage="">{
    @Override
    public IMessage onMessage(PacketUpdateHandicap message, MessageContext ctx) 
    {
    EntityPlayer player = Minecraft.getMinecraft().thePlayer;
    ExtendedEntityPropertiesPlayer props = ExtendedEntityPropertiesPlayer.get(player);
    props.setNewHandicapsSet(message.handicaps);
    return null;
    }
    }
    }
    
    

    Et enfin mon EventHandler (pas sûr que ce soit la cause du problème, mais bon…) :

    
    import cpw.mods.fml.common.eventhandler.SubscribeEvent;
    import net.minecraft.entity.monster.EntityCaveSpider;
    import net.minecraft.entity.monster.EntityCreeper;
    import net.minecraft.entity.monster.EntityEnderman;
    import net.minecraft.entity.monster.EntitySilverfish;
    import net.minecraft.entity.monster.EntitySkeleton;
    import net.minecraft.entity.monster.EntitySlime;
    import net.minecraft.entity.monster.EntitySpider;
    import net.minecraft.entity.monster.EntityWitch;
    import net.minecraft.entity.monster.EntityZombie;
    import net.minecraft.entity.passive.EntityBat;
    import net.minecraft.entity.passive.EntityHorse;
    import net.minecraft.entity.passive.EntityOcelot;
    import net.minecraft.entity.passive.EntitySheep;
    import net.minecraft.entity.passive.EntitySquid;
    import net.minecraft.entity.passive.EntityWolf;
    import net.minecraft.entity.player.EntityPlayer;
    import net.minecraft.nbt.NBTTagCompound;
    import net.minecraftforge.event.entity.EntityEvent.EntityConstructing;
    import net.minecraftforge.event.entity.EntityJoinWorldEvent;
    import net.minecraftforge.event.entity.living.LivingDeathEvent;
    
    public class ExtPropEventHandler
    {
    
    private CommonProxy commonProxy = new CommonProxy();
    
    @SubscribeEvent
    public void livingEntity(LivingUpdateEvent event) 
    {
    if (event.entityLiving instanceof EntityPlayer) 
    {
    EntityPlayer player = ((EntityPlayer)event.entityLiving);
    
    ExtendedEntityPropertiesPlayer props = ExtendedEntityPropertiesPlayer.get(player);
    if(player.worldObj.getTotalWorldTime() % 40 == 0)
    {
    if(props.hasSpecificHandicap(EnumPlayerHandicaps.KNOCKEDDOWN))
    props.removeHandicap(EnumPlayerHandicaps.KNOCKEDDOWN);
    else
    props.addHandicap(EnumPlayerHandicaps.KNOCKEDDOWN);
    System.out.println(player.worldObj.isRemote);
    System.out.println(props.getHandicapsSet().size());
    }
    }
    }
    
    @SubscribeEvent
    public void onEntityConstructing(EntityConstructing event) 
    {
    if (event.entity instanceof EntityPlayer && ExtendedEntityPropertiesPlayer.get((EntityPlayer) event.entity) == null)
    ExtendedEntityPropertiesPlayer.register((EntityPlayer) event.entity);
    }
    
    @SubscribeEvent
    public void onLivingDeathEvent(LivingDeathEvent event) 
    {
    if (!event.entity.worldObj.isRemote && event.entity instanceof EntityPlayer) 
    {
    NBTTagCompound playerData = new NBTTagCompound();
    ((ExtendedEntityPropertiesPlayer) (event.entity.getExtendedProperties(ExtendedEntityPropertiesPlayer.EXT_PROP_NAME))).saveNBTData(playerData);
    commonProxy.storeEntityData(((EntityPlayer) event.entity).getDisplayName(), playerData);
    ExtendedEntityPropertiesPlayer.saveProxyData((EntityPlayer) event.entity);
    } 
    else 
    {
    
    }
    }
    
    @SubscribeEvent
    public void onEntityJoinWorld(EntityJoinWorldEvent event) 
    {
    if (!event.entity.worldObj.isRemote && event.entity instanceof EntityPlayer) 
    {
    NBTTagCompound playerData = commonProxy .getEntityData(((EntityPlayer) event.entity) .getDisplayName());
    if (playerData != null) 
    {
    ((ExtendedEntityPropertiesPlayer) (event.entity.getExtendedProperties(ExtendedEntityPropertiesPlayer.EXT_PROP_NAME))).loadNBTData(playerData);
    }
    ((ExtendedEntityPropertiesPlayer) (event.entity.getExtendedProperties(ExtendedEntityPropertiesPlayer.EXT_PROP_NAME))).sync();
    }
    }
    }
    
    

    Et enfin les lignes d'enregistrement de mes packets dans ma classe principale :
    network.registerMessage(PacketUpdateHandicap.ClientHandler.class, PacketUpdateHandicap.class, 7, Side.CLIENT);
    network.registerMessage(PacketUpdateHandicap.CommonHandler.class, PacketUpdateHandicap.class, 8, Side.SERVER);

    Voilà, j'espère que rien ne manque, merci d'avance =)</packetupdatehandicap,></packetupdatehandicap,></string></string></string></string></string></string>


  • Administrateurs

    Salut,
    Le problème vient de ton paquet, la boucle qui fait la lecture ne fait rien car handicaps est null.
    Il faudrait plutôt faire comme ça :

    @Override
    public void fromBytes(ByteBuf buf)
    {
       int size = buf.readInt()
       handicaps = new HashSet<string>();
       for(int i = 0; i < size; i++)
       {
           this.handicaps.add(ByteBufUtils.readUTF8String(buf));
       }
    }
    
    @Override
    public void toBytes(ByteBuf buf)
    {
       buf.writeInt(handicaps.size());
       for(String current : handicaps)
       {
           ByteBufUtils.writeUTF8String(buf, current);
       }
    }
    ```</string>


  • Ce que je ne comprends pas, c'est que la variable handicaps est initialisée dans le constructeur, pourquoi faut-il le refaire encore une fois dans fromBytes() ??


  • Administrateurs

    Elle est initialisé dans le constructeur public PacketUpdateHandicap(Set <string>handicaps), ce constructeur est utilisé pour l'envoie du paquet.
    à la réception du paquet c'est le constructeur public PacketUpdateHandicap() qui est utilisé (d'où la nécessité d'avoir toujours un constructeur vide).
    Lors de la réception les données n'ont pas encore été lu, donc forcement il ne connait pas encore les variables.
    Les variables prennent leurs valeurs lorsque la méthode fromBytes est lu.</string>



  • Merci je comprends mieux. Pour le moment ça fixe le bug des valeurs non changeantes, mais désormais le client a toujours une valeur opposée à celle du serveur. Genre quand mon client est à true, le serveur est à false, et le coup prochain, c'est le contraire 😕
    C'est à croire que la méthode sync() fait mal son boulot, ou encore que le packet a des handlers buggués ?
    Dans chaque handler, je redéfinis à la fin le set de l'ExtProp avec celui reçu dans mon message, est-ce le bon moyen ou aurais-je dû faire autrement ??


  • Administrateurs

    Peux-tu envoyer le paquet qui gère les booleans ? Car dans le paquet tu as envoyé il n'y a que le set qui est synchronisé.



  • En fait il n'y a pas de packet boolean, si tu regardes bien mon println dans mon EventHandler, LivingUpdateEvent. Je fais juste un petit if(props.hasSpecificHandicap(maEnumValue)).
    Du coup si le packet avec la HashSet avait bien fonctionné, le client et le serveur seraient censés avoir tous les deux cet objet dans handicaps, ce qui n'est le cas que 1 fois sur 2 😕


  • Administrateurs

    Ah oui d'accord.
    Je croyais que tu parlais des boolean agilityState, strengthState etc …

    Faudrait afficher le contenu de ta liste à différent endroit (à la fin de l'handler après avoir reçu le paquet, avant d'envoyer le paquet, etc ...) pour trouver vers où est le souci.



  • Okay je vais bien debug cet aprèm, et je te renverrai les logs.



  • Rebonjour, le problème a l'air corrigé car si je rightclick avec un custom item changeant à chaque fois le contenu de HashSet, eh bien la console m'indique de bons résultats.
    Bref je passe en résolue, mais j'en profite également pour poser 2 petites questions à part, histoire de ne pas recréer 2 topics différents de 3 messages chacun ^^'

    1)Pourquoi la variable EntityPlayer#iteminUseCount, n'est-elle pas enregistrée dans les tags du joueur, alors qu'elle est bien unique pour chacun d'entres-eux ?
    2)Je viens de créer un projectile possédant un delay de 3 sec's avant d'exploser, je l'ai bien enregistré via EntityRegistry.registerModEntity, idem pour son rendu, mais quand je le lance et que je déco/reco de la map, il disparaît comme si il n'avait jamais été lancé 😕 Sauriez-vous par hasard d'où cela peut venir ??
    Merci d'avance 😉


  • Administrateurs

    1. Car ça serait inutile ? Enregistrer une variable dans un tag nbt permet de l'enregistrer sur le disque et donc de ne pas la perdre lorsqu'elle est supprimé de la ram (principalement quand le serveur / client est coupé). Aucun intérêt à rendre iteminUseCount persistant.

    2. tu le lances bien côté serveur ?