Jump to content

[1.7.x][SOLVED] Overriding World's base-block - Stone.


Recommended Posts

Posted

Hello,

 

What I want is quite simple - tell world generator to replace every stone with something else in all biomes.

Result should look like this: all stone generated by world is mystone and when you craft stone in furnace it will be vanillastone.

 

Is there any global field with ID of "basic-block" which I can override (with reflection or whatever)?

 

And note for "other ways": No, I can't use events to do what I want (unless there is some world-gen even that would allow me to replace all stone during generaton - please say which) and no I don't want to replace stone with myblock inside registry array.

1.7.10 is no longer supported by forge, you are on your own.

Posted

Make a custom WorldGenerator Class.

 

It should look like this.

 

public class SurfaceGen implements IWorldGenerator
{
    @Override
    public void generate(Random random, int chunkX, int chunkZ, World world, IChunkProvider chunkGenerator, IChunkProvider chunkProvider)
    {
        switch(world.provider.dimensionId)
        {
            case 0:
                generateSurface(world, random, chunkX * 16, chunkZ * 16);
        }
    }

    private void generateSurface(World world, Random random, int chunkX, int chunkZ)
    {
        for(int x = chunkX; x < chunkX + 16; x++)
        {
            for(int z = chunkZ; z < chunkZ + 16; z++)
            {
                for(int y = 0; y < 256; y++)
                {
                    if(block == Blocks.stone)
                    {
                        world.setBlock(x, y, z, CUSTOM STONE BLOCK);
                    }
                }

 

Now you need to register your WorldGenerator Class in your main mod class

 

@Mod.EventHandler
public void init(FMLInitializationEvent event)
{
      GameRegistry.registerWorldGenerator(new yourWorldGeneratorClassName(), 1);
}

Posted

Underground Biomes replaces all stone, and gets acceptable performance. I have two techniques, although both tend to have incompatibilities with other mods.

 

The original one (originally written by exterminatorJeff) acts during decoration by intercepting BiomeDecorateEvent.Post and replacing the stone there. This method requires only routine Forge calls. It is noticeably slower than vanilla, but quite tolerable if you do your coding right (don't create objects in your innermost loops). However, it's prone to get caught up in the horrible tangle that results from multi-chunk changes in Minecraft chunk-at-a-time generation, and I used to get a never-ending stream of mod interaction crashes. Recently I've tried an ad-hoc system of keeping track of which chunks I'm already modifying and if I get a call to modify one I'm currently modifying I just skip it. Somewhat to my surprise, it worked (I wasn't sure which of the multiple chunks would "count") and it's really cut down on the problems (but not completely abolished them).

 

The other method is to write a wrapper for ChunkProviderGenerate which runs the replace on chunks right after they're made (bypassing the world and neighbor block checks). This is really fast and you can't tell it's there. You have to use reflection to install wrappers onto the ChunkProviderGenerate objects in various worlds, and it is hard sometimes to figure out what to modify. This also creates a interaction problem in that you have to specifically code to manage alternatives to ChunkProviderGenerate used by other mods.

Posted

You guys are the best :)

 

Thanks for pointing out existance of Pre and Post events in decoration - wasn't aware of them, and those (diesieben07's) I'll use.

 

Will have to make some tests with Cauldron and how well that works with other mods, but It should be cool. ;)

1.7.10 is no longer supported by forge, you are on your own.

Posted

I've experimented a bit (not much) and come to this: http://pastebin.com/QgnrXri4

It works and has a decent performance. You can probably optimize it even further by pre-computing the IDs (LSB & MSB) and setting the ID manually instead of using the method that looks up the ID every time.

 

Is there a way to use this with metadata blocks?

Posted

It is an event subscription, so needs to be in a class that is registered to the proper event bus.  Interestingly, even though it is in the terraingen package, it seems to be fired on the regular EVENT_BUS.

 

So in your init() method in your main class or common proxy, you want something like:

