Ernio Posted July 23, 2014 Posted July 23, 2014 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. Quote 1.7.10 is no longer supported by forge, you are on your own.
LogicTechCorp Posted July 23, 2014 Posted July 23, 2014 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); } Quote
Zeno410 Posted July 24, 2014 Posted July 24, 2014 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. Quote
Ernio Posted July 25, 2014 Author Posted July 25, 2014 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. Quote 1.7.10 is no longer supported by forge, you are on your own.
LogicTechCorp Posted July 26, 2014 Posted July 26, 2014 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? Quote
jabelar Posted July 26, 2014 Posted July 26, 2014 Is there a way to use this with metadata blocks? Yes, look at the ExtendedBlockStorage class that he is using. There are public methods for getExtBlockMetadata() and setExtBlockMetadata() so you can both test for metadata and set metadata. Quote Check out my tutorials here: http://jabelarminecraft.blogspot.com/
LogicTechCorp Posted July 26, 2014 Posted July 26, 2014 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. Where do I call/register this method? Quote
jabelar Posted July 26, 2014 Posted July 26, 2014 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()); Quote Check out my tutorials here: http://jabelarminecraft.blogspot.com/
LogicTechCorp Posted July 26, 2014 Posted July 26, 2014 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)); } } } } } } } } Quote
LogicTechCorp Posted August 17, 2014 Posted August 17, 2014 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? Quote
sequituri Posted August 17, 2014 Posted August 17, 2014 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. Quote -S- (if I helped, please click Thank and applaud) http://6upnqa.dm2301.livefilestore.com/y2mtf-vG7Tqq1TiiVpIm53KWj7294NDPoHfSHHb4PzZiMAUfRCfK0UY0MwOu7Q3zTBNVTKqWjr2-xgBfFRpQT5p-QivtvknPpoABMNUw9br9WuZcBFkjePhnAbW500gVm-P/sequiturian.png[/img]
mickedplay Posted August 17, 2014 Posted August 17, 2014 (edited) - Edited August 29, 2022 by mickedplay Quote
Shamboozle Posted August 17, 2014 Posted August 17, 2014 Why are you trying to use an event to change things in your own dimension. Just generate your block in the dimension in the first place. Quote
mickedplay Posted August 18, 2014 Posted August 18, 2014 (edited) - Edited August 29, 2022 by mickedplay Quote
Xexanos Posted September 26, 2014 Posted September 26, 2014 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. Quote
Recommended Posts
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.