SOLVED Fonction exécutée à la création de la TE


  • Bonjour, c'est encore et toujours moi à la recherche d'une fonction précise. x)

    Cette fois-ci, je cherche une fonction qui serait exécutée lors de l'apparition de la TE, c'est à dire lorsque que le chunk se recharge et que la TE est régénérée.

    Pouvez-vous m'aider ? Merci d'avance.

  • Moddeurs confirmés

    C'est une TileEntityCustom ?
    Si oui, tu peux mettre le code dans le constructeur de ta TileEntity

    Si non, tu as un event ChunkEvent.Load 😉


  • Je vais tester demain, merci.

    EDIT : Ok, donc il s'agit d'une TE perso, cependant je ne vois pas vraiment ce que tu veux dire par le mettre dans le constructeur, sachant qu'un constructeur n'est pas forcement exécuté, non ?


  • thumbs

    @'pingoleon60':

    Je vais tester demain, merci.

    EDIT : Ok, donc il s'agit d'une TE perso, cependant je ne vois pas vraiment ce que tu veux dire par le mettre dans le constructeur, sachant qu'un constructeur n'est pas forcement exécuté, non ?

  • Moddeurs confirmés Rédacteurs Administrateurs

    Si lors du chargement d'un tile entity minecraft initialise la classe puis fait un readFromNBT, donc le constructeur est bien exécuté à chaque chargement du tile entity.

  • Moddeurs confirmés

    En règle générale, tout dépends du constructeur qui est appelé si tu en as plusieurs.
    Ici, j'imagine que tu as 2 constructeurs :

    • Un constructeur par defaut déclaré explicitement
    • Un constructeur avec des parametres pour initialiser ta TE pour la première fois.

    Comme l'a dit Robin, lorsque Minecraft charge ta TileEntity, il appel le constructeur par defaut et readFromNBT.

    Si le code en question n'a pas besoin des attributs de ton objet, tu peux mettre ton code dans le constructeur par defaut, puis d'appeler this() dans l'autre constructeur.

    Si le code a besoin des attributs, il faut créer une méthode private que tu va appeler a la fin de ton constructeur avec paramètre(s) puis a la fin de la fonction readFromNBT.

    😉


  • Alors…

    Avec ma formation que j'ai eu sur le Java, un constructeur c'est une fonction qui porte le nom de la classe. Donc comment est-ce que tu différencie clairement les deux types de constructeurs ?

  • Moddeurs confirmés

    Je ne sais pas tu as eu quoi comme formation mais c'est légers xD
    Un constructeur c'est une méthode sans type de retour et qui porte le nom de la classe.
    Elle te permet d'instancier un objet avec le mot clef new.

    Par defaut, toutes les classes ont implicitement (c'est a dire, pas besoin de l'écrire) un constructeur sans paramètre qui est le constructeur par defaut.
    Lorsque tu définis toi même un constructeur, le constructeur par defaut disparait.

    Quand tu crées une TileEntity ou tout autre objet qui va s'initialisé via l'appel d'une methode par le moteur du jeu, il te faut un constructeur par defaut.

    Donc pour répondre a ta question, toutes les methodes sans type de retour et portant le même nom que la classe sont des constructeur. Un constructeur par defaut est un contructeur qui n'a pas de parametre.

    Pour des explications plus bas niveau, le new, c'est le mot clef qui te permet de faire un malloc. A la différence du C, ce n'est pas toi qui gère la mémoire et les adresses mémoires, c'est la JVM 😉


  • Alors ok, c'est pourtant bien ce que je pensais, mais ça crash x)

    J'ai une fonction que j'appelle dans le constructeur qui fait crasher lorsque la TE se charge alors qu'elle fonctionne très bien ailleurs. Elle fait appel à du contenu se trouvant dans la… STOP. Je viens de comprendre, vu que ma fonction fait appel à du contenu se trouvant dans elle même, c'est normal que ça crash. Vous ne sauriez pas où je peux la placer alors pour qu'elle s'exécute pile à la fin du chargement ?

    Merci d'avance.

    (PS : et pour la formation c'est pas étonnant, j'ai surtout fouillé les sources de mods existants et y suis allé à la connaissance de programmation générale xD)

  • Moddeurs confirmés

    vu que ma fonction fait appel à du contenu se trouvant dans elle même, c'est normal que ça crash

    Ça ne veut rien dire.

    Donne nous le code de ta classe au pire 😉

    Comme je te l'ai dit, tu peux faire une méthode private et l'appeler a la fin du constructeur avec parametre et a la fin de readFromNBT.


  • TileEntityMultiblockControler, celle qui doit exécuter la fonction TileEntityMultiblock.newMaster() au démarrage :

    package pingo.virtualcraft.common;
    
    import net.minecraft.nbt.NBTTagCompound;
    import net.minecraft.network.NetworkManager;
    import net.minecraft.network.Packet;
    import net.minecraft.network.play.server.S35PacketUpdateTileEntity;
    
    public class TileEntityMultiblockControler extends TileEntityMultiblock {
    
    public boolean initialized = false;
    
    public void onDataPacket(NetworkManager net, S35PacketUpdateTileEntity pkt)
    
    {
    
    this.readFromNBT(pkt.func_148857_g());
    
    }
    
    public Packet getDescriptionPacket()
    
    {
    
    NBTTagCompound nbttagcompound = new NBTTagCompound();
    
    this.writeToNBT(nbttagcompound);
    
    return new S35PacketUpdateTileEntity(this.xCoord, this.yCoord, this.zCoord, 3, nbttagcompound);
    
    }
    
    public void readFromNBT(NBTTagCompound nbttag)
    {
    super.readFromNBT(nbttag);
    }
    
    public void writeToNBT(NBTTagCompound nbttag)
    {
    super.writeToNBT(nbttag);
    }
    
    public double receiveMJs(double energy){
    double energyLeft = energy;
    for (String[] row : this.elements){
    if (row[0] == "battery") {
    energyLeft = ((TileEntityMagneticBattery) worldObj.getTileEntity(xCoord, yCoord + Integer.parseInt(row[1]), zCoord)).addEnergy(energyLeft);
    }
    }
    return energyLeft;
    }
    
    public double receiveEUs(double energy){
    System.out.println("Receiving energy…");
    double energyLeft = energy/VirtualCraft.IC2EURATE;
    for (String[] row : this.elements){
    if (row[0] == "battery") {
    energyLeft = ((TileEntityMagneticBattery) worldObj.getTileEntity(xCoord, yCoord + Integer.parseInt(row[1]), zCoord)).addEnergy(energyLeft);
    }
    }
    return energyLeft * VirtualCraft.IC2EURATE;
    }
    
    }
    

    TileEntityMultiblock :

    package pingo.virtualcraft.common;
    
    import net.minecraft.block.Block;
    import net.minecraft.tileentity.TileEntity;
    import net.minecraft.world.World;
    
    public class TileEntityMultiblock extends TileEntity {
    
    protected boolean destruction = false;
    public int xMaster = 0;
    public int yMaster = 0;
    public int zMaster = 0;
    public boolean hasMaster = false;
    public int elementsCounter = 0;
    public String[][] elements;
    
    public void setMaster(int x, int y, int z){
    xMaster = x;
    yMaster = y;
    zMaster = z;
    hasMaster = true;
    System.out.println("Master set to : " + x + " " + y + " " + z);
    }
    
    public static String getMultiblockType(World world, int x, int y, int z){
    Block checkedBlock = world.getBlock(x, y, z);
    if (checkedBlock != null) {
    
    if (checkedBlock == VirtualCraft.multiblockControler) return "brain";
    if (checkedBlock == VirtualCraft.MJsInjector) return "mjsinjector";
    if (checkedBlock == VirtualCraft.EUsInjector) return "eusinjector";
    if (checkedBlock == VirtualCraft.magneticBattery) return "battery";
    
    }
    return "nothing";
    }
    
    public void linkMe(){
    String type;
    TileEntityMultiblock te;
    if (!worldObj.isRemote){
    type = getMultiblockType(worldObj, xCoord, yCoord + 1, zCoord);
    if (type == "brain") {
    ((TileEntityMultiblock) worldObj.getTileEntity(xCoord, yCoord + 1, zCoord)).elements = ((TileEntityMultiblock) worldObj.getTileEntity(xCoord, yCoord + 1, zCoord)).newMaster();
    } else if (type != "nothing") {
    te = (TileEntityMultiblock) worldObj.getTileEntity(xCoord, yCoord + 1, zCoord);
    if (te.hasMaster) { ((TileEntityMultiblock) worldObj.getTileEntity(te.xMaster, te.yMaster, te.zMaster)).elements = ((TileEntityMultiblock) worldObj.getTileEntity(te.xMaster, te.yMaster, te.zMaster)).newMaster(); }
    } else {
    type = getMultiblockType(worldObj, xCoord, yCoord - 1, zCoord);
    if (type == "brain") {
    ((TileEntityMultiblock) worldObj.getTileEntity(xCoord, yCoord - 1, zCoord)).elements = ((TileEntityMultiblock) worldObj.getTileEntity(xCoord, yCoord - 1, zCoord)).newMaster();
    } else if (type != "nothing") {
    te = (TileEntityMultiblock) worldObj.getTileEntity(xCoord, yCoord - 1, zCoord);
    if (te.hasMaster) { ((TileEntityMultiblock) worldObj.getTileEntity(te.xMaster, te.yMaster, te.zMaster)).elements = ((TileEntityMultiblock) worldObj.getTileEntity(te.xMaster, te.yMaster, te.zMaster)).newMaster(); }
    }
    }
    }
    }
    
    public String[][] newMaster(){
    System.out.println("Setting new master…");
    elementsCounter = 0;
    String[][] elements = new String[256][2];
    if (!worldObj.isRemote){
    boolean loop = true;
    String type;
    int counter = 1;
    int counter2 = 0;
    while (loop) {
    System.out.println("Analysing : " + xCoord + " " + (yCoord+counter) + " " + zCoord);
    type = getMultiblockType(worldObj, xCoord, yCoord + counter, zCoord);
    if (type == "brain") {
    this.selfDestruct();
    loop = false;
    } else if (type == "nothing") {
    loop = false;
    } else {
    System.out.println("Found one : " + type);
    ((TileEntityMultiblock) worldObj.getTileEntity(xCoord, yCoord + counter, zCoord)).setMaster(xCoord, yCoord, zCoord);
    elements[counter2][0] = type;
    elements[counter2][1] = Integer.toString(0+counter);
    counter2++;
    elementsCounter++;
    }
    counter++;
    }
    loop = true;
    counter = 1;
    while (loop) {
    System.out.println("Analysing : " + xCoord + " " + (yCoord-counter) + " " + zCoord);
    type = getMultiblockType(worldObj, xCoord, yCoord - counter, zCoord);
    if (type == "brain") {
    this.selfDestruct();
    loop = false;
    } else if (type == "nothing") {
    loop = false;
    } else {
    ((TileEntityMultiblock) worldObj.getTileEntity(xCoord, yCoord - counter, zCoord)).setMaster(xCoord, yCoord, zCoord);
    elements[counter2][0] = type;
    elements[counter2][1] = Integer.toString(0+counter);
    counter2++;
    elementsCounter++;
    }
    counter++;
    }
    }
    return elements;
    }
    
    public void selfDestruct() {
    destruction = true;
    this.invalidate();
    }
    
    }
    

    @'Blackout':

    vu que ma fonction fait appel à du contenu se trouvant dans elle même, c'est normal que ça crash

    Ça ne veut rien dire.

    Cela signifie qu'elle fait appel à des variables déclarées dans la TE, j'avais oublié de préciser TE désolé.

  • Moddeurs confirmés

    Pourquoi est ce que tu représentes tes blocs par des chaines de caractère ? ne serait ce pas plus logique/pratique/performant/viable de les représenter par des blocs directement ?
    Ton code n'est pas du tout optimisé, tu as beaucoups trop d'accès mémoire inutile.

    Est ce que tu comptes appeler newMaster depuis un autre fichier ?

    String[][] elements = new String[256][2];
    

    Mon dieu O_o

    
    int counter = 1;
    int counter2 = 0;
    

    Qu'est ce que tu comptes ?

    Bon tu n'as pas de constructeur, donc ça veut dire que tu as un constructeur par defaut.
    Du coups, il faut placer ta fonction a la fin de readFromNBTTag


  • @'Blackout':

    Pourquoi est ce que tu représentes tes blocs par des chaines de caractère ? ne serait ce pas plus logique/pratique/performant/viable de les représenter par des blocs directement ?

    Pour les identifier rapidement. Et en termes de performances, stocker un block complet dans la ram est bien pire qu'une simple chaine (même si je t'accorde que les chaines de caractère en Java c'est pas le top non plus, c'est le moins qu'on puisse dire). D'autant que je dois à la fois stocker le type de block et la distance, dans la même table.

    @'Blackout':

    Ton code n'est pas du tout optimisé, tu as beaucoups trop d'accès mémoire inutile.

    Je en comprends pas vraiment où tu veux en venir.

    @'Blackout':

    Est ce que tu comptes appeler newMaster depuis un autre fichier ?

    Oui.

    @'Blackout':

    String[][] elements = new String[256][2];
    

    Mon dieu O_o

    Cette ligne est une ligne temporaire, dans le sens où à l'avenir je me prendrais la tête à déclarer dynamiquement la taille en fonction du nombre de blocks stockés. Un truc à la con, lors de newMaster, la table locale est de 256, puis ce qui est retourné a pour taille le nombre de case occupée dans la table locale de newMaster.

    @'Blackout':

    
    int counter = 1;
    int counter2 = 0;
    

    Qu'est ce que tu comptes ?

    counter : à combien de case on est du master, en premier lieu dans +Y puis dans -Y.
    counter2 : le nombre d'éléments trouvés dans la structure pour l'ajout à la table principale.

    @'Blackout':

    Bon tu n'as pas de constructeur, donc ça veut dire que tu as un constructeur par defaut.
    Du coups, il faut placer ta fonction a la fin de readFromNBTTag

    Ok merci.

    EDIT : Après vérification, on dirait que lorsque la fonction est exécutée, worldObj est null, hors j'ai besoin de malgré tout faire du server-side only. Comment puis-je faire une alternative ?

  • Moddeurs confirmés

    @'pingoleon60':

    @'Blackout':

    Pourquoi est ce que tu représentes tes blocs par des chaines de caractère ? ne serait ce pas plus logique/pratique/performant/viable de les représenter par des blocs directement ?

    Pour les identifier rapidement. Et en termes de performances, stocker un block complet dans la ram est bien pire qu'une simple chaine (même si je t'accorde que les chaines de caractère en Java c'est pas le top non plus, c'est le moins qu'on puisse dire). D'autant que je dois à la fois stocker le type de block et la distance, dans la même table.

    Absolument pas. Quand tu stockes un objet, tu stocks ta référence c'est a dire 4 octect qui réprésente son adresse en mémoire quelque soit l'objet tant que tu ne fais pas de new. Les object sont transmis par référence et non par valeur, c'est a dire qu'il n'y a aucune recopie.

    Ici, pour chaque chaine, tu va en instancier une nouvelle a chaque fois. Outre le fait d'appeler un malloc implicitement qui est une opération couteuse, si tu veux parler taille tu stocks : 4 octect pour la taille + 1 octect par charactère de ta chaine.
    Sans compter qu'accessoirement tu dois aussi stocker le type du block non ? Donc 4 octect supplémentaire.
    Ça c'est juste pour la mémoire, concernant le CPU, tu va devoir dès que tu cherches un block parcourir une sorte de registre pour trouver l'équivalence chaine/block.

    @'pingoleon60':

    @'Blackout':

    Ton code n'est pas du tout optimisé, tu as beaucoups trop d'accès mémoire inutile.

    Je en comprends pas vraiment où tu veux en venir.

    Tu as trop de world.getTileEntity, tu devrais stocker le résultat dans la pile d'éxécution au lieu d'exécuter cette opération en double.
    Ici, ce n'est pas un simple getter qui va te renvoyer un attribut, c'est une méthode qui fait une recherche dans une structure de donné.

    @'pingoleon60':

    @'Blackout':

    
    int counter = 1;
    int counter2 = 0;
    

    Qu'est ce que tu comptes ?

    counter : à combien de case on est du master, en premier lieu dans +Y puis dans -Y.
    counter2 : le nombre d'éléments trouvés dans la structure pour l'ajout à la table principale.

    Dans ce cas la n'est pas plus évocateur de donner a tes variables le nom yOffset et foundBlock ?

    @'pingoleon60':

    EDIT : Après vérification, on dirait que lorsque la fonction est exécutée, worldObj est null, hors j'ai besoin de malgré tout faire du server-side only. Comment puis-je faire une alternative ?

    A mon avis, tu n'as pas besoin du world uniquement pour connaitre la side.
    As-tu bien appeler ta méthode a la fin de readFromNBTTag ?


    1. Ah bon, je savais pas. Mais en tout cas, j'ai besoin de stocker la distance avec, et du coup ça impliquerait la création d'un tableau d'Object, est-ce que tu penses que ça en vaut la peine ?

    2. D'accord. En fait, il me semblait que faire ça était plus économique en termes de ressources générales. Je corrigerai.

    3. J'aime obfusquer manuellement mon code.

    public void readFromNBT(NBTTagCompound nbttag)
    {
    super.readFromNBT(nbttag);
    
    this.elements = this.newMaster();
    }
    

    Lorsque je me connecte, ça crash pas. Par contre quand j'essaye de voir des valeurs normalement créées par newMaster, crash.

  • Moddeurs confirmés

    1. crée un objet qui contient un block et une distance, tu stocks cet objet dans ta structure de donné.

    2. On obfusque jamais le code source, même quand on code solo. Quand tu reviendras sur ton code après plusieurs mois sans y avoir touché tu n'y comprendra plus rien et tu perdra du temps a "deobfusquer" ton code manuellement.

    3. Personnelement j'aurais plus vu l'appel a newMaster dans la classe mère.
      Après je ne comprend pas vraiment la différence que tu fais entre le TileEntityMultiblock et le TileEntityMultiblockControler.
      Tu as peut-être des erreurs de conception qui te rendent la tache plus ardue.

    Si ça ne crash pas, c'est que tu as probablement un problème d'algo dans ta fonction newMaster.
    Mets des breakpoints et lance le debuggueur.


    1. Ok. En fait l'attribution du pointeur est automatique en Java à ce niveau. Je pensais que c'était une copie pure et simple.

    2. Ca fait 6 ans que je fais ça, j'ai jamais eu ce genre de problèmes.

    3. TileEntityMultiblock, c'est un truc général pour tous les blocks multiblocks, que ce soit les maitres ou les esclaves. TileEntityMutiblockControler, c'est la TE d'une des sortes de maitres. Faire comme ça me permet d'avoir une sorte d'API permettant l'interaction entre les blocks qui ont chacun TE et Gui indépendantes, et qui techniquement peuvent fonctionner seuls. Appeler newMaster dans la classe mère rendrait tous les éléments du Multiblock maitres.

  • Moddeurs confirmés

    1. Je te dis mon expérience la dessus, j'ai travaillé sur des projets conséquents, sur des logiciels utilisé quotidiennement par des centaines de personne et qui doivent être maintenu pendant plusieurs dixaines d'années, j'ai des diplomes et une expérience professionnel. Après tu prends ou tu prends pas, c'est comme tu veux ^^

    2. Donc tout tes blocks multiblock on forcément une TileEntity ? Et tout les TileEntityMultiblocks n'appel pas forcément newMaster a leur création ?


  • Oui c'est ça. Donc du coup je dois l'exécuter sur la TE du Controler.