You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在仅客户端的Minecraft模组中通过GeckoLib基于实体昵称替换原版生物模型

如何在仅客户端的Minecraft模组中通过GeckoLib基于实体昵称替换原版生物模型

嘿,我之前也折腾过类似的需求——在纯客户端模组里,用GeckoLib给特定昵称的原版生物换自定义Blockbench模型,踩过几个坑,刚好可以给你梳理下顺畅的实现方式~

核心思路

直接取消原版渲染再手动调用自定义渲染容易踩坑(比如光影不同步、实体状态丢失),更稳妥的方式是:通过RenderLivingEvent.Pre拦截目标实体的渲染流程,判断昵称后用GeckoLib的自定义渲染器接管,同时取消原版渲染逻辑。

具体实现步骤

1. 准备GeckoLib模型资源

先把你在Blockbench里做好的模型导出成GeckoLib格式,按规范放进客户端模组的资源目录:

  • assets/你的模组id/geo/自定义模型.geo.json(模型结构文件)
  • assets/你的模组id/animations/动画配置.json(动画逻辑文件)
  • assets/你的模组id/textures/entity/模型材质.png(材质贴图)
    确保文件路径和命名完全对应,不然GeckoLib会加载失败。

2. 编写自定义Geo渲染器与模型类

我们需要两个核心类:一个是承载模型的GeoModel,另一个是负责渲染的GeoEntityRenderer,不需要注册新实体类型,只针对原版实体做渲染劫持:

自定义GeoModel类

public class CustomNicknameMobModel extends GeoModel<LivingEntity> {
    @Override
    public ResourceLocation getModelResource(LivingEntity entity) {
        return new ResourceLocation("你的模组id", "geo/custom_mob.geo.json");
    }

    @Override
    public ResourceLocation getTextureResource(LivingEntity entity) {
        return new ResourceLocation("你的模组id", "textures/entity/custom_mob_texture.png");
    }

    @Override
    public ResourceLocation getAnimationResource(LivingEntity entity) {
        return new ResourceLocation("你的模组id", "animations/custom_mob_anim.json");
    }
}

自定义GeoEntityRenderer类

public class CustomNicknameMobRenderer extends GeoEntityRenderer<LivingEntity> {
    public CustomNicknameMobRenderer(EntityRendererProvider.Context context) {
        super(context, new CustomNicknameMobModel());
        // 调整阴影大小,和原版生物匹配
        this.shadowRadius = 0.6F;
    }

    // 可选:如果需要根据实体状态(比如行走、攻击)切换动画,重写此方法
    @Override
    public void render(LivingEntity entity, float entityYaw, float partialTick, PoseStack poseStack, MultiBufferSource bufferSource, int packedLight) {
        // 比如给模型加缩放:poseStack.scale(1.2F, 1.2F, 1.2F);
        super.render(entity, entityYaw, partialTick, poseStack, bufferSource, packedLight);
    }
}

3. 用RenderLivingEvent.Pre拦截并替换渲染

这一步是核心:在客户端事件总线注册RenderLivingEvent.Pre事件,判断实体昵称后接管渲染:

// 确保这个类在客户端初始化时注册到客户端事件总线
public class ClientEventHandler {
    @SubscribeEvent
    public void onPreLivingRender(RenderLivingEvent.Pre<LivingEntity, EntityModel<LivingEntity>> event) {
        LivingEntity targetEntity = event.getEntity();
        // 检查实体是否有自定义昵称,且是我们要替换的目标
        if (targetEntity.getCustomName() != null && targetEntity.getCustomName().equals(Component.literal("我的专属生物"))) {
            // 获取Minecraft的渲染上下文
            EntityRendererProvider.Context renderContext = Minecraft.getInstance().getEntityRenderDispatcher().getContext();
            // 实例化自定义渲染器
            CustomNicknameMobRenderer customRenderer = new CustomNicknameMobRenderer(renderContext);
            // 执行自定义渲染,传入事件里的所有渲染参数
            customRenderer.render(
                targetEntity,
                event.getEntityYaw(),
                event.getPartialTick(),
                event.getPoseStack(),
                event.getMultiBufferSource(),
                event.getPackedLight()
            );
            // 取消原版渲染,避免同一实体被画两次
            event.setCanceled(true);
        }
    }
}

⚠️ 重要提醒:

  • 这个事件必须注册到客户端事件总线FMLJavaModLoadingContext.get().getModEventBus().register(new ClientEventHandler());),绝对不能注册到服务器总线,因为是纯客户端逻辑
  • 昵称判断建议用Component对象比较,而不是直接转字符串,避免带格式的昵称(比如彩色昵称)匹配失败

4. 避坑指南

  • 不要直接修改原版实体的渲染器注册表,那样会影响所有同类型生物,我们要的是仅特定昵称的个体
  • 如果模型加载失败,先检查GeckoLib依赖版本是否匹配,再核对资源文件路径、命名是否完全正确
  • 动画不动的话,检查AnimationController是否正确绑定,以及是否在GeoModel里返回了正确的动画文件路径

内容来源于stack exchange

火山引擎 最新活动