Synchronisation Capabilities



  • Bonjour,

    J'ai crée une capability qui me sert à matérialiser le mana d'un joueur.
    J'ai ensuite créer une commande utilisant ce mana. De plus le mana est affiché sur le HUD.
    Le problème est que quand j'utilise cette commande, le mana baisse pendant une fraction de seconde avant de reprendre sa valeur initialise (c'est à peine visible.)

    Code de l'execute de la commande :

    @Override
        public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException
        {
            if(sender instanceof EntityPlayer)
            {
                EntityPlayer player = (EntityPlayer)sender;
                if(player.hasCapability(ProjectMod.MANA_CAP, null))
                {
                    ManaCapabilities cap = player.getCapability(ProjectMod.MANA_CAP, null);
                    if(cap.getMana() >= 10)
                    {
                        if(player.getHealth() < player.getMaxHealth())
                        {
                            cap.setMana(cap.getMana() - 10);
                            player.heal(2);
                            cap.sync();
                            sender.sendMessage(new TextComponentString(TextFormatting.GREEN+"[PMod] "+I18n.format("projectmod.spells.completed")));
                        }
                        else
                        {
                            sender.sendMessage(new TextComponentString(TextFormatting.RED+"[PMod] "+I18n.format("projectmod.spells.errors.heal")));
                        }
                    }
                    else
                    {
                        sender.sendMessage(new TextComponentString(TextFormatting.RED+"[PMod] "+I18n.format("projectmod.spells.errors.mana")));
                    }
                }
            }
        }
    

    Si vous voulez d'autres codes, je peux vous les fournir.

    Merci d'avance 😉


  • Moddeurs confirmés Rédacteurs Administrateurs

    Salut,

    Je ne vois pas de problème de ce côté.
    Si la mana baisse bien, il y a peut-être quelque chose qui la remonte ?



  • C'est ce que je me suis dit et la seule chose qui modifie la valeur de ma mana, outre cette commande, c'est ce timer :

    @SubscribeEvent
        public static void onPlayerTick(TickEvent.PlayerTickEvent event)
        {
            if(event.phase == TickEvent.Phase.END)
            {
                if(event.player.hasCapability(ProjectMod.MANA_CAP, null))
                {
                    ManaCapabilities cap = event.player.getCapability(ProjectMod.MANA_CAP, null);
                    cap.setTimer(cap.getTimer() - 1);
                    if(cap.getTimer() < 0)
                    {
                        if(cap.getMana() < 100)
                        {
                            cap.setMana(cap.getMana() + 1);
                        }
                        cap.setTimer(100);
                    }
                    cap.sync();
                }
            }
        }```

  • Moddeurs confirmés Rédacteurs Administrateurs

    Là on est sur une remontée toutes les 5 secondes.

    Quand tu réduis la mana, il faudrait remettre à 0 le timer au même moment.



  • J'ai ajouté un cap.setTimer(100); au niveau de l'execute de la commande
    Mais ça change rien...


  • Moddeurs confirmés Rédacteurs Administrateurs

    Tu peux envoyer le code de la classe ManaCapabilities ?


  • Moddeurs confirmés Rédacteurs

    Salut,
    Premièrement je ne suis pas d'accord sur le fait qu'il y ai besoin de remettre le timer de régénération de mana à 0 lors de l'utilisation de la commande. En soit, dans un système sort/mana, le fait d'utiliser un sort doit utiliser de la mana mais pas bloquer la régénération de celle-ci.

    Ensuite c'est de quel côté que la mana se régénère automatiquement ? Client-side only ou serveur/client ? C'est quelque chose qu'il serait bon de savoir.

    Dans tous les cas ça serait effectivement bien d'avoir la classe ManaCapabilities, et la classe du paquet te permettant de synchroniser tout ce petit monde.



  • Normalement c'est en serveur/client.

    ManaCapabilities :

    package fr.lavapower.projectmod.capabilities;
    
    import java.util.concurrent.Callable;
    
    import fr.lavapower.projectmod.ProjectMod;
    import fr.lavapower.projectmod.packets.PacketCapabilities;
    import net.minecraft.client.resources.I18n;
    import net.minecraft.entity.player.EntityPlayer;
    import net.minecraft.entity.player.EntityPlayerMP;
    import net.minecraft.nbt.NBTBase;
    import net.minecraft.nbt.NBTTagCompound;
    import net.minecraft.util.EnumFacing;
    import net.minecraftforge.common.capabilities.Capability;
    import net.minecraftforge.common.capabilities.CapabilityManager;
    import net.minecraftforge.common.capabilities.ICapabilityProvider;
    import net.minecraftforge.common.util.INBTSerializable;
    
    public class ManaCapabilities implements ICapabilityProvider, INBTSerializable<NBTTagCompound> 
    {    
        public int mana;
        public int timer;
        private EntityPlayer player;
        
        public static void register()
        {
            CapabilityManager.INSTANCE.register(ManaCapabilities.class, new ManaCapabilities.Storage(), new ManaCapabilities.Factory());
        }
         
        public ManaCapabilities(EntityPlayer entityPlayer)
        {
            this.mana = 0;
            this.timer = 100;
            this.player = entityPlayer;
        }
         
        public void sync()
        {
            PacketCapabilities packet = new PacketCapabilities(this.getMana(), 1);
            PacketCapabilities packet2 = new PacketCapabilities(this.getTimer(), 2);
            if(!this.player.world.isRemote)
            {
                EntityPlayerMP playerMP = (EntityPlayerMP)player;
                ProjectMod.network.sendTo(packet, playerMP);
                ProjectMod.network.sendTo(packet2, playerMP);
            }
            else
            {
                ProjectMod.network.sendToServer(packet);
                ProjectMod.network.sendToServer(packet2);
            }
        }
    
        @Override
        public boolean hasCapability(Capability capability, EnumFacing facing)
        {
            return ProjectMod.MANA_CAP != null && capability == ProjectMod.MANA_CAP;
        }
     
        @Override
        public <T> T getCapability(Capability <T>capability, EnumFacing facing)
        {
            return ProjectMod.MANA_CAP != null && capability == ProjectMod.MANA_CAP ? (T)this : null;
        }
     
        @Override
        public NBTTagCompound serializeNBT()
        {
            NBTTagCompound compound = new NBTTagCompound();
            compound.setInteger("Mana", this.getMana());
            compound.setInteger("Timer", this.getTimer());
            return compound;
        }
     
        @Override
        public void deserializeNBT(NBTTagCompound compound)
        {
            this.setMana(compound.getInteger("Mana"));
            this.setTimer(compound.getInteger("Timer"));
        }
        
        public void setMana(int mana)
        {
            this.mana = mana;
        }
         
        public int getMana()
        {
            return this.mana;
        }
        
        public void setTimer(int timer)
        {
            this.timer = timer;
        }
         
        public int getTimer()
        {
            return this.timer;
        }
        
        public static class Storage implements Capability.IStorage<ManaCapabilities> {
            
            @Override
            public NBTBase writeNBT(Capability<ManaCapabilities> capability, ManaCapabilities instance, EnumFacing side)
            {
                return null;
            }
         
            @Override
            public void readNBT(Capability<ManaCapabilities> capability, ManaCapabilities instance, EnumFacing side, NBTBase nbt)
            {
         
            }
         
        }
         
        public static class Factory implements Callable<ManaCapabilities> {
            @Override
            public ManaCapabilities call() throws Exception
            {
                return null;
            }
        }
    }
    
    

    Mon packet :

    package fr.lavapower.projectmod.packets;
    
    import io.netty.buffer.ByteBuf;
    import net.minecraft.client.Minecraft;
    import net.minecraft.server.MinecraftServer;
    import net.minecraft.util.IThreadListener;
    import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
    import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
    import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
    import net.minecraftforge.fml.relauncher.Side;
    import net.minecraftforge.fml.relauncher.SideOnly;
    
    public class PacketCapabilities implements IMessage
    {
        public int cap;
        public int type;
        
        public PacketCapabilities()
        {}
        
        public PacketCapabilities(int cap, int type)
        {
            this.cap = cap;
            this.type = type;
        }
    
        @Override
        public void fromBytes(ByteBuf buf)
        {
            this.cap = buf.readInt();
            this.type = buf.readInt();
        }
    
        @Override
        public void toBytes(ByteBuf buf)
        {
            buf.writeInt(this.cap);
            buf.writeInt(this.type);
        }
        
        public static class ServerHandler implements IMessageHandler <PacketCapabilities, IMessage>{
            
            @Override
            public IMessage onMessage(PacketCapabilities message, MessageContext ctx)
            {
                ctx.getServerHandler().player.mcServer.addScheduledTask(new ScheduledPacketTask(ctx.getServerHandler().player, message));
                return null;
            }
         
        }
         
        @SideOnly(Side.CLIENT)
        public static class ClientHandler implements IMessageHandler <PacketCapabilities, IMessage>{
         
            @Override
            public IMessage onMessage(PacketCapabilities message, MessageContext ctx)
            {
                Minecraft.getMinecraft().addScheduledTask(new ScheduledPacketTask(null, message));
                return null;
            }
        }
    
    }
    

    Il faut savoir que mon packet sert à cette capability mais aussi à une autre :x
    Du coup, la variable type du packet permet de savoir qu'es ce qui est synchronisé.
    (Bon autant, c'est pas une bonne méthode :x )



  • Personne ? Je peux fournir toutes les sources s'il faut :x (même si y'a pas que ça dedans)


  • Moddeurs confirmés Rédacteurs

    Salut,
    Première question : pourquoi tes classes ManaCapabilities.Storage et ManaCapabilities.Factory ont encore leur implémentation par défaut ?

    Seconde questions : pourquoi synchroniser le timer ? Et même si tu as besoin du timer client-side, pourquoi synchroniser la mana et le timer via deux envoie de paquets différents ?

    Troisième question : pourquoi dans ta méthode ManaCapabilities#sync, tu envoies des paquets au serveur ? C'est un peu bizarre, le client n'a rien à envoyer au serveur à priori, sinon il pourrait modifier son mana et se le mettre au max tout le temps.

    Quatrième question : Qu'est-ce que la classe ScheduledPacketTask ? J'aimerai bien voir ce que tu fais dedans



  • Question 1 : J'ai suivi le tuto :x
    Question 2 : Effectivement, c'est réglé
    Question 3 : De même c'est réglé
    Question 4 :

    package fr.lavapower.projectmod.packets;
    
    import fr.lavapower.projectmod.ProjectMod;
    import net.minecraft.client.Minecraft;
    import net.minecraft.entity.player.EntityPlayer;
    import net.minecraftforge.fml.relauncher.Side;
    import net.minecraftforge.fml.relauncher.SideOnly;
    
    public class ScheduledPacketTask implements Runnable
    {
    
        private EntityPlayer player;
        private PacketCapabilities message;
     
        public ScheduledPacketTask(EntityPlayer player, PacketCapabilities message)
        {
            this.player = player;
            this.message = message;
        }
     
        @Override
        public void run()
        {
            EntityPlayer player = this.player == null ? getPlayer() : this.player;
            switch(message.type)
            {
                case 0:
                    player.getCapability(ProjectMod.SPELL_CAP, null).setSpell(message.cap);
                    break;
                case 1:
                    player.getCapability(ProjectMod.MANA_CAP, null).setMana(message.cap);
                    break;
            }
        }
     
        @SideOnly(Side.CLIENT)
        private EntityPlayer getPlayer()
        {
            return Minecraft.getMinecraft().player;
        }
    
    }
    

    En réglant les deux trucs en haut, la synchro quand on utilise le sort est bonne mais faut utiliser quel event pour que quand le joueur se connecte, y'a une synchro ?
    (Ca le faisait avant mais c'est plus le cas, du coup quand on utilise le mana, y'a la synchro et le mana passe à 90 alors que pour le client il était à 0)

    C'est bon j'ai trouvé 🙂


Log in to reply