Posted November 14, 20231 yr How to add a new renderLayer to the player? In the original player class we have its constructor: Spoiler @OnlyIn(Dist.CLIENT) public class PlayerRenderer extends LivingEntityRenderer<AbstractClientPlayer, PlayerModel<AbstractClientPlayer>> { public PlayerRenderer(EntityRendererProvider.Context p_174557_, boolean p_174558_) { super(p_174557_, new PlayerModel<>(p_174557_.bakeLayer(p_174558_ ? ModelLayers.PLAYER_SLIM : ModelLayers.PLAYER), p_174558_), 0.5F); this.addLayer(new HumanoidArmorLayer<>(this, new HumanoidModel(p_174557_.bakeLayer(p_174558_ ? ModelLayers.PLAYER_SLIM_INNER_ARMOR : ModelLayers.PLAYER_INNER_ARMOR)), new HumanoidModel(p_174557_.bakeLayer(p_174558_ ? ModelLayers.PLAYER_SLIM_OUTER_ARMOR : ModelLayers.PLAYER_OUTER_ARMOR)))); this.addLayer(new PlayerItemInHandLayer<>(this, p_174557_.getItemInHandRenderer())); this.addLayer(new ArrowLayer<>(p_174557_, this)); this.addLayer(new Deadmau5EarsLayer(this)); this.addLayer(new CapeLayer(this)); this.addLayer(new CustomHeadLayer<>(this, p_174557_.getModelSet(), p_174557_.getItemInHandRenderer())); this.addLayer(new ElytraLayer<>(this, p_174557_.getModelSet())); this.addLayer(new ParrotOnShoulderLayer<>(this, p_174557_.getModelSet())); this.addLayer(new SpinAttackEffectLayer<>(this, p_174557_.getModelSet())); this.addLayer(new BeeStingerLayer<>(this)); } // ..... MORE CODE } I would like to add an additional Layer through events. I searched a lot and found the way below, using EntityRenderersEvent.AddLayers. Spoiler @Mod.EventBusSubscriber(modid = ModCraft.MOD_ID, value = Dist.CLIENT) public static class ClientForgeEvents { @SubscribeEvent public static void registerArmorRenderers(EntityRenderersEvent.AddLayers event) { boolean bool=true; //LivingEntityRenderer render = event.getRenderer(EntityType.PLAYER); LivingEntityRenderer<Player, PlayerModel<Player>> renderer = event.getRenderer(EntityType.PLAYER); ExampleTypeAcessoryLayer layer = new ExampleTypeAcessoryLayer(renderer, new HumanoidModel(event.getEntityModels().bakeLayer(bool ? ModelLayers.PLAYER_SLIM_INNER_ARMOR : ModelLayers.PLAYER_INNER_ARMOR)), new HumanoidModel(event.getEntityModels().bakeLayer(bool ? ModelLayers.PLAYER_SLIM_OUTER_ARMOR : ModelLayers.PLAYER_OUTER_ARMOR))); renderer.addLayer(layer); } } However, the code states that o renderer = null. How to add this RenderLayer to entities that already exist in vanilla?
November 14, 20231 yr The PlayerRenderer is handled seperated from all other Entity Renderers, you can get i from EntityRenderersEvent$AddLayers#getSkin.
November 15, 20231 yr Author Thanks. The renderer isn't more null. But the layer not render nothing. Let's go back a few houses!!! To check if the exampleentityLayer is working(Is working). -> I built a new entity (extends Skeleton) -> I added this render (my renderLayer) to my new created entity. It works! see My entity renderer (created by me) and the added renderlayer: Spoiler public class ExampleTypeRender extends HumanoidMobRenderer<AbstractSkeleton, HumanoidModel<AbstractSkeleton>> { private static final ResourceLocation SKELETON_LOCATION = new ResourceLocation(ModCraft.MOD_ID, "textures/entity/example_entity/skeleton.png"); public ExampleTypeRender(EntityRendererProvider.Context context) { this(context, ModelLayers.SKELETON, ModelLayers.SKELETON_INNER_ARMOR, ModelLayers.SKELETON_OUTER_ARMOR); } public ExampleTypeRender(EntityRendererProvider.Context context, ModelLayerLocation modelLayerLocation, ModelLayerLocation layerLocation, ModelLayerLocation location) { super(context, new SkeletonModel<>(context.bakeLayer(modelLayerLocation)), 0.3F); // Here I Add my Custom RenderLayer this.addLayer(new ExampleEntityLayer<>(this, new ExampleTypeModel(context.bakeLayer(layerLocation)), new ExampleTypeModel(context.bakeLayer(location)))); } public ResourceLocation getTextureLocation(AbstractSkeleton skeleton) { return SKELETON_LOCATION; } protected boolean isShaking(AbstractSkeleton p_174389_) { return p_174389_.isShaking(); } } Look at the image that works: Spoiler Now let's put my RenderLayer in a Vanila entity (a Skeleton). Not yet in the Player (we will do this later, if possible). So all Skeletons must render this armor. But this does not happen: See the image below. Adding the RenderLayer in Skeleton Vanilla via Register EntityRenderersEvent.AddLayers: Spoiler public class ClientEvents { @Mod.EventBusSubscriber(modid = ModCraft.MOD_ID, value = Dist.CLIENT) public static class ClientForgeEvents { @SubscribeEvent public static void registerArmorRenderers(final EntityRenderersEvent.AddLayers event) { boolean bool=true; LivingEntityRenderer render = event.getRenderer(EntityType.SKELETON); render.addLayer(new ExampleEntityLayer(render,new HumanoidModel(event.getEntityModels().bakeLayer(ModelLayers.PLAYER_INNER_ARMOR)),new HumanoidModel(event.getEntityModels().bakeLayer(ModelLayers.PLAYER_OUTER_ARMOR)))); } } The Vanilla Skeleton Image: Spoiler
November 16, 20231 yr Author Right. That is complete custom Skeleton: Spoiler public class ExampleTypeEntity extends AbstractSkeleton { private static final EntityDataAccessor<Boolean> DATA_STRAY_CONVERSION_ID = SynchedEntityData.defineId(Skeleton.class, EntityDataSerializers.BOOLEAN); public static final String CONVERSION_TAG = "StrayConversionTime"; private int inPowderSnowTime; private int conversionTime; @Nullable @Override public SpawnGroupData finalizeSpawn(ServerLevelAccessor p_levelAccessor2146_, DifficultyInstance instance, MobSpawnType spawnType, @Nullable SpawnGroupData groupData, @Nullable CompoundTag tag) { return super.finalizeSpawn(p_levelAccessor2146_, instance, spawnType, groupData, tag); } public ExampleTypeEntity(EntityType<? extends ExampleTypeEntity> entityType, Level level) { super(entityType, level); } protected void defineSynchedData() { super.defineSynchedData(); this.getEntityData().define(DATA_STRAY_CONVERSION_ID, false); } public boolean isFreezeConverting() { return this.getEntityData().get(DATA_STRAY_CONVERSION_ID); } public void setFreezeConverting(boolean p_149843_) { this.entityData.set(DATA_STRAY_CONVERSION_ID, p_149843_); } public boolean isShaking() { return this.isFreezeConverting(); } public void tick() { if (!this.level.isClientSide && this.isAlive() && !this.isNoAi()) { if (this.isFreezeConverting()) { --this.conversionTime; if (this.conversionTime < 0) { this.doFreezeConversion(); } } else if (this.isInPowderSnow) { ++this.inPowderSnowTime; if (this.inPowderSnowTime >= 140) { this.startFreezeConversion(300); } } else { this.inPowderSnowTime = -1; } } super.tick(); } public void addAdditionalSaveData(CompoundTag p_149836_) { super.addAdditionalSaveData(p_149836_); p_149836_.putInt("StrayConversionTime", this.isFreezeConverting() ? this.conversionTime : -1); } public void readAdditionalSaveData(CompoundTag p_149833_) { super.readAdditionalSaveData(p_149833_); if (p_149833_.contains("StrayConversionTime", 99) && p_149833_.getInt("StrayConversionTime") > -1) { this.startFreezeConversion(p_149833_.getInt("StrayConversionTime")); } } private void startFreezeConversion(int p_149831_) { this.conversionTime = p_149831_; this.entityData.set(DATA_STRAY_CONVERSION_ID, true); } protected void doFreezeConversion() { this.convertTo(EntityType.STRAY, true); if (!this.isSilent()) { this.level.levelEvent((Player)null, 1048, this.blockPosition(), 0); } } public boolean canFreeze() { return false; } protected SoundEvent getAmbientSound() { return SoundEvents.SKELETON_AMBIENT; } protected SoundEvent getHurtSound(DamageSource p_33579_) { return SoundEvents.SKELETON_HURT; } protected SoundEvent getDeathSound() { return SoundEvents.SKELETON_DEATH; } protected SoundEvent getStepSound() { return SoundEvents.SKELETON_STEP; } protected void dropCustomDeathLoot(DamageSource p_33574_, int p_33575_, boolean p_33576_) { super.dropCustomDeathLoot(p_33574_, p_33575_, p_33576_); Entity entity = p_33574_.getEntity(); if (entity instanceof Creeper creeper) { if (creeper.canDropMobsSkull()) { creeper.increaseDroppedSkulls(); this.spawnAtLocation(Items.SKELETON_SKULL); } } } } And this is the Complete Custom ExampleEntityLayer (the custom renderLayer to Custom Skeletom) (It's basically an adapted HumanoidArmorLayer class) Spoiler @OnlyIn(Dist.CLIENT) public class ExampleEntityLayer <T extends LivingEntity, M extends HumanoidModel<T>, A extends HumanoidModel<T>> extends RenderLayer<T, M> { private static final Map<String, ResourceLocation> ARMOR_LOCATION_CACHE = Maps.newHashMap(); private final A innerModel; private final A outerModel; public ExampleEntityLayer(RenderLayerParent<T, M> p_117075_, A p_117076_, A p_117077_) { super(p_117075_); this.innerModel = p_117076_; this.outerModel = p_117077_; } public void render(PoseStack p_117096_, MultiBufferSource p_117097_, int p_117098_, T p_117099_, float p_117100_, float p_117101_, float p_117102_, float p_117103_, float p_117104_, float p_117105_) { this.renderArmorPiece(p_117096_, p_117097_, p_117099_, EquipmentSlot.CHEST, p_117098_, this.getArmorModel(EquipmentSlot.CHEST)); this.renderArmorPiece(p_117096_, p_117097_, p_117099_, EquipmentSlot.LEGS, p_117098_, this.getArmorModel(EquipmentSlot.LEGS)); this.renderArmorPiece(p_117096_, p_117097_, p_117099_, EquipmentSlot.FEET, p_117098_, this.getArmorModel(EquipmentSlot.FEET)); this.renderArmorPiece(p_117096_, p_117097_, p_117099_, EquipmentSlot.HEAD, p_117098_, this.getArmorModel(EquipmentSlot.HEAD)); } private void renderArmorPiece(PoseStack poseStack, MultiBufferSource bufferSource, T livingEntity, EquipmentSlot equipmentSlot, int i1, A armorModel) { ItemStack itemstack = livingEntity.getItemBySlot(equipmentSlot); equipmentSlot = EquipmentSlot.HEAD; itemstack = new ItemStack(ModItem.STEEL_ARMOR_STANDART_HELMET.get()); if (itemstack.getItem() instanceof ArmorItem) { ArmorItem armoritem = (ArmorItem)itemstack.getItem(); if (armoritem.getSlot() == equipmentSlot) { //this.getParentModel().copyPropertiesTo(p_117124_); //ModelPartUtils.copyOriginalPropertiesTo(this.getParentModel(), armorModel,0.1F);// trabalho dobrado a frente //this.setPartVisibility(armorModel, equipmentSlot); net.minecraft.client.model.Model model = getArmorModelHook(livingEntity, itemstack, equipmentSlot, armorModel); boolean flag = this.usesInnerModel(equipmentSlot); boolean flag1 = itemstack.hasFoil(); if (armoritem instanceof net.minecraft.world.item.DyeableLeatherItem) { int i = ((net.minecraft.world.item.DyeableLeatherItem)armoritem).getColor(itemstack); float f = (float)(i >> 16 & 255) / 255.0F; float f1 = (float)(i >> 8 & 255) / 255.0F; float f2 = (float)(i & 255) / 255.0F; this.renderModel(poseStack, bufferSource, i1, flag1, model, f, f1, f2, this.getArmorResource(livingEntity, itemstack, equipmentSlot, null)); this.renderModel(poseStack, bufferSource, i1, flag1, model, 1.0F, 1.0F, 1.0F, this.getArmorResource(livingEntity, itemstack, equipmentSlot, "overlay")); } else { this.renderModel(poseStack, bufferSource, i1, flag1, model, 1.0F, 1.0F, 1.0F, this.getArmorResource(livingEntity, itemstack, equipmentSlot, null)); } } } } protected void setPartVisibility(A p_117126_, EquipmentSlot p_117127_) { p_117126_.setAllVisible(false); switch (p_117127_) { case HEAD: p_117126_.head.visible = true; p_117126_.hat.visible = true; break; case CHEST: p_117126_.body.visible = true; p_117126_.rightArm.visible = true; p_117126_.leftArm.visible = true; break; case LEGS: p_117126_.body.visible = true; p_117126_.rightLeg.visible = true; p_117126_.leftLeg.visible = true; break; case FEET: p_117126_.rightLeg.visible = true; p_117126_.leftLeg.visible = true; } } private void renderModel(PoseStack p_117107_, MultiBufferSource p_117108_, int p_117109_, ArmorItem p_117110_, boolean p_117111_, A p_117112_, boolean p_117113_, float p_117114_, float p_117115_, float p_117116_, @Nullable String p_117117_) { renderModel(p_117107_, p_117108_, p_117109_, p_117111_, p_117112_, p_117114_, p_117115_, p_117116_, this.getArmorLocation(p_117110_, p_117113_, p_117117_)); } private void renderModel(PoseStack p_117107_, MultiBufferSource p_117108_, int p_117109_, boolean p_117111_, net.minecraft.client.model.Model p_117112_, float p_117114_, float p_117115_, float p_117116_, ResourceLocation armorResource) { VertexConsumer vertexconsumer = ItemRenderer.getArmorFoilBuffer(p_117108_, RenderType.armorCutoutNoCull(armorResource), false, p_117111_); p_117112_.renderToBuffer(p_117107_, vertexconsumer, p_117109_, OverlayTexture.NO_OVERLAY, p_117114_, p_117115_, p_117116_, 1.0F); } private A getArmorModel(EquipmentSlot p_117079_) { return (A)(this.usesInnerModel(p_117079_) ? this.innerModel : this.outerModel); } private boolean usesInnerModel(EquipmentSlot p_117129_) { return p_117129_ == EquipmentSlot.LEGS; } @Deprecated //Use the more sensitive version getArmorResource below private ResourceLocation getArmorLocation(ArmorItem p_117081_, boolean p_117082_, @Nullable String p_117083_) { String s = "textures/models/armor/" + p_117081_.getMaterial().getName() + "_layer_" + (p_117082_ ? 2 : 1) + (p_117083_ == null ? "" : "_" + p_117083_) + ".png"; return ARMOR_LOCATION_CACHE.computeIfAbsent(s, ResourceLocation::new); } /*=================================== FORGE START =========================================*/ /** * Hook to allow item-sensitive armor model. for HumanoidArmorLayer. */ protected net.minecraft.client.model.Model getArmorModelHook(T entity, ItemStack itemStack, EquipmentSlot slot, A model) { return net.minecraftforge.client.ForgeHooksClient.getArmorModel(entity, itemStack, slot, model); } /** * More generic ForgeHook version of the above function, it allows for Items to have more control over what texture they provide. * * @param entity Entity wearing the armor * @param stack ItemStack for the armor * @param slot Slot ID that the item is in * @param type Subtype, can be null or "overlay" * @return ResourceLocation pointing at the armor's texture */ public ResourceLocation getArmorResource(net.minecraft.world.entity.Entity entity, ItemStack stack, EquipmentSlot slot, @Nullable String type) { ArmorItem item = (ArmorItem)stack.getItem(); String texture = item.getMaterial().getName(); String domain = "minecraft"; int idx = texture.indexOf(':'); if (idx != -1) { domain = texture.substring(0, idx); texture = texture.substring(idx + 1); } String s1 = String.format(java.util.Locale.ROOT, "%s:textures/models/armor/%s_layer_%d%s.png", domain, texture, (usesInnerModel(slot) ? 2 : 1), type == null ? "" : String.format(java.util.Locale.ROOT, "_%s", type)); s1 = net.minecraftforge.client.ForgeHooksClient.getArmorTexture(entity, stack, s1, slot, type); ResourceLocation resourcelocation = ARMOR_LOCATION_CACHE.get(s1); if (resourcelocation == null) { resourcelocation = new ResourceLocation(s1); ARMOR_LOCATION_CACHE.put(s1, resourcelocation); } return resourcelocation; } /*=================================== FORGE END ===========================================*/ }
November 16, 20231 yr Author Is Here: Spoiler public class ExampleTypeRender extends HumanoidMobRenderer<AbstractSkeleton, HumanoidModel<AbstractSkeleton>> { private static final ResourceLocation SKELETON_LOCATION = new ResourceLocation(ModCraft.MOD_ID, "textures/entity/example_entity/skeleton.png"); public ExampleTypeRender(EntityRendererProvider.Context context) { this(context, ModelLayers.SKELETON, ModelLayers.SKELETON_INNER_ARMOR, ModelLayers.SKELETON_OUTER_ARMOR); } public ExampleTypeRender(EntityRendererProvider.Context context, ModelLayerLocation modelLayerLocation, ModelLayerLocation layerLocation, ModelLayerLocation location) { super(context, new SkeletonModel<>(context.bakeLayer(modelLayerLocation)), 0.3F); this.addLayer(new ExampleEntityLayer<>(this, new ExampleTypeModel(context.bakeLayer(layerLocation)), new ExampleTypeModel(context.bakeLayer(location)))); } public ResourceLocation getTextureLocation(AbstractSkeleton skeleton) { return SKELETON_LOCATION; } protected boolean isShaking(AbstractSkeleton p_174389_) { return p_174389_.isShaking(); } }
November 17, 20231 yr On 11/15/2023 at 4:51 PM, DouglasDVale said: Adding the RenderLayer in Skeleton Vanilla via Register EntityRenderersEvent.AddLayers: Please post the full ClientEvents class
November 23, 20231 yr Author I discovered the error: My Event Bus was in the wrong place. Correct Place: Spoiler @Mod.EventBusSubscriber(modid = ModCraft.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD) public class ModEventBusEvents { @SubscribeEvent public static void registerArmorLayers(EntityRenderersEvent.AddLayers event){ LivingEntityRenderer render = event.getRenderer(EntityType.SKELETON); EntityModelSet models = Minecraft.getInstance().getEntityModels(); ModelPart rootInner = models.bakeLayer(ModelLayers.SKELETON_INNER_ARMOR); ModelPart rootOuter = models.bakeLayer(ModelLayers.SKELETON_OUTER_ARMOR); RenderLayer<LivingEntity, EntityModel<LivingEntity>> renderlayer1 = new ExampleEntityLayer(render, new HumanoidModel(rootInner), new HumanoidModel(rootOuter)); render.addLayer(renderlayer1); } }
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.