/* * Copyright (c) 2012-2017, John Campbell and other contributors. All rights reserved. * * This file is part of Tectonicus. It is subject to the license terms in the LICENSE file found in * the top-level directory of this distribution. The full list of project contributors is contained * in the AUTHORS file found in the same location. * */ package tectonicus.blockTypes; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.nio.file.DirectoryStream; import java.nio.file.FileSystem; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Random; import java.util.Set; import org.apache.commons.lang3.StringUtils; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.google.gson.JsonSyntaxException; import tectonicus.Minecraft; import tectonicus.blockTypes.BlockModel.BlockElement; import tectonicus.blockTypes.BlockModel.BlockElement.ElementFace; import tectonicus.rasteriser.Rasteriser; import tectonicus.texture.SubTexture; import tectonicus.texture.TexturePack; import tectonicus.texture.ZipStack; import tectonicus.util.Vector3f; public class BlockRegistry { private Map<String, List<BlockVariant>> blockStates = new HashMap<>(); private Map<String, BlockModel> blockModels = new HashMap<>(); private TexturePack texturePack; private ZipStack zips; public BlockRegistry() { try { zips = new ZipStack(Minecraft.findMinecraftJar(), null, null); } catch (IOException e) { e.printStackTrace(); } } public BlockRegistry(Rasteriser rasteriser) { texturePack = new TexturePack(rasteriser, Minecraft.findMinecraftJar(), null, Collections.<File>emptyList()); try { zips = new ZipStack(Minecraft.findMinecraftJar(), null, null); } catch (IOException e) { e.printStackTrace(); } } public BlockRegistry(TexturePack texturePack) { this.texturePack = texturePack; this.zips = texturePack.getZipStack(); } public Map<String, List<BlockVariant>> getBlockStates() { return Collections.unmodifiableMap(blockStates); } public Map<String, BlockModel> getBlockModels() { return Collections.unmodifiableMap(blockModels); } public List<BlockVariant> getVariants(String blockID) { return blockStates.get(blockID); } public BlockModel getModel(String model) { return blockModels.get(model); } public void deserializeBlockstates() { List<BlockVariant> blockVariants = new ArrayList<>(); //TODO: need to use override pack blockstate files first try (FileSystem fs = FileSystems.newFileSystem(Paths.get(zips.getBaseFileName()), null); DirectoryStream<Path> entries = Files.newDirectoryStream(fs.getPath("/assets/minecraft/blockstates"));) { for (Path entry : entries) { JsonObject json = new JsonParser().parse(Files.newBufferedReader(entry, StandardCharsets.UTF_8)).getAsJsonObject(); JsonObject variants = json.getAsJsonObject("variants"); Set<Entry<String, JsonElement>> entrySet = variants.entrySet(); for(Map.Entry<String,JsonElement> e : entrySet) { String key = e.getKey(); blockVariants.add(BlockVariant.deserializeVariant(key, variants.get(key))); } String name = "minecraft:" + StringUtils.removeEnd(entry.getFileName().toString(), ".json"); blockStates.put(name, blockVariants); } } catch (Exception e) { e.printStackTrace(); } } public void loadModels() throws Exception { for (Map.Entry<String, List<BlockVariant>> blockState : blockStates.entrySet()) { for(BlockVariant variant : blockState.getValue()) { for(BlockVariant.VariantModel model : variant.getModels()) { String modelName = model.getModel(); if(!blockModels.containsKey(modelName)) { Map<String, String> textureMap = new HashMap<>(); JsonArray elements = null; blockModels.put(modelName, loadModel("block/" + modelName, textureMap, elements)); } } } } } public void loadModel(String modelName) throws Exception { blockModels.put(modelName, loadModel("block/"+modelName, new HashMap<String, String>(), null)); } // Recurse through model files and get block model information TODO: This will need to change some with MC 1.9 public BlockModel loadModel(String modelPath, Map<String, String> textureMap, JsonArray elements) throws Exception { JsonObject json = new JsonParser().parse(new InputStreamReader(zips.getStream("assets/minecraft/models/" + modelPath + ".json"))).getAsJsonObject(); //JsonArray elements = null; String parent = ""; if(json.has("parent")) // Get texture information and then load parent file { parent = json.get("parent").getAsString(); if(json.has("elements") && elements == null) { elements = json.getAsJsonArray("elements"); } if(json.has("textures")) { return loadModel(parent, populateTextureMap(textureMap, json.getAsJsonObject("textures")), elements); } else { return loadModel(parent, textureMap, elements); } } else //Load all elements { Map<String, String> combineMap = new HashMap<>(textureMap); if(json.has("textures")) { combineMap.putAll(populateTextureMap(textureMap, json.getAsJsonObject("textures"))); } boolean ao = true; if (json.has("ambientocclusion")) ao = false; if(json.has("elements") && elements == null) { elements = json.getAsJsonArray("elements"); } return new BlockModel(modelPath, ao, deserializeBlockElements(combineMap, elements)); } } private List<BlockElement> deserializeBlockElements(Map<String, String> combineMap, JsonArray elements) throws JsonSyntaxException { List<BlockElement> elementsList = new ArrayList<>(); //List<BlockElement> testList; //Gson gson = new Gson(); //System.out.println(elements); //testList = gson.fromJson(elements.getAsJsonArray(), new TypeToken<List<Element>>(){}.getType()); for(JsonElement e : elements) //for (int i = 0; i < elements.size(); i++) { //Element testElement = gson.fromJson(e, Element.class); //testElement.getFaces().getUp().getTexture() JsonObject element = e.getAsJsonObject(); JsonArray from = element.getAsJsonArray("from"); Vector3f fromVector = new Vector3f(from.get(0).getAsFloat(), from.get(1).getAsFloat(), from.get(2).getAsFloat()); JsonArray to = element.getAsJsonArray("to"); Vector3f toVector = new Vector3f(to.get(0).getAsFloat(), to.get(1).getAsFloat(), to.get(2).getAsFloat()); org.joml.Vector3f rotationOrigin = new org.joml.Vector3f(8.0f, 8.0f, 8.0f); String rotationAxis = "y"; org.joml.Vector3f rotAxis = new org.joml.Vector3f(0.0f, 1.0f, 0.0f); float rotationAngle = 0; boolean rotationScale = false; if(element.has("rotation")) { JsonObject rot = element.getAsJsonObject("rotation"); JsonArray rotOrigin = rot.getAsJsonArray("origin"); rotationOrigin = new org.joml.Vector3f(rotOrigin.get(0).getAsFloat(), rotOrigin.get(1).getAsFloat(), rotOrigin.get(2).getAsFloat()); rotationAxis = rot.get("axis").getAsString(); if (rotationAxis.equals("x")) rotAxis = new org.joml.Vector3f(1.0f, 0.0f, 0.0f); else rotAxis = new org.joml.Vector3f(0.0f, 0.0f, 1.0f); rotationAngle = rot.get("angle").getAsFloat(); if(element.has("rescale")) rotationScale = true; } boolean shaded = true; if(element.has("shade")) shaded = false; JsonObject faces = element.getAsJsonObject("faces"); SubTexture subTexture = new SubTexture(null, fromVector.x(), 16-toVector.y(), toVector.x(), 16-fromVector.y()); BlockElement be = new BlockElement(fromVector, toVector, rotationOrigin, rotAxis, rotationAngle, rotationScale, shaded, deserializeElementFaces(combineMap, subTexture, faces, fromVector, toVector)); elementsList.add(be); } return elementsList; } private Map<String, ElementFace> deserializeElementFaces(Map<String, String> combineMap, SubTexture texCoords, JsonObject faces, Vector3f fromVector, Vector3f toVector) throws JsonSyntaxException { Map<String, ElementFace> elementFaces = new HashMap<>(); Set<Entry<String, JsonElement>> entrySet = faces.entrySet(); for(Map.Entry<String,JsonElement> e : entrySet) { String key = e.getKey(); JsonObject face = faces.getAsJsonObject(key); float u0 = texCoords.u0; float v0 = texCoords.v0; float u1 = texCoords.u1; float v1 = texCoords.v1; if (key.equals("up") || key.equals("down")) { v0 = fromVector.z(); v1 = toVector.z(); } else if (key.equals("north")) { u0 = 16 - texCoords.u1; u1 = 16 - texCoords.u0; } else if (key.equals("east")) { u0 = 16 - toVector.z(); u1 = 16 - fromVector.z(); } else if (key.equals("west")) { u0 = fromVector.z(); u1 = toVector.z(); } int rotation = 0; if(face.has("rotation")) rotation = face.get("rotation").getAsInt(); //System.out.println("u0="+u0+" v0="+v0+" u1="+u1+" v1="+v1); // TODO: Need to test more texture packs SubTexture subTexture = new SubTexture(null, u0*(1.0f/16.0f), v0*(1.0f/16.0f), u1*(1.0f/16.0f), v1*(1.0f/16.0f)); StringBuilder tex = new StringBuilder(face.get("texture").getAsString()); if(tex.charAt(0) == '#') { String texture = tex.deleteCharAt(0).toString(); SubTexture te = texturePack.findTexture(StringUtils.removeStart(combineMap.get(texture), "blocks/")+ ".png"); final float texHeight = te.texture.getHeight(); final float texWidth = te.texture.getWidth(); final int numTiles = te.texture.getHeight()/te.texture.getWidth(); u0 /= texWidth; v0 = (v0 / texWidth) / numTiles; u1 /= texWidth; v1 = (v1 / texWidth) / numTiles; if(face.has("uv")) { //System.out.println("Before: u0="+u0+" v0="+v0+" u1="+u1+" v1="+v1); JsonArray uv = face.getAsJsonArray("uv"); u0 = (float)(uv.get(0).getAsFloat()/16.0f); v0 = (float)(uv.get(1).getAsFloat()/16.0f) / numTiles; u1 = (float)(uv.get(2).getAsFloat()/16.0f); v1 = (float)(uv.get(3).getAsFloat()/16.0f) / numTiles; } //System.out.println(texWidth + " x " + texHeight); int frame = 1; if(numTiles > 1) { Random rand = new Random(); frame = rand.nextInt(numTiles)+1; } subTexture = new SubTexture(te.texture, u0, v0+(float)(frame-1)*(texWidth/texHeight), u1, v1+(float)(frame-1)*(texWidth/texHeight)); //subTexture = new SubTexture(test, u0, v0, u1, v1); //System.out.println("u0="+subTexture.u0+" v0="+subTexture.v0+" u1="+subTexture.u1+" v1="+subTexture.v1); } boolean cullFace = false; if(face.has("cullface")) cullFace = true; boolean tintIndex = false; if(face.has("tintindex")) tintIndex = true; ElementFace ef = new ElementFace(subTexture, cullFace, rotation, tintIndex); elementFaces.put(key, ef); } return elementFaces; } private Map<String, String> populateTextureMap(Map<String, String> textureMap, JsonObject textures) throws JsonSyntaxException { Map<String, String> newTexMap = new HashMap<>(); Set<Entry<String, JsonElement>> entrySet = textures.entrySet(); for(Map.Entry<String,JsonElement> e : entrySet) { String key = e.getKey(); StringBuilder tex = new StringBuilder(textures.get(key).getAsString()); if(tex.charAt(0) == '#') { newTexMap.put(key, textureMap.get(tex.deleteCharAt(0).toString())); } else { newTexMap.put(key, tex.toString()); } } return newTexMap; } }