Jump to content

No Fire Spread mod (working, but is it done right?)


Laike_Endaril

Recommended Posts

I just created my first minecraft mod and got it running on SP on both intelliJ and as a regular forge mod jar (tested with MultiMC).  It was harder than I expected, due to unforeseen complications and my general lack of minecraft modding knowledge (learned at  least a little about the event bus...the hard way).

 

In any case, if any modding gurus out there want to point out bits of my code that rub them the wrong way, I can try to fix them (eg. to be more compatible/stable with forge and/or other mods, etc).

 

Also, I have not tested on an integrated server and remote client, but I see no reason why there would be a difference between that and normal SP on MultiMC for this particular mod, as it stands right now.

 

 

My main class:

Spoiler

package com.fantasticsource.nofirespread;

import net.minecraft.block.Block;
import net.minecraft.block.BlockFire;
import net.minecraft.init.Blocks;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventHandler;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.registry.ForgeRegistries;
import org.apache.logging.log4j.Logger;

import java.lang.reflect.Field;
import java.util.Objects;

@Mod(modid = NoFireSpread.MODID, name = NoFireSpread.NAME, version = NoFireSpread.VERSION)
public class NoFireSpread
{
    public static final String MODID = "nofirespread";
    public static final String NAME = "No Fire Spread";
    public static final String VERSION = "@VERSION@";

    private static Logger logger;
    public static BlockFire oldFire;

    public NoFireSpread()
    {
        MinecraftForge.EVENT_BUS.register(NoFireSpread.class);
        oldFire = Blocks.FIRE;
    }

    @EventHandler
    public void preInit(FMLPreInitializationEvent event)
    {
        logger = event.getModLog();
    }

    @SubscribeEvent
    public static void registerBlocks(RegistryEvent.Register<Block> event)
    {
        BlockFireEdit newFire = (BlockFireEdit) (new BlockFireEdit()).setHardness(0.0F).setLightLevel(1.0F).setUnlocalizedName("fire").setRegistryName(Objects.requireNonNull(Blocks.FIRE.getRegistryName()));

        event.getRegistry().register(newFire);

        Field f = null;
        try {
            //noinspection JavaReflectionMemberAccess
            f = Blocks.class.getDeclaredField("field_150480_ab"); //The obfuscated field name for the current version of the Blocks class
        }
        catch (NoSuchFieldException e)
        {
            try {
                f = Blocks.class.getDeclaredField("FIRE");
            } catch (NoSuchFieldException e1) {
                e1.printStackTrace();
            }
        }

        if (f != null) try {
            f.setAccessible(true);

            Field modifiersField = Field.class.getDeclaredField("modifiers");
            modifiersField.setAccessible(true);
            modifiersField.setInt(f, f.getModifiers() & -17);

            f.set(null, newFire);
        } catch (Exception e) {
            e.printStackTrace();
        }

        //Overwrite fire-related stats for vanilla blocks
        //TODO May need to add some new event type to overwrite encouragement values for blocks from other mods
        for (Block b : ForgeRegistries.BLOCKS.getValues())
        {
            if (oldFire.getEncouragement(b) != 0 && b != Blocks.AIR)
            {
                Blocks.FIRE.setFireInfo(b, 0, oldFire.getFlammability(b));
            }
        }
    }
}

 

 

And my BlockFireEdit class (replaces the normal BlockFire class)

Spoiler

package com.fantasticsource.nofirespread;

import net.minecraft.block.Block;
import net.minecraft.block.BlockFire;
import net.minecraft.block.BlockTNT;
import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;

import java.util.Random;

