package slimeknights.tconstruct.library.client.model;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.gson.JsonParseException;
import gnu.trove.map.hash.THashMap;
import net.minecraft.client.resources.IResourceManager;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.model.ICustomModelLoader;
import net.minecraftforge.client.model.IModel;
import net.minecraftforge.client.model.ModelLoaderRegistry;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.annotation.Nonnull;
import slimeknights.tconstruct.library.TinkerRegistry;
import slimeknights.tconstruct.library.Util;
import slimeknights.tconstruct.library.client.CustomTextureCreator;
import slimeknights.tconstruct.library.modifiers.IModifier;
public class ModifierModelLoader implements ICustomModelLoader {
public static String EXTENSION = ".mod";
private static final String defaultName = "default";
private static final Logger log = Util.getLogger("modifier");
// holds additional json files that shall be loaded for a specific modifier
protected Map<String, List<ResourceLocation>> locations = Maps.newHashMap();
protected Map<String, Map<String, String>> cache;
public static ResourceLocation getLocationForToolModifiers(String toolName) {
return new ResourceLocation(Util.RESOURCE, "modifiers/" + toolName + ModifierModelLoader.EXTENSION);
}
public void registerModifierFile(String modifier, ResourceLocation location) {
List<ResourceLocation> files = locations.get(modifier);
if(files == null) {
files = Lists.newLinkedList();
locations.put(modifier, files);
}
files.add(location);
}
@Override
public boolean accepts(ResourceLocation modelLocation) {
return modelLocation.getResourcePath().endsWith(EXTENSION); // tinkermodifier extension. Foo.mod.json
}
@Override
public IModel loadModel(ResourceLocation modelLocation) {
// this function is actually getting called on a PER TOOL basis, not per modifier
// we therefore need to look through all modifiers to construct a model containing all modifiers for that tool
int start = modelLocation.getResourcePath().lastIndexOf('/');
String toolname = modelLocation.getResourcePath().substring(start < 0 ? 0 : start + 1,
modelLocation.getResourcePath().length() - EXTENSION
.length());
toolname = toolname.toLowerCase(Locale.US);
// we only load once. Without cache we'd have to load ALL modifier files again for each tool!
if(cache == null) {
cache = new THashMap<String, Map<String, String>>();
loadFilesIntoCache();
}
ModifierModel model = new ModifierModel();
if(cache.containsKey(toolname)) {
// generate the modelblocks for each entry
for(Map.Entry<String, String> entry : cache.get(toolname).entrySet()) {
// check if the modifier actually exists in the game so we don't load unnecessary textures
IModifier mod = TinkerRegistry.getModifier(entry.getKey());
/*
if(mod == null) {
log.debug("Removing texture {} for modifier {}: No modifier present for texture", entry.getValue(), entry.getKey());
continue;
}*/
// using the String from the modifier means an == check succeeds and fixes lowercasing from the loading from files
model.addModelForModifier(entry.getKey(), entry.getValue());
// register per-material modifiers for texture creation
if(mod != null && mod.hasTexturePerMaterial()) {
CustomTextureCreator.registerTexture(new ResourceLocation(entry.getValue()));
}
}
}
else {
log.debug("Tried to load modifier models for " + toolname + "but none were found");
}
return model;
}
@Override
public void onResourceManagerReload(@Nonnull IResourceManager resourceManager) {
// goodbye, my dear data. You'll be...loaded again
cache = null;
}
private void loadFilesIntoCache() {
cache.put(defaultName, new THashMap<String, String>());
// loop through all knows modifier-model-files
for(Map.Entry<String, List<ResourceLocation>> entry : locations.entrySet()) {
String modifier = entry.getKey();
List<ResourceLocation> modLocations = entry.getValue();
for(ResourceLocation location : modLocations) {
try {
// load the entries in the json file
Map<String, String> textureEntries = ModelHelper.loadTexturesFromJson(location);
// save them in the cache
for(Map.Entry<String, String> textureEntry : textureEntries.entrySet()) {
String tool = textureEntry.getKey().toLowerCase(Locale.US);
String texture = textureEntry.getValue();
if(!cache.containsKey(tool)) {
cache.put(tool, new THashMap<String, String>());
}
// we don't allow overriding
if(!cache.get(tool).containsKey(modifier)) {
cache.get(tool).put(modifier, texture);
}
}
} catch(IOException e) {
log.error("Cannot load modifier-model " + entry.getValue(), e);
} catch(JsonParseException e) {
log.error("Cannot load modifier-model " + entry.getValue(), e);
throw e;
}
}
if(!cache.get(defaultName).containsKey(modifier)) {
log.debug(String.format("%s Modifiers model does not contain a default-entry", modifier));
}
}
Map<String, String> defaults = cache.get(defaultName);
// fill in defaults where models are missing
Iterator<Map.Entry<String, Map<String, String>>> toolEntryIter = cache.entrySet().iterator();
// todo: change this to iterate over all registered tools instead?
while(toolEntryIter.hasNext()) {
Map.Entry<String, Map<String, String>> toolEntry = toolEntryIter.next();
//String tool = toolEntry.getKey();
Map<String, String> textures = toolEntry.getValue();
for(Map.Entry<String, String> defaultEntry : defaults.entrySet()) {
// check if the tool has an entry for this modifier, otherwise fill in default
if(!textures.containsKey(defaultEntry.getKey())) {
log.debug("Filling in default for modifier {} on tool {}", defaultEntry.getKey(), toolEntry.getKey());
textures.put(defaultEntry.getKey(), defaultEntry.getValue());
}
}
}
}
}