Crash serveur avec des EntityThrowable



  • Bonjour,

    Déjà un grand merci pour les tutoriels et les retours que vous faite aux moddeurs en français !!

    J'ai réalisé un mod pour les besoin d'un jeu sur un serveur modé, l'une des fonctionnalités que j'ai développé, est un périphérique CompterCraft.

    Il tire un projectile totalement décoratif (aucune impact, il permet juste de visualisé des tires entre turtle)

    #1 La premier question, peut on faire apparaître une EntityThrowable uniquement coté client ? (si oui comment ? et le crash pourrait'il se produire coté client ?)

    J'ai réussi à réaliser toutes les fonctionnalités que je voulais mais il arrive que si plusieurs projectiles sont tirés en même temps dans une condition particulière (que je n'ai pas réussi à comprendre) le serveur crash
    J'ai eu que deux crash en 4/5h de test du jeu avec que des tires multiples

    Le crash :

    Description: Exception in server tick loop
    
    java.util.ConcurrentModificationException
    at java.util.HashMap$HashIterator.nextNode(HashMap.java:1437)
    at java.util.HashMap$KeyIterator.next(HashMap.java:1461)
    at net.minecraft.entity.EntityTracker.func_72788_a(EntityTracker.java:269)
    at net.minecraft.server.MinecraftServer.func_71190_q(MinecraftServer.java:648)
    at net.minecraft.server.dedicated.DedicatedServer.func_71190_q(DedicatedServer.java:334)
    at net.minecraft.server.MinecraftServer.func_71217_p(MinecraftServer.java:547)
    at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:396)
    at net.minecraft.server.MinecraftServer$2.run(MinecraftServer.java:685)
    

    (Version complet : https://github.com/mandonnaud/houbmod/blob/master/crashReport )

    L'extrais du code du périphérique :

    EntityProjectil tire=new EntityProjectil(worldObj);
    tire.setPosition(X+0.5, Y+0.5, Z);
    tire.direction((String)arguments[3],vitesse);
    worldObj.spawnEntityInWorld(tire);
    

    ( Code ligne 105 : https://github.com/mandonnaud/houbmod/blob/master/src/main/java/fr/adslhouba/houbmod/common/TileEntityGenLaser.java Ligne

    Le projectil

    package fr.adslhouba.houbmod.common;
    
    import net.minecraft.block.Block;
    import net.minecraft.block.BlockAir;
    import net.minecraft.entity.EntityLivingBase;
    import net.minecraft.entity.projectile.EntityThrowable;
    import net.minecraft.util.MovingObjectPosition;
    import net.minecraft.util.MovingObjectPosition.MovingObjectType;
    import net.minecraft.world.World;
    
    public class EntityProjectil extends EntityThrowable {
    
    private int ticksAlive=0;
    private int ticksAliveMax=400;
    
    public EntityProjectil(World par1World, double par2, double par4, double par6)
    {
    super(par1World, par2, par4, par6);
    }
    public EntityProjectil(World par1World, EntityLivingBase par2EntityLivingBase)
    {
    super(par1World, par2EntityLivingBase);
    }
    public EntityProjectil(World par1World)
    {
    super(par1World);
    this.motionX=0;
    this.motionY=0;
    this.motionZ=0;
    }
    
    public void direction(String direct,double vitesse) {
    this.posZ+=0.5;
    vitesse=vitesse*0.3;
    this.ticksAliveMax=(int) Math.round(120/vitesse)+2;
    if (direct.equals("SOUTH")) {
    this.motionZ=vitesse;
    this.motionX=0;
    //this.posX+=0.5;
    } else if (direct.equals("NORTH")) {
    this.motionZ=vitesse*-1;
    this.motionX=0;
    //this.posX+=0.5;
    } else if (direct.equals("WEST")) {
    this.motionZ=0;
    this.motionX=vitesse*-1;
    //this.posY+=0.5;
    } else if (direct.equals("EAST")) {
    this.motionZ=0;
    this.motionX=vitesse;
    //this.posY+=0.5;
    }
    }
    @Override
    protected void onImpact(MovingObjectPosition mop)
    {
    //this.setDead();
    }
    
       @Override
       public void onUpdate()
       {
        ++this.ticksAlive;
        if (this.ticksAlive<2) {
    
        } else if (this.ticksAlive>this.ticksAliveMax) {
        this.setDead();
        } else {  
        Block test=this.worldObj.getBlock((int)Math.floor(this.posX),(int)Math.floor(this.posY),(int)Math.floor(this.posZ));    
        if (test instanceof BlockAir) {
    
        } else {    
        this.setDead();
        }
        if (!this.isDead) {
        this.setPosition(this.posX, this.posY, this.posZ);
    this.posX += this.motionX;
       this.posZ += this.motionZ;
        }
      }
        }
    }
    

    Github complet du mod : https://github.com/mandonnaud/houbmod/tree/master/src/main/java/fr/adslhouba/houbmod

    Cordialement


  • Administrateurs

    Salut,

    Les fonctions de lua sont-elle est exécuté dans un thread à part ? J'ai l'impression que oui, car ton problème c'est que tu fais spawn une entité (ce qui l'ajoute à la liste des entités) en même temps que la liste des entités est parcourus (surement par le thread du serveur).
    https://docs.oracle.com/javase/7/docs/api/java/util/ConcurrentModificationException.html

    Faudrait donc faire spawn l'entité via le thread du serveur si c'est bien ça le problème.

    Quand à faire spawn l'entité sur le client, c'est possible mais l'entité sera purement esthétique, il ne pourra pas interagir sur le monde.



  • Je suis développeur php/lua/as, je débute avec java.

    Les fonctions de lua sont-elle est exécuté dans un thread à part ? C'est tous à fait possible vu que le code est lancé via le lua de CC

    Faudrait donc faire spawn l'entité via le thread du serveur si c'est bien ça le problème. Du coup comment ?

    Quand à faire spawn l'entité sur le client, c'est possible mais l'entité sera purement esthétique, il ne pourra pas interagir sur le monde. Elle s'arrete juste quand y a un bloc, c'est tous. Aucune conséquence mais du coups même problème de thread ou pas ?


  • Administrateurs

    Pour l'exécuter dans le thread serveur, tu pourra au lieu de faire span l'entité l'ajouter à une liste et via la fonction update du tile entity itérer la liste (avec un iterator pour éviter d'avoir une exception de modification concurrente à ce niveau) et faire spawn chaque entité dans la liste puis la retirer

    Concernant le Spawn de l'entité sur le client seulement, en utilisant un paquet il y a un peu près le même soucis car l'handler du packet est exécuté dans le thread de netty. Mais il y a une fonction pour faire exécuter du contenu dans le thread client (de tête je ne sais plus, je l'envoie dès que je suis sur mon pc)



  • J'ai du te relire plusieurs fois pour tous comprendre  😄  (le temps de me remmetre dans le bain) mais j'ai compris je doit mettre le [size=smallspawnEntityInWorld dans la fonction] [size=smallonUpdate updateEntity.  Je capte bien le principe et pourquoi le crash. Merci]

    [EDIT] ok j'ai réussi

    J'attend que tu me retrouve la fonction pour le coté client car autant économisé la ressource serveur


  • Administrateurs

    Pour le paquet : https://www.minecraftforgefrance.fr/showthread.php?tid=1118

    Ensuite pour être sur que la fonction s'exécute dans le thread client :

    IThreadListener thread = FMLCommonHandler.instance().getWorldThread(ctx.netHandler);
    if(thread.isCallingFromMinecraftThread())
    {
    this.process();
    }
    else
    {
    thread.addScheduledTask(new Runnable()
    {
    @Override
    public void run()
    {
    Handler.this.process();
    }
    });
    }
    

    Et dans ta fonction process tu fais spawn l'entité.