185 lines
		
	
	
	
		
			6 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			185 lines
		
	
	
	
		
			6 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
| package net.minecraft.client.renderer.block.model;
 | |
| 
 | |
| import com.google.common.collect.Lists;
 | |
| import com.google.gson.JsonElement;
 | |
| import com.google.gson.JsonObject;
 | |
| import com.google.gson.JsonParseException;
 | |
| import com.mojang.logging.LogUtils;
 | |
| import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
 | |
| import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
 | |
| import it.unimi.dsi.fastutil.objects.Object2ObjectMaps;
 | |
| import it.unimi.dsi.fastutil.objects.ObjectIterator;
 | |
| import java.util.ArrayList;
 | |
| import java.util.HashMap;
 | |
| import java.util.List;
 | |
| import java.util.Map;
 | |
| import java.util.Map.Entry;
 | |
| import java.util.stream.Collectors;
 | |
| import net.fabricmc.api.EnvType;
 | |
| import net.fabricmc.api.Environment;
 | |
| import net.minecraft.client.resources.model.Material;
 | |
| import net.minecraft.client.resources.model.ModelDebugName;
 | |
| import net.minecraft.resources.ResourceLocation;
 | |
| import org.jetbrains.annotations.Nullable;
 | |
| import org.slf4j.Logger;
 | |
| 
 | |
| @Environment(EnvType.CLIENT)
 | |
