16 Commits

Author SHA1 Message Date
octarine-noise
ec723113d3 bump version 2014-07-26 10:00:58 +02:00
octarine-noise
4e42f63c36 don't alter ShaderMod special textures 2014-07-25 20:59:21 +02:00
octarine-noise
0daf61583a fixed leaves and grass block data for ShadersMod integration 2014-07-25 15:57:27 +02:00
octarine-noise
504f033c2e only rebuild block ID cache on client world load 2014-07-24 17:59:06 +02:00
octarine-noise
fa099b1b97 fix deadlock issue during class transformation 2014-07-24 17:50:06 +02:00
octarine-noise
b0c0cd0d1b avoid Class.forName() in world loading event 2014-07-24 01:03:35 +02:00
octarine-noise
df69605521 Update README.md 2014-07-23 02:19:18 +02:00
octarine-noise
d3b1d138ba bump version 2014-07-23 01:23:41 +02:00
octarine-noise
07369159b8 hack block ID seen by ShadersMod mid-render
move block ID override to dedicated class
2014-07-23 01:14:47 +02:00
octarine-noise
6700e724a5 emit warning message for unsupported Minecraft versions 2014-07-17 18:44:39 +02:00
octarine-noise
5b34da3e61 move default class lists to resource files 2014-07-17 18:29:19 +02:00
octarine-noise
fc7c9a5381 push down debug log to correct level 2014-07-16 23:28:35 +02:00
octarine-noise
cf7ae0efa1 removed usused internal feature 2014-07-16 23:26:46 +02:00
octarine-noise
04bb240d36 minor comment correction 2014-07-16 23:25:44 +02:00
octarine-noise
91fda1522c Unified 1.7.2 and 1.7.10 versions 2014-07-16 23:25:06 +02:00
octarine-noise
7ca25c0da7 null check for leaf icon 2014-07-14 17:52:33 +02:00
22 changed files with 309 additions and 232 deletions

View File

