package gory_moon.moarsigns.client; import gory_moon.moarsigns.api.SignRegistry; import gory_moon.moarsigns.blocks.BlockMoarSignStanding; import gory_moon.moarsigns.blocks.BlockMoarSignWall; import gory_moon.moarsigns.blocks.ModBlocks; import gory_moon.moarsigns.integration.IntegrationHandler; import gory_moon.moarsigns.items.ModItems; import gory_moon.moarsigns.items.NuggetRegistry; import gory_moon.moarsigns.items.VariantItem; import gory_moon.moarsigns.lib.Reference; import gory_moon.moarsigns.util.Utils; import net.minecraft.block.Block; import net.minecraft.block.properties.IProperty; import net.minecraft.block.state.IBlockState; import net.minecraft.client.renderer.ItemMeshDefinition; import net.minecraft.client.renderer.block.model.ModelBakery; import net.minecraft.client.renderer.block.model.ModelResourceLocation; import net.minecraft.client.renderer.block.statemap.StateMap; import net.minecraft.client.renderer.block.statemap.StateMapperBase; import net.minecraft.item.Item; import net.minecraftforge.client.event.ModelRegistryEvent; import net.minecraftforge.client.model.ModelLoader; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import java.util.ArrayList; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.function.ToIntFunction; @SideOnly(Side.CLIENT) @Mod.EventBusSubscriber(Side.CLIENT) public class ModModelManager { public static final ModModelManager INSTANCE = new ModModelManager(); private final Set<Item> itemsRegistered = new HashSet<>(); public ModModelManager() { } @SubscribeEvent public static void registerAllModels(ModelRegistryEvent event) { new IntegrationHandler().preSetupSigns(); INSTANCE.registerBlockModels(); INSTANCE.registerItemModels(); SignRegistry.clear(); } private void registerBlockModels() { ModelLoader.setCustomStateMapper(ModBlocks.SIGN_STANDING_WOOD, (new StateMap.Builder()).ignore(new IProperty[]{BlockMoarSignStanding.ROTATION}).build()); ModelLoader.setCustomStateMapper(ModBlocks.SIGN_STANDING_METAL, (new StateMap.Builder()).ignore(new IProperty[]{BlockMoarSignStanding.ROTATION}).build()); ModelLoader.setCustomStateMapper(ModBlocks.SIGN_WALL_WOOD, (new StateMap.Builder()).ignore(new IProperty[]{BlockMoarSignWall.ROTATION, BlockMoarSignWall.FACING}).build()); ModelLoader.setCustomStateMapper(ModBlocks.SIGN_WALL_METAL, (new StateMap.Builder()).ignore(new IProperty[]{BlockMoarSignWall.ROTATION, BlockMoarSignWall.FACING}).build()); ModBlocks.RegistrationHandler.ITEM_BLOCKS.stream().filter(item -> !itemsRegistered.contains(item)).forEach(this::registerItemModel); } /** * Register this mod's {@link Item} models. */ private void registerItemModels() { // Register items with custom model names first ArrayList<String> signs = SignRegistry.getTextureLocations(false); for (String s : signs) registerItemModel(ModItems.SIGN, getModel(s)); //Overrides the ItemMeshDefenition wit a custom one registerItemModel(ModItems.SIGN, new MoarSignsItemMeshDefenition()); for (Map.Entry<String, NuggetRegistry.NuggetInfo> entry : Utils.entriesSortedByValues(NuggetRegistry.getNuggets())) registerItemModelForMeta(ModItems.NUGGET, entry.getValue().id, getModel("nuggets/" + entry.getValue().modId + entry.getValue().unlocName)); registerVariantItems(ModItems.SIGN_TOOLBOX, "mode"); // Then register items with default model names ModItems.RegistrationHandler.ITEMS.stream().filter(item -> !itemsRegistered.contains(item)).forEach(this::registerItemModel); } /** * A {@link StateMapperBase} used to create property strings. */ private final StateMapperBase propertyStringMapper = new StateMapperBase() { @Override protected ModelResourceLocation getModelResourceLocation(IBlockState state) { return new ModelResourceLocation("minecraft:air"); } }; /** * Register a single model for the {@link Block}'s {@link Item}. * <p> * Uses the registry name as the domain/path and the {@link IBlockState} as the variant. * * @param state The state to use as the variant */ private void registerBlockItemModel(IBlockState state) { final Block block = state.getBlock(); final Item item = Item.getItemFromBlock(block); if (item != null) { registerItemModel(item, new ModelResourceLocation(block.getRegistryName(), propertyStringMapper.getPropertyString(state.getProperties()))); } } /** * Register a model for a metadata value of the {@link Block}'s {@link Item}. * <p> * Uses the registry name as the domain/path and the {@link IBlockState} as the variant. * * @param state The state to use as the variant * @param metadata The item metadata to register the model for */ private void registerBlockItemModelForMeta(IBlockState state, int metadata) { final Item item = Item.getItemFromBlock(state.getBlock()); if (item != null) { registerItemModelForMeta(item, metadata, propertyStringMapper.getPropertyString(state.getProperties())); } } /** * Register a model for each metadata value of the {@link Block}'s {@link Item} corresponding to the values of an {@link IProperty}. * <p> * For each value: * <li>The domain/path is the registry name</li> * <li>The variant is {@code baseState} with the {@link IProperty} set to the value</li> * <p> * The {@code getMeta} function is used to get the metadata of each value. * * @param baseState The base state to use for the variant * @param property The property whose values should be used * @param getMeta A function to get the metadata of each value * @param <T> The value type */ private <T extends Comparable<T>> void registerVariantBlockItemModels(IBlockState baseState, IProperty<T> property, ToIntFunction<T> getMeta) { property.getAllowedValues().forEach(value -> registerBlockItemModelForMeta(baseState.withProperty(property, value), getMeta.applyAsInt(value))); } private <T extends VariantItem> void registerVariantItems(T variant, String variantName) { variant.getMetas().forEach(value -> registerItemModelForMeta(variant, value, variantName + "=" + variant.getVariant(value))); } /** * Register a single model for an {@link Item}. * <p> * Uses the registry name as the domain/path and {@code "inventory"} as the variant. * * @param item The Item */ private void registerItemModel(Item item) { registerItemModel(item, item.getRegistryName().toString()); } /** * Register a single model for an {@link Item}. * <p> * Uses {@code modelLocation} as the domain/path and {@link "inventory"} as the variant. * * @param item The Item * @param modelLocation The model location */ private void registerItemModel(Item item, String modelLocation) { final ModelResourceLocation fullModelLocation = new ModelResourceLocation(modelLocation, "inventory"); registerItemModel(item, fullModelLocation); } /** * Register a single model for an {@link Item}. * <p> * Uses {@code fullModelLocation} as the domain, path and variant. * * @param item The Item * @param fullModelLocation The full model location */ private void registerItemModel(Item item, ModelResourceLocation fullModelLocation) { ModelBakery.registerItemVariants(item, fullModelLocation); // Ensure the custom model is loaded and prevent the default model from being loaded registerItemModel(item, MeshDefinitionFix.create(stack -> fullModelLocation)); } /** * Register an {@link ItemMeshDefinition} for an {@link Item}. * * @param item The Item * @param meshDefinition The ItemMeshDefinition */ private void registerItemModel(Item item, ItemMeshDefinition meshDefinition) { itemsRegistered.add(item); ModelLoader.setCustomMeshDefinition(item, meshDefinition); } /** * Register a model for a metadata value an {@link Item}. * <p> * Uses the registry name as the domain/path and {@code variant} as the variant. * * @param item The Item * @param metadata The metadata * @param variant The variant */ private void registerItemModelForMeta(Item item, int metadata, String variant) { registerItemModelForMeta(item, metadata, new ModelResourceLocation(item.getRegistryName(), variant)); } /** * Register a model for a metadata value of an {@link Item}. * <p> * Uses {@code modelResourceLocation} as the domain, path and variant. * * @param item The Item * @param metadata The metadata * @param modelResourceLocation The full model location */ private void registerItemModelForMeta(Item item, int metadata, ModelResourceLocation modelResourceLocation) { itemsRegistered.add(item); ModelLoader.setCustomModelResourceLocation(item, metadata, modelResourceLocation); } public static ModelResourceLocation getModel(String resource) { return new ModelResourceLocation(Reference.MODID + ":" + resource, "inventory"); } }