Changer la texture d'une entité en jeu, depuis une url
-
Bonsoir à tous,
Je fais suivre mon topic sur le forum anglophone de manière à obtenir des réponses sur tous les fronts. J’ai d’ailleurs remarqué que mon problème avait déjà trouvé une solution sur ce forum, mais je n’obtiens pas le même résultat.
Pour résumer (si vous n’avez pas envie de lire le post original au-dessus, quoi qu’il serait vraiment intéressant de s’y approcher puisque j’explique plutôt bien les choses), je cherche à modifier le skin d’une entité que j’ai créé moi-même (un NPC en somme), mais je souhaiterais le faire depuis une texture hébergée sur le net. Précisément, lorsque le joueur effectue un clic droit sur l’entité en question, le skin par défaut de l’entité doit être remplacé par le skin distant sur le web et je souhaiterais que tous les joueurs en soient notifiés sur le serveur, c’est à dire sans déconnexion/reconnexion.
J’ai donc commencé par chercher de moi-même dans les classes Vanilla existantes et j’y ai remarqué une méthode getDownloadImageSkin dans la classe AbstractClientPlayer. J’ai donc tout bêtement copié-collé cette méthode dans la classe de mon entité et je l’ai arrangé à ma sauce. Vous pouvez voir que sur le topic sur le forum anglophone, ça me pond un problème de cast alors que je n’ai juste fait que copié-collé la méthode déjà existante. Enfin bref, depuis ma dernière réponse sur le topic, j’ai modifié la méthode pour qu’elle retourne comme il faut et sans cast le ThreadImageDownloadData. Seulement voilà, ça me pond un joli log error parlant de contexte OpenGL n’existant pas…
Le message d’erreur exact est: No OpenGL context found in the current thread.
[19:48:27] [Server thread/ERROR] [FML]: Exception caught during firing event net.minecraftforge.event.entity.player.PlayerInteractEvent$EntityInteract@20de580d: net.minecraft.util.ReportedException: Registering texture at net.minecraft.client.renderer.texture.TextureManager.loadTexture(TextureManager.java:89) ~[TextureManager.class:?] at net.theviolentsquirrels.craftandconquer.entity.EntityNPCDialog.getDownloadImageSkin(EntityNPCDialog.java:92) ~[EntityNPCDialog.class:?] at net.theviolentsquirrels.craftandconquer.event.NPCInteractEvent.onEntityNPCInteract(NPCInteractEvent.java:27) ~[NPCInteractEvent.class:?] at net.minecraftforge.fml.common.eventhandler.ASMEventHandler_6_NPCInteractEvent_onEntityNPCInteract_EntityInteract.invoke(.dynamic) ~[?:?] at net.minecraftforge.fml.common.eventhandler.ASMEventHandler.invoke(ASMEventHandler.java:90) ~[ASMEventHandler.class:?] at net.minecraftforge.fml.common.eventhandler.EventBus.post(EventBus.java:185) [EventBus.class:?] at net.minecraftforge.common.ForgeHooks.onInteractEntity(ForgeHooks.java:1008) [ForgeHooks.class:?] at net.minecraft.entity.player.EntityPlayer.interact(EntityPlayer.java:1246) [EntityPlayer.class:?] at net.minecraft.network.NetHandlerPlayServer.processUseEntity(NetHandlerPlayServer.java:1072) [NetHandlerPlayServer.class:?] at net.minecraft.network.play.client.CPacketUseEntity.processPacket(CPacketUseEntity.java:93) [CPacketUseEntity.class:?] at net.minecraft.network.play.client.CPacketUseEntity.processPacket(CPacketUseEntity.java:14) [CPacketUseEntity.class:?] at net.minecraft.network.PacketThreadUtil$1.run(PacketThreadUtil.java:15) [PacketThreadUtil$1.class:?] at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [?:1.8.0_111] at java.util.concurrent.FutureTask.run(FutureTask.java:266) [?:1.8.0_111] at net.minecraft.util.Util.runTask(Util.java:25) [Util.class:?] at net.minecraft.server.MinecraftServer.updateTimeLightAndEntities(MinecraftServer.java:742) [MinecraftServer.class:?] at net.minecraft.server.MinecraftServer.tick(MinecraftServer.java:687) [MinecraftServer.class:?] at net.minecraft.server.integrated.IntegratedServer.tick(IntegratedServer.java:156) [IntegratedServer.class:?] at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:536) [MinecraftServer.class:?] at java.lang.Thread.run(Thread.java:745) [?:1.8.0_111] Caused by: java.lang.RuntimeException: No OpenGL context found in the current thread. at org.lwjgl.opengl.GLContext.getCapabilities(GLContext.java:124) ~[lwjgl-2.9.4-nightly-20150209.jar:?] at org.lwjgl.opengl.GL11.glGenTextures(GL11.java:1403) ~[lwjgl-2.9.4-nightly-20150209.jar:?] at net.minecraft.client.renderer.GlStateManager.generateTexture(GlStateManager.java:459) ~[GlStateManager.class:?] at net.minecraft.client.renderer.texture.TextureUtil.glGenTextures(TextureUtil.java:38) ~[TextureUtil.class:?] at net.minecraft.client.renderer.texture.AbstractTexture.getGlTextureId(AbstractTexture.java:54) ~[AbstractTexture.class:?] at net.minecraft.client.renderer.ThreadDownloadImageData.getGlTextureId(ThreadDownloadImageData.java:66) ~[ThreadDownloadImageData.class:?] at net.minecraft.client.renderer.texture.SimpleTexture.loadTexture(SimpleTexture.java:57) ~[SimpleTexture.class:?] at net.minecraft.client.renderer.ThreadDownloadImageData.loadTexture(ThreadDownloadImageData.java:83) ~[ThreadDownloadImageData.class:?] at net.minecraft.client.renderer.texture.TextureManager.loadTexture(TextureManager.java:67) ~[TextureManager.class:?] … 19 more [19:48:27] [Server thread/ERROR] [FML]: Index: 1 Listeners: [19:48:27] [Server thread/ERROR] [FML]: 0: NORMAL [19:48:27] [Server thread/ERROR] [FML]: 1: ASM: net.theviolentsquirrels.craftandconquer.event.NPCInteractEvent@1c1023e1 onEntityNPCInteract(Lnet/minecraftforge/event/entity/player/PlayerInteractEvent$EntityInteract;)V [19:48:27] [Server thread/FATAL]: Error executing task java.util.concurrent.ExecutionException: net.minecraft.util.ReportedException: Registering texture at java.util.concurrent.FutureTask.report(FutureTask.java:122) ~[?:1.8.0_111] at java.util.concurrent.FutureTask.get(FutureTask.java:192) ~[?:1.8.0_111] at net.minecraft.util.Util.runTask(Util.java:26) [Util.class:?] at net.minecraft.server.MinecraftServer.updateTimeLightAndEntities(MinecraftServer.java:742) [MinecraftServer.class:?] at net.minecraft.server.MinecraftServer.tick(MinecraftServer.java:687) [MinecraftServer.class:?] at net.minecraft.server.integrated.IntegratedServer.tick(IntegratedServer.java:156) [IntegratedServer.class:?] at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:536) [MinecraftServer.class:?] at java.lang.Thread.run(Thread.java:745) [?:1.8.0_111] Caused by: net.minecraft.util.ReportedException: Registering texture at net.minecraft.client.renderer.texture.TextureManager.loadTexture(TextureManager.java:89) ~[TextureManager.class:?] at net.theviolentsquirrels.craftandconquer.entity.EntityNPCDialog.getDownloadImageSkin(EntityNPCDialog.java:92) ~[EntityNPCDialog.class:?] at net.theviolentsquirrels.craftandconquer.event.NPCInteractEvent.onEntityNPCInteract(NPCInteractEvent.java:27) ~[NPCInteractEvent.class:?] at net.minecraftforge.fml.common.eventhandler.ASMEventHandler_6_NPCInteractEvent_onEntityNPCInteract_EntityInteract.invoke(.dynamic) ~[?:?] at net.minecraftforge.fml.common.eventhandler.ASMEventHandler.invoke(ASMEventHandler.java:90) ~[ASMEventHandler.class:?] at net.minecraftforge.fml.common.eventhandler.EventBus.post(EventBus.java:185) ~[EventBus.class:?] at net.minecraftforge.common.ForgeHooks.onInteractEntity(ForgeHooks.java:1008) ~[ForgeHooks.class:?] at net.minecraft.entity.player.EntityPlayer.interact(EntityPlayer.java:1246) ~[EntityPlayer.class:?] at net.minecraft.network.NetHandlerPlayServer.processUseEntity(NetHandlerPlayServer.java:1072) ~[NetHandlerPlayServer.class:?] at net.minecraft.network.play.client.CPacketUseEntity.processPacket(CPacketUseEntity.java:93) ~[CPacketUseEntity.class:?] at net.minecraft.network.play.client.CPacketUseEntity.processPacket(CPacketUseEntity.java:14) ~[CPacketUseEntity.class:?] at net.minecraft.network.PacketThreadUtil$1.run(PacketThreadUtil.java:15) ~[PacketThreadUtil$1.class:?] at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) ~[?:1.8.0_111] at java.util.concurrent.FutureTask.run(FutureTask.java:266) ~[?:1.8.0_111] at net.minecraft.util.Util.runTask(Util.java:25) ~[Util.class:?] … 5 more Caused by: java.lang.RuntimeException: No OpenGL context found in the current thread. at org.lwjgl.opengl.GLContext.getCapabilities(GLContext.java:124) ~[lwjgl-2.9.4-nightly-20150209.jar:?] at org.lwjgl.opengl.GL11.glGenTextures(GL11.java:1403) ~[lwjgl-2.9.4-nightly-20150209.jar:?] at net.minecraft.client.renderer.GlStateManager.generateTexture(GlStateManager.java:459) ~[GlStateManager.class:?] at net.minecraft.client.renderer.texture.TextureUtil.glGenTextures(TextureUtil.java:38) ~[TextureUtil.class:?] at net.minecraft.client.renderer.texture.AbstractTexture.getGlTextureId(AbstractTexture.java:54) ~[AbstractTexture.class:?] at net.minecraft.client.renderer.ThreadDownloadImageData.getGlTextureId(ThreadDownloadImageData.java:66) ~[ThreadDownloadImageData.class:?] at net.minecraft.client.renderer.texture.SimpleTexture.loadTexture(SimpleTexture.java:57) ~[SimpleTexture.class:?] at net.minecraft.client.renderer.ThreadDownloadImageData.loadTexture(ThreadDownloadImageData.java:83) ~[ThreadDownloadImageData.class:?] at net.minecraft.client.renderer.texture.TextureManager.loadTexture(TextureManager.java:67) ~[TextureManager.class:?] at net.theviolentsquirrels.craftandconquer.entity.EntityNPCDialog.getDownloadImageSkin(EntityNPCDialog.java:92) ~[EntityNPCDialog.class:?] at net.theviolentsquirrels.craftandconquer.event.NPCInteractEvent.onEntityNPCInteract(NPCInteractEvent.java:27) ~[NPCInteractEvent.class:?] at net.minecraftforge.fml.common.eventhandler.ASMEventHandler_6_NPCInteractEvent_onEntityNPCInteract_EntityInteract.invoke(.dynamic) ~[?:?] at net.minecraftforge.fml.common.eventhandler.ASMEventHandler.invoke(ASMEventHandler.java:90) ~[ASMEventHandler.class:?] at net.minecraftforge.fml.common.eventhandler.EventBus.post(EventBus.java:185) ~[EventBus.class:?] at net.minecraftforge.common.ForgeHooks.onInteractEntity(ForgeHooks.java:1008) ~[ForgeHooks.class:?] at net.minecraft.entity.player.EntityPlayer.interact(EntityPlayer.java:1246) ~[EntityPlayer.class:?] at net.minecraft.network.NetHandlerPlayServer.processUseEntity(NetHandlerPlayServer.java:1072) ~[NetHandlerPlayServer.class:?] at net.minecraft.network.play.client.CPacketUseEntity.processPacket(CPacketUseEntity.java:93) ~[CPacketUseEntity.class:?] at net.minecraft.network.play.client.CPacketUseEntity.processPacket(CPacketUseEntity.java:14) ~[CPacketUseEntity.class:?] at net.minecraft.network.PacketThreadUtil$1.run(PacketThreadUtil.java:15) ~[PacketThreadUtil$1.class:?] at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) ~[?:1.8.0_111] at java.util.concurrent.FutureTask.run(FutureTask.java:266) ~[?:1.8.0_111] at net.minecraft.util.Util.runTask(Util.java:25) ~[Util.class:?] … 5 more
EntityNPCDialog (mon entité perso):
public class EntityNPCDialog extends EntityLiving { // private static final DataParameter <integer>TEXTURE_INDEX = EntityDataManager.<integer>createKey(EntityNPCDialog.class, DataSerializers.VARINT); public EntityNPCDialog(World worldIn) { super(worldIn); } // @Override // protected void entityInit() { // super.entityInit(); // // this.dataManager.register(TEXTURE_INDEX, 0); // } @Nullable @Override protected SoundEvent getAmbientSound() { return (CraftAndConquerSounds.NPCDialogSoundEvent); } @Nullable @Override protected SoundEvent getHurtSound() { return (CraftAndConquerSounds.NPCDialogSoundEvent); } @Nullable @Override protected SoundEvent getDeathSound() { return (CraftAndConquerSounds.NPCDialogSoundEvent); } @Override protected SoundEvent getFallSound(int heightIn) { return (CraftAndConquerSounds.NPCDialogSoundEvent); } @Override protected SoundEvent getSwimSound() { return (CraftAndConquerSounds.NPCDialogSoundEvent); } @Override protected SoundEvent getSplashSound() { return (CraftAndConquerSounds.NPCDialogSoundEvent); } // public void setTextureIndex() { // int textureID = this.dataManager.get(TEXTURE_INDEX); // // this.dataManager.set(TEXTURE_INDEX, (textureID + 1 < 2) ? textureID + 1 : 0); // } // // public int getTextureIndex() { // return (this.dataManager.get(TEXTURE_INDEX)); // } public static ThreadDownloadImageData getDownloadImageSkin(ResourceLocation resourceLocationIn) { TextureManager textureManager = Minecraft.getMinecraft().getTextureManager(); ThreadDownloadImageData threadDownloadImageData; threadDownloadImageData = new ThreadDownloadImageData(null, "http://imgur.com/Z0pbA3P.png", DefaultNPCSkin.getDefaultSkin(), new ImageBufferDownload() { @Override public BufferedImage parseUserSkin(BufferedImage image) { return (image); } }); textureManager.loadTexture(resourceLocationIn, threadDownloadImageData); return (threadDownloadImageData); } }
RenderNPCDialog (le renderer de mon entité):
@SideOnly(Side.CLIENT) public class RenderNPCDialog extends RenderLiving <entitynpcdialog>{ // public static final ResourceLocation[] NPC_DIALOG_TEXTURES = new ResourceLocation[] { // new ResourceLocation(CraftAndConquer.MODID, "textures/entities/npc/npc_dialog.png"), // new ResourceLocation(CraftAndConquer.MODID, "textures/entities/npc/npc_dialog_2.png"), // }; public RenderNPCDialog(RenderManager renderManagerIn, ModelBase modelBaseIn, float shadowSizeIn) { super(renderManagerIn, modelBaseIn, shadowSizeIn); } @Override protected ResourceLocation getEntityTexture(EntityNPCDialog entity) { return (DefaultNPCSkin.getDefaultSkin()); } }
DefaultNPCSkin (mon équivalent personnel de la classe Vanilla existante DefaultPlayerSkin):
public class DefaultNPCSkin { private static final ResourceLocation NPC_DIALOG_DEFAULT_TEXTURE = new ResourceLocation(CraftAndConquer.MODID, "textures/entities/npc/npc_dialog.png"); public static ResourceLocation getDefaultSkin() { return (NPC_DIALOG_DEFAULT_TEXTURE); } }
Je suis au courant que je dois sauvegarder l’unicité de la texture par entité dans les DataParameters, mais pour l’instant je préfère avancer étape par étape: je suis déjà bloqué à la base. :dodgy:
Qu’en pensez-vous ? :)</entitynpcdialog></integer></integer>
-
Salut,
Le problème est que tu appels ta fonction getDownloadImageSkin depuis une autre fonction qui est exécuté soit dans le thread serveur, soit dans le thead de netty.
Dans ces deux threads il n’y a pas d’OpenGL. OpenGL n’est que disponible dans le thread client.Si on suit le stacktrace :
at net.theviolentsquirrels.craftandconquer.event.NPCInteractEvent.onEntityNPCInteract(NPCInteractEvent.java:27) ~[NPCInteractEvent.class:?]
C’est à ce niveau qu’il y a le problème, tu ne devrais pas appeler la fonction getDownloadImageSkin ici.
Tu cherches à faire quoi dans cette classe NPCInteractEvent ? -
Lmao je pensais avoir fourni le code de cette classe dans mon post, my bad.
public class NPCInteractEvent { @SubscribeEvent public void onEntityNPCInteract(PlayerInteractEvent.EntityInteract event) { ItemStack heldItem = event.getEntityPlayer().getHeldItem(EnumHand.MAIN_HAND); ItemBase npcManager = CraftAndConquerItems.npcManager; if (event.getTarget() instanceof EntityNPCDialog && event.getHand().equals(EnumHand.MAIN_HAND) && heldItem.getItem().equals(npcManager)) { if (!event.getWorld().isRemote) EntityNPCDialog.getDownloadImageSkin(DefaultNPCSkin.getDefaultSkin()); } } }
Comme tu peux le constater, si j’effectue un clic-droit avec un item spécifique dans la main hand sur l’entité, je souhaiterais que sa texture change. À terme ce que je souhaiterais faire, c’est pouvoir customiser mon entité via une GUI et de ce fait pouvoir changer sa texture et appliquer la nouvelle en appuyant sur un bouton “save”, et que ce changement de texture via url soit effectif dans l’immédiat et que tous les joueurs du serveur soit notifiés et qu’ils n’aient pas besoin de se déconnecter/reconnecter.
-
Pour changer la texture, il faudrait simplement modifier la valeur de l’url de la texture.
Rien de plus.
Ensuite côté client, lorsque l’url est changé, il faut en même temps lui demande de re-télécharger la texture. (à voir s’il y a moyen de détecter le changement d’une valeur d’un datawatcher, sinon passes par un paquet). -
D’accord.
Si j’ai bien compris le principe, ma méthode getDownloadImageSkin est correcte mais puisqu’elle est exécutée côté serveur dans le handling de mon event, elle ne fonctionne pas puisque évidemment le contexte OpenGL est côté client et non serveur. De ce fait, au lieu d’appeler cette méthode bêtement comme je le fais là, je devrais trouver un moyen de notifier tout le monde (Server –> Client) que le skin de cette entité a changé et qu’il faudrait télécharger la nouvelle texture qui lui est attribuée, right ?
Les seuls moyens que je vois sont effectivement ou bien les DataWatchers, ou bien les Packets… Si je passe par Packet, je devrais en envoyer un du Server vers tous les Clients et du côté de l’handle client, appeler cette méthode getDownloadImageSkin.
Pardon de pousser ma curiosité jusqu’au bout, mais comment devrais-je faire si je devais employer des DataWatchers ?
-
Oui c’est bien ça.
Justement pour les data watchers je ne sais pas trop.
Il faut voir s’il existe une fonction qui est appelé lors du changement d’une valeur.Sinon une solution serait de faire un variable lastTextureName, et si la valeur de lastTextureName != valeur du data watcher, alors lastTextureName prend la valeur du data watcher et tu applique le téléchargement de la texture.
Mais ce n’est pas très propre car il faudrait faire la vérification à chaque tick …