        MinecraftForge.EVENT_BUS.register(new yourClassWithEventHandlerMethods());

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Posted

I registered it with the right bus but I keep on getting this crash:

 

Crash

---- Minecraft Crash Report ----
// You should try our sister game, Minceraft!

Time: 7/26/14 4:13 PM
Description: Exception in server tick loop

java.lang.ArrayIndexOutOfBoundsException: 4096
at net.minecraft.world.chunk.storage.ExtendedBlockStorage.getBlockByExtId(ExtendedBlockStorage.java:61)
at com.logictechcorp.orizon.world.worldgen.StoneLayerGen.populateChunk(StoneLayerGen.java:58)
at cpw.mods.fml.common.eventhandler.ASMEventHandler_5_StoneLayerGen_populateChunk_Pre.invoke(.dynamic)
at cpw.mods.fml.common.eventhandler.ASMEventHandler.invoke(ASMEventHandler.java:51)
at cpw.mods.fml.common.eventhandler.EventBus.post(EventBus.java:122)
at net.minecraft.world.gen.ChunkProviderGenerate.populate(ChunkProviderGenerate.java:400)
at net.minecraft.world.gen.ChunkProviderServer.populate(ChunkProviderServer.java:315)
at net.minecraft.world.chunk.Chunk.populateChunk(Chunk.java:1163)
at net.minecraft.world.gen.ChunkProviderServer.originalLoadChunk(ChunkProviderServer.java:210)
at net.minecraft.world.gen.ChunkProviderServer.loadChunk(ChunkProviderServer.java:151)
at net.minecraft.world.gen.ChunkProviderServer.loadChunk(ChunkProviderServer.java:121)
at net.minecraft.server.MinecraftServer.initialWorldChunkLoad(MinecraftServer.java:315)
at net.minecraft.server.integrated.IntegratedServer.loadAllWorlds(IntegratedServer.java:79)
at net.minecraft.server.integrated.IntegratedServer.startServer(IntegratedServer.java:96)
at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:455)
at net.minecraft.server.MinecraftServer$2.run(MinecraftServer.java:762)


A detailed walkthrough of the error, its code path and all known details is as follows:
---------------------------------------------------------------------------------------

-- System Details --
Details:
Minecraft Version: 1.7.10
Operating System: Windows 8.1 (amd64) version 6.3
Java Version: 1.7.0_55, Oracle Corporation
Java VM Version: Java HotSpot(TM) 64-Bit Server VM (mixed mode), Oracle Corporation
Memory: 902761424 bytes (860 MB) / 1056309248 bytes (1007 MB) up to 1056309248 bytes (1007 MB)
JVM Flags: 3 total; -Xincgc -Xmx1024M -Xms1024M
AABB Pool Size: 0 (0 bytes; 0 MB) allocated, 0 (0 bytes; 0 MB) used
IntCache: cache: 0, tcache: 0, allocated: 13, tallocated: 95
FML: MCP v9.05 FML v7.10.1.1152 Minecraft Forge 10.13.0.1152 4 mods loaded, 4 mods active
mcp{9.05} [Minecraft Coder Pack] (minecraft.jar) Unloaded->Constructed->Pre-initialized->Initialized->Post-initialized->Available->Available
FML{7.10.1.1152} [Forge Mod Loader] (forgeSrc-1.7.10-10.13.0.1152.jar) Unloaded->Constructed->Pre-initialized->Initialized->Post-initialized->Available->Available
Forge{10.13.0.1152} [Minecraft Forge] (forgeSrc-1.7.10-10.13.0.1152.jar) Unloaded->Constructed->Pre-initialized->Initialized->Post-initialized->Available->Available
orizon{1.7.X-1.4} [Orizon] (Orizon) Unloaded->Constructed->Pre-initialized->Initialized->Post-initialized->Available->Available
Profiler Position: N/A (disabled)
Vec3 Pool Size: 0 (0 bytes; 0 MB) allocated, 0 (0 bytes; 0 MB) used
Player Count: 0 / 8; []
Type: Integrated Server (map_client.txt)
Is Modded: Definitely; Client brand changed to 'fml,forge'

 

Main Class

@Mod(modid = Reference.MOD_ID, name = Reference.MOD_NAME, version = Reference.MOD_VERSION)
public class Orizon
{
    @Mod.Instance(Reference.MOD_ID)
    public static Orizon instance;

    @SidedProxy(clientSide = Reference.CLIENT_SIDE_CLASS, serverSide = Reference.SERVER_SIDE_CLASS)
    public static IProxy proxy;

    @Mod.EventHandler
    public void preInit(FMLPreInitializationEvent event)
    {
        ModBlocks.init();
        ModOverrides.init();
    }

    @Mod.EventHandler
    public void init(FMLInitializationEvent event)
    {
        MinecraftForge.EVENT_BUS.register(new StoneLayerGen());
        ModRecipes.init();
        ModWorldGen.init();
    }

    @Mod.EventHandler
    public void postInit(FMLPostInitializationEvent event)
    {
        ModOreDictionary.init();
    }
}

 

Event Class

