"Accroché" une entité à une autre entité



  • Salut
    (Déjà, je sais, le titre n'est pas très explicite mais je ne savais pas quoi mettre.)
    Je vais tout d'abord expliquer ce que je voudrais faire, je pense que ça aidera certains à comprendre la suite.
    J'ai créer des rennes et un traîneau. J'arrive à contrôler les deux. Ce que je voudrais, c'est que on ne puisse contrôler le traîneau seulement si des rennes sont accrochés. Et je voudrais aussi que plus il y a de rennes, plus le traîneau ira vite. Pour ça, je sais comment faire, il suffit de multiplier la vitesse du traîneau par le nombre de renne.

    Ce que je n'arrive pas à faire, c'est accrochés les rennes au traîneau. J'ai créé une nouvelle corde auquel je peux tirer le renne (comme une "Lead" (je sais pas comment traduire ça)). Et c'est là que ça coince : quand je clique droit sur le traîneau, rien ne se passe. J'ai mis des messages et j'ai trouvé : quand je fais clique droit sur le traîneau, le jeu considère que c'est pas un traîneau.

    Je vous met les codes :
    ItemRope :

    package This_is_Christmas.Item;
    
    import This_is_Christmas.Entity.EntityRopeKnot;
    import This_is_Christmas.Entity.EntitySleigh;
    import net.minecraft.entity.Entity;
    import net.minecraft.entity.EntityLiving;
    import net.minecraft.entity.player.EntityPlayer;
    import net.minecraft.item.Item;
    import net.minecraft.item.ItemStack;
    import net.minecraft.util.ActionResult;
    import net.minecraft.util.EnumActionResult;
    import net.minecraft.util.EnumFacing;
    import net.minecraft.util.EnumHand;
    import net.minecraft.util.math.AxisAlignedBB;
    import net.minecraft.util.math.BlockPos;
    import net.minecraft.world.World;
    
    public class ItemRope extends Item{
    
    public ItemRope()
    {
    super();
    }
    
       public ActionResult <itemstack>onItemRightClick(ItemStack itemStackIn, World worldIn, EntityPlayer playerIn, EnumHand hand)
       {
    EntitySleigh entity = (EntitySleigh)worldIn.getEntityByID(504);
    
    if (!(entity instanceof EntitySleigh))
    {
    System.out.println("l'entité n'est pas une instance de EntitySleigh");
               return new ActionResult(EnumActionResult.PASS, itemStackIn);
    }
    else
    {
    if (!worldIn.isRemote)
    {
    System.out.println("l'entité est une instance de EntitySleigh");
    attachToSleigh(playerIn, worldIn, entity);
    }
    
               return new ActionResult(EnumActionResult.SUCCESS, itemStackIn);
    }
    }
    
    public static boolean attachToSleigh(EntityPlayer player, World worldIn, Entity entity)
    {
    EntityRopeKnot entityropehknot = EntityRopeKnot.getKnotForPosition(worldIn, entity);
    boolean flag = false;
    double d0 = 7.0D;
    int i = (int)entity.posX;
    int j = (int)entity.posY;
    int k = (int)entity.posZ;
    
    for (EntityLiving entityliving : worldIn.getEntitiesWithinAABB(EntityLiving.class, new AxisAlignedBB((double)i - d0, (double)j - d0, (double)k - d0, (double)i + d0, (double)j + d0, (double)k + d0)))
    {
    if (entityliving.getLeashed() && entityliving.getLeashedToEntity() == player)
    {
    if (entityropehknot == null)
    {
    entityropehknot = createKnot(worldIn, entity);
    }
    
    entityliving.setLeashedToEntity(entityropehknot, true);
    flag = true;
    }
    }
    
    return flag;
    }
    
       public static EntityRopeKnot createKnot(World worldIn, Entity entity)
       {
        EntityRopeKnot entityropeknot = new EntityRopeKnot(worldIn, entity);
        entityropeknot.forceSpawn = true;
           worldIn.spawnEntityInWorld(entityropeknot);
           entityropeknot.playPlaceSound();
           return entityropeknot;
       }
    }
    

    c'est peut-être le world.getEntityByID() qui bug. Mon traîneau est bien enregistré avec l'ID 504 pourtant.

    EntityRopeKnot :

    package This_is_Christmas.Entity;
    
    import javax.annotation.Nullable;
    
    import This_is_Christmas.CreateItems;
    import net.minecraft.block.BlockFence;
    import net.minecraft.entity.Entity;
    import net.minecraft.entity.EntityHanging;
    import net.minecraft.entity.EntityLiving;
    import net.minecraft.entity.player.EntityPlayer;
    import net.minecraft.init.Items;
    import net.minecraft.init.SoundEvents;
    import net.minecraft.item.ItemStack;
    import net.minecraft.nbt.NBTTagCompound;
    import net.minecraft.util.EnumFacing;
    import net.minecraft.util.EnumHand;
    import net.minecraft.util.math.AxisAlignedBB;
    import net.minecraft.util.math.BlockPos;
    import net.minecraft.util.math.MathHelper;
    import net.minecraft.world.World;
    import net.minecraftforge.fml.relauncher.Side;
    import net.minecraftforge.fml.relauncher.SideOnly;
    
    public class EntityRopeKnot extends EntityHanging
    {
       protected Entity entityPosition;
    
       public EntityRopeKnot(World worldIn)
       {
           super(worldIn);
       }
    
       public EntityRopeKnot(World worldIn, Entity entityPositionIn)
       {
           this(worldIn);
           this.entityPosition = entityPositionIn;
           this.setPosition((double)entityPositionIn.posX + 0.5D, (double)entityPositionIn.posY + 0.5D, (double)entityPositionIn.posZ + 0.5D);
           float f = 0.125F;
           float f1 = 0.1875F;
           float f2 = 0.25F;
           this.setEntityBoundingBox(new AxisAlignedBB(this.posX - 0.1875D, this.posY - 0.25D + 0.125D, this.posZ - 0.1875D, this.posX + 0.1875D, this.posY + 0.25D + 0.125D, this.posZ + 0.1875D));
       }
    
       /**
        * Sets the x,y,z of the entity from the given parameters. Also seems to set up a bounding box.
        */
       public void setPosition(double x, double y, double z)
       {
           super.setPosition((double)MathHelper.floor_double(x) + 0.5D, (double)MathHelper.floor_double(y) + 0.5D, (double)MathHelper.floor_double(z) + 0.5D);
       }
    
       /**
        * Updates the entity bounding box based on current facing
        */
       protected void updateBoundingBox()
       {
           this.posX = (double)this.entityPosition.posX + 0.5D;
           this.posY = (double)this.entityPosition.posY + 0.5D;
           this.posZ = (double)this.entityPosition.posZ + 0.5D;
       }
    
       /**
        * Updates facing and bounding box based on it
        */
       public void updateFacingWithBoundingBox(EnumFacing facingDirectionIn)
       {
       }
    
       public int getWidthPixels()
       {
           return 9;
       }
    
       public int getHeightPixels()
       {
           return 9;
       }
    
       public float getEyeHeight()
       {
           return -0.0625F;
       }
    
       /**
        * Checks if the entity is in range to render.
        */
       @SideOnly(Side.CLIENT)
       public boolean isInRangeToRenderDist(double distance)
       {
           return distance < 1024.0D;
       }
    
       /**
        * Called when this entity is broken. Entity parameter may be null.
        */
       public void onBroken(@Nullable Entity brokenEntity)
       {
           this.playSound(SoundEvents.ENTITY_LEASHKNOT_BREAK, 1.0F, 1.0F);
       }
    
       /**
        * Either write this entity to the NBT tag given and return true, or return false without doing anything. If this
        * returns false the entity is not saved on disk. Ridden entities return false here as they are saved with their
        * rider.
        */
       public boolean writeToNBTOptional(NBTTagCompound compound)
       {
           return false;
       }
    
       /**
        * (abstract) Protected helper method to write subclass entity data to NBT.
        */
       public void writeEntityToNBT(NBTTagCompound compound)
       {
       }
    
       /**
        * (abstract) Protected helper method to read subclass entity data from NBT.
        */
       public void readEntityFromNBT(NBTTagCompound compound)
       {
       }
    
       public boolean processInitialInteract(EntityPlayer player, @Nullable ItemStack stack, EnumHand hand)
       {
           if (this.worldObj.isRemote)
           {
               return true;
           }
           else
           {
               boolean flag = false;
    
               if (stack != null && stack.getItem() == CreateItems.Rope)
               {
                   double d0 = 7.0D;
    
                   for (EntityLiving entityliving : this.worldObj.getEntitiesWithinAABB(EntityLiving.class, new AxisAlignedBB(this.posX - d0, this.posY - d0, this.posZ - d0, this.posX + d0, this.posY + d0, this.posZ + d0)))
                   {
                       if (entityliving.getLeashed() && entityliving.getLeashedToEntity() == player)
                       {
                           entityliving.setLeashedToEntity(this, true);
                           flag = true;
                       }
                   }
               }
    
               if (!flag)
               {
                   this.setDead();
    
                   if (player.capabilities.isCreativeMode)
                   {
                       double d1 = 7.0D;
    
                       for (EntityLiving entityliving1 : this.worldObj.getEntitiesWithinAABB(EntityLiving.class, new AxisAlignedBB(this.posX - d1, this.posY - d1, this.posZ - d1, this.posX + d1, this.posY + d1, this.posZ + d1)))
                       {
                           if (entityliving1.getLeashed() && entityliving1.getLeashedToEntity() == this)
                           {
                               entityliving1.clearLeashed(true, false);
                           }
                       }
                   }
               }
    
               return true;
           }
       }
    
       /**
        * checks to make sure painting can be placed there
        */
       public boolean onValidSurface()
       {
           return this.worldObj.getEntityByID(504) instanceof EntitySleigh;
       }
    
       public static EntityRopeKnot createKnot(World worldIn, Entity entity)
       {
           EntityRopeKnot entityleashknot = new EntityRopeKnot(worldIn, entity);
           entityleashknot.forceSpawn = true;
           worldIn.spawnEntityInWorld(entityleashknot);
           entityleashknot.playPlaceSound();
           return entityleashknot;
       }
    
       public static EntityRopeKnot getKnotForPosition(World worldIn, Entity entity)
       {
           int i = (int)entity.posX;
           int j = (int)entity.posY;
           int k = (int)entity.posZ;
    
           for (EntityRopeKnot entityleashknot : worldIn.getEntitiesWithinAABB(EntityRopeKnot.class, new AxisAlignedBB((double)i - 1.0D, (double)j - 1.0D, (double)k - 1.0D, (double)i + 1.0D, (double)j + 1.0D, (double)k + 1.0D)))
           {
               if (entityleashknot.getEntityPosition().equals(entity))
               {
                   return entityleashknot;
               }
           }
    
           return null;
       }
    
       public void playPlaceSound()
       {
           this.playSound(SoundEvents.ENTITY_LEASHKNOT_PLACE, 1.0F, 1.0F);
       }
    
       public Entity getEntityPosition()
       {
           return this.entityPosition;
       }
    }
    

    Je sais qu'il faut aussi modifier l'entité du traîneau pour y inclure un getter (ou un truc comme ça) sur combien de renne sont accrochés, mais je sais pas du tout comment m'y prendre.

    Si vous avez une idée, …

    Merci d'avance</itemstack>



  • Regarde dans code de minecraft du côté des spider jockey, (le squelettes embarque sur l’araignée) D'après moi, cela pourrait peu être t'aider.



  • En fait tu ne devrais pas te servir du onitemRightClick, mais plutôt de la méthode interact, dans la classe de ton traîneau. Ensuite tu vérifies si le getHeldItem du joueur n'est pas null et si il renvoi bien ta corde. Après pour check si ta corde possédait des rennes au bout ou non, tu peux te servir des NBTTag.



  • Mais je ne sais pas comment faire avec les NBTTags. J'ai essayé de faire ça dans le onItemRightClick de ma corde :

    EntityReindeer entityReindeer = (EntityReindeer)worldIn.getEntityByID(502);
    if(entityReindeer instanceof EntityReindeer)
    {
    System.out.println("reindeer");
    }
    if(!(entityReindeer instanceof EntityReindeer))
    {
    System.out.println("not reindeer");
    }
    
    ```Quand je fait click droit autre part que sur un renne, ça me met le messae comme quoi ce n'est pas un renne, mais quand je fait click droit dessus, pas de message.
    
    J'ai aussi découvert que dans la classe EntityLiving (donc dans le renne également), il y a deux fonctions : une qui renvoie un boolean qui dit si le renne est accroché à une corde ou non et une qui dit quelle entité le tire. Je ne pense pas qu'on aura besoin de la 2ème.


  • Le getEntityByID renvoie l'instance de l'entité ayant l'ID entrée en argument. Mais ce n'est pas le même ID qu'a l'enregistrement dans le registre, comme l'a dit Plaigon il est plus simple de passer par la méthode interact() dans la classe de ton renne, et de faire référence à son instance avec un this tout simplement. Après si tu tiens à garder ton processus dans le onItemRightClick() il faudra passer par un raytracer.



  • Réexplique clairement ce que tu veux faire, car là j'ai pas tout compris. Ainsi on pourra faire en sorte de te donner un ensemble d'étapes à suivre, bien détaillé et accessible pour que tu puisses résoudre ton problème 😉



  • Je voudrais faire un truc comme ça : (j'ai mis spoiler, image trop grande)

    C'est à dire, qu'on puisse accrocher un renne à mon traîneau. Une fois qu'il sera accroché, on ne pourra plus monter dessus. Et on ne pourra avancer avec le traîneau seulement si au moins un renne est accroché, avec une limite de six rennes.

    Je ne sais pas si c'est mieux expliquer, je pense qu'avec l'image c'est déjà mieux.
    Dans la classe du renne, j'ai fait ça :

    public boolean processInteract(EntityPlayer player, EnumHand p_184645_2_, ItemStack stack)
    {
    
    if (stack != null && stack.getItem() == Items.LEAD)
    {
    return false;
    }
    else if (stack != null && stack.getItem() == CreateItems.Rope && this.canBeLeashedTo(player))
    {
    this.setLeashedToEntity(player, true);
    –stack.stackSize;
    return true;
    }
    else if (this.getLeashed() && /*le joueur click droit sur le traineau*/)
    {
    this.setLeashedToEntity(/*traîneau où le joueur click*/, true);
    return true;
    }
    else if (!this.worldObj.isRemote && (!this.isBeingRidden() || this.isRidingOrBeingRiddenBy(player)))
    {
    player.startRiding(this);
    return true;
    }
    else
    {
    return false;
    }
    }
    

    Dans la condition this.getLeashed, il faudrait pouvoir détecter où le joueur fait un click droit. Et s'il fait click droit sur le traineau, ça les attache ensemble. J'ai déjà tout préparé, il manque plus que la détection de l'endroit du click.



  • Je pense pas que tu puisse savoir grâce à un paramètre où se trouve l'autre bout de la laisse, en revanche tu dois pouvoir avoir accès à l'entité de la laisse



  • @SCAREX:

    en revanche tu dois pouvoir avoir accès à l'entité de la laisse

    Oui, si il a bien enregistré l'id de cet entity dans les tags de la laisse en question 😃



  • Salut
    @'Plaigon':

    @'SCAREX':

    en revanche tu dois pouvoir avoir accès à l'entité de la laisse

    Oui, si il a bien enregistré l'id de cet entity dans les tags de la laisse en question 😃

    Justement, je ne vois pas comment enregistré l'entité dans les tags de la laisse. D'ailleurs, de base l'entité n'est pas enregistré non plus dans des tags.
    La fonction que j'ai donné ne peut pas marcher ?

    Sinon j'avais donné une autre fonction qui ne marchais pas, y'avait un problème d'ID. J'ai essayé de faire :

    public ActionResult <itemstack>onItemRightClick(ItemStack itemStackIn, World worldIn, EntityPlayer playerIn, EnumHand hand)
       {
        EntitySleigh sleigh = new EntitySleigh(worldIn);
    EntitySleigh entitySleigh = (EntitySleigh)worldIn.getEntityByID(sleigh.getEntityId());
    
    if (!(entitySleigh instanceof EntitySleigh))
    {
    System.out.println("l'entité n'est pas une instance de EntitySleigh");
               return new ActionResult(EnumActionResult.PASS, itemStackIn);
    }
    else
    {
    if (!worldIn.isRemote)
    {
    System.out.println("l'entité est une instance de EntitySleigh");
    attachToSleigh(playerIn, worldIn, entitySleigh);
    }
    
               return new ActionResult(EnumActionResult.SUCCESS, itemStackIn);
    }
    }
    ``` mais ça ne marche pas. Ici ça récupère l'ID d'une nouvelle instance. Or je voudrais récupéré l'instance de l'entité existante mais je n'ai rien trouvé.</itemstack>


  • Il te faut un raytracer pour savoir si tu pointes bien vers une EntityLiving, et si c'est le cas, la cast ensuite en EntitySleigh 😉



  • Dans la classe de mon renne, j'ai testé : ```java
    public boolean processInteract(EntityPlayer player, EnumHand hand, ItemStack stack)
    {
    RayTraceResult rtr = player.rayTrace(50, 1);

    if(rtr.entityHit instanceof EntityReindeer)
    {
    System.out.println("le joueur regarde (ou click, je sais pas) un entityliving");
    return true;
    }
    /* if (stack != null && stack.getItem() == Items.LEAD)
    {
    return false;
    }
    else if (stack != null && stack.getItem() == CreateItems.Rope && this.canBeLeashedTo(player))
    {
    this.setLeashedToEntity(player, true);
    –stack.stackSize;
    System.out.println(this.getLeashed());
    System.out.println(this.getLeashedToEntity());
    return true;
    }
    // else if (this.getLeashed() && this.getLeashedToEntity() == player && rtr.entityHit instanceof EntityLiving/le joueur click droit sur le traineau///)
    // {
    // System.out.println("le renne est leashed au joueur ET le joueur regarde (ou click, je sais pas) un entityliving");
    // EntitySleigh sleigh = (EntitySleigh)rtr.hitInfo;
    // this.setLeashedToEntity(sleigh/traîneau où le joueur click/, true);
    // return true;
    /* }
    else if (!this.worldObj.isRemote && (!this.isBeingRidden() || this.isRidingOrBeingRiddenBy(player)))
    {
    player.startRiding(this);
    return true;
    }*/
    else
    {
    return false;
    }
    }

    Une idée ?


  • Alors ça fait longtemps que je ne m'étais plus servir des raytraces, mais de mémoire je me servais plutôt de la méthode World#rayTraceBlock, qui prenait en paramètre un simple vecteur, et en deuxième celui du regard du joueur.



  • Salut
    Si je comprend bien le nom de la fonction, c'est pour les blocks et non pour les entités. Peut-être que ça marche quand même, je sais pas

    Sinon, je pense m'y prendre très mal. J'ai fait :

    World world = player.worldObj;
    RayTraceResult rtr = player.rayTrace(50, 0);
    RayTraceResult rtr2 = world.rayTraceBlocks(this.getLookVec(), player.getLookVec());
    
    if(rtr2.hitInfo instanceof EntityReindeer)
    {
    System.out.println("le joueur regarde (ou click, je sais pas) un entityliving");
    return true;
    }
    ``` et crash au click droit, NPE. Ca m'indique la condition. Et encore ça va posé problème quand je veux faire mon truc. Il faudrait donc détecté un traîneau pour ensuite récupérer son vecteur. Ou alors on peut directement passer par l'entitySleigh, mai c'est pareil, problème. J'ai fait : ```java
    if (stack != null && stack.getItem() == CreateItems.Rope)
    {
    return ItemRope.attachToSleigh(player, player.worldObj, entity);
    }
    ``` Je me suis inspiré du blockFence : ```java
    public boolean onBlockActivated(World worldIn, BlockPos pos, IBlockState state, EntityPlayer playerIn, EnumHand hand, @Nullable ItemStack heldItem, EnumFacing side, float hitX, float hitY, float hitZ)
    {
    return worldIn.isRemote ? true : ItemLead.attachToFence(playerIn, worldIn, pos);
    }
    ``` Mais le problème, c'est que je doit entrer l'entité du renne.
    
    Donc au final, c'est pareil : on est coincé. Si on utilise la méthode dans l'entityReindeer (donc avec rayTrace), déjà ça crash et ensuite il faut récupérer l'instance d'entitySleigh sur lequel je fais click droit. Et si on utilise la méthode dans l'entitySleigh (donc inspirée du BlockFence) il faut récupéré l'instance de l'entityReindeer (donc si j'ai bien compris les messages de la page précédente, avec des NBTTags, dont je ne sais pas comment faire). C'est assez problématique :/


  • Salut. Personne ne sait comment faire ?



  • Sinon au lieu de te prendre la tête avec un RayTracer, tu peux très bien override la méthode itemInteractionForEntity, qui possède elle-même un argument de l'EntityLiving avec laquelle on a interagi 😉



  • Je te remercie, c'est plus facile. Mais du coup j'ai deux problèmes : comme c'est une fonction qui va dans l'item de ma corde, il faut détecter les deux mobs : le renne et le traîneau. J'arrive à détecter le renne, mais c'est le traîneau qu'il faut. Mais c'est plus dur pour celui-ci car target est un EntityLivingBase. Or mon traîneau est un Entity. Et pis si j'arrive à détecter le traîneau, il faudrait quand même que je détecte si un renne est accroché à la corde.

    Au pire si y'a aucune autre solution, je pourrais modifier le model du traîneau pour y inclure les modèles des rennes. Je mettrais un nouveau loot quand on tue le renne, et je l'utiliserait dans le craft du traîneau. Ca fera bizarre, mais au pire je peux faire ça si y'a pas de solution, et je réessayerait pour ma version de l'année prochaine, j'aurai plus de temps pour m'y consacrer. Après, si toi ou quelqu'un d'autre à une autre solution avant la fin du mois, j'essayerais et je vous dirais ce que ça fait, si ça marche ou pas.



  • C'est pour ça que tu dois enregistrer le tout dans les itemstack de ta rope. On te l'a déjà dit plusieurs fois ^^
    Sinon vois pour l'extends EntityLiving…
    Ou peut-être que l'event EntityinteractEvent supporte les Entity 😉



  • @'Plaigon':

    C'est pour ça que tu dois enregistrer le tout dans les itemstack de ta rope. On te l'a déjà dit plusieurs fois ^^

    Justement, je l'ai aussi dit, je ne sais pas comment faire pour enregistrer l'entité dans les NBT de l'item. Je sais utiliser des NBTTags, mais il faut détecter l'entité au bout de la corde pour ensuite l'enregsitrer. Et ça, je ne sais pas



  • Y'a juste énormément de demandes sur comment se servir des NBT d'Itemstack, fais une recherche là…
    Autre question, ta rope peut-elle être utilisé sur plusieurs rennes ou alors sur qu'un seul ?
    Dans tous les cas, il faudra register un integer dans les NBT, l'id du renne. Si il est possible d'en attacher plusieurs, il faudra opter pour une NBTTagList d'integer 😉