Jump to content

treebranch

Members
  • Posts

    40
  • Joined

  • Last visited

Everything posted by treebranch

  1. Okay, I need to move on with my mod. I've went back to the original method of indiscriminately overwriting chunks every time they're loaded. Mostly this will involve replacing rare ores with stone unless the chunk is a certain distance away from spawn, or unless the block's Y level is deep enough. My solution to the problem of player-placed ores getting overwritten looks something like this: @SubscribeEvent public void onBlockHarvestDrops(BlockEvent.HarvestDropsEvent event) { if (event.isSilkTouching() && event.getState() == Blocks.COAL_ORE.getDefaultState()) { event.getDrops().clear(); event.getDrops().add(new ItemStack(Items.COAL)); } } If anybody has a problem with this, please let me know the way you'd do it instead, and I'll happily switch. Until then...I guess I'll just warn people on the mod page that they shouldn't use this mod with creative mode.
  2. I was having this problem with ChunkDataEvent.Load. My guess is that Forge hasn't properly implemented these things yet for 1.13, but I could be wrong.
  3. Well, I'm just about at the end of my wits trying to figure this out. I went as far as to turn the HashSet into a ConcurrentHashMap and iterate through it every ServerTickEvent to deal with new chunks. Theoretically this should always modify chunks the tick after they're created. But ChunkGeneratorEvent.ReplaceBiomeBlocks is called on so many not-loaded chunks that this method slowed the game down to a crawl. Distributing it over several ticks is too slow and introduces the problem of people closing the game before every chunk has been replaced. Does anybody here know of a simpler way for me to just edit a chunk after its been created?
  4. Wasn't aware of HashSet, it looks like it just uses a HashTable internally so I'll switch anyway since it makes more sense for my code. Unfortunately there's no chunk decorate event in 1.13. I've looked at all the past code examples I could, and it seems like almost every event used for purposes like this has been removed. ChunkGeneratorEvent.ReplaceBiomeBlocks is the closest I could find.
  5. So after a good night's sleep I've rethought my approach and come up with a solution that doesn't involve any data saving. It simply marks chunks as new on ChunkGeneratorEvent.ReplaceBiomeBlocks—this event could be anything, I'm just using it because it's called during the generation of new chunks—then the chunks are replaced later in on ChunkEvent.Load. It works, almost too well. However it's causing a memory leak. Even though I remove new chunks from my NewChunks list after they've been replaced, it seems that ReplaceBiomeBlocks is being called more often than ChunkEvent.Load is, and the list steadily grows faster than it shrinks. Here's the code: @SubscribeEvent public void onReplaceBiomeBlocks(ChunkGeneratorEvent.ReplaceBiomeBlocks event) { // This event is called whenever a new chunk is being generated, so we can prepare the chunk for replacement NewChunks.put(event.getChunk().getPos().asLong(), true); } @SubscribeEvent public void onChunkLoad(ChunkEvent.Load event) { Chunk chunk = (Chunk) event.getChunk(); // If this chunk isn't marked as a new chunk, don't modify it (return immediately) if (!NewChunks.containsKey(chunk.getPos().asLong())) { return; } IBlockState coaldefault = Blocks.COAL_ORE.getDefaultState(); IBlockState diamonddefault = Blocks.DIAMOND_ORE.getDefaultState(); try (PooledMutableBlockPos pos = PooledMutableBlockPos.retain()) { for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { for (int y = 2; y <= 256; y++) { pos.setPos(x, y, z); if (chunk.getBlockState(pos) == coaldefault) { chunk.setBlockState(pos, diamonddefault, false); } } } } } // Remove this chunk from the list of new chunks to free up memory and prevent it from being replaced again NewChunks.remove(chunk.getPos().asLong()); chunk.markDirty(); }
  6. Okay so I ended up creating a table called IgnoreChunks to keep track of what chunks have been modified and therefore should be ignored. The chunk's position is added to IgnoreChunks after it's been modified, and the position is unloaded when the chunk is unloaded. The chunk's ignore status is saved via NBT on OnChunkData.Save, and that NBT data is checked on OnChunkData.Load to populate the IgnoreChunks table again. It works as expected, and there are no memory leaks, but there's a problem. The ignore state is lost when the game is entirely restarted (closed then re-opened) which causes chunks to get overwritten again. The cause seems to be that ChunkDataEvent.Load is never called (!!!) and I can't tell whether this is a Forge bug or my own mistake. Here's the code: @SubscribeEvent public void onChunkLoadData(ChunkDataEvent.Load event) { NBTTagCompound chunkdata = event.getData(); // If this chunk is marked as ignored in NBT, load its position to the ignore list so that onChunkLoad knows not to modify it if (chunkdata.getBoolean(ModInfo.MODID + "_ignore")) { IgnoreChunks.put(event.getChunk().getPos().asLong(), true); } } @SubscribeEvent public void onChunkSaveData(ChunkDataEvent.Save event) { NBTTagCompound chunkdata = event.getData(); // If this chunk's position is loaded in the ignore list, mark it as ignored in NBT before it's saved if (IgnoreChunks.containsKey(event.getChunk().getPos().asLong())) { chunkdata.setBoolean(ModInfo.MODID + "_ignore", true); } } @SubscribeEvent public void onChunkLoad(ChunkEvent.Load event) { Chunk chunk = (Chunk) event.getChunk(); // If this chunk's position is loaded in the ignore list, don't modify it (return immediately) if (IgnoreChunks.containsKey(chunk.getPos().asLong())) { return; } IBlockState coaldefault = Blocks.COAL_ORE.getDefaultState(); IBlockState diamonddefault = Blocks.DIAMOND_ORE.getDefaultState(); try (PooledMutableBlockPos pos = PooledMutableBlockPos.retain()) { for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { for (int y = 2; y <= 256; y++) { pos.setPos(x, y, z); if (chunk.getBlockState(pos) == coaldefault) { chunk.setBlockState(pos, diamonddefault, false); } } } } } // Load the chunk's position to the ignore list IgnoreChunks.put(chunk.getPos().asLong(), true); chunk.markDirty(); } @SubscribeEvent public void onChunkUnload(ChunkEvent.Unload event) { // Unload this chunk's position from the ignore list if it's loaded Long pos = event.getChunk().getPos().asLong(); if (IgnoreChunks.containsKey(pos)) { IgnoreChunks.remove(pos); } }
  7. I think IChunk is immutable, and that's why .markDirty() doesn't exist. Older versions of Forge had this method simply return a mutable Chunk. I can't figure out how to get my hands on a Chunk instead of an IChunk, and searching for IChunk on this forum brings this thread up as the only result. Does anybody here have more info? Edit: So far I've had no visible problems casting my IChunk to a Chunk and calling the method anyway. Not sure if this is a bad idea or not.
  8. It may be inefficient but I'm blindly trusting what @Draco18s said on the other thread: Removing generators won't do me well because I'm going to need certain blocks to generate differently depending on how far away from world center the chunk is. And don't worry, I know it's fired everytime a chunk loads. I'm still looking for a good way to keep track of what chunks have been modified and which ones haven't. However I appreciate your help, and please continue suggesting things if you know alternative ways to do what I want, because there isn't much info out there.
  9. Thanks for the tips. Could you please further explain what PooledMutableBlockPos is? What does .retain() do?
  10. I came across this thread: Here's the code I ended up coming up with as a test, replacing all coal ore with diamond ore every time a chunk loads: @SubscribeEvent public void oreGenMinable(ChunkEvent.Load event) { IChunk chunk = event.getChunk(); LOGGER.info("SCANNING CHUNK at " + chunk.getPos().toString()); IBlockState coaldefault = Blocks.COAL_ORE.getDefaultState(); IBlockState diamonddefault = Blocks.DIAMOND_ORE.getDefaultState(); for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { for (int y = 2; y <= 256; y++) { BlockPos pos = new BlockPos(x, y, z); if (chunk.getBlockState(pos) == coaldefault) { chunk.setBlockState(pos, diamonddefault, false); } } } } } I noticed the chunk class no longer has .markDirty(), I'm wondering if this is still necessary. I also still need a way to avoid overwriting the same chunk twice.
  11. As somebody just getting started it seems like everything has changed in 1.13.
  12. I'm trying to handle when a vanilla ore is generated so I can cancel it under certain conditions. So far I've tried looking into OreGenEvent.GenerateMinable and MinecraftForge.ORE_GEN_BUS, but neither of those appear to exist in 1.13. I tried searching these forums, but nobody seems to have asked about this yet. There isn't any up-to-date online documentation either. I tried skimming through events manually and guessing by their names, but I couldn't find anything. Does anybody know the new way to handle when an ore block is generated?
  13. Hello, I'm brand new to Minecraft modding and I'm trying to wrap my mind around the basics. I've set up Forge and currently I'm somewhat lost about where to go next. I first tried following the official documentation (https://mcforge.readthedocs.io/en/latest/ ) but quickly ran into some dead ends and realized that the documentation is designed for older versions of Minecraft. I had some luck finding information about 1.13 by searching these forums, but there aren't a lot of threads on it yet, and most of them don't have enough information to help me as a beginner. I've found many tutorials, but none of the ones I've seen are explaining basic Forge concepts or telling me why to use certain code or what it does. Is there any one reliable place I can trust to be up-to-date and accurate? Lots of people here seem to know exactly what they're doing. So what am I missing? Thanks
×
×
  • Create New...

Important Information

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