Résolu Instancier une entité à partir d'un nom ou du UUID
-
Bonjour !
Je vous explique un peu le problème, j’essaie de faire un système de bestiaire pour mon projet, pour le moment ça fonctionne plutôt bien, chaque jour a son bestiaire, la synchronisation entre client et serveur et ok, bref le plus “dur” est fait. Je passe donc à la partie GUI. Et voici mon plan :
- Afficher le rendu de l’entité
- Afficher quelques informations (comme les points de vie, la vitesse, etc…)
Et voici un aperçu de ce que mon système de bestiaire fait :
Quand un entité meurt et que c’est une créature
alors
ajouter la créature au bestiaire en créant une fiche de créature avec le nom de la créature (pour le moment)
(ici je lance un événement pour notifier que j’ai ajouté une créature au bestiaire, ça me sert à lancer un message dans le chat)
finMais au moment d’arriver à la GUI, je tombe sur un problème, je n’ai aucune instance de cette entité. Et pour cause, on ne peut pas sauvegarder une entité sous un nbt (ou j’ai pas trouvé de moyen de le faire). Et je ne peux donc pas utiliser le rendu d’une entité qui n’existe plus.
J’ai donc réfléchi à plusieurs solution, et je me demandais si avec le UUID on ne pouvait pas recréer une instance de l’entité. Mais pareil, dans mes recherches, je n’ai trouvé que le moyen de récupérer une entité dans le monde grâce au UUID mais pas de créer une instance de cette entité.
Pour le moment, la seule solution que je trouve est d’utiliser la réflexivité de java. C’est à dire de sauvegarder le nom de la class de l’entité dans mes nbttag et de recréer l’instance avec Class. Mais c’est pour moi pas du tout élégant.
Avez vous une idée de comment je pourrais y arriver ? Est-ce que ma solution est la bonne et qu’il n’y en a pas d’autre ? (je pense que ça peu marcher, mais j’aime pas trop utiliser la réflexivité).
-
Ca sent le projet Dofus à plein nez ^^ !
Je pense que dans ton cas la réflexion est le mieux à utiliser, cependant il faut le faire intelligemment, lors de ton event il te faut get le nom de la classe et la remettre sous-forme de string dans un Extended Entity Properties et puis lors du gui tu lis ses EEP et tu fais générer les classes (entité côté client) ou tu lis des variables que tu as défini comme publiques dans tes classes d’entités (ce que je ferai)
-
Le principale problème c’est que tu veux récupérer l’instance lors de la mort, or l’instance de l’entité n’existe plus après sa mort.
Si ce qu’il te faut c’est juste le nom + d’autres informations, alors autant créer une nouvelle classe pour stocker ça et les envoyer via un paquet. -
@'Benjamin:
Ca sent le projet Dofus à plein nez ^^ !
Je pense que dans ton cas la réflexion est le mieux à utiliser, cependant il faut le faire intelligemment, lors de ton event il te faut get le nom de la classe et la remettre sous-forme de string dans un Extended Entity Properties et puis lors du gui tu lis ses EEP et tu fais générer les classes (entité côté client) ou tu lis des variables que tu as défini comme publiques dans tes classes d’entités (ce que je ferai)
Pas du tout pour dofus, je suis occupé de faire un mod type RPG très très inspiré de The Witcher 3. Mais sinon c’est un peu comme ça que j’imaginais faire la chose aussi à l’exception que je voudrais que ça fonctionne pour tout EntityCreature, mais ça change pas grand chose à la solution.
@‘robin4002’:
Le principale problème c’est que tu veux récupérer l’instance lors de la mort, or l’instance de l’entité n’existe plus après sa mort.
Si ce qu’il te faut c’est juste le nom + d’autres informations, alors autant créer une nouvelle classe pour stocker ça et les envoyer via un paquet.C’est exactement ça que j’ai pour le moment, j’ai une class BestiaryCard qui s’occupe de récupérer les infos comme le nom, la vie max, et pourquoi pas plus (j’ai pas trop réfléchi à ce qui peut être intéressant sur un mob ^^]. Le truc c’est que je voudrais pouvoir ajouter sur la gui un rendu de la créature. J’ai regardé comment on le faisait dans GuiInventory et j’ai vu qu’on avait besoin de l’instance de l’entité.
-
D’accord, je comprend mieux le problème.
Donc oui il faut créer une nouvelle instance, suffit de mettre comme world FMLClientHandler.instance().getClientWorld() puis tu mets des coordonnées bidon (0,0,0). -
J’ai réussi à avoir un truc qui marche de temps en temps, j’ai un NullPointerException qui se lance de temps en temps :
Caused by: java.lang.NullPointerException at net.minecraft.entity.Entity.getTeam(Entity.java:2435) ~[Entity.class:?] at net.minecraft.entity.Entity.isInvisibleToPlayer(Entity.java:2427) ~[Entity.class:?] at net.minecraft.client.renderer.entity.RenderLivingBase.canRenderName(RenderLivingBase.java:506) ~[RenderLivingBase.class:?] at net.minecraft.client.renderer.entity.RenderLiving.canRenderName(RenderLiving.java:26) ~[RenderLiving.class:?] at net.minecraft.client.renderer.entity.RenderLiving.canRenderName(RenderLiving.java:16) ~[RenderLiving.class:?] at net.minecraft.client.renderer.entity.RenderLivingBase.renderName(RenderLivingBase.java:488) ~[RenderLivingBase.class:?]
C’est causé par cette méthode :
@Nullable public Team getTeam() { return this.worldObj.getScoreboard().getPlayersTeam(this.getCachedUniqueIdString()); }
A mon avis c’est à cause du worldObj car je crée une instance de l’entité côté client :
@SideOnly(Side.CLIENT) private EntityCreature createCreature(String type) { try { return (EntityCreature) Class.forName(type).getConstructor(World.class).newInstance(FMLClientHandler.instance().getWorldClient()); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } return null; }
Du coup je me demande si je suis pas obligé de l’instancier à la fois côté client et serveur.
-
à mon avis c’est plutôt getScoreboard qui renvoie null au lieu de renvoyer la valeur voulu.
Il n’y a aucune raison pour que FMLClientHandler.instance().getWorldClient() soit null. -
Bon finalement j’ai trouvé une façon d’instancier facilement une entité à partir du nom :
@SideOnly(Side.CLIENT) private EntityCreature createCreature(String type) { EntityCreature creature = (EntityCreature) EntityList.createEntityByName(type, FMLClientHandler.instance().getWorldClient()); return creature; }
Pour le peut te test que j’ai fais, ça ne crash pas. Merci de vos réponses !