minecraft-src/net/minecraft/client/renderer/item/SelectItemModel.java
2025-07-04 03:15:13 +03:00

118 lines
4.5 KiB
Java

package net.minecraft.client.renderer.item;
import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import java.util.List;
import java.util.Optional;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.item.properties.select.SelectItemModelProperties;
import net.minecraft.client.renderer.item.properties.select.SelectItemModelProperty;
import net.minecraft.client.resources.model.ResolvableModel;
import net.minecraft.util.ExtraCodecs;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemDisplayContext;
import net.minecraft.world.item.ItemStack;
import org.jetbrains.annotations.Nullable;
@Environment(EnvType.CLIENT)
public class SelectItemModel<T> implements ItemModel {
private final SelectItemModelProperty<T> property;
private final Object2ObjectMap<T, ItemModel> models;
public SelectItemModel(SelectItemModelProperty<T> property, Object2ObjectMap<T, ItemModel> models) {
this.property = property;
this.models = models;
}
@Override
public void update(
ItemStackRenderState renderState,
ItemStack stack,
ItemModelResolver itemModelResolver,
ItemDisplayContext displayContext,
@Nullable ClientLevel level,
@Nullable LivingEntity entity,
int seed
) {
T object = this.property.get(stack, level, entity, seed, displayContext);
ItemModel itemModel = this.models.get(object);
if (itemModel != null) {
itemModel.update(renderState, stack, itemModelResolver, displayContext, level, entity, seed);
}
}
@Environment(EnvType.CLIENT)
public record SwitchCase<T>(List<T> values, ItemModel.Unbaked model) {
public static <T> Codec<SelectItemModel.SwitchCase<T>> codec(Codec<T> codec) {
return RecordCodecBuilder.create(
instance -> instance.group(
ExtraCodecs.nonEmptyList(ExtraCodecs.compactListCodec(codec)).fieldOf("when").forGetter(SelectItemModel.SwitchCase::values),
ItemModels.CODEC.fieldOf("model").forGetter(SelectItemModel.SwitchCase::model)
)
.apply(instance, SelectItemModel.SwitchCase::new)
);
}
}
@Environment(EnvType.CLIENT)
public record Unbaked(SelectItemModel.UnbakedSwitch<?, ?> unbakedSwitch, Optional<ItemModel.Unbaked> fallback) implements ItemModel.Unbaked {
public static final MapCodec<SelectItemModel.Unbaked> MAP_CODEC = RecordCodecBuilder.mapCodec(
instance -> instance.group(
SelectItemModel.UnbakedSwitch.MAP_CODEC.forGetter(SelectItemModel.Unbaked::unbakedSwitch),
ItemModels.CODEC.optionalFieldOf("fallback").forGetter(SelectItemModel.Unbaked::fallback)
)
.apply(instance, SelectItemModel.Unbaked::new)
);
@Override
public MapCodec<SelectItemModel.Unbaked> type() {
return MAP_CODEC;
}
@Override
public ItemModel bake(ItemModel.BakingContext context) {
ItemModel itemModel = (ItemModel)this.fallback.map(unbaked -> unbaked.bake(context)).orElse(context.missingItemModel());
return this.unbakedSwitch.bake(context, itemModel);
}
@Override
public void resolveDependencies(ResolvableModel.Resolver resolver) {
this.unbakedSwitch.resolveDependencies(resolver);
this.fallback.ifPresent(unbaked -> unbaked.resolveDependencies(resolver));
}
}
@Environment(EnvType.CLIENT)
public record UnbakedSwitch<P extends SelectItemModelProperty<T>, T>(P property, List<SelectItemModel.SwitchCase<T>> cases) {
public static final MapCodec<SelectItemModel.UnbakedSwitch<?, ?>> MAP_CODEC = SelectItemModelProperties.CODEC
.dispatchMap("property", unbakedSwitch -> unbakedSwitch.property().type(), SelectItemModelProperty.Type::switchCodec);
public ItemModel bake(ItemModel.BakingContext bakingContext, ItemModel model) {
Object2ObjectMap<T, ItemModel> object2ObjectMap = new Object2ObjectOpenHashMap<>();
for (SelectItemModel.SwitchCase<T> switchCase : this.cases) {
ItemModel.Unbaked unbaked = switchCase.model;
ItemModel itemModel = unbaked.bake(bakingContext);
for (T object : switchCase.values) {
object2ObjectMap.put(object, itemModel);
}
}
object2ObjectMap.defaultReturnValue(model);
return new SelectItemModel<>(this.property, object2ObjectMap);
}
public void resolveDependencies(ResolvableModel.Resolver resolver) {
for (SelectItemModel.SwitchCase<?> switchCase : this.cases) {
switchCase.model.resolveDependencies(resolver);
}
}
}
}