| public class TextureSlots {
 | |
| 	public static final TextureSlots EMPTY = new TextureSlots(Map.of());
 | |
| 	private static final char REFERENCE_CHAR = '#';
 | |
| 	private final Map<String, Material> resolvedValues;
 | |
| 
 | |
| 	TextureSlots(Map<String, Material> resolvedValues) {
 | |
| 		this.resolvedValues = resolvedValues;
 | |
| 	}
 | |
| 
 | |
| 	@Nullable
 | |
| 	public Material getMaterial(String name) {
 | |
| 		if (isTextureReference(name)) {
 | |
| 			name = name.substring(1);
 | |
| 		}
 | |
| 
 | |
| 		return (Material)this.resolvedValues.get(name);
 | |
| 	}
 | |
| 
 | |
| 	private static boolean isTextureReference(String name) {
 | |
| 		return name.charAt(0) == '#';
 | |
| 	}
 | |
| 
 | |
| 	public static TextureSlots.Data parseTextureMap(JsonObject json, ResourceLocation atlas) {
 | |
| 		TextureSlots.Data.Builder builder = new TextureSlots.Data.Builder();
 | |
| 
 | |
| 		for (Entry<String, JsonElement> entry : json.entrySet()) {
 | |
| 			parseEntry(atlas, (String)entry.getKey(), ((JsonElement)entry.getValue()).getAsString(), builder);
 | |
| 		}
 | |
| 
 | |
| 		return builder.build();
 | |
| 	}
 | |
| 
 | |
| 	private static void parseEntry(ResourceLocation atlas, String name, String material, TextureSlots.Data.Builder builder) {
 | |
| 		if (isTextureReference(material)) {
 | |
| 			builder.addReference(name, material.substring(1));
 | |
| 		} else {
 | |
| 			ResourceLocation resourceLocation = ResourceLocation.tryParse(material);
 | |
| 			if (resourceLocation == null) {
 | |
| 				throw new JsonParseException(material + " is not valid resource location");
 | |
| 			}
 | |
| 
 | |
| 			builder.addTexture(name, new Material(atlas, resourceLocation));
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	@Environment(EnvType.CLIENT)
 | |
| 	public record Data(Map<String, TextureSlots.SlotContents> values) {
 | |
| 		public static final TextureSlots.Data EMPTY = new TextureSlots.Data(Map.of());
 | |
| 
 | |
| 		@Environment(EnvType.CLIENT)
 | |
| 		public static class Builder {
 | |
| 			private final Map<String, TextureSlots.SlotContents> textureMap = new HashMap();
 | |
| 
 | |
| 			public TextureSlots.Data.Builder addReference(String name, String material) {
 | |
| 				this.textureMap.put(name, new TextureSlots.Reference(material));
 | |
| 				return this;
 | |
| 			}
 | |
| 
 | |
| 			public TextureSlots.Data.Builder addTexture(String name, Material material) {
 | |
| 				this.textureMap.put(name, new TextureSlots.Value(material));
 | |
| 				return this;
 | |
| 			}
 | |
| 
 | |
| 			public TextureSlots.Data build() {
 | |
| 				return this.textureMap.isEmpty() ? TextureSlots.Data.EMPTY : new TextureSlots.Data(Map.copyOf(this.textureMap));
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	@Environment(EnvType.CLIENT)
 | |
| 	record Reference(String target) implements TextureSlots.SlotContents {
 | |
| 	}
 | |
| 
 | |
| 	@Environment(EnvType.CLIENT)
 | |
| 	public static class Resolver {
 | |
| 		private static final Logger LOGGER = LogUtils.getLogger();
 | |
| 		private final List<TextureSlots.Data> entries = new ArrayList();
 | |
| 
 | |
| 		public TextureSlots.Resolver addLast(TextureSlots.Data data) {
 | |
| 			this.entries.addLast(data);
 | |
| 			return this;
 | |
| 		}
 | |
| 
 | |
| 		public TextureSlots.Resolver addFirst(TextureSlots.Data data) {
 | |
| 			this.entries.addFirst(data);
 | |
| 			return this;
 | |
| 		}
 | |
| 
 | |
| 		public TextureSlots resolve(ModelDebugName name) {
 | |
| 			if (this.entries.isEmpty()) {
 | |
| 				return TextureSlots.EMPTY;
 | |
| 			} else {
 | |
| 				Object2ObjectMap<String, Material> object2ObjectMap = new Object2ObjectArrayMap<>();
 | |
| 				Object2ObjectMap<String, TextureSlots.Reference> object2ObjectMap2 = new Object2ObjectArrayMap<>();
 | |
| 
 | |
| 				for (TextureSlots.Data data : Lists.reverse(this.entries)) {
 | |
| 					data.values.forEach((string, slotContents) -> {
 | |
| 						switch (slotContents) {
 | |
| 							case TextureSlots.Value value:
 | |
| 								object2ObjectMap2.remove(string);
 | |
| 								object2ObjectMap.put(string, value.material());
 | |
| 								break;
 | |
| 							case TextureSlots.Reference reference:
 | |
| 								object2ObjectMap.remove(string);
 | |
| 								object2ObjectMap2.put(string, reference);
 | |
| 								break;
 | |
| 							default:
 | |
| 								throw new MatchException(null, null);
 | |
| 						}
 | |
| 					});
 | |
| 				}
 | |
| 
 | |
| 				if (object2ObjectMap2.isEmpty()) {
 | |
| 					return new TextureSlots(object2ObjectMap);
 | |
| 				} else {
 | |
| 					boolean bl = true;
 | |
| 
 | |
| 					while (bl) {
 | |
| 						bl = false;
 | |
| 						ObjectIterator<it.unimi.dsi.fastutil.objects.Object2ObjectMap.Entry<String, TextureSlots.Reference>> objectIterator = Object2ObjectMaps.fastIterator(
 | |
| 							object2ObjectMap2
 | |
| 						);
 | |
| 
 | |
| 						while (objectIterator.hasNext()) {
 | |
| 							it.unimi.dsi.fastutil.objects.Object2ObjectMap.Entry<String, TextureSlots.Reference> entry = (it.unimi.dsi.fastutil.objects.Object2ObjectMap.Entry<String, TextureSlots.Reference>)objectIterator.next();
 | |
| 							Material material = object2ObjectMap.get(((TextureSlots.Reference)entry.getValue()).target);
 | |
| 							if (material != null) {
 | |
| 								object2ObjectMap.put((String)entry.getKey(), material);
 | |
| 								objectIterator.remove();
 | |
| 								bl = true;
 | |
| 							}
 | |
| 						}
 | |
| 					}
 | |
| 
 | |
| 					if (!object2ObjectMap2.isEmpty()) {
 | |
| 						LOGGER.warn(
 | |
| 							"Unresolved texture references in {}:\n{}",
 | |
| 							name.debugName(),
 | |
| 							object2ObjectMap2.entrySet()
 | |
| 								.stream()
 | |
| 								.map(entryx -> "\t#" + (String)entryx.getKey() + "-> #" + ((TextureSlots.Reference)entryx.getValue()).target + "\n")
 | |
| 								.collect(Collectors.joining())
 | |
| 						);
 | |
| 					}
 | |
| 
 | |
| 					return new TextureSlots(object2ObjectMap);
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	@Environment(EnvType.CLIENT)
 | |
| 	public sealed interface SlotContents permits TextureSlots.Value, TextureSlots.Reference {
 | |
| 	}
 | |
| 
 | |
| 	@Environment(EnvType.CLIENT)
 | |
| 	record Value(Material material) implements TextureSlots.SlotContents {
 | |
| 	}
 | |
| }
 |