Jump to content

[1.10.2] Change the texture of a custom entity and make it working on a server ?


Recommended Posts

Posted

Good evening,

 

Following my topic today, I would like to change the skin of a custom entity (a NPC) by right-clicking on it with a specific item. As a naive approach, I tried to change the index of the texture array to redirect the correct texture in my getEntityTexture method.

 

So far, this works on a client, the texture of the entity changes when I correctly right-click on the entity, but this does not work on a server. I have a NoClassDefFoundError that pops on the server console when processing the texture change (the client, however, does not crash).

 

RenderNPCDialog (the renderer):

public class    RenderNPCDialog extends RenderLiving<EntityNPCDialog> {

    private 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"),
    };

    private static int  textureID = 0;

    public      RenderNPCDialog(RenderManager renderManagerIn, ModelBase modelBaseIn, float shadowSizeIn) {
        super(renderManagerIn, modelBaseIn, shadowSizeIn);
    }

    @Override
    protected ResourceLocation  getEntityTexture(EntityNPCDialog entity) {
        return (RenderNPCDialog.NPC_DIALOG_TEXTURES[textureID]);
    }



    public static void          setEntityTextureID() {
        textureID = (textureID + 1 < NPC_DIALOG_TEXTURES.length) ? textureID + 1 : 0;
    }
}

 

NPCInteractEvent (the event that processes the texture change):

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)
                RenderNPCDialog.setEntityTextureID();
        }
    }
}

 

ClientProxy:

public class    ClientProxy extends CommonProxy {

    @Override
    public void preInit() {
        super.preInit();
    }

    @Override
    public void init() {
        super.init();
    }

    @Override
    public void postInit() {
        super.postInit();
    }

    @Override
    public void registerItemRenderer(Item item, int meta, String id) {
        ModelLoader.setCustomModelResourceLocation(item, meta,
                new ModelResourceLocation(CraftAndConquer.MODID + ":" + id, "inventory"));
    }

    @Override
    public void         registerEntityRenderers() {
        RenderManager   renderManager = Minecraft.getMinecraft().getRenderManager();

        RenderingRegistry.registerEntityRenderingHandler(EntityNPCDialog.class, new RenderNPCDialog(renderManager, new ModelEntityNPCDialog(), 0.5f));
    }
}

 

CommonProxy:

public class    CommonProxy {

    public void preInit() {
        CraftAndConquerBlocks.init();
        CraftAndConquerItems.init();
        CraftAndConquerSounds.registerSounds();
        CraftAndConquerEntities.registerEntities();

        NetworkRegistry.INSTANCE.registerGuiHandler(CraftAndConquer.instance, new GuiHandler());
    }

    public void init() {
        CraftAndConquerRecipes.init();
        CraftAndConquer.proxy.registerEntityRenderers();
        
        MinecraftForge.EVENT_BUS.register(new NPCInteractEvent());
    }

    public void postInit() {

    }

    public void registerItemRenderer(Item item, int meta, String id) {

    }

    public void registerEntityRenderers() {

    }
}

 

Logs from the server console:

 

