Jump to content

Recommended Posts

Posted

I have an item with nbt and multiple render passes. Basically there are parts of the sword that can be randomized. Each part has a different texture. I want the sword to render all the correct textures based on its parts (which are stored in the NBT). How do I do that with the new 1.8 rendering system?

Creator of the MyFit, MagiCraft, Tesseract gun, and Papa's Wingeria mod.

Posted

You mean like this? (this is 1.8 )

 

2iqimad.jpg

Note: Each part can have different texture, all their layers (defined by their model "layer") and colors (that also use renderPass).

 

You basically need to bake models for every provided part's texture (register variants and use ModelBakeEvent) and then use them (models) to put up new model in SmartItemModel.

 

Things you should know:

* This is really fkn hard! (took me days if not weeks of digging).

* Don't expect much help on this field - new model system is still too new. You will need to dig your own "mine".

 

Actual things:

The "renderPass" is actually the "tintIndex" of given BakedQuad.

When you would make model of some part and make it have multiple layers the tintIndex is derived from "layer0" to "layer4" (vanilla allows 5 layers, but it might have changed).

Following this: When you bake part of weapon (let's say blade) you will have e.g 5 BakedQuads for it's front (for each layer) which you can manipulate.

Obviously there is also load more of those quads (for all sides and item's back).

 

Anyway - Using SmartItemModel you can grab tintIndex and make new BakedQuads from old ones and change their tintIndex to fit your needs. This is just an integer that you can manipulate.

1.7.10 is no longer supported by forge, you are on your own.

Posted

How did you do that? I've been looking for forever and experimenting and I can't find anything

Creator of the MyFit, MagiCraft, Tesseract gun, and Papa's Wingeria mod.

Posted

Just like @Ernio said, bake models for each provided texture. Create a wrapper class implementing ISmartItemModel and return different lists of baked quads in the getFaceQuads() and getGeneralQuads() methods. To do this with your item NBT, you need to provide various conditions in the handleItemState(ItemStack itemStack) method. I've been doing work similar to this, it is extremely hard! Be ready to code for a while, but with a little effort, it can be done.

 

EDIT: Changing BakedQuads / drawing new ones is going to be a whole lot harder, I recommend using a .JSON model creator and create all the pieces, then place them into code, bake them, and then return whichever model piece you want to be rendered based on NBT information - to me, this seems easier but do as best pleases yourself.

 

Great work there, @Ernio!

Development of Plugins [2012 - 2014] Development of Mods [2012 - Current]

Posted

Ok I can't figure it out. Here's my code.

 

Smart Model:

 

package com.apmods.rpg.handler;

import java.awt.Color;
import java.util.ArrayList;
import java.util.List;

import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.block.model.ItemCameraTransforms;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.resources.model.IBakedModel;
import net.minecraft.client.resources.model.ModelResourceLocation;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing;
import net.minecraftforge.client.event.ModelBakeEvent;
import net.minecraftforge.client.model.ISmartItemModel;

import com.apmods.rpg.item.models.ItemRPGBladeModels;
import com.apmods.rpg.item.models.ItemRPGGuardModels;
import com.apmods.rpg.item.models.ItemRPGHiltModels;
import com.apmods.rpg.item.rpgBase.RPGBase;
import com.apmods.rpg.main.RPG;
import com.google.common.primitives.Ints;

public class RPGSwordSmartModel implements ISmartItemModel{

/**
   * Create a smart model, using the given baked model as a base to add extra BakedQuads to.
   * @param i_baseChessboardModel the base model
   */
  public RPGSwordSmartModel(ModelBakeEvent event)
  {
	 this.event = event;
  }

  // create a tag (ModelResourceLocation) for our model.
  //  "inventory" is used for items. If you don't specify it, you will end up with "normal" by default,
  //  which is used for blocks.
  public static final ModelResourceLocation modelResourceLocation
          = new ModelResourceLocation(RPG.MODID + ":rpgSword" , "inventory");

  @SuppressWarnings("deprecation")  // IBakedModel is deprecated to encourage folks to use IFlexibleBakedModel instead
                                    // .. but IFlexibleBakedModel is of no use here...

  // handleItemState() is used to create a suitable IBakedModel based on the itemstack information.
  //  Typically, this will extract NBT information from the itemstack and customise the model based on that.
  // I think it is ok to just modify this instance instead of creating a new instance, because the IBakedModel
  //   isn't stored or cached and is discarded after rendering.  Haven't run into any problems yet.
  @Override
  public IBakedModel handleItemState(ItemStack stack) {
    material = new int[]{0, 0, 0};
    if (stack != null) {
    	RPGBase item = (RPGBase) stack.getItem();
      if(stack.getTagCompound() !=  null){
    	  for(int i = 0; i < 3; i++){
    		  material[i] = item.getMaterial(stack, i, true);
    	  }
      }
    }
    return this;
  }

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

  // for the difference between face quads and general quads, see here
  //  http://minecraft.gamepedia.com/Block_models#Item_models
  @Override
  public List getFaceQuads(EnumFacing enumFacing) {
    return baseSwordModel.getFaceQuads(enumFacing);
  }

  // during handleItemState(), we stored the number of chess pieces in a member variable.
  // now, we use that stored information to add extra BakedQuads to the list of Quads to be rendered.
  @Override
  public List getGeneralQuads() {
//	    Item itemBlockSimple = GameRegistry.findItem("minecraftbyexample", "mbe01_block_simple");       // code for testing.. renders a cube with numbered sides
//	    ItemStack itemStack = new ItemStack(itemBlockSimple);
//	    IBakedModel baseCube = Minecraft.getMinecraft().getRenderItem().getItemModelMesher().getItemModel(itemStack);
//	    List<BakedQuad> combinedQuadsList = new ArrayList();

    List<BakedQuad> combinedQuadsList = new ArrayList(baseSwordModel.getGeneralQuads());
    combinedQuadsList.addAll(getPartsForSword());
    return combinedQuadsList;
//	    FaceBakery.makeBakedQuad() can be useful for generating quads
  }

  // not needed for items, but hey
  @Override
  public boolean isAmbientOcclusion() {
    return baseSwordModel.isAmbientOcclusion();
  }

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

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

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

  public List<BakedQuad> getPartsForSword(){
	  IBakedModel blade = event.modelManager.getModel(ItemRPGBladeModels.getInstance().getModel(material[0]));
	  IBakedModel guard = event.modelManager.getModel(ItemRPGGuardModels.getInstance().getModel(material[1]));
	  IBakedModel hilt = event.modelManager.getModel(ItemRPGHiltModels.getInstance().getModel(material[2]));
	  List<BakedQuad> quads = new ArrayList<BakedQuad>(blade.getGeneralQuads());
	  quads.addAll(guard.getGeneralQuads());
	  quads.addAll(hilt.getGeneralQuads());
	  return quads;
  }


  private IBakedModel baseSwordModel;
  private int[] material;
  private ModelBakeEvent event;

}

 

 

Client Proxy:

 

package com.apmods.rpg.proxy;

import net.minecraft.client.Minecraft;
import net.minecraft.client.resources.model.ModelBakery;
import net.minecraft.client.resources.model.ModelResourceLocation;
import net.minecraft.item.Item;
import net.minecraftforge.common.MinecraftForge;

import com.apmods.rpg.gui.GuiHealthBar;
import com.apmods.rpg.item.ItemManager;
import com.apmods.rpg.main.RPG;

public class ClientProxy extends CommonProxy{

public void registerRenderers(){

}

public void init(){
	regTex(ItemManager.rpgSword, "rpgSword");
	regTex(ItemManager.blade, "blade");
	regTex(ItemManager.guard, "guard");
	regTex(ItemManager.hilt, "hilt");
}

public void preInit(){
	ModelBakery.addVariantName(ItemManager.blade, this.getNameOfBlade(0), this.getNameOfBlade(1), this.getNameOfBlade(2), this.getNameOfBlade(3), this.getNameOfBlade(4));
	ModelBakery.addVariantName(ItemManager.guard, this.getNameOfGuard(0), this.getNameOfGuard(1), this.getNameOfGuard(2), this.getNameOfGuard(3), this.getNameOfGuard(4));
	ModelBakery.addVariantName(ItemManager.hilt, this.getNameOfHilt(0), this.getNameOfHilt(1), this.getNameOfHilt(2), this.getNameOfHilt(3));
}

public void registerHandlers(){

}

public void postInit() {
	MinecraftForge.EVENT_BUS.register(new GuiHealthBar(Minecraft.getMinecraft()));

}

public void regTex(Item item, String name){
    	ModelResourceLocation itemModelResourceLocation = new ModelResourceLocation(RPG.MODID + ":" + name, "inventory");
        final int DEFAULT_ITEM_SUBTYPE = 0;
        Minecraft.getMinecraft().getRenderItem().getItemModelMesher().register(item, DEFAULT_ITEM_SUBTYPE, itemModelResourceLocation);
    }

public String getNameOfBlade(int i){
	String[] s = new String[]{"bronze", "silver", "gold", "platinum", "acutium"};
	return RPG.MODID + ":blade_" + s[i];
}

public String getNameOfGuard(int i){
	String[] s = new String[]{"bronze", "silver", "gold", "platinum", "acutium"};
	return RPG.MODID + ":guard_" + s[i];
}

public String getNameOfHilt(int i){
	String[] s = new String[]{"bone", "rubber", "leather", "elf"};
	return RPG.MODID + ":hilt_" + s[i];
}


}

 

 

Model Classes (Blade for example):

 

package com.apmods.rpg.item.models;

import java.util.ArrayList;

import com.apmods.rpg.main.RPG;

import net.minecraft.client.resources.model.ModelResourceLocation;

public class ItemRPGBladeModels{
private static ItemRPGBladeModels instance;
  private ArrayList<ModelResourceLocation> models = new ArrayList<ModelResourceLocation>();
  
  public static ItemRPGBladeModels getInstance(){
	  if(instance == null){
		  instance = new ItemRPGBladeModels();
	  }
	  return instance;
  }
  
  public ModelResourceLocation getModel(int modelIndex) {
	    return models.get(modelIndex);
  }
  
  public void createModels(){
	  String[] materials = new String[]{"bronze", "silver", "gold", "platinum", "acutium"};
	  for(String s : materials){
		  models.add(new ModelResourceLocation(RPG.MODID + ":blade_" + s, "inventory"));
	  }
  }
  
  public ItemRPGBladeModels(){
	  this.createModels();
  }
  
}

 

 

ModelBakeHandler:

 

package com.apmods.rpg.handler;

import com.apmods.rpg.item.models.ItemRPGHiltModels;

import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.resources.model.IBakedModel;
import net.minecraftforge.client.event.ModelBakeEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;

public class ModelBakeHandler {
@SubscribeEvent
public void modelBakeEvent(ModelBakeEvent event){
	// Find the existing mapping for ChessboardSmartItemModel - we added it in StartupClientOnly.initClientOnly(), which
    //   caused it to be loaded from resources (model/items/mbe15_item_chessboard.json) just like an ordinary item
    // Replace the mapping with our ISmartBlockModel, using the existing mapped model as the base for the smart model.
    Object object =  event.modelRegistry.getObject(RPGSwordSmartModel.modelResourceLocation);
    if (object instanceof IBakedModel) {
    	IBakedModel existingModel = (IBakedModel)object;
    	IBakedModel model = (IBakedModel) event.modelRegistry.getObject(ItemRPGHiltModels.getInstance().getModel(0)); 
    	TextureAtlasSprite sprite = model.getTexture();
    	RPGSwordSmartModel customModel = new RPGSwordSmartModel(event);
    	event.modelRegistry.putObject(RPGSwordSmartModel.modelResourceLocation, customModel);
    }
}
}

 

Creator of the MyFit, MagiCraft, Tesseract gun, and Papa's Wingeria mod.

Posted

An easy way of doing this - make two models - one the blade, the other the handle. Create a class implementing ISmartItemModel containg two IBakedModel fields and initialize them in the constructor. In every method not including getFaceQuads(), getGeneralQuads(), and handleItemState(), return this.FIRSTBAKEDMODELFIELDNAME.similarMethodName(). In your getFace / getGeneral Quads methods, you should create an array of quads for the first bakedmodel (sword blade) and the secoond bakedmodel (sword handle) and combine them - finally, return them in that method.

 

Here is a useful example (Sorry for the crazy indentations, I tried to fix most):

public class SmartSwordModel implements ISmartItemModel
{

private final IBakedModel blade;
        private final IBakedModel handle;

public SmartItemModel(IBakedModel blade, IBakedModel handle)
{
	this.blade = blade;
                this.handle = handle;
}

@Override
public List getFaceQuads(EnumFacing enumFacing) 
{
                List<BakedQuad> bladeQuads= new ArrayList<BakedQuad>(this.blade.getFaceQuads(enumFacing));                         List<BakedQuad> handleQuads = new ArrayList<BakedQuad>(this.handle.getFaceQuads(enumFacing));
	return //Combine the two quad arraylists and return as one; make sure your models are in the correct pos
}

@Override
public List getGeneralQuads() 
{
                List<BakedQuad> bladeQuads= new ArrayList<BakedQuad>(this.blade.getGeneralQuads());
                List<BakedQuad> handleQuads= new ArrayList<BakedQuad>(this.handle.getGeneralQuads());
	return //Combine the two quad arraylists and return as one; make sure your models are in the correct pos
}

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

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

@Override
public boolean isBuiltInRenderer() 
{
	return this.blade.isBuiltInRenderer();
}

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

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

@Override
public IBakedModel handleItemState(ItemStack stack) 
{		
	return this; // Return "this" - this is an instanceof IBakedModel - you can return different models here based           //on ItemStack information such as NBT
}

}

Development of Plugins [2012 - 2014] Development of Mods [2012 - Current]

Posted

How would I know which models to put in the constructor if I can't get nbt in the event handler?

Creator of the MyFit, MagiCraft, Tesseract gun, and Papa's Wingeria mod.

Posted

Lol, you don't.

 

What you literally want is to bake some amount of models somehow (can be done by registering variants to some item, or simply on your own).

Then in ISmartItemModel you just get those models from registry.

 

EverythingGames just gave example, but it is good only as example.

1.7.10 is no longer supported by forge, you are on your own.

Posted

I'm confused as to a) where do I retrieve the correct models based on nbt? B) how do I make my own bakedmodels for the different nbt values? C) do I use lista.addAll(listb) to combine lists?

Creator of the MyFit, MagiCraft, Tesseract gun, and Papa's Wingeria mod.

Posted

IBakedModel is a combination of BakedQuads which can be obtained using getGeneralQuads().

You can collect (from model registry) any number of IBakedModels and get their general quads and then inside your smart model - return them all in one list (list returned by getGeneralQuads()). Note that you should not manipulate list directly as it is mutable! You need to make new list and addAll from all other IBakedModel you want.

 

To actually get IBakedModel instances into getGeneralQuads() method you can use handleItemState() in which you will read Stack's NBT and retrieve, for example via names, models from model registry and put them in some local field which you can later use in getGeneralQuads().

 

ModelManager modelManager = Minecraft.getMinecraft().getRenderItem().getItemModelMesher().getModelManager();

ModelResourceLocation resource = new ModelResourceLocation(InitUtil.ModID + ":some_resource, "inventory");

IBakedModel ibm = modelManager.getModel(resource);

 

Note that for ModelManager to actually return an IBakedModel - it needs to be there, read: It need to be "baked" 1st.

For model to be baked and put in registry you can simply make some item register variants with different textures - for each variant vanilla will generate model which can be later obtained.

I don't remember how to bake model on your own - I recommend looking into model bakery (look into places where json is read and bakes models).

I remmeber that you might wanna use ModelBakeEvent to add your own stuff to be baked.

1.7.10 is no longer supported by forge, you are on your own.

Posted

Basically, getGeneralQuads() returns the list of desired model quads - I don't see the need to create them manually unless your doing something tedious. Rather, I would create the two models I want, position the first .JSON model in-game, then the second over top of it in place - should be very easy. For baking your models, don't perform that yourself, subscribe to the ModelBakeEvent and add your IBakedModels to the ModelRegistry and then put the wrapped model object (implementing ISmartIteModel, for ex.) in the registry replacing the old .JSON model. If you setup your wrapper class to hold final instance fields initialized in the construction of the object, you can pass whatever models you like to be combined when instantiating a new wrapper object (if you have the wrapper class setup correctly to do that, of course). Hope that helps a bit!

Development of Plugins [2012 - 2014] Development of Mods [2012 - Current]

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



×
×
  • Create New...

Important Information

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