Jump to content

[SOLVED] About ModelBakeEvent, ISmartItemModel and loading JSON models


Recommended Posts

Posted

Hello.

 

My goal is to merge 2 models together using the ModelBakeEvent and ISmartItemModel. The first model is used by an item so it has been registered @ItemModelMesher. The second one however, is not being used by any item (and not registered ofc). I figured out that the code works if I use 2 models that have been registered and are used by an item. So I guess I have to load those unused models as well, however, after deep google'ing I still have no idea how to do it.

Yes, I checked if all strings and file names are correct.

 

Code (might be little bit dirty, since Im still trying to get used to this new system):

 

ModelGun (ISmartItemModel)

 

public class ModelGun implements ISmartItemModel
{
private IBakedModel baseModel;
private HashMap<String, IBakedModel> map;

private ItemGun gun = null;

private ItemScope scope = null;
private ItemAccessory accessory = null;
private ItemBarrel barrel = null;
private ItemUnderbarrel underbarrel = null;
private ItemPaint paint = null;

public ModelGun(IBakedModel baseModel, HashMap map)
{
	this.baseModel = baseModel;
	this.map = map;
}

@SuppressWarnings("deprecation")
@Override
public IBakedModel handleItemState(ItemStack stack)
{
	if (stack != null && stack.getItem() instanceof ItemGun)
	{
		ItemGun gun = (ItemGun) stack.getItem();

		this.gun = gun;
		this.scope = gun.getScope(stack);
		this.accessory = gun.getAccessory(stack);
		this.barrel = gun.getBarrel(stack);
		this.underbarrel = gun.getUnderbarrel(stack);
		this.paint = gun.getPaint(stack);
	}

	return this;
}

@Override
public TextureAtlasSprite getTexture()
{
	return baseModel.getTexture();
}

@Override
public List getFaceQuads(EnumFacing enumFacing)
{
	List<BakedQuad> combinedQuadsList = new ArrayList(baseModel.getFaceQuads(enumFacing));

	if(this.scope != null)
	{
		IBakedModel model = this.map.get(this.scope.getUnlocalizedDirect());

		if(model != null)
		{
			combinedQuadsList.addAll(model.getFaceQuads(enumFacing));
		}
	}

	return combinedQuadsList;
}

@Override
public List getGeneralQuads()
{
	List<BakedQuad> combinedQuadsList = new ArrayList(baseModel.getGeneralQuads());

	if(this.scope != null)
	{
		IBakedModel model = this.map.get(this.scope.getUnlocalizedDirect());

		if(model != null)
		{
			combinedQuadsList.addAll(model.getGeneralQuads());
		}
	}

	return combinedQuadsList;
}

@Override
public boolean isAmbientOcclusion()
{
	return baseModel.isAmbientOcclusion();
}

@Override
public boolean isGui3d()
{
	return baseModel.isGui3d();
}

@Override
public boolean isBuiltInRenderer()
{
	return false;
}

@Override
public ItemCameraTransforms getItemCameraTransforms()
{
	return baseModel.getItemCameraTransforms();
}
}

 

 

ModelBakeHandler (ModelBakeEvent)

 

public class ModelBakeHandler
{
@SubscribeEvent
public void onModelBakeEvent(ModelBakeEvent event)
{
	for(ItemGun gun : ItemGun.guns)
	{
		ModelResourceLocation mrl = new ModelResourceLocation(GunCus.MOD_ID + ":" + gun.getUnlocalizedDirect(), "inventory");

		Object object = event.modelRegistry.getObject(mrl);

		if(object instanceof IBakedModel)
		{
			HashMap<String, IBakedModel> modelMap = new HashMap<String, IBakedModel>();

			for(ItemAttachment attachment : ItemAttachment.attachments)
			{
// Trying to get a model that is not used by any item; does not work
				ModelResourceLocation mrl2 = new ModelResourceLocation(GunCus.MOD_ID + ":" + gun.getUnlocalizedDirect() + "_" + attachment.getUnlocalizedDirect(), "inventory");

// Getting a model used by an item; works
				ModelResourceLocation mrl2 = new ModelResourceLocation(GunCus.MOD_ID + ":" + attachment.getUnlocalizedDirect(), "inventory");

				Object object2 = event.modelManager.getModel(mrl2);

				if(object2 != null && object2 instanceof IBakedModel)
				{
					modelMap.put(attachment.getUnlocalizedDirect(), (IBakedModel) object2);
				}
			}

			event.modelRegistry.putObject(mrl, new ModelGun((IBakedModel) object, modelMap));
		}
	}
}
}

 

 

 