public class StoneLayerGen
{
    @SubscribeEvent
    public  void populateChunk(PopulateChunkEvent.Pre event)
    {
        Chunk chunk = event.world.getChunkFromChunkCoords(event.chunkX, event.chunkZ);
        for(ExtendedBlockStorage storage : chunk.getBlockStorageArray())
        {
            if(storage != null)
            {
                for(int x = 0; x < 16; x++)
                {
                    for(int z = 0; z < 16; z++)
                    {
                        for(int y = 0; y < 16; y++)
                        {
                            if(storage.getBlockByExtId(x, y, z) == Blocks.coal_ore)
                            {
                                storage.setExtBlockMetadata(x, y, z, ModBlocks.stratifiedCoalOre.damageDropped(0));
                            }

                            if(storage.getBlockByExtId(x, y, z) == Blocks.emerald_ore)
                            {
                                storage.setExtBlockMetadata(x, y, z, ModBlocks.stratifiedEmeraldOre.damageDropped(0));
                            }

                            if(storage.getBlockByExtId(x, y, z) == Blocks.gold_ore)
                            {
                                storage.setExtBlockMetadata(x, y, z, ModBlocks.stratifiedGoldOre.damageDropped(0));
                            }

                            if(storage.getBlockByExtId(x, y, z) == Blocks.iron_ore)
                            {
                                storage.setExtBlockMetadata(x, y, z, ModBlocks.stratifiedIronOre.damageDropped(0));
                            }

                            if(storage.getBlockByExtId(x, y, z) == Blocks.lapis_ore)
                            {
                                storage.setExtBlockMetadata(x, y, z, ModBlocks.stratifiedLapisOre.damageDropped(0));
                            }

                            if(storage.getBlockByExtId(x, y, z) == Blocks.stone)
                            {
                                storage.setExtBlockMetadata(x, y, z, ModBlocks.coloredStone.damageDropped(4));
                            }
                        }
                        for(int y = 16; y < 32; y++)
                        {
                            if(storage.getBlockByExtId(x, y, z) == Blocks.coal_ore)
                            {
                                storage.setExtBlockMetadata(x, y, z, ModBlocks.stratifiedCoalOre.damageDropped(2));
                            }

                            if(storage.getBlockByExtId(x, y, z) == Blocks.emerald_ore)
                            {
                                storage.setExtBlockMetadata(x, y, z, ModBlocks.stratifiedEmeraldOre.damageDropped(1));
                            }

                            if(storage.getBlockByExtId(x, y, z) == Blocks.gold_ore)
                            {
                                storage.setExtBlockMetadata(x, y, z, ModBlocks.stratifiedGoldOre.damageDropped(1));
                            }

                            if(storage.getBlockByExtId(x, y, z) == Blocks.iron_ore)
                            {
                                storage.setExtBlockMetadata(x, y, z, ModBlocks.stratifiedIronOre.damageDropped(2));
                            }

                            if(storage.getBlockByExtId(x, y, z) == Blocks.lapis_ore)
                            {
                                storage.setExtBlockMetadata(x, y, z, ModBlocks.stratifiedLapisOre.damageDropped(1));
                            }

                            if(storage.getBlockByExtId(x, y, z) == Blocks.stone)
                            {
                                storage.setExtBlockMetadata(x, y, z, ModBlocks.coloredStone.damageDropped(1));
                            }
                        }
                        for(int y = 32; y < 48; y++)
                        {
                            if(storage.getBlockByExtId(x, y, z) == Blocks.coal_ore)
                            {
                                storage.setExtBlockMetadata(x, y, z, ModBlocks.stratifiedCoalOre.damageDropped(3));
                            }

                            if(storage.getBlockByExtId(x, y, z) == Blocks.emerald_ore)
                            {
                                storage.setExtBlockMetadata(x, y, z, ModBlocks.stratifiedEmeraldOre.damageDropped(2));
                            }

                            if(storage.getBlockByExtId(x, y, z) == Blocks.gold_ore)
                            {
                                storage.setExtBlockMetadata(x, y, z, ModBlocks.stratifiedGoldOre.damageDropped(2));
                            }

                            if(storage.getBlockByExtId(x, y, z) == Blocks.iron_ore)
                            {
                                storage.setExtBlockMetadata(x, y, z, ModBlocks.stratifiedIronOre.damageDropped(3));
                            }

                            if(storage.getBlockByExtId(x, y, z) == Blocks.lapis_ore)
                            {
                                storage.setExtBlockMetadata(x, y, z, ModBlocks.stratifiedLapisOre.damageDropped(2));
                            }

                            if(storage.getBlockByExtId(x, y, z) == Blocks.stone)
                            {
                                storage.setExtBlockMetadata(x, y, z, ModBlocks.coloredStone.damageDropped(14));
                            }
                        }
                        for(int y = 64; y < 256; y++)
                        {
                            if(storage.getBlockByExtId(x, y, z) == Blocks.coal_ore)
                            {
                                storage.setExtBlockMetadata(x, y, z, ModBlocks.stratifiedCoalOre.damageDropped(1));
                            }

                            if(storage.getBlockByExtId(x, y, z) == Blocks.iron_ore)
                            {
                                storage.setExtBlockMetadata(x, y, z, ModBlocks.stratifiedIronOre.damageDropped(1));
                            }

                            if(storage.getBlockByExtId(x, y, z) == Blocks.stone)
                            {
                                storage.setExtBlockMetadata(x, y, z, ModBlocks.coloredStone.damageDropped(6));
                            }
                        }
                    }
                }
            }
        }
    }
}

  • 3 weeks later...