[00:16:38] [server thread/ERROR] [FML]: Exception caught during firing event net.minecraftforge.event.entity.player.PlayerInteractEvent$EntityInteract@5a71b038:
java.lang.NoClassDefFoundError: net/theviolentsquirrels/craftandconquer/client/renderer/entity/RenderNPCDialog
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.dedicated.DedicatedServer.updateTimeLightAndEntities(DedicatedServer.java:408) [DedicatedServer.class:?]
at net.minecraft.server.MinecraftServer.tick(MinecraftServer.java:687) [MinecraftServer.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.ClassNotFoundException: net.theviolentsquirrels.craftandconquer.client.renderer.entity.RenderNPCDialog
at net.minecraft.launchwrapper.LaunchClassLoader.findClass(LaunchClassLoader.java:191) ~[launchwrapper-1.12.jar:?]
at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[?:1.8.0_111]
at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[?:1.8.0_111]
... 18 more
Caused by: java.lang.NoClassDefFoundError: net/minecraft/client/renderer/entity/RenderLiving
at java.lang.ClassLoader.defineClass1(Native Method) ~[?:1.8.0_111]
at java.lang.ClassLoader.defineClass(ClassLoader.java:763) ~[?:1.8.0_111]
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) ~[?:1.8.0_111]
at net.minecraft.launchwrapper.LaunchClassLoader.findClass(LaunchClassLoader.java:182) ~[launchwrapper-1.12.jar:?]
at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[?:1.8.0_111]
at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[?:1.8.0_111]
... 18 more
Caused by: java.lang.ClassNotFoundException: net.minecraft.client.renderer.entity.RenderLiving
at net.minecraft.launchwrapper.LaunchClassLoader.findClass(LaunchClassLoader.java:101) ~[launchwrapper-1.12.jar:?]
at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[?:1.8.0_111]
at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[?:1.8.0_111]
at java.lang.ClassLoader.defineClass1(Native Method) ~[?:1.8.0_111]
at java.lang.ClassLoader.defineClass(ClassLoader.java:763) ~[?:1.8.0_111]
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) ~[?:1.8.0_111]
at net.minecraft.launchwrapper.LaunchClassLoader.findClass(LaunchClassLoader.java:182) ~[launchwrapper-1.12.jar:?]
at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[?:1.8.0_111]
at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[?:1.8.0_111]
... 18 more
[00:16:38] [server thread/ERROR] [FML]: Index: 1 Listeners:
[00:16:38] [server thread/ERROR] [FML]: 0: NORMAL
[00:16:38] [server thread/ERROR] [FML]: 1: ASM: net.theviolentsquirrels.craftandconquer.event.NPCInteractEvent@4d7d80dd onEntityNPCInteract(Lnet/minecraftforge/event/entity/player/PlayerInteractEvent$EntityInteract;)V
[00:16:38] [server thread/FATAL] [net.minecraft.server.MinecraftServer]: Error executing task
java.util.concurrent.ExecutionException: java.lang.NoClassDefFoundError: net/theviolentsquirrels/craftandconquer/client/renderer/entity/RenderNPCDialog
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.dedicated.DedicatedServer.updateTimeLightAndEntities(DedicatedServer.java:408) [DedicatedServer.class:?]
at net.minecraft.server.MinecraftServer.tick(MinecraftServer.java:687) [MinecraftServer.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.NoClassDefFoundError: net/theviolentsquirrels/craftandconquer/client/renderer/entity/RenderNPCDialog
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.ClassNotFoundException: net.theviolentsquirrels.craftandconquer.client.renderer.entity.RenderNPCDialog
at net.minecraft.launchwrapper.LaunchClassLoader.findClass(LaunchClassLoader.java:191) ~[launchwrapper-1.12.jar:?]
at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[?:1.8.0_111]
at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[?:1.8.0_111]
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.NoClassDefFoundError: net/minecraft/client/renderer/entity/RenderLiving
at java.lang.ClassLoader.defineClass1(Native Method) ~[?:1.8.0_111]
at java.lang.ClassLoader.defineClass(ClassLoader.java:763) ~[?:1.8.0_111]
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) ~[?:1.8.0_111]
at net.minecraft.launchwrapper.LaunchClassLoader.findClass(LaunchClassLoader.java:182) ~[launchwrapper-1.12.jar:?]
at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[?:1.8.0_111]
at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[?:1.8.0_111]
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.ClassNotFoundException: net.minecraft.client.renderer.entity.RenderLiving
at net.minecraft.launchwrapper.LaunchClassLoader.findClass(LaunchClassLoader.java:101) ~[launchwrapper-1.12.jar:?]
at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[?:1.8.0_111]
at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[?:1.8.0_111]
at java.lang.ClassLoader.defineClass1(Native Method) ~[?:1.8.0_111]
at java.lang.ClassLoader.defineClass(ClassLoader.java:763) ~[?:1.8.0_111]
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) ~[?:1.8.0_111]
at net.minecraft.launchwrapper.LaunchClassLoader.findClass(LaunchClassLoader.java:182) ~[launchwrapper-1.12.jar:?]
at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[?:1.8.0_111]
at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[?:1.8.0_111]
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

 

 

I have explored the code of the Custom NPC mod to get some hints, but it seems that I am unable to find what I would like to do. I have checked the content of my .jar file and the class RenderNPCDialog does exist, so I don't quite understand what is going on. :)

 

Thank you for your help !

Squirrel ! Squirrel ! Squirrel !

Posted

You will need to create a packet that sends this to the client(s).

 

Okay so I just checked Vanilla and it seems that EntityWolf has the same thing as me: three different textures regarding the wolf behavior (tamed, not tamed and angry) and the getEntityTexture returns the correct one according to the correct behavior. But it does not seem to send any packet to the client.

 

I don't understand why would I need to send any packet here since there is a NoClassDefFoundError. Would you mean to send a packet to the client so that - on the client - it calls the function from RenderNPCDialog ? If yes, is it the correct thing to do in general in Minecraft to notify players of a texture change ?

Squirrel ! Squirrel ! Squirrel !

Posted

First of all, you cannot have this as a static field in your renderer. It would mean that the texture for all of your entities always change at once. You need to store the texture in the entity.

 