public class BlockFireEdit extends BlockFire
{
    @Override
    public void updateTick(World worldIn, BlockPos pos, IBlockState state, Random rand)
    {
        if (worldIn.getGameRules().getBoolean("doFireTick"))
        {
            if (!worldIn.isAreaLoaded(pos, 2)) return; // Forge: prevent loading unloaded chunks when spreading fire
            if (!this.canPlaceBlockAt(worldIn, pos))
            {
                worldIn.setBlockToAir(pos);
            }

            Block block = worldIn.getBlockState(pos.down()).getBlock();
            boolean flag = block.isFireSource(worldIn, pos.down(), EnumFacing.UP);

            int i = state.getValue(AGE);

            if (!flag && worldIn.isRaining() && this.canDie(worldIn, pos) && rand.nextFloat() < 0.2F + (float)i * 0.03F)
            {
                worldIn.setBlockToAir(pos);
            }
            else
            {
                if (i < 15)
                {
                    state = state.withProperty(AGE, i + rand.nextInt(3) / 2);
                    worldIn.setBlockState(pos, state, 4);
                }

                worldIn.scheduleUpdate(pos, this, this.tickRate(worldIn) + rand.nextInt(10));

                if (!flag)
                {
                    if (!this.canNeighborCatchFire(worldIn, pos))
                    {
                        if (!worldIn.getBlockState(pos.down()).isSideSolid(worldIn, pos.down(), EnumFacing.UP) || i > 3)
                        {
                            worldIn.setBlockToAir(pos);
                        }

                        return;
                    }

                    if (!this.canCatchFire(worldIn, pos.down(), EnumFacing.UP) && i == 15 && rand.nextInt(4) == 0)
                    {
                        worldIn.setBlockToAir(pos);
                        return;
                    }
                }

                boolean flag1 = worldIn.isBlockinHighHumidity(pos);
                int j = 0;

                if (flag1)
                {
                    j = -50;
                }

                this.tryCatchFire(worldIn, pos.east(), 300 + j, rand, i, EnumFacing.WEST);
                this.tryCatchFire(worldIn, pos.west(), 300 + j, rand, i, EnumFacing.EAST);
                this.tryCatchFire(worldIn, pos.down(), 250 + j, rand, i, EnumFacing.UP);
                this.tryCatchFire(worldIn, pos.up(), 250 + j, rand, i, EnumFacing.DOWN);
                this.tryCatchFire(worldIn, pos.north(), 300 + j, rand, i, EnumFacing.SOUTH);
                this.tryCatchFire(worldIn, pos.south(), 300 + j, rand, i, EnumFacing.NORTH);

                for (int k = -1; k <= 1; ++k)
                {
                    for (int l = -1; l <= 1; ++l)
                    {
                        for (int i1 = -1; i1 <= 4; ++i1)
                        {
                            if (k != 0 || i1 != 0 || l != 0)
                            {
                                int j1 = 100;

                                if (i1 > 1)
                                {
                                    j1 += (i1 - 1) * 100;
                                }

                                BlockPos blockpos = pos.add(k, i1, l);
                                int k1 = this.getNeighborEncouragement(worldIn, blockpos);

                                if (k1 > 0)
                                {
                                    int l1 = (k1 + 40 + worldIn.getDifficulty().getDifficultyId() * 7) / (i + 30);

                                    if (flag1)
                                    {
                                        l1 /= 2;
                                    }

                                    if (l1 > 0 && rand.nextInt(j1) <= l1 && (!worldIn.isRaining() || !this.canDie(worldIn, blockpos)))
                                    {
                                        int i2 = i + rand.nextInt(5) / 4;

                                        if (i2 > 15)
                                        {
                                            i2 = 15;
                                        }

                                        worldIn.setBlockState(blockpos, state.withProperty(AGE, i2), 3);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    private void tryCatchFire(World worldIn, BlockPos pos, int chance, Random random, int age, EnumFacing face)
    {
        int i = worldIn.getBlockState(pos).getBlock().getFlammability(worldIn, pos, face);

        if (random.nextInt(chance) < i)
        {
            IBlockState iblockstate = worldIn.getBlockState(pos);

            worldIn.setBlockToAir(pos);

            if (iblockstate.getBlock() == Blocks.TNT)
            {
                Blocks.TNT.onBlockDestroyedByPlayer(worldIn, pos, iblockstate.withProperty(BlockTNT.EXPLODE, true));
            }
        }
    }

    private boolean canNeighborCatchFire(World worldIn, BlockPos pos)
    {
        for (EnumFacing enumfacing : EnumFacing.values())
        {
            if (canCatchFire(worldIn, pos.offset(enumfacing), enumfacing.getOpposite()))
            {
                return true;
            }
        }

        return false;
    }

    private int getNeighborEncouragement(World worldIn, BlockPos pos)
    {
        if (!worldIn.isAirBlock(pos))
        {
            return 0;
        }
        else
        {
            int i = 0;

            for (EnumFacing enumfacing : EnumFacing.values())
            {
                i = Math.max(worldIn.getBlockState(pos.offset(enumfacing)).getBlock().getFireSpreadSpeed(worldIn, pos.offset(enumfacing), enumfacing.getOpposite()), i);
            }

            return i;
        }
    }
}

 

 

 

 

For posterity, here are the source files for THE VERSION THAT WORKS WITH MY MASSIVE MODPACK:

Main file:
 

Spoiler

package com.fantasticsource.nofirespread;

import net.minecraft.block.Block;
import net.minecraft.block.BlockFire;
import net.minecraft.init.Blocks;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventHandler;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.registry.ForgeRegistries;
import net.minecraftforge.fml.relauncher.ReflectionHelper;
import org.apache.logging.log4j.Logger;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Objects;

@Mod(modid = NoFireSpread.MODID, name = NoFireSpread.NAME, version = NoFireSpread.VERSION)
public class NoFireSpread
{
    public static final String MODID = "nofirespread";
    public static final String NAME = "No Fire Spread";
    public static final String VERSION = "@VERSION@";

    public static boolean fireSpreadDisabled = true;
    public static boolean debug = false;

    private static Logger logger;
    public static BlockFire oldFire;

    public NoFireSpread()
    {
        MinecraftForge.EVENT_BUS.register(NoFireSpread.class);
        oldFire = Blocks.FIRE;
    }

    @EventHandler
    public void preInit(FMLPreInitializationEvent event)
    {
        logger = event.getModLog();
    }

    @SubscribeEvent
    public static void registerBlocks(RegistryEvent.Register<Block> event)
    {
        BlockFireEdit newFire = (BlockFireEdit) (new BlockFireEdit()).setHardness(0.0F).setLightLevel(1.0F).setUnlocalizedName("fire").setRegistryName(Objects.requireNonNull(Blocks.FIRE.getRegistryName()));

        event.getRegistry().register(newFire);

        Field f;
        try {
            f = ReflectionHelper.findField(Blocks.class, "field_150480_ab");
        }
        catch (ReflectionHelper.UnableToFindFieldException e)
        {
            f = ReflectionHelper.findField(Blocks.class, "FIRE");
        }

        try {
            f.setAccessible(true);

            Field modifiersField = Field.class.getDeclaredField("modifiers");
            modifiersField.setAccessible(true);
            modifiersField.setInt(f, f.getModifiers() & ~Modifier.FINAL);

            f.set(null, newFire);
        } catch (Exception e) {
            e.printStackTrace();
        }

        //Copy fire-related stats for vanilla blocks
        //TODO May need to add some new event type to overwrite encouragement values for blocks from other mods
        for (Block b : ForgeRegistries.BLOCKS.getValues())
        {
            if (oldFire.getEncouragement(b) != 0 && b != Blocks.AIR)
            {
                Blocks.FIRE.setFireInfo(b, oldFire.getEncouragement(b), oldFire.getFlammability(b));
            }
        }
    }
}

 

 

BlockFireEdit, which extends the original BlockFire:
 

Spoiler

package com.fantasticsource.nofirespread;

import net.minecraft.block.Block;
import net.minecraft.block.BlockFire;
import net.minecraft.block.BlockTNT;
import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;

import java.util.Random;

public class BlockFireEdit extends BlockFire
{
    @Override
    public void updateTick(World worldIn, BlockPos pos, IBlockState state, Random rand)
    {
        if (worldIn.getGameRules().getBoolean("doFireTick"))
        {
            if (!worldIn.isAreaLoaded(pos, 2)) return; // Forge: prevent loading unloaded chunks when spreading fire
            if (!this.canPlaceBlockAt(worldIn, pos))
            {
                worldIn.setBlockToAir(pos);
            }

            Block block = worldIn.getBlockState(pos.down()).getBlock();
            boolean flag = block.isFireSource(worldIn, pos.down(), EnumFacing.UP);

            int i = state.getValue(AGE);

            if (!flag && worldIn.isRaining() && this.canDie(worldIn, pos) && rand.nextFloat() < 0.2F + (float)i * 0.03F)
            {
                worldIn.setBlockToAir(pos);
            }
            else
            {
                if (i < 15)
                {
                    state = state.withProperty(AGE, i + rand.nextInt(3) / 2);
                    worldIn.setBlockState(pos, state, 4);
                }

                worldIn.scheduleUpdate(pos, this, this.tickRate(worldIn) + rand.nextInt(10));

                if (!flag)
                {
                    if (!this.canNeighborCatchFire(worldIn, pos))
                    {
                        if (!worldIn.getBlockState(pos.down()).isSideSolid(worldIn, pos.down(), EnumFacing.UP) || i > 3)
                        {
                            worldIn.setBlockToAir(pos);
                        }

                        return;
                    }

                    if (!this.canCatchFire(worldIn, pos.down(), EnumFacing.UP) && i == 15 && rand.nextInt(4) == 0)
                    {
                        worldIn.setBlockToAir(pos);
                        return;
                    }
                }

                boolean flag1 = worldIn.isBlockinHighHumidity(pos);
                int j = 0;

                if (flag1)
                {
                    j = -50;
                }

                if (NoFireSpread.debug) System.out.println("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW " + pos.toString());
                this.tryCatchFire(worldIn, pos.east(), 300 + j, rand, i, EnumFacing.WEST);
                this.tryCatchFire(worldIn, pos.west(), 300 + j, rand, i, EnumFacing.EAST);
                this.tryCatchFire(worldIn, pos.down(), 250 + j, rand, i, EnumFacing.UP);
                this.tryCatchFire(worldIn, pos.up(), 250 + j, rand, i, EnumFacing.DOWN);
                this.tryCatchFire(worldIn, pos.north(), 300 + j, rand, i, EnumFacing.SOUTH);
                this.tryCatchFire(worldIn, pos.south(), 300 + j, rand, i, EnumFacing.NORTH);

                for (int k = -1; k <= 1; ++k)
                {
                    for (int l = -1; l <= 1; ++l)
                    {
                        for (int i1 = -1; i1 <= 4; ++i1)
                        {
                            if (k != 0 || i1 != 0 || l != 0)
                            {
                                int j1 = 100;

                                if (i1 > 1)
                                {
                                    j1 += (i1 - 1) * 100;
                                }

                                BlockPos blockpos = pos.add(k, i1, l);
                                int k1 = this.getNeighborEncouragement(worldIn, blockpos);

                                if (k1 > 0)
                                {
                                    int l1 = (k1 + 40 + worldIn.getDifficulty().getDifficultyId() * 7) / (i + 30);

                                    if (flag1)
                                    {
                                        l1 /= 2;
                                    }

                                    if (l1 > 0 && rand.nextInt(j1) <= l1 && (!worldIn.isRaining() || !this.canDie(worldIn, blockpos)))
                                    {
                                        int i2 = i + rand.nextInt(5) / 4;

                                        if (i2 > 15)
                                        {
                                            i2 = 15;
                                        }

                                        worldIn.setBlockState(blockpos, state.withProperty(AGE, i2), 3);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    @Override
    public int getEncouragement(Block blockIn)
    {
        if (NoFireSpread.fireSpreadDisabled) return 0;
        else return super.getEncouragement(blockIn);
    }

    private void tryCatchFire(World worldIn, BlockPos pos, int chance, Random random, int age, EnumFacing face)
    {
        int i = worldIn.getBlockState(pos).getBlock().getFlammability(worldIn, pos, face);

        if (NoFireSpread.debug) System.out.println(worldIn.getBlockState(pos).getBlock().getLocalizedName() + " == " + getEncouragement(worldIn.getBlockState(pos).getBlock()));
        if (random.nextInt(chance) < i)
        {
            IBlockState iblockstate = worldIn.getBlockState(pos);

            worldIn.setBlockToAir(pos);

            if (iblockstate.getBlock() == Blocks.TNT)
            {
                Blocks.TNT.onBlockDestroyedByPlayer(worldIn, pos, iblockstate.withProperty(BlockTNT.EXPLODE, true));
            }
        }
    }

    private boolean canNeighborCatchFire(World worldIn, BlockPos pos)
    {
        for (EnumFacing enumfacing : EnumFacing.values())
        {
            if (canCatchFire(worldIn, pos.offset(enumfacing), enumfacing.getOpposite()))
            {
                return true;
            }
        }

        return false;
    }

    private int getNeighborEncouragement(World worldIn, BlockPos pos)
    {
        if (!worldIn.isAirBlock(pos))
        {
            return 0;
        }
        else
        {
            int i = 0;

            for (EnumFacing enumfacing : EnumFacing.values())
            {
                i = Math.max(worldIn.getBlockState(pos.offset(enumfacing)).getBlock().getFireSpreadSpeed(worldIn, pos.offset(enumfacing), enumfacing.getOpposite()), i);
            }

            return i;
        }
    }
}

 

 

And just to make it a complete example in case another newb modder like myself sees this...

...my mcmod.info file:
 

Spoiler

[
{
  "modid": "nofirespread",
  "name": "No Fire Spread",
  "description": "Fire still burns things...it JUST...DOESN'T...SPREAD!",
  "version": "${version}",
  "mcversion": "${mcversion}",
  "url": "",
  "updateUrl": "",
  "authorList": ["Laike_Endaril"],
  "credits": "",
  "logoFile": "",
  "screenshots": [],
  "dependencies": []
}
]

 

...and my build.gradle file:
 

Spoiler

buildscript {
    repositories {
        jcenter()
        maven { url = "http://files.minecraftforge.net/maven" }
    }
    dependencies {
        classpath 'net.minecraftforge.gradle:ForgeGradle:2.3-SNAPSHOT'
    }
}
apply plugin: 'net.minecraftforge.gradle.forge'
//Only edit below this line, the above code adds and enables the necessary things for Forge to be setup.


version = "1.12.2.002"
group = "com.fantasticsource.nofirespread" // http://maven.apache.org/guides/mini/guide-naming-conventions.html
archivesBaseName = "NoFireSpread"

sourceCompatibility = targetCompatibility = '1.8' // Need this here so eclipse task generates correctly.
compileJava {
    sourceCompatibility = targetCompatibility = '1.8'
}

minecraft {
    version = "1.12.2-14.23.5.2768"
    runDir = "run"
    
    // the mappings can be changed at any time, and must be in the following format.
    // snapshot_YYYYMMDD   snapshot are built nightly.
    // stable_#            stables are built at the discretion of the MCP team.
    // Use non-default mappings at your own risk. they may not always work.
    // simply re-run your setup task after changing the mappings to update your workspace.
    mappings = "snapshot_20171003"
    // makeObfSourceJar = false // an Srg named sources jar is made by default. uncomment this to disable.

    replace "@VERSION@", project.version
    replaceIn "NoFireSpread.java"
}

dependencies {
    // you may put jars on which you depend on in ./libs
    // or you may define them like so..
    //compile "some.group:artifact:version:classifier"
    //compile "some.group:artifact:version"
      
    // real examples
    //compile 'com.mod-buildcraft:buildcraft:6.0.8:dev'  // adds buildcraft to the dev env
    //compile 'com.googlecode.efficient-java-matrix-library:ejml:0.24' // adds ejml to the dev env

    // the 'provided' configuration is for optional dependencies that exist at compile-time but might not at runtime.
    //provided 'com.mod-buildcraft:buildcraft:6.0.8:dev'

    // the deobf configurations:  'deobfCompile' and 'deobfProvided' are the same as the normal compile and provided,
    // except that these dependencies get remapped to your current MCP mappings
    //deobfCompile 'com.mod-buildcraft:buildcraft:6.0.8:dev'
    //deobfProvided 'com.mod-buildcraft:buildcraft:6.0.8:dev'

    // for more info...
    // http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html
    // http://www.gradle.org/docs/current/userguide/dependency_management.html

}

processResources {
    // this will ensure that this task is redone when the versions change.
    inputs.property "version", project.version
    inputs.property "mcversion", project.minecraft.version

    // replace stuff in mcmod.info, nothing else
    from(sourceSets.main.resources.srcDirs) {
        include 'mcmod.info'
                
        // replace version and mcversion
        expand 'version':project.version, 'mcversion':project.minecraft.version
    }
        
    // copy everything else except the mcmod.info
    from(sourceSets.main.resources.srcDirs) {
        exclude 'mcmod.info'
    }
}

 

 

 

I think this thread is pretty well done and overwith, so here's a link to the mod on curseforge: https://minecraft.curseforge.com/projects/no-fire-spread

I will also be making a more advanced version with a bunch of fire-tweaking config options soon and releasing it under the title "Controlled Burn"

Edited by Laike_Endaril
Mod Released
Link to comment
Share on other sites

31 minutes ago, nov4e said:

On every join just set the gamerule doFireTick to false.

Unfortunately, that gamerule does not have the result I wanted.  Setting doFireTick to false does prevent fire spread, but at the same time, it also prevents fires from extinguishing and prevents fires from breaking blocks, neither of which were desirable for my modpack (and I couldn't find a mod that did prevent fire spread on minecraft.curseforge.com, so I made one).

Link to comment
Share on other sites

3 hours ago, Laike_Endaril said:

In any case, if any modding gurus out there want to point out bits of my code that rub them the wrong way, I can try to fix them (eg. to be more compatible/stable with forge and/or other mods, etc).

If I'm not mistaken, I don't believe the reflection you are using to modify the Block field is necessary. As its value is obtained by the value in the registry.

VANILLA MINECRAFT CLASSES ARE THE BEST RESOURCES WHEN MODDING

I will be posting 1.15.2 modding tutorials on this channel. If you want to be notified of it do the normal YouTube stuff like subscribing, ect.

Forge and vanilla BlockState generator.

Link to comment
Share on other sites

37 minutes ago, Animefan8888 said:

If I'm not mistaken, I don't believe the reflection you are using to modify the Block field is necessary. As its value is obtained by the value in the registry.

I did try that, but I couldn't seem to get the timing right.  Maybe I wasn't doing it in the right event?  If I'm not mistaken, I would have to re-enter the registry for it *after* it is first set by the Block class (not to be confused with the Blocks class), but before it is accessed by the Blocks class (again, not to be confused with the Block class).  I may try at this again, since it would be nice to remove the reflection.

 

Edit 1 ============================================================

I just noticed that you said "Block field" and not "Blocks field".  Not sure if you were looking at the right class or not (both exist, and are 2 different classes).  In any case, I just ran a test on this.

 

I added this to my main class constructor (the symbols make it easier for me to find the line in the output terminal; I always remove them later):

        System.out.println("Constructor" + Blocks.FIRE + " @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");

And then I added this in the class itself (not in a method) to force the constructor to fire the first time my class is ever referenced anywhere (I believe):

    public static NoFireSpread test = new NoFireSpread();

 

With those 2 new lines of code, the result of the println was still this:

[17:18:16] [main/INFO] [STDOUT]: [com.fantasticsource.nofirespread.NoFireSpread:<init>:32]: Block{minecraft:fire} @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
[17:18:16] [main/INFO] [STDOUT]: [com.fantasticsource.nofirespread.NoFireSpread:<init>:32]: Block{minecraft:fire} @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

It prints twice because one is from the "normally created" instance of my class (the one forge is using) and the other is from my "artificially created" instance.  So even at the earliest code entry point I personally know of, it's already too late to set the Blocks.FIRE field without reflection (being a static field).

 

Edit 2 =============================================================

On a separate note, I found out that while my mod works on its own (jar mode as well as in intelliJ), it does NOT work in my modpack that I made it for (doh) so I'm currently trying to track down that issue.  My best guess atm is that another mod is overwriting the encouragement values *after* I run my code to set them all to 0 (in the RegistryEvent.Register<Block> event).  Honestly I'd rather set them all in some event that I know is after all block registry events, but I haven't found a decent one yet (tried WorldEvent.Load but it doesn't seem to have registry access built in...guess I can pass a reference to the registry from elsewhere though, trying that next)

Edited by Laike_Endaril
Link to comment
Share on other sites

Field f = null;
        try {
            //noinspection JavaReflectionMemberAccess
            f = Blocks.class.getDeclaredField("field_150480_ab"); //The obfuscated field name for the current version of the Blocks class
        }
        catch (NoSuchFieldException e)
        {
            try {
                f = Blocks.class.getDeclaredField("FIRE");
            } catch (NoSuchFieldException e1) {
                e1.printStackTrace();
            }
        }

Instead of all this you could've just used ReflectionHelper.findField

 

4 hours ago, Laike_Endaril said:

modifiersField.setInt(f, f.getModifiers() & -17);

It might just be me but I really dislike magic numbers like this one. Although in this case it is quite easy to understand what this is doing I would still write this with a reference to the constant instead:

Quote

modifiersField.setInt(f, f.getModifiers() & ~Modifier.FINAL);

 

25 minutes ago, Animefan8888 said:

I don't believe the reflection you are using to modify the Block field is necessary. As its value is obtained by the value in the registry.

That's kinda what I thought too but from my debugging the Blocks class gets initialized before the block registry event is fired, so it always grabs the vanilla blocks from the registy even if mods override them later. I will do more debugging later.

Link to comment
Share on other sites

1 minute ago, V0idWa1k3r said:

That's kinda what I thought too but from my debugging the Blocks class gets initialized before the block registry event is fired, so it always grabs the vanilla blocks from the registy even if mods override them later. I will do more debugging later.

I believe they are static fields so it is kinda hard to tell when they are instantiated. ? So laike should use reflection just to secure that it happens.

VANILLA MINECRAFT CLASSES ARE THE BEST RESOURCES WHEN MODDING

I will be posting 1.15.2 modding tutorials on this channel. If you want to be notified of it do the normal YouTube stuff like subscribing, ect.

Forge and vanilla BlockState generator.

Link to comment
Share on other sites

1 hour ago, V0idWa1k3r said:

Instead of all this you could've just used ReflectionHelper.findField

Holy crap I didn't realize we had reflection support...nice.  I'll try that.

 

 

1 hour ago, V0idWa1k3r said:

modifiersField.setInt(f, f.getModifiers() & ~Modifier.FINAL);

I will most certainly use this.

 

 

1 hour ago, Animefan8888 said:

I believe they are static fields so it is kinda hard to tell when they are instantiated. ? So laike should use reflection just to secure that it happens.

Yeah, I'm pretty sure I need that reflection.  See Edit 1 in my previous reply for a test I ran.

 

 

Also, for this part:

1 hour ago, Laike_Endaril said:

(tried WorldEvent.Load but it doesn't seem to have registry access built in...guess I can pass a reference to the registry from elsewhere though, trying that next)

I remembered I can access the block registry with ForgeRegistries.BLOCKS...you know...like I already did previously...I probably need more sleep but I'd rather code right now lol

Link to comment
Share on other sites

6 minutes ago, Laike_Endaril said:

I remembered I can access the block registry with ForgeRegistries.BLOCKS...you know...like I already did previously...I probably need more sleep but I'd rather code right now lol

Instead of the World Load event you should just use the FMLPostInitializationEvent in your @Mod class.

VANILLA MINECRAFT CLASSES ARE THE BEST RESOURCES WHEN MODDING

I will be posting 1.15.2 modding tutorials on this channel. If you want to be notified of it do the normal YouTube stuff like subscribing, ect.

Forge and vanilla BlockState generator.

Link to comment
Share on other sites

1 hour ago, Animefan8888 said:

Instead of the World Load event you should just use the FMLPostInitializationEvent in your @Mod class.

I feel like I already tried this, but can't remember for sure, so I'll double check.  But before I even try either one again I'll probably throw a println into my BlockFireEdit.fireTick() method and see if it's even being run in my modpack or if the instance of said class itself is being overridden (and not just the settings within it).  That would suck...

 

Edit 1 ====================================================

My fireTick() is firing! (Fire joke ha!) ...so that's good.  That being the case, it's pretty likely that I was right about the encouragement values being overwritten, though I'll also test to make sure that my tryCatchFire() is acting as expected, just in case (not likely to be an issue there though).  Once I have it working with my modpack I'll try out the ReflectionHelper.

 

Edit 2 ===============================================================

GREAT NEWS!  Hey, I'm excited at least lol...

I...

...got it working with my modpack

...used ReflectionHelper calls to reduce a bit of reflection code (still needed 2 different calls for obfuscated and non-obfuscated though)

...accomplished the goal (removing fire spread) in a more elegant way, which preserves original fire-related stats and enables toggling of fire spread using a flag

...I feel like there was something else I improved too but I forgot what, so yeah, that random thing is also probably better than it was before


For posterity, I will post the source for the updated version (which works in my massive modpack) in the main post shortly!

Edited by Laike_Endaril
Major improvement of mod
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.