@@ -6,6 +6,4 @@ More info: http://www.minecraftforum.net/topic/2776217-better-foliage/
Download Download
======== ========
[BetterFoliage 0.9.4-beta] (http://goo.gl/pNBE23) (MC 1.7.2) [BetterFoliage 0.9.6-beta] (http://goo.gl/8qVKMl) (MC 1.7.2 & 1.7.10)
[BetterFoliage 0.9.4-beta] (http://goo.gl/ywT6Xg) (MC 1.7.10)

View File

@@ -17,12 +17,12 @@ buildscript {
apply plugin: 'forge' apply plugin: 'forge'
minecraft { minecraft {
version = '1.7.10-10.13.0.1159' version = '1.7.2-10.12.2.1147'
} }
jar.baseName = 'BetterFoliage-1.7.10' jar.baseName = 'BetterFoliage'
group = 'com.github.octarine-noise' group = 'com.github.octarine-noise'
version='0.9.5b' version='0.9.7b'
processResources { processResources {
inputs.property "version", project.version inputs.property "version", project.version

View File

@@ -18,7 +18,7 @@ public class BetterFoliage {
public static final String MOD_ID = "BetterFoliage"; public static final String MOD_ID = "BetterFoliage";
public static final String MOD_NAME = "Better Foliage"; public static final String MOD_NAME = "Better Foliage";
public static final String MC_VERSIONS = "[1.7.10]"; public static final String MC_VERSIONS = "[1.7.2,1.7.10]";
public static final String GUI_FACTORY = "mods.betterfoliage.client.gui.ConfigGuiFactory"; public static final String GUI_FACTORY = "mods.betterfoliage.client.gui.ConfigGuiFactory";
@Mod.Instance @Mod.Instance

View File

@@ -14,19 +14,10 @@ import mods.betterfoliage.client.render.impl.RenderBlockBetterLilypad;
import mods.betterfoliage.client.render.impl.RenderBlockBetterReed; import mods.betterfoliage.client.render.impl.RenderBlockBetterReed;
import mods.betterfoliage.client.resource.BlockTextureGenerator; import mods.betterfoliage.client.resource.BlockTextureGenerator;
import mods.betterfoliage.client.resource.HalfTextureResource; import mods.betterfoliage.client.resource.HalfTextureResource;
import mods.betterfoliage.client.resource.ILeafTextureRecognizer;
import mods.betterfoliage.client.resource.LeafTextureGenerator; import mods.betterfoliage.client.resource.LeafTextureGenerator;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.BlockCarrot;
import net.minecraft.block.BlockCrops;
import net.minecraft.block.BlockDoublePlant;
import net.minecraft.block.BlockLeavesBase;
import net.minecraft.block.BlockPotato;
import net.minecraft.block.BlockReed;
import net.minecraft.block.BlockTallGrass;
import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.resources.IResource; import net.minecraft.client.resources.IResource;
import net.minecraft.init.Blocks;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraft.world.IBlockAccess; import net.minecraft.world.IBlockAccess;
import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.MinecraftForge;
@@ -36,13 +27,13 @@ import com.google.common.collect.Maps;
import cpw.mods.fml.client.registry.RenderingRegistry; import cpw.mods.fml.client.registry.RenderingRegistry;
import cpw.mods.fml.common.FMLCommonHandler; import cpw.mods.fml.common.FMLCommonHandler;
public class BetterFoliageClient implements ILeafTextureRecognizer { public class BetterFoliageClient {
public static Map<Integer, IRenderBlockDecorator> decorators = Maps.newHashMap(); public static Map<Integer, IRenderBlockDecorator> decorators = Maps.newHashMap();
public static LeafTextureGenerator leafGenerator; public static LeafTextureGenerator leafGenerator;
public static BlockMatcher leaves; public static BlockMatcher leaves = new BlockMatcher();
public static BlockMatcher crops; public static BlockMatcher crops = new BlockMatcher();
public static void preInit() { public static void preInit() {
FMLCommonHandler.instance().bus().register(new KeyHandler()); FMLCommonHandler.instance().bus().register(new KeyHandler());
@@ -55,26 +46,15 @@ public class BetterFoliageClient implements ILeafTextureRecognizer {
registerRenderer(new RenderBlockBetterReed()); registerRenderer(new RenderBlockBetterReed());
registerRenderer(new RenderBlockBetterAlgae()); registerRenderer(new RenderBlockBetterAlgae());
leaves = new BlockMatcher(BlockLeavesBase.class.getName(), leaves.load(new File(BetterFoliage.configDir, "classesLeaves.cfg"), new ResourceLocation("betterfoliage:classesLeavesDefault.cfg"));
"forestry.arboriculture.gadgets.BlockLeaves", MinecraftForge.EVENT_BUS.register(leaves);
"thaumcraft.common.blocks.BlockMagicalLeaves");
leaves.load(new File(BetterFoliage.configDir, "classesLeaves.cfg"));
crops = new BlockMatcher(BlockCrops.class.getName(), crops.load(new File(BetterFoliage.configDir, "classesCrops.cfg"), new ResourceLocation("betterfoliage:classesCropsDefault.cfg"));
"-" + BlockCarrot.class.getName(), MinecraftForge.EVENT_BUS.register(crops);
"-" + BlockPotato.class.getName(),
BlockTallGrass.class.getName(),
BlockDoublePlant.class.getName(),
BlockReed.class.getName(),
"biomesoplenty.common.blocks.BlockBOPFlower",
"biomesoplenty.common.blocks.BlockBOPFlower2",
"tconstruct.blocks.slime.SlimeTallGrass");
crops.load(new File(BetterFoliage.configDir, "classesCrops.cfg"));
BetterFoliage.log.info("Registering leaf texture generator"); BetterFoliage.log.info("Registering leaf texture generator");
leafGenerator = new LeafTextureGenerator(); leafGenerator = new LeafTextureGenerator();
MinecraftForge.EVENT_BUS.register(leafGenerator); MinecraftForge.EVENT_BUS.register(leafGenerator);
leafGenerator.recognizers.add(new BetterFoliageClient());
MinecraftForge.EVENT_BUS.register(new BlockTextureGenerator("bf_reed_bottom", new ResourceLocation("betterfoliage", "textures/blocks/missing_leaf.png")) { MinecraftForge.EVENT_BUS.register(new BlockTextureGenerator("bf_reed_bottom", new ResourceLocation("betterfoliage", "textures/blocks/missing_leaf.png")) {
@Override @Override
@@ -90,9 +70,11 @@ public class BetterFoliageClient implements ILeafTextureRecognizer {
}); });
MinecraftForge.EVENT_BUS.register(new BetterFoliageClient()); MinecraftForge.EVENT_BUS.register(new BetterFoliageClient());
ShadersModIntegration.init();
} }
public boolean isLeafTexture(TextureAtlasSprite icon) { public static boolean isLeafTexture(TextureAtlasSprite icon) {
String resourceLocation = icon.getIconName(); String resourceLocation = icon.getIconName();
if (resourceLocation.startsWith("forestry:leaves/")) return true; if (resourceLocation.startsWith("forestry:leaves/")) return true;
return false; return false;
@@ -109,14 +91,6 @@ public class BetterFoliageClient implements ILeafTextureRecognizer {
return original; return original;
} }
public static int getGLSLBlockIdOverride(int original, Block block) {
if (leaves.matchesID(original & 0xFFFF))
return Block.blockRegistry.getIDForObject(Blocks.leaves) & 0xFFFF | block.getRenderType() << 16;
if (crops.matchesID(original & 0xFFFF))
return Block.blockRegistry.getIDForObject(Blocks.tallgrass) & 0xFFFF | block.getRenderType() << 16;
return original;
}
public static void registerRenderer(IRenderBlockDecorator decorator) { public static void registerRenderer(IRenderBlockDecorator decorator) {
int renderId = RenderingRegistry.getNextAvailableRenderId(); int renderId = RenderingRegistry.getNextAvailableRenderId();
decorators.put(renderId, decorator); decorators.put(renderId, decorator);

View File

@@ -2,16 +2,15 @@ package mods.betterfoliage.client;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader; import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Iterator; import java.util.Iterator;
import java.util.Set; import java.util.Set;
import mods.betterfoliage.BetterFoliage; import mods.betterfoliage.BetterFoliage;
import mods.betterfoliage.common.util.Utils;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraftforge.common.MinecraftForge; import net.minecraft.client.multiplayer.WorldClient;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.event.world.WorldEvent; import net.minecraftforge.event.world.WorldEvent;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
@@ -20,35 +19,22 @@ import cpw.mods.fml.common.eventhandler.SubscribeEvent;
public class BlockMatcher { public class BlockMatcher {
public Set<String> whiteList = Sets.newHashSet(); public Set<Class<?>> whiteList = Sets.newHashSet();
public Set<String> blackList = Sets.newHashSet(); public Set<Class<?>> blackList = Sets.newHashSet();
public Set<Integer> blockIDs = Sets.newHashSet(); public Set<Integer> blockIDs = Sets.newHashSet();
public BlockMatcher(String... defaults) {
for (String clazz : defaults) addClass(clazz);
MinecraftForge.EVENT_BUS.register(this);
}
public void addClass(String className) { public void addClass(String className) {
if (className.startsWith("-")) try {
blackList.add(className.substring(1)); if (className.startsWith("-"))
else blackList.add(Class.forName(className.substring(1)));
whiteList.add(className); else
whiteList.add(Class.forName(className));
} catch(ClassNotFoundException e) {}
} }
public boolean matchesClass(Block block) { public boolean matchesClass(Block block) {
for (String className : blackList) { for (Class<?> clazz : blackList) if (clazz.isAssignableFrom(block.getClass())) return false;
try { for (Class<?> clazz : whiteList) if (clazz.isAssignableFrom(block.getClass())) return true;
Class<?> clazz = Class.forName(className);
if (clazz.isAssignableFrom(block.getClass())) return false;
} catch(ClassNotFoundException e) {}
}
for (String className : whiteList) {
try {
Class<?> clazz = Class.forName(className);
if (clazz.isAssignableFrom(block.getClass())) return true;
} catch(ClassNotFoundException e) {}
}
return false; return false;
} }
@@ -60,7 +46,9 @@ public class BlockMatcher {
return blockIDs.contains(Block.blockRegistry.getIDForObject(block)); return blockIDs.contains(Block.blockRegistry.getIDForObject(block));
} }
public void load(File file) { public void load(File file, ResourceLocation defaults) {
if (!file.exists()) Utils.copyFromTextResource(defaults, file);
BufferedReader reader = null; BufferedReader reader = null;
try { try {
reader = new BufferedReader(new FileReader(file)); reader = new BufferedReader(new FileReader(file));
@@ -72,40 +60,19 @@ public class BlockMatcher {
line = reader.readLine(); line = reader.readLine();
} }
reader.close(); reader.close();
} catch (FileNotFoundException e) { } catch (Exception e) {
saveDefaults(file);
} catch (IOException e) {
BetterFoliage.log.warn(String.format("Error reading configuration: %s", file.getName())); BetterFoliage.log.warn(String.format("Error reading configuration: %s", file.getName()));
} }
} }
public void saveDefaults(File file) {
FileWriter writer = null;
try {
writer = new FileWriter(file);
for (String className : whiteList) {
writer.write(className);
writer.write("\n");
}
for (String className : blackList) {
writer.write("-");
writer.write(className);
writer.write("\n");
}
writer.close();
} catch (FileNotFoundException e) {
saveDefaults(file);
} catch (IOException e) {
BetterFoliage.log.warn(String.format("Error writing default configuration: %s", file.getName()));
}
}
/** Caches block IDs on world load for fast lookup /** Caches block IDs on world load for fast lookup
* @param event * @param event
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@SubscribeEvent @SubscribeEvent
public void handleWorldLoad(WorldEvent.Load event) { public void handleWorldLoad(WorldEvent.Load event) {
if (!(event.world instanceof WorldClient)) return;
blockIDs.clear(); blockIDs.clear();
Iterator<Block> iter = Block.blockRegistry.iterator(); Iterator<Block> iter = Block.blockRegistry.iterator();
while (iter.hasNext()) { while (iter.hasNext()) {

View File

@@ -0,0 +1,55 @@
package mods.betterfoliage.client;
import java.lang.reflect.Field;
import net.minecraft.block.Block;
import net.minecraft.init.Blocks;
public class ShadersModIntegration {
private static boolean hasShadersMod = false;
private static int tallGrassEntityData;
private static int leavesEntityData;
private static Field shadersEntityData;
private static Field shadersEntityDataIndex;
private ShadersModIntegration() {}
public static void init() {
tallGrassEntityData = Block.blockRegistry.getIDForObject(Blocks.tallgrass) & 0xFFFF | Blocks.tallgrass.getRenderType() << 16;
leavesEntityData = Block.blockRegistry.getIDForObject(Blocks.leaves) & 0xFFFF | Blocks.leaves.getRenderType() << 16;
try {
Class<?> classShaders = Class.forName("shadersmodcore.client.Shaders");
shadersEntityData = classShaders.getDeclaredField("entityData");
shadersEntityDataIndex = classShaders.getDeclaredField("entityDataIndex");
hasShadersMod = true;
} catch(Exception e) {
}
}
public static void startGrassQuads() {
if (!hasShadersMod) return;
setShadersEntityData(tallGrassEntityData);
}
public static void startLeavesQuads() {
if (!hasShadersMod) return;
setShadersEntityData(leavesEntityData);
}
private static void setShadersEntityData(int data) {
try {
int[] entityData = (int[]) shadersEntityData.get(null);
int entityDataIndex = shadersEntityDataIndex.getInt(null);
entityData[(entityDataIndex * 2)] = data;
} catch (Exception e) {
}
}
public static int getBlockIdOverride(int original, Block block) {
if (BetterFoliageClient.leaves.matchesID(original & 0xFFFF)) return leavesEntityData;
if (BetterFoliageClient.crops.matchesID(original & 0xFFFF)) return tallGrassEntityData;
return original;
}
}

View File

@@ -43,7 +43,7 @@ public class RenderBlockBetterAlgae extends RenderBlockAOBase implements IRender
// store world for later use // store world for later use
blockAccess = world; blockAccess = world;
// render grass block // render dirt block
setPassCounters(1); setPassCounters(1);
setRenderBoundsFromBlock(block); setRenderBoundsFromBlock(block);
renderStandardBlock(block, x, y, z); renderStandardBlock(block, x, y, z);

View File

@@ -1,6 +1,7 @@
package mods.betterfoliage.client.render.impl; package mods.betterfoliage.client.render.impl;
import mods.betterfoliage.BetterFoliage; import mods.betterfoliage.BetterFoliage;
import mods.betterfoliage.client.ShadersModIntegration;
import mods.betterfoliage.client.render.IRenderBlockDecorator; import mods.betterfoliage.client.render.IRenderBlockDecorator;
import mods.betterfoliage.client.render.IconSet; import mods.betterfoliage.client.render.IconSet;
import mods.betterfoliage.client.render.RenderBlockAOBase; import mods.betterfoliage.client.render.RenderBlockAOBase;
@@ -49,6 +50,9 @@ public class RenderBlockBetterGrass extends RenderBlockAOBase implements IRender
double scale = BetterFoliage.config.grassSize.value * 0.5; double scale = BetterFoliage.config.grassSize.value * 0.5;
double halfHeight = 0.5 * (BetterFoliage.config.grassHeightMin.value + pRand[heightVariation] * (BetterFoliage.config.grassHeightMax.value - BetterFoliage.config.grassHeightMin.value)); double halfHeight = 0.5 * (BetterFoliage.config.grassHeightMin.value + pRand[heightVariation] * (BetterFoliage.config.grassHeightMax.value - BetterFoliage.config.grassHeightMin.value));
// render short grass
ShadersModIntegration.startGrassQuads();
Tessellator.instance.setBrightness(getBrightness(block, x, y + 1, z)); Tessellator.instance.setBrightness(getBrightness(block, x, y + 1, z));
renderCrossedSideQuads(new Double3(x + 0.5, y + 1.0 - 0.125 * halfHeight, z + 0.5), ForgeDirection.UP, scale, halfHeight, pRot[variation], BetterFoliage.config.grassHOffset.value, renderIcon, 0, false); renderCrossedSideQuads(new Double3(x + 0.5, y + 1.0 - 0.125 * halfHeight, z + 0.5), ForgeDirection.UP, scale, halfHeight, pRot[variation], BetterFoliage.config.grassHOffset.value, renderIcon, 0, false);

View File

@@ -44,6 +44,10 @@ public class RenderBlockBetterLeaves extends RenderBlockAOBase implements IRende
// find generated texture to render with, assume the // find generated texture to render with, assume the
// "true" texture of the block is the one on the north size // "true" texture of the block is the one on the north size
TextureAtlasSprite blockLeafIcon = (TextureAtlasSprite) block.getIcon(world, x, y, z, ForgeDirection.NORTH.ordinal()); TextureAtlasSprite blockLeafIcon = (TextureAtlasSprite) block.getIcon(world, x, y, z, ForgeDirection.NORTH.ordinal());
if (blockLeafIcon == null) {
BetterFoliage.log.debug(String.format("null leaf texture, x:%d, y:%d, z:%d, meta:%d, block:%s", x, y, z, blockAccess.getBlockMetadata(x, y, z), block.getClass().getName()));
return true;
}
IIcon crossLeafIcon = Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite(BetterFoliageClient.leafGenerator.domainName + ":" + blockLeafIcon.getIconName()); IIcon crossLeafIcon = Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite(BetterFoliageClient.leafGenerator.domainName + ":" + blockLeafIcon.getIconName());
if (crossLeafIcon == null) { if (crossLeafIcon == null) {
return true; return true;

View File

@@ -30,7 +30,7 @@ public class RenderBlockBetterLilypad extends FakeRenderBlockAOBase implements I
// store world for later use // store world for later use
blockAccess = world; blockAccess = world;
// render grass block // render lilypad block
renderBlockLilyPad(block, x, y, z); renderBlockLilyPad(block, x, y, z);
int chanceVariation = getSemiRandomFromPos(x, y, z, 0); int chanceVariation = getSemiRandomFromPos(x, y, z, 0);

View File

@@ -3,6 +3,7 @@ package mods.betterfoliage.client.render.impl;
import java.util.Random; import java.util.Random;
import mods.betterfoliage.BetterFoliage; import mods.betterfoliage.BetterFoliage;
import mods.betterfoliage.client.ShadersModIntegration;
import mods.betterfoliage.client.render.IRenderBlockDecorator; import mods.betterfoliage.client.render.IRenderBlockDecorator;
import mods.betterfoliage.client.render.IconSet; import mods.betterfoliage.client.render.IconSet;
import mods.betterfoliage.client.render.RenderBlockAOBase; import mods.betterfoliage.client.render.RenderBlockAOBase;
@@ -44,7 +45,7 @@ public class RenderBlockBetterReed extends RenderBlockAOBase implements IRenderB
// store world for later use // store world for later use
blockAccess = world; blockAccess = world;
// render grass block // render dirt block
setPassCounters(1); setPassCounters(1);
setRenderBoundsFromBlock(block); setRenderBoundsFromBlock(block);
renderStandardBlock(block, x, y, z); renderStandardBlock(block, x, y, z);
@@ -59,6 +60,9 @@ public class RenderBlockBetterReed extends RenderBlockAOBase implements IRenderB
double quarterHeight = 0.25 * (BetterFoliage.config.reedHeightMin.value + pRand[heightVariation] * (BetterFoliage.config.reedHeightMax.value - BetterFoliage.config.reedHeightMin.value)); double quarterHeight = 0.25 * (BetterFoliage.config.reedHeightMin.value + pRand[heightVariation] * (BetterFoliage.config.reedHeightMax.value - BetterFoliage.config.reedHeightMin.value));
Tessellator.instance.setBrightness(getBrightness(block, x, y + 2, z)); Tessellator.instance.setBrightness(getBrightness(block, x, y + 2, z));
Tessellator.instance.setColorOpaque(255, 255, 255); Tessellator.instance.setColorOpaque(255, 255, 255);
// render reeds
ShadersModIntegration.startGrassQuads();
renderCrossedSideQuads(new Double3(x + 0.5, y + 1.0, z + 0.5), ForgeDirection.UP, 0.5, quarterHeight, pRot[iconVariation], BetterFoliage.config.reedHOffset.value, bottomIcon, 0, true); renderCrossedSideQuads(new Double3(x + 0.5, y + 1.0, z + 0.5), ForgeDirection.UP, 0.5, quarterHeight, pRot[iconVariation], BetterFoliage.config.reedHOffset.value, bottomIcon, 0, true);
renderCrossedSideQuads(new Double3(x + 0.5, y + 1.0 + 2.0 * quarterHeight, z + 0.5), ForgeDirection.UP, 0.5, quarterHeight, pRot[iconVariation], BetterFoliage.config.reedHOffset.value, topIcon, 0, true); renderCrossedSideQuads(new Double3(x + 0.5, y + 1.0 + 2.0 * quarterHeight, z + 0.5), ForgeDirection.UP, 0.5, quarterHeight, pRot[iconVariation], BetterFoliage.config.reedHOffset.value, topIcon, 0, true);

View File

@@ -1,11 +0,0 @@
package mods.betterfoliage.client.resource;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
@SideOnly(Side.CLIENT)
public interface ILeafTextureRecognizer {
public boolean isLeafTexture(TextureAtlasSprite icon);
}

View File

@@ -2,14 +2,13 @@ package mods.betterfoliage.client.resource;
import java.io.IOException; import java.io.IOException;
import java.util.Iterator; import java.util.Iterator;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import mods.betterfoliage.BetterFoliage; import mods.betterfoliage.BetterFoliage;
import mods.betterfoliage.client.BetterFoliageClient; import mods.betterfoliage.client.BetterFoliageClient;
import mods.betterfoliage.common.util.DeobfNames;
import mods.betterfoliage.common.util.Utils; import mods.betterfoliage.common.util.Utils;
import mods.betterfoliage.loader.DeobfHelper;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.texture.IIconRegister; import net.minecraft.client.renderer.texture.IIconRegister;
@@ -20,7 +19,6 @@ import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.event.TextureStitchEvent.Post; import net.minecraftforge.client.event.TextureStitchEvent.Post;
import net.minecraftforge.client.event.TextureStitchEvent.Pre; import net.minecraftforge.client.event.TextureStitchEvent.Pre;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.Side;
@@ -40,9 +38,6 @@ public class LeafTextureGenerator extends BlockTextureGenerator implements IIcon
super("bf_leaves_autogen", new ResourceLocation("betterfoliage", "textures/blocks/missing_leaf.png")); super("bf_leaves_autogen", new ResourceLocation("betterfoliage", "textures/blocks/missing_leaf.png"));
} }
/** List of helpers which can identify leaf textures loaded by alternate means */
public List<ILeafTextureRecognizer> recognizers = Lists.newLinkedList();
public IResource getResource(ResourceLocation resourceLocation) throws IOException { public IResource getResource(ResourceLocation resourceLocation) throws IOException {
ResourceLocation original = unwrapResource(resourceLocation); ResourceLocation original = unwrapResource(resourceLocation);
@@ -92,16 +87,15 @@ public class LeafTextureGenerator extends BlockTextureGenerator implements IIcon
// enumerate all registered textures, find leaf textures among them // enumerate all registered textures, find leaf textures among them
Map<String, TextureAtlasSprite> mapAtlas = null; Map<String, TextureAtlasSprite> mapAtlas = null;
mapAtlas = Utils.getField(blockTextures, DeobfNames.TM_MRS_SRG, Map.class); mapAtlas = Utils.getField(blockTextures, DeobfHelper.transformElementSearge("mapRegisteredSprites"), Map.class);
if (mapAtlas == null) mapAtlas = Utils.getField(blockTextures, DeobfNames.TM_MRS_MCP, Map.class); if (mapAtlas == null) mapAtlas = Utils.getField(blockTextures, "mapRegisteredSprites", Map.class);
if (mapAtlas == null) { if (mapAtlas == null) {
BetterFoliage.log.warn("Failed to reflect texture atlas, textures may be missing"); BetterFoliage.log.warn("Failed to reflect texture atlas, textures may be missing");
} else { } else {
Set<String> foundLeafTextures = Sets.newHashSet(); Set<String> foundLeafTextures = Sets.newHashSet();
for (TextureAtlasSprite icon : mapAtlas.values()) for (TextureAtlasSprite icon : mapAtlas.values())
for (ILeafTextureRecognizer recognizer : recognizers) if (BetterFoliageClient.isLeafTexture(icon))
if (recognizer.isLeafTexture(icon)) foundLeafTextures.add(icon.getIconName());
foundLeafTextures.add(icon.getIconName());
for (String resourceLocation : foundLeafTextures) { for (String resourceLocation : foundLeafTextures) {
BetterFoliage.log.debug(String.format("Found non-block-registered leaf texture: %s", resourceLocation)); BetterFoliage.log.debug(String.format("Found non-block-registered leaf texture: %s", resourceLocation));
blockTextures.registerIcon(new ResourceLocation(domainName, resourceLocation).toString()); blockTextures.registerIcon(new ResourceLocation(domainName, resourceLocation).toString());

View File

@@ -39,8 +39,14 @@ public class LeafTextureResource implements IResource {
IResourceManager resourceManager = Minecraft.getMinecraft().getResourceManager(); IResourceManager resourceManager = Minecraft.getMinecraft().getResourceManager();
try { try {
// load normal leaf texture
ResourceLocation origResource = new ResourceLocation(resLeaf.getResourceDomain(), "textures/blocks/" + resLeaf.getResourcePath()); ResourceLocation origResource = new ResourceLocation(resLeaf.getResourceDomain(), "textures/blocks/" + resLeaf.getResourcePath());
if (origResource.getResourcePath().toLowerCase().endsWith("_n.png") || origResource.getResourcePath().toLowerCase().endsWith("_s.png")) {
// Don't alter ShaderMod normal and specular maps
fallbackResource = resourceManager.getResource(origResource);
return;
}
// load normal leaf texture
BufferedImage origImage = ImageIO.read(resourceManager.getResource(origResource).getInputStream()); BufferedImage origImage = ImageIO.read(resourceManager.getResource(origResource).getInputStream());
if (origImage.getWidth() != origImage.getHeight()) return; if (origImage.getWidth() != origImage.getHeight()) return;
int size = origImage.getWidth(); int size = origImage.getWidth();

View File

@@ -1,71 +0,0 @@
package mods.betterfoliage.common.util;
public class DeobfNames {
private DeobfNames() {}
/** MCP name of RenderBlocks */
public static final String RB_NAME_MCP = "net/minecraft/client/renderer/RenderBlocks";
/** Obfuscated name of RenderBlocks */
public static final String RB_NAME_OBF = "blm";
/** MCP name of RenderBlocks.blockAccess */
public static final String RB_BA_NAME_MCP = "blockAccess";
/** Obfuscated name of RenderBlocks.blockAccess */
public static final String RB_BA_NAME_OBF = "a";
/** MCP signature of RenderBlocks.blockAccess */
public static final String RB_BA_SIG_MCP = "Lnet/minecraft/world/IBlockAccess;";
/** Obfuscated signature of RenderBlocks.blockAccess */
public static final String RB_BA_SIG_OBF = "Lahl;";
/** MCP name of RenderBlocks.renderBlockByRenderType() */
public static final String RB_RBBRT_NAME_MCP = "renderBlockByRenderType";
/** Obfuscated name of RenderBlocks.renderBlockByRenderType() */
public static final String RB_RBBRT_NAME_OBF = "b";
/** MCP signature of RenderBlocks.renderBlockByRenderType() */
public static final String RB_RBBRT_SIG_MCP = "(Lnet/minecraft/block/Block;III)Z";
/** Obfuscated signature of RenderBlocks.renderBlockByRenderType() */
public static final String RB_RBBRT_SIG_OBF = "(Laji;III)Z";
/** MCP signature of BetterFoliageClient.getRenderTypeOverride() */
public static final String BFC_GRTO_SIG_MCP = "(Lnet/minecraft/world/IBlockAccess;IIILnet/minecraft/block/Block;I)I";
/** Obfuscated signature of BetterFoliageClient.getRenderTypeOverride() */
public static final String BFC_GRTO_SIG_OBF = "(Lahl;IIILaji;I)I";
/** MCP name of SimpleReloadableResourceManager.domainResourceManagers */
public static final String SRRM_DRM_MCP = "domainResourceManagers";
/** SRG name of SimpleReloadableResourceManager.domainResourceManagers */
public static final String SRRM_DRM_SRGNAME = "field_110548_a";
/** MCP name of TextureMap.mapRegisteredSprites */
public static final String TM_MRS_MCP = "mapRegisteredSprites";
/** Obfuscated name of TextureMap.mapRegisteredSprites */
public static final String TM_MRS_OBF = "bpr";
/** SRG name of TextureMap.mapRegisteredSprites */
public static final String TM_MRS_SRG = "field_110574_e";
/** MCP signature of Shaders.pushEntity() */
public static final String SHADERS_PE_SIG_MCP = "(Lnet/minecraft/client/renderer/RenderBlocks;Lnet/minecraft/block/Block;III)V";
/** Obfuscated signature of Shaders.pushEntity() */
public static final String SHADERS_PE_SIG_OBF = "(Lblm;Laji;III)V";
/** MCP signature of BetterFoliageClient.getGLSLBlockIdOverride() */
public static final String BFC_GLSLID_SIG_MCP = "(ILnet/minecraft/block/Block;)I";
/** Obfuscated signature of BetterFoliageClient.getGLSLBlockIdOverride() */
public static final String BFC_GLSLID_SIG_OBF = "(ILaji;)I";
}

View File

@@ -1,9 +1,16 @@
package mods.betterfoliage.common.util; package mods.betterfoliage.common.util;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.Map; import java.util.Map;
import com.google.common.base.Charsets;
import mods.betterfoliage.loader.DeobfHelper;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.resources.IResource; import net.minecraft.client.resources.IResource;
import net.minecraft.client.resources.IResourceManager; import net.minecraft.client.resources.IResourceManager;
@@ -18,8 +25,8 @@ public class Utils {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static Map<String, IResourceManager> getDomainResourceManagers() { public static Map<String, IResourceManager> getDomainResourceManagers() {
IResourceManager manager = Minecraft.getMinecraft().getResourceManager(); IResourceManager manager = Minecraft.getMinecraft().getResourceManager();
Map<String, IResourceManager> result = getField(manager, DeobfNames.SRRM_DRM_MCP, Map.class); Map<String, IResourceManager> result = getField(manager, "domainResourceManagers", Map.class);
if (result == null) result = getField(manager, DeobfNames.SRRM_DRM_SRGNAME, Map.class); if (result == null) result = getField(manager, DeobfHelper.transformElementSearge("domainResourceManagers"), Map.class);
return result; return result;
} }
@@ -67,4 +74,21 @@ public class Utils {
} }
return false; return false;
} }
public static void copyFromTextResource(ResourceLocation resourceLocation, File target) {
try {
IResource defaults = Minecraft.getMinecraft().getResourceManager().getResource(resourceLocation);
BufferedReader reader = new BufferedReader(new InputStreamReader(defaults.getInputStream(), Charsets.UTF_8));
FileWriter writer = new FileWriter(target);
String line = reader.readLine();
while(line != null) {
writer.write(line + System.lineSeparator());
line = reader.readLine();
}
reader.close();
writer.close();
} catch(IOException e) {
}
}
} }

View File

@@ -4,7 +4,6 @@ import java.util.Map;
import cpw.mods.fml.relauncher.IFMLLoadingPlugin; import cpw.mods.fml.relauncher.IFMLLoadingPlugin;
@IFMLLoadingPlugin.MCVersion("1.7.10")
@IFMLLoadingPlugin.TransformerExclusions({"mods.betterfoliage.loader"}) @IFMLLoadingPlugin.TransformerExclusions({"mods.betterfoliage.loader"})
public class BetterFoliageLoader implements IFMLLoadingPlugin { public class BetterFoliageLoader implements IFMLLoadingPlugin {

View File

@@ -1,7 +1,5 @@
package mods.betterfoliage.loader; package mods.betterfoliage.loader;
import mods.betterfoliage.common.util.DeobfNames;
import org.objectweb.asm.Opcodes; import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.FieldInsnNode; import org.objectweb.asm.tree.FieldInsnNode;
@@ -9,40 +7,49 @@ import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.VarInsnNode; import org.objectweb.asm.tree.VarInsnNode;
import com.google.common.collect.ImmutableList;
import cpw.mods.fml.relauncher.FMLInjectionData;
public class BetterFoliageTransformer extends EZTransformerBase { public class BetterFoliageTransformer extends EZTransformerBase {
public BetterFoliageTransformer() {
String mcVersion = FMLInjectionData.data()[4].toString();
if (!ImmutableList.<String>of("1.7.2", "1.7.10").contains(mcVersion))
logger.warn(String.format("Unsupported Minecraft version %s", mcVersion));
DeobfHelper.init();
}
@MethodTransform(className="net.minecraft.client.renderer.RenderBlocks", @MethodTransform(className="net.minecraft.client.renderer.RenderBlocks",
obf=@MethodMatch(name=DeobfNames.RB_RBBRT_NAME_OBF, signature=DeobfNames.RB_RBBRT_SIG_OBF), methodName="renderBlockByRenderType",
deobf=@MethodMatch(name=DeobfNames.RB_RBBRT_NAME_MCP, signature=DeobfNames.RB_RBBRT_SIG_MCP), signature="(Lnet/minecraft/block/Block;III)Z",
log="Applying RenderBlocks.renderBlockByRenderType() render type ovverride") log="Applying RenderBlocks.renderBlockByRenderType() render type ovverride")
public void handleRenderBlockOverride(MethodNode method, boolean obf) { public void handleRenderBlockOverride(MethodNode method) {
AbstractInsnNode invokeGetRenderType = findNext(method.instructions.getFirst(), matchInvokeAny()); AbstractInsnNode invokeGetRenderType = findNext(method.instructions.getFirst(), matchInvokeAny());
AbstractInsnNode storeRenderType = findNext(invokeGetRenderType, matchOpcode(Opcodes.ISTORE)); AbstractInsnNode storeRenderType = findNext(invokeGetRenderType, matchOpcode(Opcodes.ISTORE));
insertAfter(method.instructions, storeRenderType, insertAfter(method.instructions, storeRenderType,
new VarInsnNode(Opcodes.ALOAD, 0), new VarInsnNode(Opcodes.ALOAD, 0),
obf ? new FieldInsnNode(Opcodes.GETFIELD, DeobfNames.RB_NAME_OBF, DeobfNames.RB_BA_NAME_OBF, DeobfNames.RB_BA_SIG_OBF) : new FieldInsnNode(Opcodes.GETFIELD, className("net/minecraft/client/renderer/RenderBlocks"), element("blockAccess"), signature("Lnet/minecraft/world/IBlockAccess;")),
new FieldInsnNode(Opcodes.GETFIELD, DeobfNames.RB_NAME_MCP, DeobfNames.RB_BA_NAME_MCP, DeobfNames.RB_BA_SIG_MCP),
new VarInsnNode(Opcodes.ILOAD, 2), new VarInsnNode(Opcodes.ILOAD, 2),
new VarInsnNode(Opcodes.ILOAD, 3), new VarInsnNode(Opcodes.ILOAD, 3),
new VarInsnNode(Opcodes.ILOAD, 4), new VarInsnNode(Opcodes.ILOAD, 4),
new VarInsnNode(Opcodes.ALOAD, 1), new VarInsnNode(Opcodes.ALOAD, 1),
new VarInsnNode(Opcodes.ILOAD, 5), new VarInsnNode(Opcodes.ILOAD, 5),
obf ? new MethodInsnNode(Opcodes.INVOKESTATIC, "mods/betterfoliage/client/BetterFoliageClient", "getRenderTypeOverride", DeobfNames.BFC_GRTO_SIG_OBF) : new MethodInsnNode(Opcodes.INVOKESTATIC, "mods/betterfoliage/client/BetterFoliageClient", "getRenderTypeOverride", signature("(Lnet/minecraft/world/IBlockAccess;IIILnet/minecraft/block/Block;I)I")),
new MethodInsnNode(Opcodes.INVOKESTATIC, "mods/betterfoliage/client/BetterFoliageClient", "getRenderTypeOverride", DeobfNames.BFC_GRTO_SIG_MCP),
new VarInsnNode(Opcodes.ISTORE, 5) new VarInsnNode(Opcodes.ISTORE, 5)
); );
} }
@MethodTransform(className="shadersmodcore.client.Shaders", @MethodTransform(className="shadersmodcore.client.Shaders",
obf=@MethodMatch(name="pushEntity", signature=DeobfNames.SHADERS_PE_SIG_OBF), methodName="pushEntity",
deobf=@MethodMatch(name="pushEntity", signature=DeobfNames.SHADERS_PE_SIG_MCP), signature="(Lnet/minecraft/client/renderer/RenderBlocks;Lnet/minecraft/block/Block;III)V",
log="Applying Shaders.pushEntity() block id ovverride") log="Applying Shaders.pushEntity() block id ovverride")
public void handleGLSLBlockIDOverride(MethodNode method, boolean obf) { public void handleGLSLBlockIDOverride(MethodNode method) {
AbstractInsnNode arrayStore = findNext(method.instructions.getFirst(), matchOpcode(Opcodes.IASTORE)); AbstractInsnNode arrayStore = findNext(method.instructions.getFirst(), matchOpcode(Opcodes.IASTORE));
insertAfter(method.instructions, arrayStore.getPrevious(), insertAfter(method.instructions, arrayStore.getPrevious(),
new VarInsnNode(Opcodes.ALOAD, 1), new VarInsnNode(Opcodes.ALOAD, 1),
obf ? new MethodInsnNode(Opcodes.INVOKESTATIC, "mods/betterfoliage/client/BetterFoliageClient", "getGLSLBlockIdOverride", DeobfNames.BFC_GLSLID_SIG_OBF) : new MethodInsnNode(Opcodes.INVOKESTATIC, "mods/betterfoliage/client/ShadersModIntegration", "getBlockIdOverride", signature("(ILnet/minecraft/block/Block;)I"))
new MethodInsnNode(Opcodes.INVOKESTATIC, "mods/betterfoliage/client/BetterFoliageClient", "getGLSLBlockIdOverride", DeobfNames.BFC_GLSLID_SIG_MCP)
); );
} }
} }

View File

@@ -0,0 +1,62 @@
package mods.betterfoliage.loader;
import java.util.Map;
import com.google.common.collect.Maps;
import cpw.mods.fml.relauncher.FMLInjectionData;
public class DeobfHelper {
private static Map<String, String> obfClasses = Maps.newHashMap();
private static Map<String, String> obfElements = Maps.newHashMap();
private static Map<String, String> srgElements = Maps.newHashMap();
public static void init() {
String mcVersion = FMLInjectionData.data()[4].toString();
srgElements.put("domainResourceManagers", "field_110548_a");
srgElements.put("mapRegisteredSprites", "field_110574_e");
if ("1.7.2".equals(mcVersion)) {
obfClasses.put("net/minecraft/client/renderer/RenderBlocks", "ble");
obfClasses.put("net/minecraft/world/IBlockAccess", "afx");
obfClasses.put("net/minecraft/block/Block", "ahu");
obfElements.put("blockAccess", "a");
obfElements.put("renderBlockByRenderType", "b");
obfElements.put("mapRegisteredSprites", "bpr");
} else if ("1.7.10".equals(mcVersion)) {
obfClasses.put("net/minecraft/client/renderer/RenderBlocks", "blm");
obfClasses.put("net/minecraft/world/IBlockAccess", "ahl");
obfClasses.put("net/minecraft/block/Block", "aji");
obfElements.put("blockAccess", "a");
obfElements.put("renderBlockByRenderType", "b");
obfElements.put("mapRegisteredSprites", "bpr");
}
}
public static String transformClassName(String className) {
return obfClasses.containsKey(className) ? obfClasses.get(className) : className;
}
public static String transformElementName(String elementName) {
return obfElements.containsKey(elementName) ? obfElements.get(elementName) : elementName;
}
public static String transformElementSearge(String elementName) {
return srgElements.containsKey(elementName) ? srgElements.get(elementName) : elementName;
}
public static String transformSignature(String signature) {
String result = signature;
boolean hasChanged = false;
do {
hasChanged = false;
for (Map.Entry<String, String> entry : obfClasses.entrySet()) if (result.contains("L" + entry.getKey() + ";")) {
result = result.replace("L" + entry.getKey() + ";", "L" + entry.getValue() + ";");
hasChanged = true;
}
} while(hasChanged);
return result;
}
}

View File

@@ -24,23 +24,19 @@ public class EZTransformerBase implements IClassTransformer {
public boolean matches(AbstractInsnNode node); public boolean matches(AbstractInsnNode node);
} }
@Retention(RetentionPolicy.RUNTIME)
public static @interface MethodMatch {
public String name();
public String signature();
}
@Target(ElementType.METHOD) @Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public static @interface MethodTransform { public static @interface MethodTransform {
public String className(); public String className();
public MethodMatch deobf(); public String methodName();
public MethodMatch obf(); public String signature();
public String log(); public String log();
} }
protected Logger logger = LogManager.getLogger(getClass().getSimpleName()); protected Logger logger = LogManager.getLogger(getClass().getSimpleName());
protected Boolean isObfuscated;
public byte[] transform(String name, String transformedName, byte[] basicClass) { public byte[] transform(String name, String transformedName, byte[] basicClass) {
// ??? // ???
if (basicClass == null) return null; if (basicClass == null) return null;
@@ -53,30 +49,44 @@ public class EZTransformerBase implements IClassTransformer {
for (Method classMethod : getClass().getMethods()) { for (Method classMethod : getClass().getMethods()) {
// check for annotated method with correct signature // check for annotated method with correct signature
MethodTransform annot = classMethod.getAnnotation(MethodTransform.class); String aClassName = null;
if (annot == null) continue; String aMethodName = null;
if (classMethod.getParameterTypes().length != 2) continue; String aSignature = null;
String aLog = null;
synchronized (this) {
MethodTransform annotation = classMethod.getAnnotation(MethodTransform.class);
if (annotation != null) {
aClassName = annotation.className();
aMethodName = annotation.methodName();
aSignature = annotation.signature();
aLog = annotation.log();
}
}
if (aClassName == null) continue;
if (classMethod.getParameterTypes().length != 1) continue;
if (!classMethod.getParameterTypes()[0].equals(MethodNode.class)) continue; if (!classMethod.getParameterTypes()[0].equals(MethodNode.class)) continue;
if (!classMethod.getParameterTypes()[1].equals(boolean.class)) continue;
// try to find specified method in class // try to find specified method in class
if (!transformedName.equals(annot.className())) continue; if (!transformedName.equals(aClassName)) continue;
logger.debug(String.format("Found class: %s -> %s", name, transformedName));
for (MethodNode methodNode : classNode.methods) { for (MethodNode methodNode : classNode.methods) {
Boolean obf = null; logger.trace(String.format("Checking method: %s, sig: %s", methodNode.name, methodNode.desc));
if (methodNode.name.equals(annot.obf().name()) && methodNode.desc.equals(annot.obf().signature())) { isObfuscated = null;
obf = true; if (methodNode.name.equals(DeobfHelper.transformElementName(aMethodName)) && methodNode.desc.equals(DeobfHelper.transformSignature(aSignature))) {
} else if (methodNode.name.equals(annot.deobf().name()) && methodNode.desc.equals(annot.deobf().signature())) { isObfuscated = true;
obf = false; } else if (methodNode.name.equals(aMethodName) && methodNode.desc.equals(aSignature)) {
isObfuscated = false;
} }
if (obf != null) { if (isObfuscated != null) {
// transform // transform
hasTransformed = true; hasTransformed = true;
try { try {
classMethod.invoke(this, new Object[] {methodNode, obf}); classMethod.invoke(this, new Object[] {methodNode});
logger.info(String.format("%s: SUCCESS", annot.log())); logger.info(String.format("%s: SUCCESS", aLog));
} catch (Exception e) { } catch (Exception e) {
logger.info(String.format("%s: FAILURE", annot.log())); logger.info(String.format("%s: FAILURE", aLog));
} }
break; break;
} }
@@ -89,6 +99,18 @@ public class EZTransformerBase implements IClassTransformer {
return !hasTransformed ? basicClass : writer.toByteArray(); return !hasTransformed ? basicClass : writer.toByteArray();
} }
protected String className(String className) {
return isObfuscated ? DeobfHelper.transformClassName(className) : className;
}
protected String element(String fieldName) {
return isObfuscated ? DeobfHelper.transformElementName(fieldName) : fieldName;
}
protected String signature(String signature) {
return isObfuscated ? DeobfHelper.transformSignature(signature) : signature;
}
protected AbstractInsnNode findNext(AbstractInsnNode start, IInstructionMatch match) { protected AbstractInsnNode findNext(AbstractInsnNode start, IInstructionMatch match) {
AbstractInsnNode current = start; AbstractInsnNode current = start;
while(current != null) { while(current != null) {

View File

@@ -0,0 +1,35 @@
// Vanilla
net.minecraft.block.BlockTallGrass
net.minecraft.block.BlockCrops
net.minecraft.block.BlockReed
net.minecraft.block.BlockDoublePlant
-net.minecraft.block.BlockCarrot
-net.minecraft.block.BlockPotato
// Biomes O'Plenty
biomesoplenty.common.blocks.BlockBOPFlower
biomesoplenty.common.blocks.BlockBOPFlower2
// Tinkers' Construct
tconstruct.blocks.slime.SlimeTallGrass
// Plant Mega Pack
plantmegapack.block.PMPBlockBerrybush
plantmegapack.block.PMPBlockCrops
plantmegapack.block.PMPBlockDesert
plantmegapack.block.PMPBlockFern
plantmegapack.block.PMPBlockFlowerMulti
plantmegapack.block.PMPBlockFlowerSingle
plantmegapack.block.PMPBlockForest
plantmegapack.block.PMPBlockGrass
plantmegapack.block.PMPBlockJungle
plantmegapack.block.PMPBlockMountain
plantmegapack.block.PMPBlockSavanna
plantmegapack.block.PMPBlockShrub
plantmegapack.block.PMPBlockWetlands
// Pam's HarvestCraft
com.pam.harvestcraft.BlockPamCrop
com.pam.harvestcraft.BlockPamDesertGarden
com.pam.harvestcraft.BlockPamNormalGarden
com.pam.harvestcraft.BlockPamWaterGarden

View File

@@ -0,0 +1,4 @@
net.minecraft.block.BlockLeavesBase
forestry.arboriculture.gadgets.BlockLeaves
thaumcraft.common.blocks.BlockMagicalLeaves
-tconstruct.blocks.OreberryBushEssence