package coloredlightscore.server; import cpw.mods.fml.common.FMLCommonHandler; import cpw.mods.fml.common.FMLLog; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.NibbleArray; import net.minecraft.world.chunk.storage.ExtendedBlockStorage; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * Methods for loading/saving RGB data to/from world save * * @author heaton84 */ public class ChunkStorageRGB { private static String EVENT_SOURCE = "coloredlightscore.server.ChunkStorageRGB"; private static Method methodSetRedColorArray = null; private static Method methodSetGreenColorArray = null; private static Method methodSetBlueColorArray = null; private static Method methodGetRedColorArray = null; private static Method methodGetGreenColorArray = null; private static Method methodGetBlueColorArray = null; private static Method methodGetValueArray = null; /** * Builds references to the getter/setter methods for each RGB Color Array. * These methods are built at runtime using ASM transformation. */ private static void getReflectionData() { if (ChunkStorageRGB.methodSetRedColorArray == null) { // We must use reflection for coremod-defined methods for (Method m : ExtendedBlockStorage.class.getMethods()) { if (m.getName().equals("setRedColorArray")) methodSetRedColorArray = m; else if (m.getName().equals("setGreenColorArray")) methodSetGreenColorArray = m; else if (m.getName().equals("setBlueColorArray")) methodSetBlueColorArray = m; else if (m.getName().equals("getRedColorArray")) methodGetRedColorArray = m; else if (m.getName().equals("getGreenColorArray")) methodGetGreenColorArray = m; else if (m.getName().equals("getBlueColorArray")) methodGetBlueColorArray = m; } try { methodGetValueArray = NibbleArray.class.getMethod("getValueArray"); } catch (NoSuchMethodException e) { FMLLog.info("Unable to hook getValueArray, Ignore if not running cauldron"); } catch (SecurityException e) { e.printStackTrace(); } if (methodSetRedColorArray == null) FMLLog.severe("%s.getReflectionData() Unable to locate method setRedColorArray in ExtendedBlockStorage!", EVENT_SOURCE); if (methodSetGreenColorArray == null) FMLLog.severe("%s.getReflectionData() Unable to locate method setGreenColorArray in ExtendedBlockStorage!", EVENT_SOURCE); if (methodSetBlueColorArray == null) FMLLog.severe("%s.getReflectionData() Unable to locate method setBlueColorArray in ExtendedBlockStorage!", EVENT_SOURCE); if (methodGetRedColorArray == null) FMLLog.severe("%s.getReflectionData() Unable to locate method getRedColorArray in ExtendedBlockStorage!", EVENT_SOURCE); if (methodGetGreenColorArray == null) FMLLog.severe("%s.getReflectionData() Unable to locate method getGreenColorArray in ExtendedBlockStorage!", EVENT_SOURCE); if (methodGetBlueColorArray == null) FMLLog.severe("%s.getReflectionData() Unable to locate method getBlueColorArray in ExtendedBlockStorage!", EVENT_SOURCE); } } /** * Constructs a NibbleArray from a raw stream of byte data. If the * byte data is incomplete, returns an empty array. * * @param rawdata The raw bytestream to build an array from. * @return Instance of a NibbleArray. */ private static NibbleArray checkedGetNibbleArray(byte[] rawdata) { if (rawdata.length == 0) { return new NibbleArray(4096, 4); } else if (rawdata.length < 2048) { FMLLog.warning("checkedGetNibbleArray: rawdata is too short: %s, expected 2048", rawdata.length); return new NibbleArray(4096, 4); } else return new NibbleArray(rawdata, 4); } /** * Loads RGB color data from a world store, if present. * * @param chunk The chunk to populate with data * @param data Top-level NBTTag, must contain "Level" tag. * @return true if color data was loaded, false if not present or an error was encountered */ public static boolean loadColorData(Chunk chunk, NBTTagCompound data) { NibbleArray rColorArray; NibbleArray gColorArray; NibbleArray bColorArray; ExtendedBlockStorage[] chunkStorageArrays = chunk.getBlockStorageArray(); NBTTagCompound level = data.getCompoundTag("Level"); NBTTagList nbttaglist = level.getTagList("Sections", 10); boolean foundColorData = false; getReflectionData(); for (int k = 0; k < nbttaglist.tagCount(); ++k) { NBTTagCompound nbtYCompound = nbttaglist.getCompoundTagAt(k); if (chunkStorageArrays[k] != null) { if (nbtYCompound.hasKey("RedColorArray")) //, 7)) { rColorArray = checkedGetNibbleArray(nbtYCompound.getByteArray("RedColorArray")); gColorArray = checkedGetNibbleArray(nbtYCompound.getByteArray("GreenColorArray")); bColorArray = checkedGetNibbleArray(nbtYCompound.getByteArray("BlueColorArray")); try { // Set color arrays on chunk.storageArrays methodSetRedColorArray.invoke(chunkStorageArrays[k], rColorArray); methodSetGreenColorArray.invoke(chunkStorageArrays[k], gColorArray); methodSetBlueColorArray.invoke(chunkStorageArrays[k], bColorArray); foundColorData = true; } catch (IllegalAccessException e) { FMLLog.severe("%s.loadColorData() Unexpected IllegalAccessException while setting RGB color data!", EVENT_SOURCE); return false; } catch (IllegalArgumentException e) { FMLLog.severe("%s.loadColorData() Unexpected IllegalArgumentException while setting RGB color data!", EVENT_SOURCE); return false; } catch (InvocationTargetException e) { FMLLog.severe("%s.loadColorData() Unexpected InvocationTargetException while setting RGB color data!", EVENT_SOURCE); return false; } //FMLLog.info("Loaded nibble array for %s %s %s", chunk.xPosition, chunk.zPosition, k); } //else //FMLLog.warning("NO NIBBLE ARRAY EXISTS FOR %s %s %s", chunk.xPosition, chunk.zPosition, k); } } return foundColorData; } /** * Loads RGB color data from a world store, if present. * * @param chunk The chunk to populate with data * @param data Top-level NBTTag, must contain "Level" tag. * @return true if color data was loaded, false if not present or an error was encountered */ public static boolean loadColorData(Chunk chunk, int arraySize, int[] yLocation, NibbleArray[] redColorData, NibbleArray[] greenColorData, NibbleArray[] blueColorData) { NibbleArray rColorArray; NibbleArray gColorArray; NibbleArray bColorArray; ExtendedBlockStorage[] chunkStorageArrays = chunk.getBlockStorageArray(); boolean foundColorData = false; getReflectionData(); for (int k = 0; k < arraySize; ++k) { if (chunkStorageArrays[k] != null) { if (chunkStorageArrays[k].getYLocation() != yLocation[k]) FMLLog.severe("EBS DATA OUT OF SEQUENCE. Expected %s, got %s", chunkStorageArrays[k].getYLocation(), yLocation[k]); try { rColorArray = redColorData[k]; gColorArray = greenColorData[k]; bColorArray = blueColorData[k]; // Set color arrays on chunk.storageArrays methodSetRedColorArray.invoke(chunkStorageArrays[k], rColorArray); methodSetGreenColorArray.invoke(chunkStorageArrays[k], gColorArray); methodSetBlueColorArray.invoke(chunkStorageArrays[k], bColorArray); foundColorData = true; } catch (IllegalAccessException e) { FMLLog.severe("%s.loadColorData() Unexpected IllegalAccessException while setting RGB color data!", EVENT_SOURCE); return false; } catch (IllegalArgumentException e) { FMLLog.severe("%s.loadColorData() Unexpected IllegalArgumentException while setting RGB color data!", EVENT_SOURCE); return false; } catch (InvocationTargetException e) { FMLLog.severe("%s.loadColorData() Unexpected InvocationTargetException while setting RGB color data!", EVENT_SOURCE); return false; } catch (Exception e) { FMLLog.getLogger().error("loadColorData() ", e); } //FMLLog.info("Loaded nibble array for %s %s %s", chunk.xPosition, chunk.zPosition, k); } //else //FMLLog.warning("NO NIBBLE ARRAY EXISTS FOR %s %s %s", chunk.xPosition, chunk.zPosition, k); } return foundColorData; } /** * Saves RGB color data into world store NBTTag data. Should be called before chunk is saved. * * @param chunk The chunk to extract RGB color data from. * @param data Top-level NBTTag, must contain "Level" tag. * @return true if color data was saved, false if an error was encountered */ public static boolean saveColorData(Chunk chunk, NBTTagCompound data) { NibbleArray rColorArray; NibbleArray gColorArray; NibbleArray bColorArray; ExtendedBlockStorage[] chunkStorageArrays = chunk.getBlockStorageArray(); NBTTagCompound level = data.getCompoundTag("Level"); NBTTagList nbttaglist = level.getTagList("Sections", 10); getReflectionData(); for (int k = 0; k < chunkStorageArrays.length; k++) { if (chunkStorageArrays[k] != null) { NBTTagCompound nbtYCompound = nbttaglist.getCompoundTagAt(k); // Add our RGB arrays to it try { rColorArray = (NibbleArray) methodGetRedColorArray.invoke(chunkStorageArrays[k]); gColorArray = (NibbleArray) methodGetGreenColorArray.invoke(chunkStorageArrays[k]); bColorArray = (NibbleArray) methodGetBlueColorArray.invoke(chunkStorageArrays[k]); if (FMLCommonHandler.instance().getModName().contains("cauldron")) {//cauldron has a patch that will cause a crash if we don't do this instead.. nbtYCompound.setByteArray("RedColorArray", (byte[]) methodGetValueArray.invoke(rColorArray)); nbtYCompound.setByteArray("GreenColorArray", (byte[]) methodGetValueArray.invoke(gColorArray)); nbtYCompound.setByteArray("BlueColorArray", (byte[]) methodGetValueArray.invoke(bColorArray)); } else {//run as base forge/mc nbtYCompound.setByteArray("RedColorArray", rColorArray.data); nbtYCompound.setByteArray("GreenColorArray", gColorArray.data); nbtYCompound.setByteArray("BlueColorArray", bColorArray.data); } } catch (IllegalAccessException e) { FMLLog.severe("%s.saveColorData() Unexpected IllegalAccessException while getting RGB color data!", EVENT_SOURCE); return false; } catch (IllegalArgumentException e) { FMLLog.severe("%s.saveColorData() Unexpected IllegalArgumentException while getting RGB color data!", EVENT_SOURCE); return false; } catch (InvocationTargetException e) { FMLLog.severe("%s.saveColorData() Unexpected InvocationTargetException while getting RGB color data!", EVENT_SOURCE); return false; } catch (Exception e) { FMLLog.severe("%s.saveColorData() Unexpected Exception while getting RGB color data!", EVENT_SOURCE); return false; } } } return true; } /** * Extracts all the red color arrays from a chunk's extended block storage * * @param chunk chunk containing data * @return An array of NibbleArrays containing red color data for the chunk */ public static NibbleArray[] getRedColorArrays(Chunk chunk) { ExtendedBlockStorage[] chunkStorageArrays = chunk.getBlockStorageArray(); NibbleArray[] redColorArrays; getReflectionData(); redColorArrays = new NibbleArray[chunkStorageArrays.length]; for (int i = 0; i < chunkStorageArrays.length; i++) { try { if (chunkStorageArrays[i] != null) redColorArrays[i] = (NibbleArray) methodGetRedColorArray.invoke(chunkStorageArrays[i]); else redColorArrays[i] = null; } catch (IllegalAccessException e) { FMLLog.severe("%s.getRedColorArrays() Unexpected IllegalAccessException while getting RGB color data!", EVENT_SOURCE); return null; } catch (IllegalArgumentException e) { FMLLog.severe("%s.getRedColorArrays() Unexpected IllegalArgumentException while getting RGB color data!", EVENT_SOURCE); return null; } catch (InvocationTargetException e) { FMLLog.severe("%s.getRedColorArrays() Unexpected InvocationTargetException while getting RGB color data!", EVENT_SOURCE); return null; } catch (Exception e) { FMLLog.severe("%s.getRedColorArrays() Unexpected Exception while getting RGB color data!", EVENT_SOURCE); return null; } } return redColorArrays; } /** * Extracts all the green color arrays from a chunk's extended block storage * * @param chunk chunk containing data * @return An array of NibbleArrays containing green color data for the chunk */ public static NibbleArray[] getGreenColorArrays(Chunk chunk) { ExtendedBlockStorage[] chunkStorageArrays = chunk.getBlockStorageArray(); NibbleArray[] greenColorArrays; getReflectionData(); greenColorArrays = new NibbleArray[chunkStorageArrays.length]; for (int i = 0; i < chunkStorageArrays.length; i++) { try { if (chunkStorageArrays[i] != null) greenColorArrays[i] = (NibbleArray) methodGetGreenColorArray.invoke(chunkStorageArrays[i]); else greenColorArrays[i] = null; } catch (IllegalAccessException e) { FMLLog.severe("%s.getGreenColorArrays() Unexpected IllegalAccessException while getting RGB color data!", EVENT_SOURCE); return null; } catch (IllegalArgumentException e) { FMLLog.severe("%s.getGreenColorArrays() Unexpected IllegalArgumentException while getting RGB color data!", EVENT_SOURCE); return null; } catch (InvocationTargetException e) { FMLLog.severe("%s.getGreenColorArrays() Unexpected InvocationTargetException while getting RGB color data!", EVENT_SOURCE); return null; } catch (Exception e) { FMLLog.severe("%s.getGreenColorArrays() Unexpected Exception while getting RGB color data!", EVENT_SOURCE); return null; } } return greenColorArrays; } /** * Extracts all the blue color arrays from a chunk's extended block storage * * @param chunk chunk containing data * @return An array of NibbleArrays containing blue color data for the chunk */ public static NibbleArray[] getBlueColorArrays(Chunk chunk) { ExtendedBlockStorage[] chunkStorageArrays = chunk.getBlockStorageArray(); NibbleArray[] blueColorArrays; getReflectionData(); blueColorArrays = new NibbleArray[chunkStorageArrays.length]; for (int i = 0; i < chunkStorageArrays.length; i++) { try { if (chunkStorageArrays[i] != null) blueColorArrays[i] = (NibbleArray) methodGetBlueColorArray.invoke(chunkStorageArrays[i]); else blueColorArrays[i] = null; } catch (IllegalAccessException e) { FMLLog.severe("%s.getBlueColorArrays() Unexpected IllegalAccessException while getting RGB color data!", EVENT_SOURCE); return null; } catch (IllegalArgumentException e) { FMLLog.severe("%s.getBlueColorArrays() Unexpected IllegalArgumentException while getting RGB color data!", EVENT_SOURCE); return null; } catch (InvocationTargetException e) { FMLLog.severe("%s.getBlueColorArrays() Unexpected InvocationTargetException while getting RGB color data!", EVENT_SOURCE); return null; } catch (Exception e) { FMLLog.severe("%s.getBlueColorArrays() Unexpected Exception while getting RGB color data!", EVENT_SOURCE); return null; } } return blueColorArrays; } public static int[] getYLocationArray(Chunk chunk) { ExtendedBlockStorage[] ebs = chunk.getBlockStorageArray(); int y[] = new int[ebs.length]; for (int i = 0; i < ebs.length; i++) { if (ebs[i] == null) y[i] = -1; else y[i] = ebs[i].getYLocation(); } return y; } }