Note: I know Im still using the deprecated IBakedModel. Will change that in future ofc. 2 pages that helped me a lot:

https://github.com/TheGreyGhost/MinecraftByExample/tree/master/src/main/java/minecraftbyexample/mbe15_item_smartitemmodel (amazing)

http://www.minecraftforge.net/forum/index.php/topic,32309.0/nowap.html (helped me understanding the basics)

 

thanks

Posted

You may not need to bake them at all if you just want to do combine that model / texture with another one that is already baked:

// in your ISmartItemModel
IBakedModel model = Minecraft.getMinecraft().getRenderItem().getItemModelMesher().getModelManager().getModel(new ModelResourceLocation("yourmodid:name_of_the_model_you_want", "inventory"));

// now you can add the model's quads to the current smart item model, e.g.:
this.quads.addAll(model.getGeneralQuads());

I use something similar to combine the front and back of my shield models and only the front one is registered and baked.

 

Actually, that reminds me: I DID add those additional names as variants of my item, even though they are not themselves real items (they don't exist anywhere and can't be had by any means).

 

For one or all of your Attachment item classes, try adding the extra names as variants:

ModelBakery.addVariantName(YourAttachmentItem, real_attachment_name, gun_name_plus_attachment_name_1, etc.);

 

Also, instanceof checks for null, so the following are functionally equivalent:

if (object != null && object instanceof Something)
if (object instanceof Something)

Posted

You may not need to bake them at all if you just want to do combine that model / texture with another one that is already baked:

// in your ISmartItemModel
IBakedModel model = Minecraft.getMinecraft().getRenderItem().getItemModelMesher().getModelManager().getModel(new ModelResourceLocation("yourmodid:name_of_the_model_you_want", "inventory"));

// now you can add the model's quads to the current smart item model, e.g.:
this.quads.addAll(model.getGeneralQuads());

I use something similar to combine the front and back of my shield models and only the front one is registered and baked.

 

Actually, that reminds me: I DID add those additional names as variants of my item, even though they are not themselves real items (they don't exist anywhere and can't be had by any means).

 

For one or all of your Attachment item classes, try adding the extra names as variants:

ModelBakery.addVariantName(YourAttachmentItem, real_attachment_name, gun_name_plus_attachment_name_1, etc.);

 

Also, instanceof checks for null, so the following are functionally equivalent:

if (object != null && object instanceof Something)
if (object instanceof Something)

 

Thank you very much. Its working now.

 