Yup, thank you. I will change that so that the texture index has to be stored directly in this entity. :) Maybe I can do it with DataWatchers ?

 

The wolf synchronizes the necessary state (tamed, angry) to the client via the DataWatcher mechanic, you should be able to find a tutorial if you don't know how to use it.

 

There was an old tutorial on the wiki, but the link isn't available anymore... I'm gonna try to read through the source code tho.

Squirrel ! Squirrel ! Squirrel !

Posted

Good evening,

 

I managed to use DataWatchers - not really DataWatchers, more DataParameter and EntityDataManager :D - to store the texture index in the entity and thus being able to make it work.

 

EntityNPCDialog:

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));
    }
}

 

NPCInteractEvent:

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) event.getTarget()).setTextureIndex();
        }
    }
}

 

NPCInteractEvent

@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 (RenderNPCDialog.NPC_DIALOG_TEXTURES[entity.getTextureIndex()]);
    }
}

 

Here is what I did :

 

  • I took a look at the EntityWolf and RenderWolf vanilla classes which cover the purpose of my question. The Wolf has three skins according to its state (tamed, not tamed and angry as written above).
  • The getEntityTexture method in RenderWolf returns the correct texture according to different checks (isTamed and isAngry). Actually, those booleans are updated at the same time the EntityWolf's DataParameters are. (You can see a DataParameter named TAMED in EntityTameable which is the extend of the EntityWolf class.)
  • All I had to do was to create a custom DataParameter for my entity (TEXTURE_INDEX), override the entityInit method to register my DataParameter into the EntityDataManager of my custom entity, and correctly get and set the value in my TEXTURE_INDEX parameter.

 

The NoClassDefFoundError was there because I was trying to access my Render class from my Entity class, now there is no access anymore. :) The last thing I have to do is to store the index in NBT tags in order to retrieve the correct texture when the server restarts.

 

I have one question though: what if I don't want to get the texture from an existing array, but loading it from a folder ? Right now, all the clients are aware of the different textures of the entity because they are stored in the class. Would it be possible to load the texture from a folder from the server, applying it to the entity and notify all the clients that the texture has changed ? Right now, I would see a problem because the clients would not be aware of this specific texture applied on the entity (you know, same when a player changes his skin from minecraft.net, there has to be a reconnect on the server in order to update the thing).

Squirrel ! Squirrel ! Squirrel !

Posted

You would either have to transfer the texture to the client through normal packets and then manually inject it into the texture system, or use the same mechanic skins use and host them on a server somewhere.

 

I didn't really know where to start, so I took a look at vanilla classes and I noticed the getDownloadImageSkin method in AbstractClientPlayer. I naively and simply copy-pasted the method into my custom entity class and changed the method's content so that it downloads a specific texture (hard-coded, I will change this later once it works) from imgur and then put this texture instead of the NPC default one. Moreover, I created a DefaultNPCSkin class (similar to the existing DefaultPlayerSkin vanilla class) which holds the default texture for NPCs and is accessible from my Renderer and the NPCInteractEvent class.

 

I don't know why, but I'm getting a cast error between ThreadDownloadImageData and SimpleTexture in my own getDownloadImageSkin method. The thing is, I just copy-pasted the existing one from vanilla and it seems to work well, so I don't quite understand what is going on: yet, ThreadDownloadImageData extends from multiple classes (SimpleTexture, which itself extends from AbstractTexture), especially AbstractTexture which implements the ITextureObject. Could you help me on this one ? :D

 

EntityNPCDialog:

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();
        ITextureObject itextureobject = texturemanager.getTexture(resourceLocationIn);

        if (itextureobject == null) {
            itextureobject = new ThreadDownloadImageData((File) null,
                    "http://imgur.com/Z0pbA3P.png",
                    DefaultNPCSkin.getDefaultSkin(), new ImageBufferDownload());

            texturemanager.loadTexture(resourceLocationIn, itextureobject);
        }

        return ((ThreadDownloadImageData) itextureobject);
    }
}

 

NPCInteractEvent

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());
        }
    }
}

 

DefaultNPCSkin:

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);
    }
}

 

RenderNPCDialog:

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());
    }
}

 

Logs from the console (I tested on singleplayer first, before going further with dedicated server):

