176 lines
9.5 KiB
Java
176 lines
9.5 KiB
Java
/*
|
|
* Decompiled with CFR 0.152.
|
|
*
|
|
* Could not load the following classes:
|
|
* com.mojang.logging.LogUtils
|
|
* org.slf4j.Logger
|
|
*/
|
|
package net.minecraft.client.resources.model;
|
|
|
|
import com.mojang.logging.LogUtils;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.concurrent.CompletableFuture;
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
import java.util.concurrent.Executor;
|
|
import java.util.function.Function;
|
|
import java.util.stream.Collectors;
|
|
import java.util.stream.IntStream;
|
|
import net.minecraft.client.model.geom.EntityModelSet;
|
|
import net.minecraft.client.renderer.PlayerSkinRenderCache;
|
|
import net.minecraft.client.renderer.Sheets;
|
|
import net.minecraft.client.renderer.block.model.BlockStateModel;
|
|
import net.minecraft.client.renderer.block.model.ItemTransforms;
|
|
import net.minecraft.client.renderer.block.model.SimpleModelWrapper;
|
|
import net.minecraft.client.renderer.block.model.SingleVariant;
|
|
import net.minecraft.client.renderer.block.model.TextureSlots;
|
|
import net.minecraft.client.renderer.item.ClientItem;
|
|
import net.minecraft.client.renderer.item.ItemModel;
|
|
import net.minecraft.client.renderer.item.MissingItemModel;
|
|
import net.minecraft.client.renderer.item.ModelRenderProperties;
|
|
import net.minecraft.client.renderer.rendertype.RenderType;
|
|
import net.minecraft.client.renderer.rendertype.RenderTypes;
|
|
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
|
import net.minecraft.client.resources.model.BlockModelRotation;
|
|
import net.minecraft.client.resources.model.Material;
|
|
import net.minecraft.client.resources.model.MaterialSet;
|
|
import net.minecraft.client.resources.model.ModelBaker;
|
|
import net.minecraft.client.resources.model.QuadCollection;
|
|
import net.minecraft.client.resources.model.ResolvedModel;
|
|
import net.minecraft.client.resources.model.SpriteGetter;
|
|
import net.minecraft.resources.Identifier;
|
|
import net.minecraft.util.thread.ParallelMapTransform;
|
|
import net.minecraft.world.level.block.state.BlockState;
|
|
import org.slf4j.Logger;
|
|
|
|
public class ModelBakery {
|
|
public static final Material FIRE_0 = Sheets.BLOCKS_MAPPER.defaultNamespaceApply("fire_0");
|
|
public static final Material FIRE_1 = Sheets.BLOCKS_MAPPER.defaultNamespaceApply("fire_1");
|
|
public static final Material LAVA_FLOW = Sheets.BLOCKS_MAPPER.defaultNamespaceApply("lava_flow");
|
|
public static final Material WATER_FLOW = Sheets.BLOCKS_MAPPER.defaultNamespaceApply("water_flow");
|
|
public static final Material WATER_OVERLAY = Sheets.BLOCKS_MAPPER.defaultNamespaceApply("water_overlay");
|
|
public static final Material BANNER_BASE = new Material(Sheets.BANNER_SHEET, Identifier.withDefaultNamespace("entity/banner_base"));
|
|
public static final Material SHIELD_BASE = new Material(Sheets.SHIELD_SHEET, Identifier.withDefaultNamespace("entity/shield_base"));
|
|
public static final Material NO_PATTERN_SHIELD = new Material(Sheets.SHIELD_SHEET, Identifier.withDefaultNamespace("entity/shield_base_nopattern"));
|
|
public static final int DESTROY_STAGE_COUNT = 10;
|
|
public static final List<Identifier> DESTROY_STAGES = IntStream.range(0, 10).mapToObj(i -> Identifier.withDefaultNamespace("block/destroy_stage_" + i)).collect(Collectors.toList());
|
|
public static final List<Identifier> BREAKING_LOCATIONS = DESTROY_STAGES.stream().map(location -> location.withPath(path -> "textures/" + path + ".png")).collect(Collectors.toList());
|
|
public static final List<RenderType> DESTROY_TYPES = BREAKING_LOCATIONS.stream().map(RenderTypes::crumbling).collect(Collectors.toList());
|
|
private static final Logger LOGGER = LogUtils.getLogger();
|
|
private final EntityModelSet entityModelSet;
|
|
private final MaterialSet materials;
|
|
private final PlayerSkinRenderCache playerSkinRenderCache;
|
|
private final Map<BlockState, BlockStateModel.UnbakedRoot> unbakedBlockStateModels;
|
|
private final Map<Identifier, ClientItem> clientInfos;
|
|
private final Map<Identifier, ResolvedModel> resolvedModels;
|
|
private final ResolvedModel missingModel;
|
|
|
|
public ModelBakery(EntityModelSet entityModelSet, MaterialSet materials, PlayerSkinRenderCache playerSkinRenderCache, Map<BlockState, BlockStateModel.UnbakedRoot> unbakedBlockStateModels, Map<Identifier, ClientItem> clientInfos, Map<Identifier, ResolvedModel> resolvedModels, ResolvedModel missingModel) {
|
|
this.entityModelSet = entityModelSet;
|
|
this.materials = materials;
|
|
this.playerSkinRenderCache = playerSkinRenderCache;
|
|
this.unbakedBlockStateModels = unbakedBlockStateModels;
|
|
this.clientInfos = clientInfos;
|
|
this.resolvedModels = resolvedModels;
|
|
this.missingModel = missingModel;
|
|
}
|
|
|
|
public CompletableFuture<BakingResult> bakeModels(SpriteGetter sprites, Executor taskExecutor) {
|
|
MissingModels missingModels = MissingModels.bake(this.missingModel, sprites);
|
|
ModelBakerImpl baker = new ModelBakerImpl(sprites);
|
|
CompletableFuture<Map<BlockState, BlockStateModel>> bakedBlockStateModelFuture = ParallelMapTransform.schedule(this.unbakedBlockStateModels, (blockState, model) -> {
|
|
try {
|
|
return model.bake((BlockState)blockState, baker);
|
|
}
|
|
catch (Exception e) {
|
|
LOGGER.warn("Unable to bake model: '{}': {}", blockState, (Object)e);
|
|
return null;
|
|
}
|
|
}, taskExecutor);
|
|
CompletableFuture<Map<Identifier, ItemModel>> bakedItemStackModelFuture = ParallelMapTransform.schedule(this.clientInfos, (location, clientInfo) -> {
|
|
try {
|
|
return clientInfo.model().bake(new ItemModel.BakingContext(baker, this.entityModelSet, this.materials, this.playerSkinRenderCache, missingModels.item, clientInfo.registrySwapper()));
|
|
}
|
|
catch (Exception e) {
|
|
LOGGER.warn("Unable to bake item model: '{}'", location, (Object)e);
|
|
return null;
|
|
}
|
|
}, taskExecutor);
|
|
HashMap itemStackModelProperties = new HashMap(this.clientInfos.size());
|
|
this.clientInfos.forEach((id, clientInfo) -> {
|
|
ClientItem.Properties properties = clientInfo.properties();
|
|
if (!properties.equals(ClientItem.Properties.DEFAULT)) {
|
|
itemStackModelProperties.put(id, properties);
|
|
}
|
|
});
|
|
return bakedBlockStateModelFuture.thenCombine(bakedItemStackModelFuture, (bakedBlockStateModels, bakedItemStateModels) -> new BakingResult(missingModels, (Map<BlockState, BlockStateModel>)bakedBlockStateModels, (Map<Identifier, ItemModel>)bakedItemStateModels, itemStackModelProperties));
|
|
}
|
|
|
|
public record MissingModels(BlockStateModel block, ItemModel item) {
|
|
public static MissingModels bake(ResolvedModel unbaked, final SpriteGetter sprites) {
|
|
ModelBaker missingModelBakery = new ModelBaker(){
|
|
|
|
@Override
|
|
public ResolvedModel getModel(Identifier location) {
|
|
throw new IllegalStateException("Missing model can't have dependencies, but asked for " + String.valueOf(location));
|
|
}
|
|
|
|
@Override
|
|
public <T> T compute(ModelBaker.SharedOperationKey<T> key) {
|
|
return key.compute(this);
|
|
}
|
|
|
|
@Override
|
|
public SpriteGetter sprites() {
|
|
return sprites;
|
|
}
|
|
};
|
|
TextureSlots textureSlots = unbaked.getTopTextureSlots();
|
|
boolean hasAmbientOcclusion = unbaked.getTopAmbientOcclusion();
|
|
boolean usesBlockLight = unbaked.getTopGuiLight().lightLikeBlock();
|
|
ItemTransforms transforms = unbaked.getTopTransforms();
|
|
QuadCollection geometry = unbaked.bakeTopGeometry(textureSlots, missingModelBakery, BlockModelRotation.IDENTITY);
|
|
TextureAtlasSprite particleSprite = unbaked.resolveParticleSprite(textureSlots, missingModelBakery);
|
|
SingleVariant bakedBlockModel = new SingleVariant(new SimpleModelWrapper(geometry, hasAmbientOcclusion, particleSprite));
|
|
MissingItemModel bakedItemModel = new MissingItemModel(geometry.getAll(), new ModelRenderProperties(usesBlockLight, particleSprite, transforms));
|
|
return new MissingModels(bakedBlockModel, bakedItemModel);
|
|
}
|
|
}
|
|
|
|
private class ModelBakerImpl
|
|
implements ModelBaker {
|
|
private final SpriteGetter sprites;
|
|
private final Map<ModelBaker.SharedOperationKey<Object>, Object> operationCache = new ConcurrentHashMap<ModelBaker.SharedOperationKey<Object>, Object>();
|
|
private final Function<ModelBaker.SharedOperationKey<Object>, Object> cacheComputeFunction = k -> k.compute(this);
|
|
|
|
private ModelBakerImpl(SpriteGetter textures) {
|
|
this.sprites = textures;
|
|
}
|
|
|
|
@Override
|
|
public SpriteGetter sprites() {
|
|
return this.sprites;
|
|
}
|
|
|
|
@Override
|
|
public ResolvedModel getModel(Identifier location) {
|
|
ResolvedModel result = ModelBakery.this.resolvedModels.get(location);
|
|
if (result == null) {
|
|
LOGGER.warn("Requested a model that was not discovered previously: {}", (Object)location);
|
|
return ModelBakery.this.missingModel;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
@Override
|
|
public <T> T compute(ModelBaker.SharedOperationKey<T> key) {
|
|
return (T)this.operationCache.computeIfAbsent(key, this.cacheComputeFunction);
|
|
}
|
|
}
|
|
|
|
public record BakingResult(MissingModels missingModels, Map<BlockState, BlockStateModel> blockStateModels, Map<Identifier, ItemModel> itemStackModels, Map<Identifier, ClientItem.Properties> itemProperties) {
|
|
}
|
|
}
|
|
|