For those who want to know: I run the following code right after registering all items to the item model mesher.

 

 

		for(ItemGun gun : ItemGun.guns)
	{
		ArrayList<String> list = new ArrayList<String>();
		list.add(GunCus.MOD_ID + ":" + gun.getUnlocalizedDirect());

		for(ItemAttachment attachment : ItemAttachment.attachments)
		{
			list.add(GunCus.MOD_ID + ":" + gun.getUnlocalizedDirect() + "_" + attachment.getUnlocalizedDirect());
		}

		ModelBakery.addVariantName(gun, list.toArray(new String[list.size()]));
	}

 

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

    • To prevent dependency errors, yes  
    • All of the Dynamic Tree mods?
    • dynamictrees and dtneapolitan are the last mentioned mod - remove these
    • https://mclo.gs/9y5ciD2 anyone ever had this issue?  Internal exception illegal argument exception: unable to fit 3194354 into 3
    • Hi! I'm trying to add my custom models/textures renderer like this: public class PonyPlayerWrapperRenderer extends EntityRenderer<Player> { // wrapper class under my LivingEntityRenderer class implementation private final PonyPlayerRenderer innerRenderer; private final PonyPlayerRenderer innerSlimRenderer; public PonyPlayerWrapperRenderer(final EntityRendererProvider.Context context) { super(context); System.out.println("creating new PonyPlayerWrapperRenderer"); this.innerRenderer = new PonyPlayerRenderer(context, false); this.innerSlimRenderer = new PonyPlayerRenderer(context, true); } @Override public void render(final Player entity, final float yaw, final float partialTicks, final PoseStack poseStack, final MultiBufferSource bufferSource, final int packedLight) { System.out.println("PonyPlayerWrapperRenderer render: " + entity.toString()); if (entity instanceof AbstractClientPlayer clientPlayer) { if (clientPlayer.getModelName().contains("slim")) { innerSlimRenderer.render(clientPlayer, yaw, partialTicks, poseStack, bufferSource, packedLight); } else { innerRenderer.render(clientPlayer, yaw, partialTicks, poseStack, bufferSource, packedLight); } } } @Override public ResourceLocation getTextureLocation(final Player player) { System.out.println("PonyPlayerWrapperRenderer getTextureLocation"); if (player instanceof AbstractClientPlayer clientPlayer) { return clientPlayer.getSkinTextureLocation(); } System.out.println("player instanceof AbstractClientPlayer is false"); return getDefaultSkin(player.getUUID()); } } public class PonyPlayerRenderer extends LivingEntityRenderer<AbstractClientPlayer, PlayerModel<AbstractClientPlayer>> { private final PlayerModel<AbstractClientPlayer> earthModel; private final PlayerModel<AbstractClientPlayer> pegasusModel; private final PlayerModel<AbstractClientPlayer> unicornModel; public PonyPlayerRenderer(final EntityRendererProvider.Context context, final boolean slim) { super( context, slim ? new PonyModelSlim(context.bakeLayer(PonyModelSlim.LAYER_LOCATION)) : new PonyModel(context.bakeLayer(PonyModel.LAYER_LOCATION)), 0.5f ); System.out.println("creating new PonyPlayerRenderer"); this.earthModel = slim ? new PonyModelSlim(context.bakeLayer(PonyModelSlim.LAYER_LOCATION)) : new PonyModel(context.bakeLayer(PonyModel.LAYER_LOCATION)); this.pegasusModel = new PegasusModel(context.bakeLayer(PegasusModel.LAYER_LOCATION)); this.unicornModel = new UnicornModel(context.bakeLayer(UnicornModel.LAYER_LOCATION)); } @Override public void render(final AbstractClientPlayer player, final float entityYaw, final float partialTicks, final PoseStack poseStack, final MultiBufferSource buffer, final int packedLight) { final PonyRace race = player.getCapability(PONY_DATA) .map(data -> ofNullable(data.getRace()).orElse(PonyRace.EARTH)) .orElse(PonyRace.EARTH); this.model = switch (race) { case PEGASUS -> pegasusModel; case UNICORN -> unicornModel; case EARTH -> earthModel; }; super.render(player, entityYaw, partialTicks, poseStack, buffer, packedLight); } @Override public ResourceLocation getTextureLocation(final AbstractClientPlayer player) { final PonyRace race = player.getCapability(PONY_DATA) .map(data -> ofNullable(data.getRace()).orElse(PonyRace.EARTH)) .orElse(PonyRace.EARTH); return switch (race) { case EARTH -> fromNamespaceAndPath(MODID, "textures/entity/earth_pony.png"); case PEGASUS -> fromNamespaceAndPath(MODID, "textures/entity/pegasus.png"); case UNICORN -> fromNamespaceAndPath(MODID, "textures/entity/unicorn.png"); }; } } @Mod.EventBusSubscriber(modid = MODID, bus = MOD, value = CLIENT) public class ClientRenderers { // mod bus render registration config @SubscribeEvent public static void onRegisterLayerDefinitions(final EntityRenderersEvent.RegisterLayerDefinitions event) { event.registerLayerDefinition(PonyModel.LAYER_LOCATION, PonyModel::createBodyLayer); event.registerLayerDefinition(PonyModelSlim.LAYER_LOCATION, PonyModelSlim::createBodyLayer); event.registerLayerDefinition(PegasusModel.LAYER_LOCATION, PegasusModel::createBodyLayer); event.registerLayerDefinition(UnicornModel.LAYER_LOCATION, UnicornModel::createBodyLayer); event.registerLayerDefinition(InnerPonyArmorModel.LAYER_LOCATION, InnerPonyArmorModel::createBodyLayer); event.registerLayerDefinition(OuterPonyArmorModel.LAYER_LOCATION, OuterPonyArmorModel::createBodyLayer); } @SubscribeEvent public static void onRegisterRenderers(final EntityRenderersEvent.RegisterRenderers event) { event.registerEntityRenderer(EntityType.PLAYER, PonyPlayerWrapperRenderer::new); System.out.println("onRegisterRenderers end"); } } Method onRegisterRenderers() is called and I can see it being logged. But when I enter the world, my PonyWrapperRenderer render() method doesn't ever seem to be called. I also tried to put my renderer to EntityRenderDispatcher's playerRenderers via reflection: @Mod.EventBusSubscriber(modid = MODID, bus = MOD, value = CLIENT) public class ClientRenderers { @SubscribeEvent public static void onRegisterLayerDefinitions(final EntityRenderersEvent.RegisterLayerDefinitions event) { event.registerLayerDefinition(PonyModel.LAYER_LOCATION, PonyModel::createBodyLayer); event.registerLayerDefinition(PonyModelSlim.LAYER_LOCATION, PonyModelSlim::createBodyLayer); event.registerLayerDefinition(PegasusModel.LAYER_LOCATION, PegasusModel::createBodyLayer); event.registerLayerDefinition(UnicornModel.LAYER_LOCATION, UnicornModel::createBodyLayer); event.registerLayerDefinition(InnerPonyArmorModel.LAYER_LOCATION, InnerPonyArmorModel::createBodyLayer); event.registerLayerDefinition(OuterPonyArmorModel.LAYER_LOCATION, OuterPonyArmorModel::createBodyLayer); } @SubscribeEvent public static void onClientSetup(final FMLClientSetupEvent event) { event.enqueueWork(() -> { try { final EntityRenderDispatcher dispatcher = Minecraft.getInstance().getEntityRenderDispatcher(); final Field renderersField = getEntityRenderDispatcherField("playerRenderers"); final Field itemInHandRenderer = getEntityRenderDispatcherField("itemInHandRenderer"); @SuppressWarnings("unchecked") final Map<String, EntityRenderer<? extends Player>> playerRenderers = (Map<String, EntityRenderer<? extends Player>>)renderersField.get(dispatcher); final PonyPlayerWrapperRenderer renderer = new PonyPlayerWrapperRenderer( new EntityRendererProvider.Context( dispatcher, Minecraft.getInstance().getItemRenderer(), Minecraft.getInstance().getBlockRenderer(), (ItemInHandRenderer)itemInHandRenderer.get(dispatcher), Minecraft.getInstance().getResourceManager(), Minecraft.getInstance().getEntityModels(), Minecraft.getInstance().font ) ); playerRenderers.put("default", renderer); playerRenderers.put("slim", renderer); System.out.println("Player renderers replaced"); } catch (final Exception e) { throw new RuntimeException("Failed to replace player renderers", e); } }); } private static Field getEntityRenderDispatcherField(final String fieldName) throws NoSuchFieldException { final Field field = EntityRenderDispatcher.class.getDeclaredField(fieldName); field.setAccessible(true); return field; } } But I receive the error before Minecraft Client appears (RuntimeException: Failed to replace player renderers - from ClientRenderers onClientSetup() method - and its cause below): java.lang.IllegalArgumentException: No model for layer anotherlittlepony:earth_pony#main at net.minecraft.client.model.geom.EntityModelSet.bakeLayer(EntityModelSet.java:18) ~[forge-1.20.1-47.4.0_mapped_official_1.20.1-recomp.jar:?] {re:classloading,pl:runtimedistcleaner:A} at net.minecraft.client.renderer.entity.EntityRendererProvider$Context.bakeLayer(EntityRendererProvider.java:69) ~[forge-1.20.1-47.4.0_mapped_official_1.20.1-recomp.jar:?] {re:classloading,pl:runtimedistcleaner:A} at com.thuggeelya.anotherlittlepony.client.renderer.pony.PonyPlayerRenderer.<init>(PonyPlayerRenderer.java:32) ~[main/:?] {re:classloading} at com.thuggeelya.anotherlittlepony.client.renderer.pony.PonyPlayerWrapperRenderer.<init>(PonyPlayerWrapperRenderer.java:24) ~[main/:?] {re:classloading} at com.thuggeelya.anotherlittlepony.client.renderer.ClientRenderers.lambda$onClientSetup$0(ClientRenderers.java:79) ~[main/:?] {re:classloading} ... 33 more Problem appears when EntityRendererProvider context tries to bakeLayer with my model layer location: new PonyModel(context.bakeLayer(PonyModel.LAYER_LOCATION)); // PonyPlayerRenderer.java:32 public class PonyModel extends PlayerModel<AbstractClientPlayer> { // the model class itself public static final ModelLayerLocation LAYER_LOCATION = new ModelLayerLocation( ResourceLocation.fromNamespaceAndPath(MODID, "earth_pony"), "main" ); public PonyModel(final ModelPart root) { super(root, false); } public static LayerDefinition createBodyLayer() { // some CubeListBuilder stuff for model appearance } } Textures PNGs are placed at: resources/assets/[my mod id]/textures/entity. My forge version is 1.20.1. Would appreciate any help.
  • Topics

  • Who's Online (See full list)

×
×
  • Create New...

Important Information

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