diff --git a/src/main/java/net/minecraftforge/client/model/ModelLoader.java b/src/main/java/net/minecraftforge/client/model/ModelLoader.java index d9bdcb6fe22..751d7d732a9 100644 --- a/src/main/java/net/minecraftforge/client/model/ModelLoader.java +++ b/src/main/java/net/minecraftforge/client/model/ModelLoader.java @@ -701,14 +701,17 @@ public IModel uvlock(boolean value) private static final class WeightedRandomModel implements IModel { private final List variants; - private final List locations = new ArrayList<>(); - private final Set textures = Sets.newHashSet(); - private final List models = new ArrayList<>(); + private final List locations; + private final Set textures; + private final List models; private final IModelState defaultState; public WeightedRandomModel(ResourceLocation parent, VariantList variants) throws Exception { this.variants = variants.getVariantList(); + this.locations = new ArrayList<>(); + this.textures = Sets.newHashSet(); + this.models = new ArrayList<>(); ImmutableList.Builder> builder = ImmutableList.builder(); for (Variant v : this.variants) { @@ -754,6 +757,15 @@ public WeightedRandomModel(ResourceLocation parent, VariantList variants) throws defaultState = new MultiModelState(builder.build()); } + private WeightedRandomModel(List variants, List locations, Set textures, List models, IModelState defaultState) + { + this.variants = variants; + this.locations = locations; + this.textures = textures; + this.models = models; + this.defaultState = defaultState; + } + @Override public Collection getDependencies() { @@ -792,6 +804,28 @@ public IModelState getDefaultState() { return defaultState; } + + @Override + public WeightedRandomModel retexture(ImmutableMap textures) + { + if (textures.isEmpty()) + return this; + + // rebuild the texture list taking into account new textures + Set modelTextures = Sets.newHashSet(); + // also recreate the MultiModelState so IModelState data is properly applied to the retextured model + ImmutableList.Builder> builder = ImmutableList.builder(); + List retexturedModels = Lists.newArrayList(); + for(int i = 0; i < this.variants.size(); i++) + { + IModel retextured = this.models.get(i).retexture(textures); + modelTextures.addAll(retextured.getTextures()); + retexturedModels.add(retextured); + builder.add(Pair.of(retextured, this.variants.get(i).getState())); + } + + return new WeightedRandomModel(this.variants, this.locations, modelTextures, retexturedModels, new MultiModelState(builder.build())); + } } protected IModel getMissingModel() @@ -1243,6 +1277,13 @@ public MultipartModel(ResourceLocation location, Multipart multipart) throws Exc partModels = builder.build(); } + private MultipartModel(ResourceLocation location, Multipart multipart, ImmutableMap partModels) + { + this.location = location; + this.multipart = multipart; + this.partModels = partModels; + } + // FIXME: represent selectors as dependencies? // FIXME @Override @@ -1258,5 +1299,20 @@ public IBakedModel bake(IModelState state, VertexFormat format, Function textures) + { + if (textures.isEmpty()) + return this; + + ImmutableMap.Builder builder = ImmutableMap.builder(); + for (Entry partModel : this.partModels.entrySet()) + { + builder.put(partModel.getKey(), partModel.getValue().retexture(textures)); + } + + return new MultipartModel(location, multipart, builder.build()); + } } } diff --git a/src/test/java/net/minecraftforge/debug/BlockstateRetextureTest.java b/src/test/java/net/minecraftforge/debug/BlockstateRetextureTest.java new file mode 100644 index 00000000000..f26a490d315 --- /dev/null +++ b/src/test/java/net/minecraftforge/debug/BlockstateRetextureTest.java @@ -0,0 +1,61 @@ +package net.minecraftforge.debug; + +import java.util.function.Function; + +import com.google.common.collect.ImmutableMap; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.block.model.IBakedModel; +import net.minecraft.client.renderer.block.model.ModelResourceLocation; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.client.event.ModelBakeEvent; +import net.minecraftforge.client.model.IModel; +import net.minecraftforge.client.model.ModelLoaderRegistry; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.relauncher.Side; + +@Mod(modid = BlockstateRetextureTest.MODID, name = "BlockstateRetextureTest", version = BlockstateRetextureTest.VERSION, acceptableRemoteVersions = "*") +public class BlockstateRetextureTest +{ + public static final String MODID = "forge_blockstate_retexture_test"; + public static final String VERSION = "1.0"; + static final boolean ENABLED = false; + + private static ResourceLocation fenceName = new ResourceLocation("minecraft", "fence"); + private static ModelResourceLocation fenceLocation = new ModelResourceLocation(fenceName, "east=true,north=false,south=false,west=true"); + private static ResourceLocation stoneName = new ResourceLocation("minecraft", "stone"); + private static ModelResourceLocation stoneLocation = new ModelResourceLocation(stoneName, "normal"); + + private static Function textureGetter = location -> + { + assert location != null; + return Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite(location.toString()); + }; + + @Mod.EventBusSubscriber(modid = MODID, value = Side.CLIENT) + public static class ClientEvents + { + @SubscribeEvent + public static void onModelBakeEvent(ModelBakeEvent event) + { + if (!ENABLED) + { + return; + } + + IModel fence = ModelLoaderRegistry.getModelOrLogError(fenceLocation, "Error loading fence model"); + IModel stone = ModelLoaderRegistry.getModelOrLogError(stoneLocation, "Error loading planks model"); + IModel retexturedFence = fence.retexture(ImmutableMap.of("texture", "blocks/log_oak")); + IModel retexturedStone = stone.retexture(ImmutableMap.of("all", "blocks/diamond_block")); + + IBakedModel fenceResult = retexturedFence.bake(fence.getDefaultState(), DefaultVertexFormats.BLOCK, textureGetter); + IBakedModel stoneResult = retexturedStone.bake(stone.getDefaultState(), DefaultVertexFormats.BLOCK, textureGetter); + + event.getModelRegistry().putObject(fenceLocation, fenceResult); + event.getModelRegistry().putObject(stoneLocation, stoneResult); + } + } +}