diff --git a/README.md b/README.md index a6da81e..93bef65 100644 --- a/README.md +++ b/README.md @@ -33,9 +33,6 @@ directory you downloaded the source to. If you're on Windows, type `gradlew.bat build`. Otherwise, type `./gradlew build`. Once it's done, the mod will be saved to build/libs/infinitefluids-*version*.jar. -### When I try to run this mod from my IDE, it doesn't load! -Copy the dummy.jar file into the IDE instance's mods/ directory. - ### How can I contribute to this mod's development? Send pull requests. Note that by doing so, you agree to release your contributions under this mod's license. diff --git a/build.gradle b/build.gradle index c851b8d..35f3d9b 100644 --- a/build.gradle +++ b/build.gradle @@ -20,7 +20,7 @@ plugins { id "net.minecraftforge.gradle.forge" version "2.0.2" } */ -version = "1.0.1" +version = "1.1.0" group= "josephcsible.infinitefluids" // http://maven.apache.org/guides/mini/guide-naming-conventions.html archivesBaseName = "infinitefluids" @@ -37,12 +37,6 @@ minecraft { // makeObfSourceJar = false // an Srg named sources jar is made by default. uncomment this to disable. } -jar { - manifest { - attributes 'FMLCorePlugin': 'josephcsible.infinitefluids.InfiniteFluidsLoadingPlugin' - } -} - dependencies { // you may put jars on which you depend on in ./libs // or you may define them like so.. diff --git a/dummy.jar b/dummy.jar deleted file mode 100644 index fe1d4d3..0000000 Binary files a/dummy.jar and /dev/null differ diff --git a/src/main/java/josephcsible/infinitefluids/InfiniteFluidsModContainer.java b/src/main/java/josephcsible/infinitefluids/InfiniteFluids.java similarity index 62% rename from src/main/java/josephcsible/infinitefluids/InfiniteFluidsModContainer.java rename to src/main/java/josephcsible/infinitefluids/InfiniteFluids.java index ecfc3e3..7343586 100644 --- a/src/main/java/josephcsible/infinitefluids/InfiniteFluidsModContainer.java +++ b/src/main/java/josephcsible/infinitefluids/InfiniteFluids.java @@ -23,64 +23,46 @@ import java.util.HashSet; import java.util.Set; -import com.google.common.eventbus.EventBus; -import com.google.common.eventbus.Subscribe; - +import net.minecraft.block.Block; +import net.minecraft.init.Blocks; +import net.minecraft.world.World; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.config.Configuration; +import net.minecraftforge.event.world.BlockEvent.CreateFluidSourceEvent; import net.minecraftforge.fml.client.event.ConfigChangedEvent.OnConfigChangedEvent; -import net.minecraftforge.fml.common.DummyModContainer; -import net.minecraftforge.fml.common.LoadController; -import net.minecraftforge.fml.common.ModMetadata; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.Mod.EventHandler; import net.minecraftforge.fml.common.event.FMLInitializationEvent; import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; +import net.minecraftforge.fml.common.eventhandler.Event.Result; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -public class InfiniteFluidsModContainer extends DummyModContainer { - public static Configuration config; - public static boolean invertInsideNether, invertOutsideNether; - public static Set fluidsInsideNether, fluidsOutsideNether; - public static final String[] INSIDE_NETHER_DEFAULT = {}, OUTSIDE_NETHER_DEFAULT = {"minecraft:water"}; - +@Mod(modid = InfiniteFluids.MODID, version = InfiniteFluids.VERSION, dependencies = "required-after:Forge@[12.18.1.2023,)", guiFactory = "josephcsible.infinitefluids.InfiniteFluidsGuiFactory") +public class InfiniteFluids +{ // XXX duplication with mcmod.info and build.gradle public static final String MODID = "infinitefluids"; - public static final String VERSION = "1.0.1"; - - public InfiniteFluidsModContainer() { - super(new ModMetadata()); - ModMetadata metadata = getMetadata(); - metadata.modId = MODID; - metadata.version = VERSION; - metadata.name = "InfiniteFluids"; - metadata.description = "Allows fluids other than water to be infinite (i.e., turn non-source blocks next to source blocks into source blocks)."; - metadata.url = "http://minecraft.curseforge.com/projects/infinitefluids"; - metadata.authorList.add("Joseph C. Sible"); - } - - @Override - public String getGuiClassName() { - return InfiniteFluidsGuiFactory.class.getName(); - } + public static final String VERSION = "1.1.0"; - @Override - public boolean registerBus(EventBus bus, LoadController controller) { - bus.register(this); - return true; - } + public static Configuration config; + protected static boolean invertInsideNether, invertOutsideNether; + protected static Set fluidsInsideNether, fluidsOutsideNether; + protected static final String[] INSIDE_NETHER_DEFAULT = {}, OUTSIDE_NETHER_DEFAULT = {"minecraft:water"}; - @Subscribe - public void preInit(FMLPreInitializationEvent event) { + @EventHandler + public static void preInit(FMLPreInitializationEvent event) { config = new Configuration(event.getSuggestedConfigurationFile()); syncConfig(); } - @Subscribe - public void init(FMLInitializationEvent event) { - MinecraftForge.EVENT_BUS.register(this); + @EventHandler + public static void init(FMLInitializationEvent event) + { + MinecraftForge.EVENT_BUS.register(InfiniteFluids.class); } @SubscribeEvent - public void onConfigChanged(OnConfigChangedEvent eventArgs) { + public static void onConfigChanged(OnConfigChangedEvent eventArgs) { if(eventArgs.getModID().equals(MODID)) syncConfig(); } @@ -107,4 +89,25 @@ protected static void syncConfig() { if(config.hasChanged()) config.save(); } + + protected static boolean fluidIsInfinite(Block block, World world) { + if(world.provider.doesWaterVaporize()) { + return fluidsInsideNether.contains(Block.REGISTRY.getNameForObject(block).toString()) ^ invertInsideNether; + } else { + return fluidsOutsideNether.contains(Block.REGISTRY.getNameForObject(block).toString()) ^ invertOutsideNether; + } + } + + @SubscribeEvent + public static void onCreateFluidSource(CreateFluidSourceEvent event) { + Block block = event.getState().getBlock(); + // Be careful not to change the result if it's the default anyway, so we don't unnecessarily interfere with other mods. + if(fluidIsInfinite(block, event.getWorld())) { + if(block != Blocks.FLOWING_WATER) { + event.setResult(Result.ALLOW); + } + } else if(block == Blocks.FLOWING_WATER) { + event.setResult(Result.DENY); + } + } } diff --git a/src/main/java/josephcsible/infinitefluids/InfiniteFluidsClassTransformer.java b/src/main/java/josephcsible/infinitefluids/InfiniteFluidsClassTransformer.java deleted file mode 100644 index 8a049e5..0000000 --- a/src/main/java/josephcsible/infinitefluids/InfiniteFluidsClassTransformer.java +++ /dev/null @@ -1,159 +0,0 @@ -/* -InfiniteFluids Minecraft Mod -Copyright (C) 2016 Joseph C. Sible - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -*/ - -package josephcsible.infinitefluids; - -import java.util.Iterator; - -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.Label; -import org.objectweb.asm.Type; -import org.objectweb.asm.tree.*; -import static org.objectweb.asm.Opcodes.*; - -import net.minecraft.launchwrapper.IClassTransformer; - -public class InfiniteFluidsClassTransformer implements IClassTransformer { - private static String updateTickName, updateTickDesc, fluidIsInfiniteDesc, maybeCreateSourceBlockDesc; - - public static void setObfuscated(boolean isObfuscated) { - if(isObfuscated) { - updateTickName = "b"; - updateTickDesc = "(Laid;Lcm;Lars;Ljava/util/Random;)V"; - fluidIsInfiniteDesc = "(Lakf;Laid;)Z"; - maybeCreateSourceBlockDesc = "(Lnet/minecraftforge/fluids/BlockFluidClassic;Laid;Lcm;Lars;)V"; - } else { - updateTickName = "updateTick"; - updateTickDesc = "(Lnet/minecraft/world/World;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/state/IBlockState;Ljava/util/Random;)V"; - fluidIsInfiniteDesc = "(Lnet/minecraft/block/Block;Lnet/minecraft/world/World;)Z"; - maybeCreateSourceBlockDesc = "(Lnet/minecraftforge/fluids/BlockFluidClassic;Lnet/minecraft/world/World;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/state/IBlockState;)V"; - } - } - - private static void transformVanillaUpdateTick(MethodNode mn) { - /* - We're trying to change this: - if (this.adjacentSourceBlocks >= 2 && this.blockMaterial == Material.WATER) - to this: - if (this.adjacentSourceBlocks >= 2 && InfiniteFluidsHooks.fluidIsInfinite(this, worldIn)) - - Here's the relevant piece of the bytecode: - L18 - LINENUMBER 70 L18 - FRAME SAME - ALOAD 0 - GETFIELD net/minecraft/block/BlockDynamicLiquid.adjacentSourceBlocks : I - ICONST_2 *** searched for - IF_ICMPLT L22 *** searched for - ALOAD 0 *** target node - *** new stuff goes here - GETFIELD net/minecraft/block/BlockDynamicLiquid.blockMaterial : Lnet/minecraft/block/material/Material; *** removed - GETSTATIC net/minecraft/block/material/Material.WATER : Lnet/minecraft/block/material/Material; *** removed - IF_ACMPNE L22 *** removed - */ - AbstractInsnNode targetNode = null; - for (AbstractInsnNode instruction : mn.instructions.toArray()) - { - if (instruction.getOpcode() == ICONST_2 && instruction.getNext().getOpcode() == IF_ICMPLT) - { - targetNode = instruction.getNext().getNext(); // this is ALOAD 0 - break; - } - } - if (targetNode == null) - { - System.err.println("Failed to find the part of BlockDynamicLiquid.updateTick we need to patch!"); - return; - } - System.out.println("Patching BlockDynamicLiquid.updateTick"); - mn.instructions.remove(targetNode.getNext()); // remove GETFIELD - mn.instructions.remove(targetNode.getNext()); // remove GETSTATIC - JumpInsnNode n = (JumpInsnNode)targetNode.getNext(); - LabelNode ln = n.label; - mn.instructions.remove(n); // remove IF_ACMPNE - InsnList toInsert = new InsnList(); - toInsert.add(new VarInsnNode(ALOAD, 1)); - toInsert.add(new MethodInsnNode(INVOKESTATIC, Type.getInternalName(InfiniteFluidsHooks.class), "fluidIsInfinite", fluidIsInfiniteDesc, false)); - toInsert.add(new JumpInsnNode(IFEQ, ln)); - mn.instructions.insert(targetNode, toInsert); - } - - private static void transformForgeUpdateTick(MethodNode mn) { - System.out.println("Patching BlockFluidClassic.updateTick"); - // We're adding this line to the beginning of the method: - // InfiniteFluidsHooks.maybeCreateSourceBlock(this, world, pos, state); - Label oldBeginLabel = ((LabelNode)mn.instructions.getFirst()).getLabel(); - Label beginLabel = new Label(); - InsnList toInsert = new InsnList(); - toInsert.add(new LabelNode(beginLabel)); - toInsert.add(new VarInsnNode(ALOAD, 0)); - toInsert.add(new VarInsnNode(ALOAD, 1)); - toInsert.add(new VarInsnNode(ALOAD, 2)); - toInsert.add(new VarInsnNode(ALOAD, 3)); - toInsert.add(new MethodInsnNode(INVOKESTATIC, Type.getInternalName(InfiniteFluidsHooks.class), "maybeCreateSourceBlock", maybeCreateSourceBlockDesc, false)); - mn.instructions.insert(toInsert); - // Make sure nothing looks like it's out of scope in our injected code - Iterator iter = mn.localVariables.iterator(); - while(iter.hasNext()) { - LocalVariableNode lvn = iter.next(); - if(lvn.start.getLabel() == oldBeginLabel) { - lvn.start = new LabelNode(beginLabel); - } - } - } - - private static ClassNode byteArrayToClassNode(byte[] basicClass) { - ClassNode cn = new ClassNode(); - ClassReader cr = new ClassReader(basicClass); - cr.accept(cn, ClassReader.SKIP_FRAMES); - return cn; - } - - private static byte[] classNodeToByteArray(ClassNode cn) { - ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); - cn.accept(cw); - return cw.toByteArray(); - } - - @Override - public byte[] transform(String name, String transformedName, byte[] basicClass) - { - if(transformedName.equals("net.minecraft.block.BlockDynamicLiquid")) { - ClassNode cn = byteArrayToClassNode(basicClass); - for(MethodNode mn : cn.methods) { - if (mn.name.equals(updateTickName) && mn.desc.equals(updateTickDesc)) { - transformVanillaUpdateTick(mn); - return classNodeToByteArray(cn); - } - } - System.err.println("Failed to find the BlockDynamicLiquid.updateTick method!"); - } else if(transformedName.equals("net.minecraftforge.fluids.BlockFluidClassic")) { - ClassNode cn = byteArrayToClassNode(basicClass); - for(MethodNode mn : cn.methods) { - if (mn.name.equals(updateTickName) && mn.desc.equals(updateTickDesc)) { - transformForgeUpdateTick(mn); - return classNodeToByteArray(cn); - } - } - System.err.println("Failed to find the BlockFluidClassic.updateTick method!"); - } - return basicClass; - } -} diff --git a/src/main/java/josephcsible/infinitefluids/InfiniteFluidsGuiFactory.java b/src/main/java/josephcsible/infinitefluids/InfiniteFluidsGuiFactory.java index deb4c97..a27bbfd 100644 --- a/src/main/java/josephcsible/infinitefluids/InfiniteFluidsGuiFactory.java +++ b/src/main/java/josephcsible/infinitefluids/InfiniteFluidsGuiFactory.java @@ -34,8 +34,8 @@ public static class InfiniteFluidsGuiConfig extends GuiConfig { public InfiniteFluidsGuiConfig(GuiScreen parent) { super( parent, - new ConfigElement(InfiniteFluidsModContainer.config.getCategory(Configuration.CATEGORY_GENERAL)).getChildElements(), - InfiniteFluidsModContainer.MODID, false, false, GuiConfig.getAbridgedConfigPath(InfiniteFluidsModContainer.config.toString()) + new ConfigElement(InfiniteFluids.config.getCategory(Configuration.CATEGORY_GENERAL)).getChildElements(), + InfiniteFluids.MODID, false, false, GuiConfig.getAbridgedConfigPath(InfiniteFluids.config.toString()) ); } } diff --git a/src/main/java/josephcsible/infinitefluids/InfiniteFluidsHooks.java b/src/main/java/josephcsible/infinitefluids/InfiniteFluidsHooks.java deleted file mode 100644 index 157693f..0000000 --- a/src/main/java/josephcsible/infinitefluids/InfiniteFluidsHooks.java +++ /dev/null @@ -1,50 +0,0 @@ -/* -InfiniteFluids Minecraft Mod -Copyright (C) 2016 Joseph C. Sible - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -*/ - -package josephcsible.infinitefluids; - -import net.minecraft.block.Block; -import net.minecraft.block.state.IBlockState; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; -import net.minecraftforge.fluids.BlockFluidClassic; - -public class InfiniteFluidsHooks { - public static boolean fluidIsInfinite(Block block, World world) { - if(world.provider.doesWaterVaporize()) { - return InfiniteFluidsModContainer.fluidsInsideNether.contains(Block.REGISTRY.getNameForObject(block).toString()) ^ InfiniteFluidsModContainer.invertInsideNether; - } else { - return InfiniteFluidsModContainer.fluidsOutsideNether.contains(Block.REGISTRY.getNameForObject(block).toString()) ^ InfiniteFluidsModContainer.invertOutsideNether; - } - } - - public static void maybeCreateSourceBlock(BlockFluidClassic block, World world, BlockPos pos, IBlockState state) { - if(!block.isSourceBlock(world, pos) && fluidIsInfinite(block, world)) { - int adjacentSourceBlocks = - (block.isSourceBlock(world, pos.north()) ? 1 : 0) + - (block.isSourceBlock(world, pos.south()) ? 1 : 0) + - (block.isSourceBlock(world, pos.east()) ? 1 : 0) + - (block.isSourceBlock(world, pos.west()) ? 1 : 0); - int densityDir = block.getDensity(world, pos) > 0 ? -1 : 1; - if(adjacentSourceBlocks >= 2 && (world.getBlockState(pos.up(densityDir)).getMaterial().isSolid() || block.isSourceBlock(world, pos.up(densityDir)))) { - world.setBlockState(pos, state.withProperty(BlockFluidClassic.LEVEL, 0)); - } - } - } -} diff --git a/src/main/java/josephcsible/infinitefluids/InfiniteFluidsLoadingPlugin.java b/src/main/java/josephcsible/infinitefluids/InfiniteFluidsLoadingPlugin.java deleted file mode 100644 index 74c54b0..0000000 --- a/src/main/java/josephcsible/infinitefluids/InfiniteFluidsLoadingPlugin.java +++ /dev/null @@ -1,52 +0,0 @@ -/* -InfiniteFluids Minecraft Mod -Copyright (C) 2016 Joseph C. Sible - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -*/ - -package josephcsible.infinitefluids; - -import java.util.Map; -import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin; -import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin.MCVersion; - -@MCVersion("1.10.2") -public class InfiniteFluidsLoadingPlugin implements IFMLLoadingPlugin { - @Override - public String[] getASMTransformerClass() { - return new String[]{InfiniteFluidsClassTransformer.class.getName()}; - } - - @Override - public String getModContainerClass() { - return InfiniteFluidsModContainer.class.getName(); - } - - @Override - public String getSetupClass() { - return null; - } - - @Override - public void injectData(Map data) { - InfiniteFluidsClassTransformer.setObfuscated((Boolean) data.get("runtimeDeobfuscationEnabled")); - } - - @Override - public String getAccessTransformerClass() { - return null; - } -}