Compare commits

...

24 Commits

Author SHA1 Message Date
octarine-noise
bd4a4885fe bump version 2014-07-28 22:04:14 +02:00
octarine-noise
9d59105af1 don't crash coral rendering if textures are missing 2014-07-28 22:03:58 +02:00
octarine-noise
7cdddef1bf new feature: snowed grass 2014-07-28 21:52:23 +02:00
octarine-noise
168fad883d new feature: coral 2014-07-28 20:32:40 +02:00
octarine-noise
572d517828 tweak short grass texture offset 2014-07-28 18:12:20 +02:00
octarine-noise
d4963ec173 new feature: generate short grass texture 2014-07-28 18:06:09 +02:00
octarine-noise
ad83a511fb slightly more robust leaf texture generation 2014-07-27 23:42:22 +02:00
octarine-noise
e351af2369 get rid of annotations in class transformer 2014-07-27 23:38:40 +02:00
octarine-noise
32a88fa824 Update README.md 2014-07-26 10:49:51 +02:00
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
33 changed files with 794 additions and 395 deletions

View File

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

View File

@@ -20,9 +20,9 @@ minecraft {
version = '1.7.2-10.12.2.1147'
}
jar.baseName = 'BetterFoliage-1.7.2'
jar.baseName = 'BetterFoliage'
group = 'com.github.octarine-noise'
version='0.9.5b'
version='0.9.8b'
processResources {
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_NAME = "Better Foliage";
public static final String MC_VERSIONS = "[1.7.2]";
public static final String MC_VERSIONS = "[1.7.2,1.7.10]";
public static final String GUI_FACTORY = "mods.betterfoliage.client.gui.ConfigGuiFactory";
@Mod.Instance

View File

@@ -8,25 +8,18 @@ import mods.betterfoliage.BetterFoliage;
import mods.betterfoliage.client.render.IRenderBlockDecorator;
import mods.betterfoliage.client.render.impl.RenderBlockBetterAlgae;
import mods.betterfoliage.client.render.impl.RenderBlockBetterCactus;
import mods.betterfoliage.client.render.impl.RenderBlockBetterCoral;
import mods.betterfoliage.client.render.impl.RenderBlockBetterGrass;
import mods.betterfoliage.client.render.impl.RenderBlockBetterLeaves;
import mods.betterfoliage.client.render.impl.RenderBlockBetterLilypad;
import mods.betterfoliage.client.render.impl.RenderBlockBetterReed;
import mods.betterfoliage.client.resource.BlockTextureGenerator;
import mods.betterfoliage.client.resource.HalfTextureResource;
import mods.betterfoliage.client.resource.ILeafTextureRecognizer;
import mods.betterfoliage.client.resource.LeafTextureGenerator;
import mods.betterfoliage.client.resource.ShortGrassTextureResource;
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.resources.IResource;
import net.minecraft.init.Blocks;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.IBlockAccess;
import net.minecraftforge.common.MinecraftForge;
@@ -36,13 +29,13 @@ import com.google.common.collect.Maps;
import cpw.mods.fml.client.registry.RenderingRegistry;
import cpw.mods.fml.common.FMLCommonHandler;
public class BetterFoliageClient implements ILeafTextureRecognizer {
public class BetterFoliageClient {
public static Map<Integer, IRenderBlockDecorator> decorators = Maps.newHashMap();
public static LeafTextureGenerator leafGenerator;
public static BlockMatcher leaves;
public static BlockMatcher crops;
public static BlockMatcher leaves = new BlockMatcher();
public static BlockMatcher crops = new BlockMatcher();
public static void preInit() {
FMLCommonHandler.instance().bus().register(new KeyHandler());
@@ -54,27 +47,17 @@ public class BetterFoliageClient implements ILeafTextureRecognizer {
registerRenderer(new RenderBlockBetterLilypad());
registerRenderer(new RenderBlockBetterReed());
registerRenderer(new RenderBlockBetterAlgae());
registerRenderer(new RenderBlockBetterCoral());
leaves = new BlockMatcher(BlockLeavesBase.class.getName(),
"forestry.arboriculture.gadgets.BlockLeaves",
"thaumcraft.common.blocks.BlockMagicalLeaves");
leaves.load(new File(BetterFoliage.configDir, "classesLeaves.cfg"));
leaves.load(new File(BetterFoliage.configDir, "classesLeaves.cfg"), new ResourceLocation("betterfoliage:classesLeavesDefault.cfg"));
MinecraftForge.EVENT_BUS.register(leaves);
crops = new BlockMatcher(BlockCrops.class.getName(),
"-" + BlockCarrot.class.getName(),
"-" + 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"));
crops.load(new File(BetterFoliage.configDir, "classesCrops.cfg"), new ResourceLocation("betterfoliage:classesCropsDefault.cfg"));
MinecraftForge.EVENT_BUS.register(crops);
BetterFoliage.log.info("Registering leaf texture generator");
leafGenerator = new LeafTextureGenerator();
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")) {
@Override
@@ -88,11 +71,25 @@ public class BetterFoliageClient implements ILeafTextureRecognizer {
return new HalfTextureResource(unwrapResource(var1), false, getMissingResource());
}
});
MinecraftForge.EVENT_BUS.register(new BlockTextureGenerator("bf_shortgrass", new ResourceLocation("betterfoliage", "textures/blocks/missing_leaf.png")) {
@Override
public IResource getResource(ResourceLocation var1) throws IOException {
return new ShortGrassTextureResource(unwrapResource(var1), false, getMissingResource());
}
});
MinecraftForge.EVENT_BUS.register(new BlockTextureGenerator("bf_shortgrass_snow", new ResourceLocation("betterfoliage", "textures/blocks/missing_leaf.png")) {
@Override
public IResource getResource(ResourceLocation var1) throws IOException {
return new ShortGrassTextureResource(unwrapResource(var1), true, getMissingResource());
}
});
MinecraftForge.EVENT_BUS.register(new BetterFoliageClient());
ShadersModIntegration.init();
}
public boolean isLeafTexture(TextureAtlasSprite icon) {
public static boolean isLeafTexture(TextureAtlasSprite icon) {
String resourceLocation = icon.getIconName();
if (resourceLocation.startsWith("forestry:leaves/")) return true;
return false;
@@ -109,14 +106,6 @@ public class BetterFoliageClient implements ILeafTextureRecognizer {
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) {
int renderId = RenderingRegistry.getNextAvailableRenderId();
decorators.put(renderId, decorator);

View File

@@ -2,16 +2,15 @@ package mods.betterfoliage.client;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Iterator;
import java.util.Set;
import mods.betterfoliage.BetterFoliage;
import mods.betterfoliage.common.util.Utils;
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 com.google.common.collect.Sets;
@@ -20,35 +19,22 @@ import cpw.mods.fml.common.eventhandler.SubscribeEvent;
public class BlockMatcher {
public Set<String> whiteList = Sets.newHashSet();
public Set<String> blackList = Sets.newHashSet();
public Set<Class<?>> whiteList = Sets.newHashSet();
public Set<Class<?>> blackList = 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) {
if (className.startsWith("-"))
blackList.add(className.substring(1));
else
whiteList.add(className);
try {
if (className.startsWith("-"))
blackList.add(Class.forName(className.substring(1)));
else
whiteList.add(Class.forName(className));
} catch(ClassNotFoundException e) {}
}
public boolean matchesClass(Block block) {
for (String className : blackList) {
try {
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) {}
}
for (Class<?> clazz : blackList) if (clazz.isAssignableFrom(block.getClass())) return false;
for (Class<?> clazz : whiteList) if (clazz.isAssignableFrom(block.getClass())) return true;
return false;
}
@@ -60,7 +46,9 @@ public class BlockMatcher {
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;
try {
reader = new BufferedReader(new FileReader(file));
@@ -72,40 +60,19 @@ public class BlockMatcher {
line = reader.readLine();
}
reader.close();
} catch (FileNotFoundException e) {
saveDefaults(file);
} catch (IOException e) {
} catch (Exception e) {
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
* @param event
*/
@SuppressWarnings("unchecked")
@SubscribeEvent
public void handleWorldLoad(WorldEvent.Load event) {
if (!(event.world instanceof WorldClient)) return;
blockIDs.clear();
Iterator<Block> iter = Block.blockRegistry.iterator();
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

@@ -0,0 +1,34 @@
package mods.betterfoliage.client.gui;
import cpw.mods.fml.client.FMLClientHandler;
import mods.betterfoliage.BetterFoliage;
import mods.betterfoliage.client.gui.widget.OptionDoubleWidget;
import mods.betterfoliage.client.gui.widget.OptionIntegerWidget;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.resources.I18n;
public class ConfigGuiCoral extends ConfigGuiScreenBase {
public ConfigGuiCoral(GuiScreen parent) {
super(parent);
int id = 10;
widgets.add(new OptionDoubleWidget(BetterFoliage.config.coralCrustSize, -100, -100, 200, 50, id++, id++, "message.betterfoliage.crustSize", "%.2f"));
widgets.add(new OptionDoubleWidget(BetterFoliage.config.coralVOffset, -100, -70, 200, 50, id++, id++, "message.betterfoliage.vOffset", "%.3f"));
widgets.add(new OptionDoubleWidget(BetterFoliage.config.coralSize, -100, -40, 200, 50, id++, id++, "message.betterfoliage.size", "%.2f"));
widgets.add(new OptionDoubleWidget(BetterFoliage.config.coralHOffset, -100, -10, 200, 50, id++, id++, "message.betterfoliage.hOffset", "%.3f"));
widgets.add(new OptionIntegerWidget(BetterFoliage.config.coralPopulation, -100, 20, 200, 50, id++, id++, "message.betterfoliage.coralPopulation"));
widgets.add(new OptionIntegerWidget(BetterFoliage.config.coralChance, -100, 50, 200, 50, id++, id++, "message.betterfoliage.coralChance"));
}
@SuppressWarnings("unchecked")
@Override
public void addButtons(int x, int y) {
buttonList.add(new GuiButton(0, x - 50, y + 80, 100, 20, I18n.format("message.betterfoliage.back")));
}
@Override
protected void onButtonPress(int id) {
if (id == 0) FMLClientHandler.instance().showGuiScreen(parent);
}
}

View File

@@ -9,24 +9,32 @@ import cpw.mods.fml.client.FMLClientHandler;
public class ConfigGuiGrass extends ConfigGuiScreenBase {
public enum Button {CLOSE, GRASS_USE_GENERATED}
public ConfigGuiGrass(GuiScreen parent) {
super(parent);
int id = 10;
widgets.add(new OptionDoubleWidget(BetterFoliage.config.grassSize, -100, -70, 200, 50, id++, id++, "message.betterfoliage.size", "%.2f"));
widgets.add(new OptionDoubleWidget(BetterFoliage.config.grassHOffset, -100, -40, 200, 50, id++, id++, "message.betterfoliage.hOffset", "%.3f"));
widgets.add(new OptionDoubleWidget(BetterFoliage.config.grassHeightMin, -100, -10, 200, 50, id++, id++, "message.betterfoliage.minHeight", "%.2f"));
widgets.add(new OptionDoubleWidget(BetterFoliage.config.grassHeightMax, -100, 20, 200, 50, id++, id++, "message.betterfoliage.maxHeight", "%.2f"));
widgets.add(new OptionDoubleWidget(BetterFoliage.config.grassHOffset, -100, -10, 200, 50, id++, id++, "message.betterfoliage.hOffset", "%.3f"));
widgets.add(new OptionDoubleWidget(BetterFoliage.config.grassHeightMin, -100, 20, 200, 50, id++, id++, "message.betterfoliage.minHeight", "%.2f"));
widgets.add(new OptionDoubleWidget(BetterFoliage.config.grassHeightMax, -100, 50, 200, 50, id++, id++, "message.betterfoliage.maxHeight", "%.2f"));
}
@SuppressWarnings("unchecked")
@Override
public void addButtons(int x, int y) {
buttonList.add(new GuiButton(0, x - 50, y + 50, 100, 20, I18n.format("message.betterfoliage.back")));
buttonList.add(new GuiButton(Button.CLOSE.ordinal(), x - 50, y + 80, 100, 20, I18n.format("message.betterfoliage.back")));
buttonList.add(new GuiButton(Button.GRASS_USE_GENERATED.ordinal(), x - 100, y - 40, 200, 20, ""));
}
protected void updateButtons() {
setButtonOptionBoolean(Button.GRASS_USE_GENERATED.ordinal(), "message.betterfoliage.genShortgrass", BetterFoliage.config.grassUseGenerated);
}
@Override
protected void onButtonPress(int id) {
if (id == 0) FMLClientHandler.instance().showGuiScreen(parent);
if (id == Button.CLOSE.ordinal()) FMLClientHandler.instance().showGuiScreen(parent);
if (id == Button.GRASS_USE_GENERATED.ordinal()) BetterFoliage.config.grassUseGenerated = !BetterFoliage.config.grassUseGenerated;
if (BetterFoliage.config.grassHeightMin.value > BetterFoliage.config.grassHeightMax.value) BetterFoliage.config.grassHeightMin.value = BetterFoliage.config.grassHeightMax.value;
}

View File

@@ -18,7 +18,8 @@ public class ConfigGuiMain extends ConfigGuiScreenBase {
TOGGLE_CACTUS, CONFIG_CACTUS,
TOGGLE_LILYPAD, CONFIG_LILYPAD,
TOGGLE_REED, CONFIG_REED,
TOGGLE_ALGAE, CONFIG_ALGAE}
TOGGLE_ALGAE, CONFIG_ALGAE,
TOGGLE_CORAL, CONFIG_CORAL}
public ConfigGuiMain(GuiScreen parent) {
super(parent);
@@ -28,7 +29,7 @@ public class ConfigGuiMain extends ConfigGuiScreenBase {
@SuppressWarnings("unchecked")
@Override
protected void addButtons(int x, int y) {
buttonList.add(new GuiButton(Button.CLOSE.ordinal(), x - 50, y + 80, 100, 20, I18n.format("message.betterfoliage.close")));
buttonList.add(new GuiButton(Button.CLOSE.ordinal(), x - 50, y + 110, 100, 20, I18n.format("message.betterfoliage.close")));
buttonList.add(new GuiButton(Button.TOGGLE_LEAVES.ordinal(), x - 100, y - 100, 150, 20, ""));
buttonList.add(new GuiButton(Button.CONFIG_LEAVES.ordinal(), x + 60, y - 100, 40, 20, I18n.format("message.betterfoliage.config")));
@@ -47,6 +48,9 @@ public class ConfigGuiMain extends ConfigGuiScreenBase {
buttonList.add(new GuiButton(Button.TOGGLE_ALGAE.ordinal(), x - 100, y + 50, 150, 20, ""));
buttonList.add(new GuiButton(Button.CONFIG_ALGAE.ordinal(), x + 60, y + 50, 40, 20, I18n.format("message.betterfoliage.config")));
buttonList.add(new GuiButton(Button.TOGGLE_CORAL.ordinal(), x - 100, y + 80, 150, 20, ""));
buttonList.add(new GuiButton(Button.CONFIG_CORAL.ordinal(), x + 60, y + 80, 40, 20, I18n.format("message.betterfoliage.config")));
}
protected void updateButtons() {
@@ -56,6 +60,7 @@ public class ConfigGuiMain extends ConfigGuiScreenBase {
setButtonOptionBoolean(Button.TOGGLE_LILYPAD.ordinal(), "message.betterfoliage.betterLilypad", BetterFoliage.config.lilypadEnabled);
setButtonOptionBoolean(Button.TOGGLE_REED.ordinal(), "message.betterfoliage.betterReed", BetterFoliage.config.reedEnabled);
setButtonOptionBoolean(Button.TOGGLE_ALGAE.ordinal(), "message.betterfoliage.betterAlgae", BetterFoliage.config.algaeEnabled);
setButtonOptionBoolean(Button.TOGGLE_CORAL.ordinal(), "message.betterfoliage.betterCoral", BetterFoliage.config.coralEnabled);
((GuiButton) buttonList.get(Button.CONFIG_CACTUS.ordinal())).enabled = false;
}
@@ -72,12 +77,14 @@ public class ConfigGuiMain extends ConfigGuiScreenBase {
if (id == Button.TOGGLE_LILYPAD.ordinal()) BetterFoliage.config.lilypadEnabled = !BetterFoliage.config.lilypadEnabled;
if (id == Button.TOGGLE_REED.ordinal()) BetterFoliage.config.reedEnabled = !BetterFoliage.config.reedEnabled;
if (id == Button.TOGGLE_ALGAE.ordinal()) BetterFoliage.config.algaeEnabled = !BetterFoliage.config.algaeEnabled;
if (id == Button.TOGGLE_CORAL.ordinal()) BetterFoliage.config.coralEnabled = !BetterFoliage.config.coralEnabled;
if (id== Button.CONFIG_LEAVES.ordinal()) FMLClientHandler.instance().showGuiScreen(new ConfigGuiLeaves(this));
if (id== Button.CONFIG_GRASS.ordinal()) FMLClientHandler.instance().showGuiScreen(new ConfigGuiGrass(this));
if (id== Button.CONFIG_LILYPAD.ordinal()) FMLClientHandler.instance().showGuiScreen(new ConfigGuiLilypad(this));
if (id== Button.CONFIG_REED.ordinal()) FMLClientHandler.instance().showGuiScreen(new ConfigGuiReed(this));
if (id== Button.CONFIG_ALGAE.ordinal()) FMLClientHandler.instance().showGuiScreen(new ConfigGuiAlgae(this));
if (id== Button.CONFIG_CORAL.ordinal()) FMLClientHandler.instance().showGuiScreen(new ConfigGuiCoral(this));
}
}

View File

@@ -37,6 +37,9 @@ public class RenderBlockAOBase extends RenderBlocks {
public float red;
public float green;
public float blue;
public void setGray(float value) {
red = value; green = value; blue = value;
}
}
protected double[] uValues = new double[] {0.0, 16.0, 16.0, 0.0};

View File

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

View File

@@ -0,0 +1,98 @@
package mods.betterfoliage.client.render.impl;
import java.util.Random;
import mods.betterfoliage.BetterFoliage;
import mods.betterfoliage.client.render.IRenderBlockDecorator;
import mods.betterfoliage.client.render.IconSet;
import mods.betterfoliage.client.render.RenderBlockAOBase;
import mods.betterfoliage.common.util.Double3;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.RenderBlocks;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.init.Blocks;
import net.minecraft.util.IIcon;
import net.minecraft.util.MathHelper;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.gen.NoiseGeneratorSimplex;
import net.minecraftforge.client.event.TextureStitchEvent;
import net.minecraftforge.common.util.ForgeDirection;
import net.minecraftforge.event.world.WorldEvent;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
public class RenderBlockBetterCoral extends RenderBlockAOBase implements IRenderBlockDecorator {
public IconSet coralCrustIcons = new IconSet("bettergrassandleaves", "better_crust_%d");
public IconSet coralCrossIcons = new IconSet("bettergrassandleaves", "better_coral_%d");
public NoiseGeneratorSimplex noise;
public boolean isBlockAccepted(IBlockAccess blockAccess, int x, int y, int z, Block block, int original) {
if (!BetterFoliage.config.coralEnabled) return false;
if (block != Blocks.sand) return false;
int terrainVariation = MathHelper.floor_double((noise.func_151605_a(x * 0.1, z * 0.1) + 1.0) * 32.0);
return terrainVariation < BetterFoliage.config.coralPopulation.value;
}
public boolean renderWorldBlock(IBlockAccess world, int x, int y, int z, Block block, int modelId, RenderBlocks renderer) {
// store world for later use
blockAccess = world;
// render sand block
setPassCounters(1);
setRenderBoundsFromBlock(block);
renderStandardBlock(block, x, y, z);
Double3 blockCenter = new Double3(x + 0.5, y + 0.5, z + 0.5);
double offset = pRand[getSemiRandomFromPos(x, y, z, 6)] * BetterFoliage.config.coralVOffset.value;
double halfSize = BetterFoliage.config.coralSize.value * 0.5;
double halfCrustSize = BetterFoliage.config.coralCrustSize.value * 0.5;
Tessellator.instance.setBrightness(getBrightness(block, x, y, z));
for (ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) {
if (blockAccess.getBlock(x + dir.offsetX, y + dir.offsetY, z + dir.offsetZ).getMaterial() != Material.water) continue;
if (blockAccess.isAirBlock(x + dir.offsetX, y + dir.offsetY + 1, z + dir.offsetZ)) continue;
int variation = getSemiRandomFromPos(x, y, z, dir.ordinal());
if (variation < BetterFoliage.config.coralChance.value) {
IIcon crustIcon = coralCrustIcons.get(variation);
IIcon coralIcon = coralCrossIcons.get(variation);
if (crustIcon != null) renderCoralCrust(blockCenter, dir, offset, halfCrustSize, crustIcon, variation);
if (coralIcon != null) renderCrossedSideQuads(blockCenter.add(new Double3(dir).scale(0.5)), dir,
halfSize, halfSize,
pRot[variation], BetterFoliage.config.coralHOffset.value,
coralIcon, 0, false);
}
}
return true;
}
protected void renderCoralCrust(Double3 blockCenter, ForgeDirection dir, double offset, double scale, IIcon icon, int uvRot) {
Double3 face1 = new Double3(faceDir1[dir.ordinal()]).scale(scale);
Double3 face2 = new Double3(faceDir2[dir.ordinal()]).scale(scale);
Double3 drawCenter = blockCenter.add(new Double3(dir).scale(0.5 + offset));
if (Minecraft.isAmbientOcclusionEnabled()) {
setShadingForFace(dir);
renderQuadWithShading(icon, drawCenter, face1, face2, uvRot, faceAOPP, faceAONP, faceAONN, faceAOPN);
} else {
renderQuad(icon, drawCenter, face1, face2, uvRot);
}
}
@SubscribeEvent
public void handleTextureReload(TextureStitchEvent.Pre event) {
if (event.map.getTextureType() != 0) return;
coralCrustIcons.registerIcons(event.map);
coralCrossIcons.registerIcons(event.map);
BetterFoliage.log.info(String.format("Found %d coral crust textures", coralCrustIcons.numLoaded));
BetterFoliage.log.info(String.format("Found %d coral textures", coralCrossIcons.numLoaded));
}
@SubscribeEvent
public void handleWorldLoad(WorldEvent.Load event) {
noise = new NoiseGeneratorSimplex(new Random(event.world.getWorldInfo().getSeed() + 2));
}
}

View File

@@ -1,6 +1,7 @@
package mods.betterfoliage.client.render.impl;
import mods.betterfoliage.BetterFoliage;
import mods.betterfoliage.client.ShadersModIntegration;
import mods.betterfoliage.client.render.IRenderBlockDecorator;
import mods.betterfoliage.client.render.IconSet;
import mods.betterfoliage.client.render.RenderBlockAOBase;
@@ -22,13 +23,15 @@ import cpw.mods.fml.relauncher.SideOnly;
public class RenderBlockBetterGrass extends RenderBlockAOBase implements IRenderBlockDecorator {
public IconSet grassIcons = new IconSet("bettergrassandleaves", "better_grass_long_%d");
public IconSet snowGrassIcons = new IconSet("bettergrassandleaves", "better_grass_snowed_%d");
public IconSet myceliumIcons = new IconSet("bettergrassandleaves", "better_mycel_%d");
public IIcon grassGenIcon;
public IIcon snowGrassGenIcon;
public boolean isBlockAccepted(IBlockAccess blockAccess, int x, int y, int z, Block block, int original) {
if (!BetterFoliage.config.grassEnabled) return false;
if (!((block instanceof BlockGrass || block == Blocks.mycelium))) return false;
if (y == 255 || !blockAccess.isAirBlock(x, y + 1, z)) return false;
if (!blockAccess.isAirBlock(x, y + 1, z) && blockAccess.getBlock(x, y + 1, z) != Blocks.snow_layer) return false;
return true;
}
@@ -43,14 +46,32 @@ public class RenderBlockBetterGrass extends RenderBlockAOBase implements IRender
int variation = getSemiRandomFromPos(x, y, z, 0);
int heightVariation = getSemiRandomFromPos(x, y, z, 1);
boolean isSnowed = blockAccess.getBlock(x, y + 1, z) == Blocks.snow_layer;
IIcon renderIcon = (block == Blocks.mycelium) ? myceliumIcons.get(variation) : grassIcons.get(variation);
IIcon renderIcon = null;
if (block instanceof BlockGrass) {
if (BetterFoliage.config.grassUseGenerated) {
renderIcon = isSnowed ? snowGrassGenIcon : grassGenIcon;
} else {
renderIcon = isSnowed ? snowGrassIcons.get(variation) : grassIcons.get(variation);
}
} else if (block == Blocks.mycelium && !isSnowed) {
renderIcon = myceliumIcons.get(variation);
}
if (renderIcon == null) return true;
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));
if (isSnowed) {
aoYPXZNN.setGray(0.9f); aoYPXZNP.setGray(0.9f); aoYPXZPN.setGray(0.9f); aoYPXZPP.setGray(0.9f);
Tessellator.instance.setColorOpaque(230, 230, 230);
}
// render short grass
ShadersModIntegration.startGrassQuads();
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 + (isSnowed ? 0.0625 : 0.0), z + 0.5), ForgeDirection.UP, scale, halfHeight, pRot[variation], BetterFoliage.config.grassHOffset.value, renderIcon, 0, false);
return true;
}
@@ -60,8 +81,12 @@ public class RenderBlockBetterGrass extends RenderBlockAOBase implements IRender
if (event.map.getTextureType() != 0) return;
grassIcons.registerIcons(event.map);
snowGrassIcons.registerIcons(event.map);
myceliumIcons.registerIcons(event.map);
grassGenIcon = event.map.registerIcon("bf_shortgrass:minecraft:tallgrass");
snowGrassGenIcon = event.map.registerIcon("bf_shortgrass_snow:minecraft:tallgrass");
BetterFoliage.log.info(String.format("Found %d short grass textures", grassIcons.numLoaded));
BetterFoliage.log.info(String.format("Found %d snowy grass textures", snowGrassIcons.numLoaded));
BetterFoliage.log.info(String.format("Found %d mycelium textures", myceliumIcons.numLoaded));
}

View File

@@ -45,7 +45,7 @@ public class RenderBlockBetterLeaves extends RenderBlockAOBase implements IRende
// "true" texture of the block is the one on the north size
TextureAtlasSprite blockLeafIcon = (TextureAtlasSprite) block.getIcon(world, x, y, z, ForgeDirection.NORTH.ordinal());
if (blockLeafIcon == null) {
BetterFoliage.log.warn(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()));
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());

View File

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

View File

@@ -3,6 +3,7 @@ package mods.betterfoliage.client.render.impl;
import java.util.Random;
import mods.betterfoliage.BetterFoliage;
import mods.betterfoliage.client.ShadersModIntegration;
import mods.betterfoliage.client.render.IRenderBlockDecorator;
import mods.betterfoliage.client.render.IconSet;
import mods.betterfoliage.client.render.RenderBlockAOBase;
@@ -44,7 +45,7 @@ public class RenderBlockBetterReed extends RenderBlockAOBase implements IRenderB
// store world for later use
blockAccess = world;
// render grass block
// render dirt block
setPassCounters(1);
setRenderBoundsFromBlock(block);
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));
Tessellator.instance.setBrightness(getBrightness(block, x, y + 2, z));
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 + 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,25 +2,24 @@ package mods.betterfoliage.client.resource;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import mods.betterfoliage.BetterFoliage;
import mods.betterfoliage.client.BetterFoliageClient;
import mods.betterfoliage.common.util.DeobfNames;
import mods.betterfoliage.common.util.Utils;
import mods.betterfoliage.loader.DeobfHelper;
import net.minecraft.block.Block;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.texture.IIconRegister;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.resources.IResource;
import net.minecraft.client.resources.IResourceManager;
import net.minecraft.util.IIcon;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.event.TextureStitchEvent.Post;
import net.minecraftforge.client.event.TextureStitchEvent.Pre;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import cpw.mods.fml.relauncher.Side;
@@ -40,23 +39,32 @@ public class LeafTextureGenerator extends BlockTextureGenerator implements IIcon
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 {
ResourceLocation original = unwrapResource(resourceLocation);
IResourceManager resourceManager = Minecraft.getMinecraft().getResourceManager();
ResourceLocation originalNoDirs = unwrapResource(resourceLocation);
ResourceLocation originalWithDirs = new ResourceLocation(originalNoDirs.getResourceDomain(), "textures/blocks/" + originalNoDirs.getResourcePath());
// check for provided texture
ResourceLocation handDrawnLocation = new ResourceLocation(nonGeneratedDomain, String.format("textures/blocks/%s/%s", original.getResourceDomain(), original.getResourcePath()));
ResourceLocation handDrawnLocation = new ResourceLocation(nonGeneratedDomain, String.format("textures/blocks/%s/%s", originalNoDirs.getResourceDomain(), originalNoDirs.getResourcePath()));
if (Utils.resourceExists(handDrawnLocation)) {
nonGeneratedCounter++;
return Minecraft.getMinecraft().getResourceManager().getResource(handDrawnLocation);
return resourceManager.getResource(handDrawnLocation);
}
// Don't alter ShaderMod normal and specular maps
if (originalWithDirs.getResourcePath().toLowerCase().endsWith("_n.png") || originalWithDirs.getResourcePath().toLowerCase().endsWith("_s.png")) {
resourceManager.getResource(originalWithDirs);
}
// generate our own
LeafTextureResource result = new LeafTextureResource(original, getMissingResource());
if (result.data != null) counter++;
return result;
if (!Utils.resourceExists(originalWithDirs)) return getMissingResource();
LeafTextureResource result = new LeafTextureResource(resourceManager.getResource(originalWithDirs));
if (result.data != null) {
counter++;
return result;
} else {
return getMissingResource();
}
}
/** Leaf blocks register their textures here. An extra texture will be registered in the atlas
@@ -92,16 +100,15 @@ public class LeafTextureGenerator extends BlockTextureGenerator implements IIcon
// enumerate all registered textures, find leaf textures among them
Map<String, TextureAtlasSprite> mapAtlas = null;
mapAtlas = Utils.getField(blockTextures, DeobfNames.TM_MRS_SRG, Map.class);
if (mapAtlas == null) mapAtlas = Utils.getField(blockTextures, DeobfNames.TM_MRS_MCP, Map.class);
mapAtlas = Utils.getField(blockTextures, DeobfHelper.transformElementSearge("mapRegisteredSprites"), Map.class);
if (mapAtlas == null) mapAtlas = Utils.getField(blockTextures, "mapRegisteredSprites", Map.class);
if (mapAtlas == null) {
BetterFoliage.log.warn("Failed to reflect texture atlas, textures may be missing");
} else {
Set<String> foundLeafTextures = Sets.newHashSet();
for (TextureAtlasSprite icon : mapAtlas.values())
for (ILeafTextureRecognizer recognizer : recognizers)
if (recognizer.isLeafTexture(icon))
foundLeafTextures.add(icon.getIconName());
if (BetterFoliageClient.isLeafTexture(icon))
foundLeafTextures.add(icon.getIconName());
for (String resourceLocation : foundLeafTextures) {
BetterFoliage.log.debug(String.format("Found non-block-registered leaf texture: %s", resourceLocation));
blockTextures.registerIcon(new ResourceLocation(domainName, resourceLocation).toString());

View File

@@ -4,7 +4,6 @@ import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
@@ -31,17 +30,10 @@ public class LeafTextureResource implements IResource {
/** Name of the default alpha mask to use */
public static String defaultMask = "rough";
/** Resource to return if generation fails */
public IResource fallbackResource;
public LeafTextureResource(ResourceLocation resLeaf, IResource fallbackResource) {
this.fallbackResource = fallbackResource;
IResourceManager resourceManager = Minecraft.getMinecraft().getResourceManager();
public LeafTextureResource(IResource resLeaf) {
try {
// load normal leaf texture
ResourceLocation origResource = new ResourceLocation(resLeaf.getResourceDomain(), "textures/blocks/" + resLeaf.getResourcePath());
BufferedImage origImage = ImageIO.read(resourceManager.getResource(origResource).getInputStream());
BufferedImage origImage = ImageIO.read(resLeaf.getInputStream());
if (origImage.getWidth() != origImage.getHeight()) return;
int size = origImage.getWidth();
@@ -72,7 +64,6 @@ public class LeafTextureResource implements IResource {
data = baos.toByteArray();
} catch (Exception e) {
// stop log spam with GLSL installed
if (e instanceof FileNotFoundException) return;
BetterFoliage.log.info(String.format("Could not create leaf texture: %s, exception: %s", resLeaf.toString(), e.getClass().getSimpleName()));
}
}
@@ -102,7 +93,7 @@ public class LeafTextureResource implements IResource {
}
public InputStream getInputStream() {
return data != null ? new ByteArrayInputStream(data) : fallbackResource.getInputStream();
return new ByteArrayInputStream(data);
}
public boolean hasMetadata() {

View File

@@ -0,0 +1,82 @@
package mods.betterfoliage.client.resource;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import javax.imageio.ImageIO;
import mods.betterfoliage.BetterFoliage;
import net.minecraft.client.Minecraft;
import net.minecraft.client.resources.IResource;
import net.minecraft.client.resources.IResourceManager;
import net.minecraft.client.resources.data.IMetadataSection;
import net.minecraft.util.ResourceLocation;
public class ShortGrassTextureResource implements IResource {
/** Raw PNG data*/
public byte[] data = null;
/** Resource to return if generation fails */
public IResource fallbackResource;
public ShortGrassTextureResource(ResourceLocation resource, boolean isSnowed, IResource fallbackResource) {
this.fallbackResource = fallbackResource;
boolean isSpecialTexture = resource.getResourcePath().toLowerCase().endsWith("_n.png") || resource.getResourcePath().toLowerCase().endsWith("_s.png");
IResourceManager resourceManager = Minecraft.getMinecraft().getResourceManager();
try {
// load full texture
ResourceLocation origResource = new ResourceLocation(resource.getResourceDomain(), "textures/blocks/" + resource.getResourcePath());
BufferedImage origImage = ImageIO.read(resourceManager.getResource(origResource).getInputStream());
// draw bottom half of texture
BufferedImage result = new BufferedImage(origImage.getWidth(), origImage.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D graphics = result.createGraphics();
graphics.drawImage(origImage, 0, 3 * origImage.getHeight() / 8, null);
// blend with white if snowed
if (isSnowed && !isSpecialTexture) {
for (int x = 0; x < result.getWidth(); x++) for (int y = 0; y < result.getHeight(); y++) {
result.setRGB(x, y, blend(result.getRGB(x, y), 0xFFFFFF, 2, 3));
}
}
// create PNG image
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(result, "PNG", baos);
data = baos.toByteArray();
} catch (Exception e) {
// stop log spam with GLSL installed
BetterFoliage.log.info(String.format("Could not load texture: %s, exception: %s", resource.toString(), e.getClass().getSimpleName()));
}
}
protected int blend(int rgbOrig, int rgbBlend, int weightOrig, int weightBlend) {
int r = ((rgbOrig & 0xFF) * weightOrig + (rgbBlend & 0xFF) * weightBlend) / (weightOrig + weightBlend);
int g = (((rgbOrig >> 8) & 0xFF) * weightOrig + ((rgbBlend >> 8) & 0xFF) * weightBlend) / (weightOrig + weightBlend);
int b = (((rgbOrig >> 16) & 0xFF) * weightOrig + ((rgbBlend >> 16) & 0xFF) * weightBlend) / (weightOrig + weightBlend);
int a = (rgbOrig >> 24) & 0xFF;
int result = (int) (a << 24 | b << 16 | g << 8 | r);
return result;
}
@Override
public InputStream getInputStream() {
return data != null ? new ByteArrayInputStream(data) : fallbackResource.getInputStream();
}
@Override
public boolean hasMetadata() {
return false;
}
@Override
public IMetadataSection getMetadata(String var1) {
return null;
}
}

View File

@@ -11,6 +11,9 @@ public class BetterFoliageConfig extends ConfigBase {
@CfgElement(category="grass", key="enabled")
public boolean grassEnabled = true;
@CfgElement(category="grass", key="useGenerated")
public boolean grassUseGenerated = false;
@CfgElement(category="cactus", key="enabled")
public boolean cactusEnabled = true;
@@ -23,6 +26,9 @@ public class BetterFoliageConfig extends ConfigBase {
@CfgElement(category="algae", key="enabled")
public boolean algaeEnabled = true;
@CfgElement(category="coral", key="enabled")
public boolean coralEnabled = true;
@CfgElement(category="leaves", key="horizontalOffset")
public OptionDouble leavesHOffset = new OptionDouble(0.0, 0.4, 0.025, 0.2);
@@ -79,4 +85,22 @@ public class BetterFoliageConfig extends ConfigBase {
@CfgElement(category="algae", key="chance")
public OptionInteger algaeChance = new OptionInteger(0, 64, 1, 48);
@CfgElement(category="coral", key="population")
public OptionInteger coralPopulation = new OptionInteger(0, 64, 1, 32);
@CfgElement(category="coral", key="chance")
public OptionInteger coralChance = new OptionInteger(0, 64, 1, 32);
@CfgElement(category="coral", key="verticalOffset")
public OptionDouble coralVOffset = new OptionDouble(0.0, 0.25, 0.025, 0.1);
@CfgElement(category="coral", key="horizontalOffset")
public OptionDouble coralHOffset = new OptionDouble(0.0, 0.4, 0.025, 0.2);
@CfgElement(category="coral", key="crustSize")
public OptionDouble coralCrustSize = new OptionDouble(0.75, 1.75, 0.05, 1.4);
@CfgElement(category="coral", key="size")
public OptionDouble coralSize = new OptionDouble(0.25, 1.0, 0.05, 0.7);
}

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 = "ble";
/** 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 = "Lafx;";
/** 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 = "(Lahu;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 = "(Lafx;IIILahu;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 = "(Lble;Lahu;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 = "(ILahu;)I";
}

View File

@@ -1,9 +1,16 @@
package mods.betterfoliage.common.util;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.util.Map;
import com.google.common.base.Charsets;
import mods.betterfoliage.loader.DeobfHelper;
import net.minecraft.client.Minecraft;
import net.minecraft.client.resources.IResource;
import net.minecraft.client.resources.IResourceManager;
@@ -18,8 +25,8 @@ public class Utils {
@SuppressWarnings("unchecked")
public static Map<String, IResourceManager> getDomainResourceManagers() {
IResourceManager manager = Minecraft.getMinecraft().getResourceManager();
Map<String, IResourceManager> result = getField(manager, DeobfNames.SRRM_DRM_MCP, Map.class);
if (result == null) result = getField(manager, DeobfNames.SRRM_DRM_SRGNAME, Map.class);
Map<String, IResourceManager> result = getField(manager, "domainResourceManagers", Map.class);
if (result == null) result = getField(manager, DeobfHelper.transformElementSearge("domainResourceManagers"), Map.class);
return result;
}
@@ -67,4 +74,21 @@ public class Utils {
}
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;
@IFMLLoadingPlugin.MCVersion("1.7.2")
@IFMLLoadingPlugin.TransformerExclusions({"mods.betterfoliage.loader"})
public class BetterFoliageLoader implements IFMLLoadingPlugin {

View File

@@ -1,48 +1,78 @@
package mods.betterfoliage.loader;
import mods.betterfoliage.common.util.DeobfNames;
import net.minecraft.launchwrapper.IClassTransformer;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.FieldInsnNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.VarInsnNode;
public class BetterFoliageTransformer extends EZTransformerBase {
import com.google.common.collect.ImmutableList;
@MethodTransform(className="net.minecraft.client.renderer.RenderBlocks",
obf=@MethodMatch(name=DeobfNames.RB_RBBRT_NAME_OBF, signature=DeobfNames.RB_RBBRT_SIG_OBF),
deobf=@MethodMatch(name=DeobfNames.RB_RBBRT_NAME_MCP, signature=DeobfNames.RB_RBBRT_SIG_MCP),
log="Applying RenderBlocks.renderBlockByRenderType() render type ovverride")
public void handleRenderBlockOverride(MethodNode method, boolean obf) {
AbstractInsnNode invokeGetRenderType = findNext(method.instructions.getFirst(), matchInvokeAny());
AbstractInsnNode storeRenderType = findNext(invokeGetRenderType, matchOpcode(Opcodes.ISTORE));
insertAfter(method.instructions, storeRenderType,
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, DeobfNames.RB_NAME_MCP, DeobfNames.RB_BA_NAME_MCP, DeobfNames.RB_BA_SIG_MCP),
new VarInsnNode(Opcodes.ILOAD, 2),
new VarInsnNode(Opcodes.ILOAD, 3),
new VarInsnNode(Opcodes.ILOAD, 4),
new VarInsnNode(Opcodes.ALOAD, 1),
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", DeobfNames.BFC_GRTO_SIG_MCP),
new VarInsnNode(Opcodes.ISTORE, 5)
);
import cpw.mods.fml.relauncher.FMLInjectionData;
public class BetterFoliageTransformer implements IClassTransformer {
protected Iterable<MethodTransformerBase> transformers = ImmutableList.<MethodTransformerBase>of(
new TransformRenderBlockOverride(),
new TransformShaderModBlockOverride()
);
protected Logger logger = LogManager.getLogger(getClass().getSimpleName());
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="shadersmodcore.client.Shaders",
obf=@MethodMatch(name="pushEntity", signature=DeobfNames.SHADERS_PE_SIG_OBF),
deobf=@MethodMatch(name="pushEntity", signature=DeobfNames.SHADERS_PE_SIG_MCP),
log="Applying Shaders.pushEntity() block id ovverride")
public void handleGLSLBlockIDOverride(MethodNode method, boolean obf) {
AbstractInsnNode arrayStore = findNext(method.instructions.getFirst(), matchOpcode(Opcodes.IASTORE));
insertAfter(method.instructions, arrayStore.getPrevious(),
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/BetterFoliageClient", "getGLSLBlockIdOverride", DeobfNames.BFC_GLSLID_SIG_MCP)
);
@Override
public byte[] transform(String name, String transformedName, byte[] basicClass) {
// ???
if (basicClass == null) return null;
// read class
ClassNode classNode = new ClassNode();
ClassReader classReader = new ClassReader(basicClass);
classReader.accept(classNode, 0);
boolean hasTransformed = false;
for (MethodTransformerBase transformer : transformers) {
// try to find specified method in class
if (!transformedName.equals(transformer.getClassName())) continue;
logger.debug(String.format("Found class: %s -> %s", name, transformedName));
for (MethodNode methodNode : classNode.methods) {
logger.trace(String.format("Checking method: %s, sig: %s", methodNode.name, methodNode.desc));
Boolean isObfuscated = null;
if (methodNode.name.equals(DeobfHelper.transformElementName(transformer.getMethodName())) && methodNode.desc.equals(DeobfHelper.transformSignature(transformer.getSignature()))) {
isObfuscated = true;
} else if (methodNode.name.equals(transformer.getMethodName()) && methodNode.desc.equals(transformer.getSignature())) {
isObfuscated = false;
}
if (isObfuscated != null) {
// transform
hasTransformed = true;
try {
transformer.transform(methodNode, isObfuscated);
logger.info(String.format("%s: SUCCESS", transformer.getLogMessage()));
} catch (Exception e) {
logger.info(String.format("%s: FAILURE", transformer.getLogMessage()));
}
break;
}
}
}
// return result
ClassWriter writer = new ClassWriter(0);
if (hasTransformed) classNode.accept(writer);
return !hasTransformed ? basicClass : writer.toByteArray();
}
}

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

@@ -1,131 +0,0 @@
package mods.betterfoliage.loader;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
import net.minecraft.launchwrapper.IClassTransformer;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
public class EZTransformerBase implements IClassTransformer {
public static interface IInstructionMatch {
public boolean matches(AbstractInsnNode node);
}
@Retention(RetentionPolicy.RUNTIME)
public static @interface MethodMatch {
public String name();
public String signature();
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public static @interface MethodTransform {
public String className();
public MethodMatch deobf();
public MethodMatch obf();
public String log();
}
protected Logger logger = LogManager.getLogger(getClass().getSimpleName());
public byte[] transform(String name, String transformedName, byte[] basicClass) {
// ???
if (basicClass == null) return null;
// read class
ClassNode classNode = new ClassNode();
ClassReader classReader = new ClassReader(basicClass);
classReader.accept(classNode, 0);
boolean hasTransformed = false;
for (Method classMethod : getClass().getMethods()) {
// check for annotated method with correct signature
MethodTransform annot = classMethod.getAnnotation(MethodTransform.class);
if (annot == null) continue;
if (classMethod.getParameterTypes().length != 2) continue;
if (!classMethod.getParameterTypes()[0].equals(MethodNode.class)) continue;
if (!classMethod.getParameterTypes()[1].equals(boolean.class)) continue;
// try to find specified method in class
if (!transformedName.equals(annot.className())) continue;
for (MethodNode methodNode : classNode.methods) {
Boolean obf = null;
if (methodNode.name.equals(annot.obf().name()) && methodNode.desc.equals(annot.obf().signature())) {
obf = true;
} else if (methodNode.name.equals(annot.deobf().name()) && methodNode.desc.equals(annot.deobf().signature())) {
obf = false;
}
if (obf != null) {
// transform
hasTransformed = true;
try {
classMethod.invoke(this, new Object[] {methodNode, obf});
logger.info(String.format("%s: SUCCESS", annot.log()));
} catch (Exception e) {
logger.info(String.format("%s: FAILURE", annot.log()));
}
break;
}
}
}
// return result
ClassWriter writer = new ClassWriter(0);
if (hasTransformed) classNode.accept(writer);
return !hasTransformed ? basicClass : writer.toByteArray();
}
protected AbstractInsnNode findNext(AbstractInsnNode start, IInstructionMatch match) {
AbstractInsnNode current = start;
while(current != null) {
if (match.matches(current)) break;
current = current.getNext();
}
return current;
}
protected AbstractInsnNode findPrevious(AbstractInsnNode start, IInstructionMatch match) {
AbstractInsnNode current = start;
while(current != null) {
if (match.matches(current)) break;
current = current.getPrevious();
}
return current;
}
protected static IInstructionMatch matchInvokeAny() {
return new IInstructionMatch() {
public boolean matches(AbstractInsnNode node) {
return node instanceof MethodInsnNode;
}
};
}
protected static IInstructionMatch matchOpcode(final int opcode) {
return new IInstructionMatch() {
public boolean matches(AbstractInsnNode node) {
return node.getOpcode() == opcode;
}
};
}
protected static void insertAfter(InsnList insnList, AbstractInsnNode node, AbstractInsnNode... added) {
InsnList listAdd = new InsnList();
for (AbstractInsnNode inst : added) listAdd.add(inst);
insnList.insert(node, listAdd);
}
}

View File

@@ -0,0 +1,72 @@
package mods.betterfoliage.loader;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
public abstract class MethodTransformerBase {
public static interface IInstructionMatch {
public boolean matches(AbstractInsnNode node);
}
public abstract String getClassName();
public abstract String getMethodName();
public abstract String getSignature();
public abstract String getLogMessage();
public abstract void transform(MethodNode method, boolean obf);
protected static String className(String className, boolean isObfuscated) {
return isObfuscated ? DeobfHelper.transformClassName(className) : className;
}
protected static String element(String fieldName, boolean isObfuscated) {
return isObfuscated ? DeobfHelper.transformElementName(fieldName) : fieldName;
}
protected static String signature(String signature, boolean isObfuscated) {
return isObfuscated ? DeobfHelper.transformSignature(signature) : signature;
}
protected AbstractInsnNode findNext(AbstractInsnNode start, IInstructionMatch match) {
AbstractInsnNode current = start;
while(current != null) {
if (match.matches(current)) break;
current = current.getNext();
}
return current;
}
protected AbstractInsnNode findPrevious(AbstractInsnNode start, IInstructionMatch match) {
AbstractInsnNode current = start;
while(current != null) {
if (match.matches(current)) break;
current = current.getPrevious();
}
return current;
}
protected IInstructionMatch matchInvokeAny() {
return new IInstructionMatch() {
public boolean matches(AbstractInsnNode node) {
return node instanceof MethodInsnNode;
}
};
}
protected IInstructionMatch matchOpcode(final int opcode) {
return new IInstructionMatch() {
public boolean matches(AbstractInsnNode node) {
return node.getOpcode() == opcode;
}
};
}
protected void insertAfter(InsnList insnList, AbstractInsnNode node, AbstractInsnNode... added) {
InsnList listAdd = new InsnList();
for (AbstractInsnNode inst : added) listAdd.add(inst);
insnList.insert(node, listAdd);
}
}

View File

@@ -0,0 +1,49 @@
package mods.betterfoliage.loader;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.FieldInsnNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.VarInsnNode;
public class TransformRenderBlockOverride extends MethodTransformerBase {
@Override
public String getClassName() {
return "net.minecraft.client.renderer.RenderBlocks";
}
@Override
public String getMethodName() {
return "renderBlockByRenderType";
}
@Override
public String getSignature() {
return "(Lnet/minecraft/block/Block;III)Z";
}
@Override
public String getLogMessage() {
return "Applying RenderBlocks.renderBlockByRenderType() render type ovverride";
}
@Override
public void transform(MethodNode method, boolean obf) {
AbstractInsnNode invokeGetRenderType = findNext(method.instructions.getFirst(), matchInvokeAny());
AbstractInsnNode storeRenderType = findNext(invokeGetRenderType, matchOpcode(Opcodes.ISTORE));
insertAfter(method.instructions, storeRenderType,
new VarInsnNode(Opcodes.ALOAD, 0),
new FieldInsnNode(Opcodes.GETFIELD, className("net/minecraft/client/renderer/RenderBlocks", obf), element("blockAccess", obf), signature("Lnet/minecraft/world/IBlockAccess;", obf)),
new VarInsnNode(Opcodes.ILOAD, 2),
new VarInsnNode(Opcodes.ILOAD, 3),
new VarInsnNode(Opcodes.ILOAD, 4),
new VarInsnNode(Opcodes.ALOAD, 1),
new VarInsnNode(Opcodes.ILOAD, 5),
new MethodInsnNode(Opcodes.INVOKESTATIC, "mods/betterfoliage/client/BetterFoliageClient", "getRenderTypeOverride", signature("(Lnet/minecraft/world/IBlockAccess;IIILnet/minecraft/block/Block;I)I", obf)),
new VarInsnNode(Opcodes.ISTORE, 5)
);
}
}

View File

@@ -0,0 +1,40 @@
package mods.betterfoliage.loader;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.VarInsnNode;
public class TransformShaderModBlockOverride extends MethodTransformerBase {
@Override
public String getClassName() {
return "shadersmodcore.client.Shaders";
}
@Override
public String getMethodName() {
return "pushEntity";
}
@Override
public String getSignature() {
return "(Lnet/minecraft/client/renderer/RenderBlocks;Lnet/minecraft/block/Block;III)V";
}
@Override
public String getLogMessage() {
return "Applying Shaders.pushEntity() block id ovverride";
}
@Override
public void transform(MethodNode method, boolean obf) {
AbstractInsnNode arrayStore = findNext(method.instructions.getFirst(), matchOpcode(Opcodes.IASTORE));
insertAfter(method.instructions, arrayStore.getPrevious(),
new VarInsnNode(Opcodes.ALOAD, 1),
new MethodInsnNode(Opcodes.INVOKESTATIC, "mods/betterfoliage/client/ShadersModIntegration", "getBlockIdOverride", signature("(ILnet/minecraft/block/Block;)I", obf))
);
}
}

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

View File

@@ -12,6 +12,7 @@ message.betterfoliage.betterCactus=Better Cactus: %s
message.betterfoliage.betterLilypad=Better Lilypad: %s
message.betterfoliage.betterReed=Reeds: %s
message.betterfoliage.betterAlgae=Algae: %s
message.betterfoliage.betterCoral=Coral: %s
message.betterfoliage.size=Size
message.betterfoliage.hOffset=H.Offset
@@ -19,8 +20,12 @@ message.betterfoliage.vOffset=V.Offset
message.betterfoliage.minHeight=Min.Height
message.betterfoliage.maxHeight=Max.Height
message.betterfoliage.flowerChance=Flower Chance
message.betterfoliage.reedChance=Reed Chance
message.betterfoliage.reedChance=Reed Population
message.betterfoliage.leavesMode=Leaves Offset: %s
message.betterfoliage.genShortgrass=Use generated: %s
message.betterfoliage.leavesSkew=Skew
message.betterfoliage.leavesTranslate=Translate
message.betterfoliage.algaeChance=Algae Chance
message.betterfoliage.algaeChance=Algae Population
message.betterfoliage.crustSize=Crust Size
message.betterfoliage.coralChance=Coral Chance
message.betterfoliage.coralPopulation=Coral Population