[18:10:29] [server thread/ERROR] [FML]: Exception caught during firing event net.minecraftforge.event.entity.player.PlayerInteractEvent$EntityInteract@32971884:
java.lang.ClassCastException: net.minecraft.client.renderer.texture.SimpleTexture cannot be cast to net.minecraft.client.renderer.ThreadDownloadImageData
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]
[18:10:29] [server thread/ERROR] [FML]: Index: 1 Listeners:
[18:10:29] [server thread/ERROR] [FML]: 0: NORMAL
[18:10:29] [server thread/ERROR] [FML]: 1: ASM: net.theviolentsquirrels.craftandconquer.event.NPCInteractEvent@664a3770 onEntityNPCInteract(Lnet/minecraftforge/event/entity/player/PlayerInteractEvent$EntityInteract;)V
[18:10:29] [server thread/FATAL]: Error executing task
java.util.concurrent.ExecutionException: java.lang.ClassCastException: net.minecraft.client.renderer.texture.SimpleTexture cannot be cast to net.minecraft.client.renderer.ThreadDownloadImageData
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: java.lang.ClassCastException: net.minecraft.client.renderer.texture.SimpleTexture cannot be cast to net.minecraft.client.renderer.ThreadDownloadImageData
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

Squirrel ! Squirrel ! Squirrel !

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • It i have Create Stuff and Additions, i get an error that Create is at the wrong version (0.5.1j instead of 0.6.3) and if i remove it, i just end up getting an error for 11 different mods that are unable to load properly. What should i do? Without Create Stuff and Additions: https://ibb.co/fz6Mbw8x With Create Stuff and Additions: https://ibb.co/RTkvnCXN  And no, i can't update Create since i have other mods that don't support 0.6.0 yet.
    • I can usually figure out solutions to these, but I'm stumped. New modpack, made today. I have tried removing pehkui, but origins++ needs it, I have also tried removing amendments, supplementaries, and moonlight Attempted removing origins++ and pehkui and the server started, is there any way to add them to the server without crashing?   Crash log https://pastebin.com/xEm9rDLQ   Latest debug log https://pastebin.com/ChCRGegF    
    • Unlock Massive Savings with  Temu Coupon Codes: Save Big with $100 OFF and More!  Temu is a revolutionary online marketplace that offers a huge collection of trending items at unbeatable prices. Whether you're looking for gadgets, home décor, fashion, or beauty products,  Temu has something for everyone. By using the  Temu coupon code $100 OFF → [acu639380] for existing customers, you can unlock incredible discounts, save up to 90%, and even enjoy free shipping to over 67 countries. In this blog, we will explore the latest  Temu coupon code offerings, including $100 off for new and existing users, a special 40% discount on select items, and the incredible  Temu coupon bundle. Read on to discover how you can make the most of these discounts and enjoy amazing deals with  Temu this June! What is  Temu and Why Should You Shop There?  Temu is a one-stop online shopping destination that offers a vast selection of products at prices that are hard to beat. Whether you're purchasing for yourself or looking for gifts,  Temu delivers a wide variety of high-quality products across different categories. From clothing to electronics, home essentials, beauty products, and much more,  Temu has something for everyone. With its fast delivery, free shipping in over 67 countries, and discounts of up to 90% off, it’s no wonder why shoppers worldwide love this platform. Not only does  Temu offer competitive prices, but their frequent promotions and coupon codes make shopping even more affordable. In this blog, we’ll focus on how you can save even more with  Temu coupon codes, including the highly sought-after $100 OFF and 40% OFF codes. The Power of  Temu Coupon Code $100 OFF → [acu639380] for Existing Customers If you're a  Temu existing customer, you can unlock a fantastic $100 OFF by using the code [acu639380]. This coupon code provides a generous discount, allowing you to save big on your next purchase, whether it’s electronics, fashion, or home décor. Here’s why you should take advantage of this offer: Flat $100 off: This code gives you a flat $100 discount on your order. Available for Existing Users: If you've shopped with  Temu before, this coupon code is for you! Unbeatable Deals: Use this coupon in combination with other ongoing sales for even bigger savings. Huge Selection: Apply the code across  Temu’s massive inventory, from tech gadgets to everyday essentials.  Temu Coupon Code $100 OFF → [acu639380] for New Users Are you new to  Temu? You’re in luck!  Temu has a special $100 off coupon code just for you. By using [acu639380], new users can enjoy a $100 discount on their first purchase. This is an excellent way to try out the platform without breaking the bank. Here’s how to make the most of your  Temu coupon code as a new user: $100 Off Your First Order: If you’ve never shopped with  Temu before, the [acu639380] code gets you $100 off your first purchase. Great for First-Time Shoppers: Explore  Temu's range of trending items while saving money right from the start. Free Gifts: As a new user, you June also receive a special gift with your order as part of the ongoing promotions.  Temu Coupon Code 40% Off → [acu639380] for Extra Savings Looking for even more savings? The 40% off coupon is an amazing deal that’s available for a limited time. By using the code [acu639380], you can enjoy an extra 40% off on selected items. Whether you're shopping for electronics, home goods, or fashion, this coupon code allows you to grab even better deals on top of existing discounts. 40% Extra Off: This discount can be applied to select categories and items, giving you incredible savings. Stack with Other Offers: Combine it with other promotions for unbeatable prices. Popular Items: Use the 40% off code to save on some of  Temu’s hottest items of the season.  Temu Coupon Bundle: Unlock Even More Savings When you use the  Temu coupon bundle, you get even more benefits.  Temu offers a $100 coupon bundle, which allows both new and existing users to save even more on a variety of products. Whether you're shopping for yourself or buying gifts for others, this bundle can help you save big. $100 Coupon Bundle: The  Temu coupon bundle lets you apply multiple discounts at once, ensuring maximum savings. Available to All Users: Whether you’re a first-time shopper or a returning customer, the bundle is available for you to enjoy. Stacked Savings: When combined with other codes like the 40% off or the $100 off, you can save up to 90%.  Temu Coupon Code June 2025: New Offers and Promotions If you're shopping in June 2025, you're in for a treat!  Temu is offering a range of new offers and discount codes for the month. Whether you're shopping for electronics, clothing, or home décor, you’ll find discounts that will help you save a ton. Don’t miss out on the  Temu promo code and  Temu discount code that are available only for a limited time this month.  Temu New User Coupon: New users can save up to $100 off their first order with the [acu639380] code.  Temu Existing User Coupon: Existing users can unlock $100 off using the [acu639380] code.  Temu Coupon Code for June 2025: Get discounts on select items with up to 40% off this June.  Temu Coupon Code for Different Countries No matter where you live,  Temu has something special for you! You can use  Temu coupon codes tailored to your country to unlock great savings. Here’s a breakdown of how you can apply the [acu639380] coupon code in different regions:  Temu Coupon Code $100 Off for USA: Use the [acu639380] code in the USA to save $100 off your order.  Temu Coupon Code $100 Off for Canada: Canadians can enjoy $100 off using the [acu639380] code.  Temu Coupon Code $100 Off for UK: British shoppers can save $100 with the [acu639380] code.  Temu Coupon Code $100 Off for Japan: If you’re in Japan, apply the [acu639380] code to get $100 off.  Temu Coupon Code 40% Off for Mexico: Mexican shoppers can get 40% off with the [acu639380] code.  Temu Coupon Code 40% Off for Brazil: Brazil residents can save 40% by using the [acu639380] code. Why Shop with  Temu?  Temu isn’t just about the discounts; it’s about providing you with an exceptional shopping experience. Here’s why you should choose  Temu for your next shopping spree: Huge Selection of Trending Items: From the latest tech gadgets to fashion and home essentials,  Temu offers everything you need at amazing prices. Unbeatable Prices: With  Temu, you can shop for quality items at prices that are hard to match elsewhere. Fast Delivery: Enjoy fast and reliable delivery on all your orders. Free Shipping in Over 67 Countries: No matter where you are,  Temu ensures you get your products without any extra shipping fees. Up to 90% Off: Take advantage of massive discounts on selected products, so you can get more for less. Conclusion: Maximize Your Savings with  Temu Coupon Codes If you're looking for incredible deals, there’s no better time to shop at  Temu. With  Temu coupon code $100 OFF for existing and new users, an extra 40% off, and amazing coupon bundles, there are plenty of ways to save big. Don’t forget to check out the  Temu promo code for June 2025 and other exciting offers throughout the month. By using [acu639380], you can make the most of your shopping experience and enjoy unbeatable prices on all your favorite products. So, what are you waiting for? Start shopping with  Temu today, and enjoy massive savings with the $100 off and 40% off coupon codes. Happy shopping!  Temu Coupon Code Summary:  Temu Coupon Code $100 Off → [acu639380]: Save $100 on your purchase.  Temu Coupon Code $100 Off for New Users → [acu639380]: New users can get $100 off.  Temu Coupon Code $100 Off for Existing Users → [acu639380]: Existing users can save $100.  Temu Coupon Code 40% Off → [acu639380]: Enjoy 40% off select items.  Temu Coupon Bundle: Access a $100 coupon bundle for even more savings.  Temu Promo Code for June 2025: Latest deals for June 2025.  
    • it didnt make any different his game still crashes (https://www.mediafire.com/file/qmuanorha0d87b5/LOGSBURAK.zip/file) the crash log after without shield expansion mod
    • I am using Linux, I did Java --version and it shows I have Java 8 installed
  • Topics

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.