Posted

You need to understand what the "ExtendedBlockStorage" is. The Minecraft world is (as everyone probably knows) split into 16x16 chunks. Then every chunk is split into so called "sections" (introduced with the "new" Anvil Save-format) which are 16 blocks high. If a section is empty, it is not saved / rendered at all, which allowed Mojang to increase the world height to 256 without the save-size doubling in size.

 

Now each "ExtendedBlockStorage" that I am iterating in the code I posted is one of these sections. Therefor it's X coordinate only goes 0-15 (because it's 16 blocks high). If you want different Blocks based on world height you'll need to select the right section.

 

Sorry to bring up an old topic but how would I select a different selection?

Posted

The ExtendedBlockStorage array has one element for each strata (16 strata are possible, each of 16 blocks height).

So, extBlockArray[0] is the lowest strata (blocks x,0-15,y) are in it.

 

 

 

Use something like this:

import net.minecraft.block.Block;
import net.minecraft.init.Blocks;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
import net.minecraftforge.event.terraingen.PopulateChunkEvent;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;

public class StoneLayerGen {
@SubscribeEvent
public void populateChunk(PopulateChunkEvent.Pre event) {
	final Chunk chunk = event.world.getChunkFromChunkCoords(event.chunkX, event.chunkZ);
	final ExtendedBlockStorage[] storageArray = chunk.getBlockStorageArray();
	for (int x = 0; x < 16; x++) {
		for (int z = 0; z < 16; z++) {
			ExtendedBlockStorage storage = storageArray[0]; // 0 <= y < 16
			if (storage != null) {
				for (int y = 0; y < 16; y++) {
					final Block block = storage.getBlockByExtId(x, y, z);
					if (block == Blocks.coal_ore) {
						storage.setExtBlockMetadata(x, level, z, ModBlocks.stratifiedCoalOre.damageDropped(0));
					}

					if (block == Blocks.emerald_ore) {
						storage.setExtBlockMetadata(x, level, z, ModBlocks.stratifiedEmeraldOre.damageDropped(0));
					}

					if (block == Blocks.gold_ore) {
						storage.setExtBlockMetadata(x, y, z, ModBlocks.stratifiedGoldOre.damageDropped(0));
					}

					if (block == Blocks.iron_ore) {
						storage.setExtBlockMetadata(x, y, z, ModBlocks.stratifiedIronOre.damageDropped(0));
					}

					if (block == Blocks.lapis_ore) {
						storage.setExtBlockMetadata(x, y, z,
								ModBlocks.stratifiedLapisOre.damageDropped(0));
					}

					if (block == Blocks.stone) {
						storage.setExtBlockMetadata(x, y, z,
								ModBlocks.coloredStone.damageDropped(4));
					}
				}
			}
			storage = storageArray[1]; // 16 <= y < 32
			if (storage != null) {
				for (int y = 0; y < 16; y++) {
					if (storage != null) {
						final Block block = storage[strata]
								.getBlockByExtId(x, level, z);

						if (storage.getBlockByExtId(x, y, z) == Blocks.coal_ore) {
							storage.setExtBlockMetadata(x, y, z,
									ModBlocks.stratifiedCoalOre
											.damageDropped(2));
						}

						if (storage.getBlockByExtId(x, y, z) == Blocks.emerald_ore) {
							storage.setExtBlockMetadata(x, y, z,
									ModBlocks.stratifiedEmeraldOre
											.damageDropped(1));
						}

						if (storage.getBlockByExtId(x, y, z) == Blocks.gold_ore) {
							storage.setExtBlockMetadata(x, y, z,
									ModBlocks.stratifiedGoldOre
											.damageDropped(1));
						}

						if (storage.getBlockByExtId(x, y, z) == Blocks.iron_ore) {
							storage.setExtBlockMetadata(x, y, z,
									ModBlocks.stratifiedIronOre
											.damageDropped(2));
						}

						if (storage.getBlockByExtId(x, y, z) == Blocks.lapis_ore) {
							storage.setExtBlockMetadata(x, y, z,
									ModBlocks.stratifiedLapisOre
											.damageDropped(1));
						}

						if (storage.getBlockByExtId(x, y, z) == Blocks.stone) {
							storage.setExtBlockMetadata(x, y, z,
									ModBlocks.coloredStone.damageDropped(1));
						}
					}
					storage = storageArray[2]; // 32 <= y < 48
					if (storage != null) {
						for (int y = 0; y < 16; y++) {
							if (storage.getBlockByExtId(x, y, z) == Blocks.coal_ore) {
								storage.setExtBlockMetadata(x, y, z,
										ModBlocks.stratifiedCoalOre.damageDropped(3));
							}

							if (storage.getBlockByExtId(x, y, z) == Blocks.emerald_ore) {
								storage.setExtBlockMetadata(x, y, z,
										ModBlocks.stratifiedEmeraldOre.damageDropped(2));
							}

							if (storage.getBlockByExtId(x, y, z) == Blocks.gold_ore) {
								storage.setExtBlockMetadata(x, y, z,
										ModBlocks.stratifiedGoldOre.damageDropped(2));
							}

							if (storage.getBlockByExtId(x, y, z) == Blocks.iron_ore) {
								storage.setExtBlockMetadata(x, y, z,
										ModBlocks.stratifiedIronOre.damageDropped(3));
							}

							if (storage.getBlockByExtId(x, y, z) == Blocks.lapis_ore) {
								storage.setExtBlockMetadata(x, y, z,
										ModBlocks.stratifiedLapisOre.damageDropped(2));
							}

							if (storage.getBlockByExtId(x, y, z) == Blocks.stone) {
								storage.setExtBlockMetadata(x, y, z,
										ModBlocks.coloredStone.damageDropped(14));
							}
						}
					}
					for (int y = 64; y < 256; y++) {
						storage = storageArray[y >> 4];
						final int level = y & 15;
						if (storage != null) {
							if (storage.getBlockByExtId(x, level, z) == Blocks.coal_ore) {
								storage.setExtBlockMetadata(x, level, z,
										ModBlocks.stratifiedCoalOre.damageDropped(1));
							}

							if (storage.getBlockByExtId(x, level, z) == Blocks.iron_ore) {
								storage.setExtBlockMetadata(x, level, z,
										ModBlocks.stratifiedIronOre.damageDropped(1));
							}

							if (storage.getBlockByExtId(x, level, z) == Blocks.stone) {
								storage.setExtBlockMetadata(x, level, z,
										ModBlocks.coloredStone.damageDropped(6));
							}
						}
					}
				}
			}
		}
	}
}

 

 

Hope this helps.

  • 1 month later...
Posted

I know, this is a little bit of an old thread,but I have a similar Problem and tried to solve it with the code provided by diesieben07:

For a mod I am writing at the Moment (PoorOres) I need to disable worldgen for the ores I add myself. to do that I used the following code:

    public void onEvent(PopulateChunkEvent.Pre event)
    {
        // replace all oreblocks of a type with stone
        // diesieben07 came up with this method (http://www.minecraftforge.net/forum/index.php/topic,21625.0.html)

        Chunk chunk = event.world.getChunkFromChunkCoords(event.chunkX, event.chunkZ);

        for (ExtendedBlockStorage storage : chunk.getBlockStorageArray())
        {
            if (storage != null)
            {
                for (int x = 0; x < 16; ++x)
                {
                    for (int y = 0; y < 16; ++y)
                    {
                        for (int z = 0; z < 16; ++z)
                        {
                            Block curBlock = storage.getBlockByExtId(x, y, z);
                            for (PoorOre poorOre : Reference.WORLDGEN) {
                                if (curBlock == poorOre.getBaseBlock()) {
//                                    LogHelper.info("Replace " + poorOre.getBaseBlock().getLocalizedName() + " at " + x + ", " + y + ", " + z + " with " + poorOre.getUnderlyingBlock().getLocalizedName());
                                    storage.func_150818_a(x, y, z, poorOre.getUnderlyingBlock());
                                }
                            }
                        }
                    }
                }
            }
        }
        chunk.isModified = true; // this is important as it marks it to be saved
    }

 

Any idea, what I am doing wrong? It works fine, when I try to replace stone or grass.

 

Edit: found out, what I was doing wrong. I simply used the OreGenEvent.GenerateMinable event instead and now it works like a charm.

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.