Jump to content

Blocking structures, liquids, initial creature spawns for Skyblock generation mod (1.12.2)


jks

Recommended Posts

Hello all. I'm trying to create a simple Skyblock (void + a single spawn island) mod that preserves biomes (only as visible through F3) along with their sizes and distributions, including those created by mods like Biomes O'Plenty as an optional mod compatibility. The goal is to support the unique spawning and growing logic through mods (Pixelmon being front of mind) and to encourage building the island out to these locations. A map won't suffice in that it will be the same every time and will have restrictive hard world limits. I want to preserve existing Nether/End/mod dimension gen logic and to only modify the Overworld, at least for now. I'm doing this first in 1.12.2, though I plan to write it eventually for 1.16.5 and potentially beyond. This mod will be for single player and multiplayer servers.

I've identified two ways of doing this, both somewhat brittle due to the nature of the mod. The first is to block many of the world gen events or substitute my own post generation event that wipes the generation and substitutes a floating skyblock island if it is the spawn area. The second is to rewrite the entire vanilla + mod biome gen logic in a similar manner to Realistic Terrain Generation, with the added complexity that I don't want to change the biome size or borders (I'm admittedly not sure how this works. If there's simple logic for this and biomes borders are locked at chunk boundaries instead of something more freeform, this might not be tough) I'm concerned however that this would be a lot of excess code and class bloat, and small additions would break it. As such, and given that logically what I am doing is simply taking existing biome gen but totally voiding it and writing in a small island, the first seems simplest and most intuitive if possible

Eventually the plan is to also add a command + simple object that can generate a new island in a random location, set the player's spawn point to that island, and teleport them there. Not immediately relevant or important, but if others see unique concerns with this, I'm all ears.

The way I'm accomplishing the void and rewrite is to write a class WorldGenHandler, registered during the FMLPreInitializationEvent handler in the main mod class in the following manner:

MinecraftForge.TERRAIN_GEN_BUS.register(WorldGenHandler.class);

and in the class subscribe to a series of chunk loading, decoration, replace biome blocks, and init map gen events. I'm aware it's likely messy and redundant or contains methods that effectively do nothing in conjunction with others, but right now I'm spitballing and seeing what sticks:

 

package com.jks.skygenmod.util;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import net.minecraft.init.Blocks;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
import net.minecraft.world.gen.MapGenBase;
import net.minecraftforge.event.terraingen.BiomeEvent.GetVillageBlockID;
import net.minecraftforge.event.terraingen.ChunkGeneratorEvent.ReplaceBiomeBlocks;
import net.minecraftforge.event.terraingen.DecorateBiomeEvent;
import net.minecraftforge.event.terraingen.InitMapGenEvent;
import net.minecraftforge.event.terraingen.PopulateChunkEvent;
import net.minecraftforge.event.world.BlockEvent.CreateFluidSourceEvent;
import net.minecraftforge.event.world.BlockEvent.FluidPlaceBlockEvent;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
import net.minecraftforge.fml.common.eventhandler.Event.Result;
import net.minecraftforge.fml.common.eventhandler.EventPriority;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;

@EventBusSubscriber
public class WorldGenHandler {
	private static final HashSet<InitMapGenEvent.EventType> permittedMapGenEvents 
		= new HashSet<InitMapGenEvent.EventType>(
				Arrays.asList(
						InitMapGenEvent.EventType.END_CITY,
						InitMapGenEvent.EventType.NETHER_BRIDGE,
						InitMapGenEvent.EventType.NETHER_CAVE
						)
				);
	
	@SubscribeEvent(priority=EventPriority.LOWEST, receiveCanceled=true)
	public static void onPopulate(PopulateChunkEvent.Populate event)
	{
		Logger logger = LogManager.getLogger(Reference.MOD_ID);
		logger.info("<< JKS SKYGEN >> BLOCK POPULATE OF TYPE {}", event.getType().name());
	    
		if (!event.getWorld().isRemote)
		{
		    event.setResult(Result.DENY);
		}
	}
	
	@SubscribeEvent(priority=EventPriority.LOWEST, receiveCanceled=true)
	public static void onEvent(PopulateChunkEvent.Post event)
	{
		Logger logger = LogManager.getLogger(Reference.MOD_ID);
		logger.info("<< JKS SKYGEN >> REWRITING BLOCKS TO AIR");
	    
		if (!event.getWorld().isRemote)
		{
		    Chunk chunk = event.getWorld().getChunkFromChunkCoords(event.getChunkX(), event.getChunkZ());
	
		    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) 
		                    {
		                    	//logger.info("<< JKS SKYGEN >> REWRITING BLOCK AT X:{}, Y: {}, Z: {}", x, y, z);
		                    	storage.set(x, y, z, Blocks.AIR.getDefaultState());
		                    }
		                }
		            }
		        }
		    }  
		    chunk.setModified(true); // this is important as it marks it to be saved
		}
	}
	
	@SubscribeEvent
	public static void onDecorateBiome(DecorateBiomeEvent.Decorate event)
	{
		Logger logger = LogManager.getLogger(Reference.MOD_ID);
		logger.info("<< JKS >> onDecorateBiome: {}", event.getType().name());
		if (!event.getWorld().isRemote)
		{
			event.setResult(Result.DENY);
		}
	}
	
	@SubscribeEvent
	public static void onReplaceBiomeBlocks(ReplaceBiomeBlocks event)
	{
		Logger logger = LogManager.getLogger(Reference.MOD_ID);
		logger.info("<< JKS >> onReplaceBiomeBlocks");
		if (!event.getWorld().isRemote)
		{
			event.setResult(Result.DENY);
		}
	}
	
	@SubscribeEvent
	public static void onInitMapGen(InitMapGenEvent event)
	{
		Logger logger = LogManager.getLogger(Reference.MOD_ID);
		logger.info("<< JKS >> onInitMapGen: {}", event.getType().name());
		if (!permittedMapGenEvents.contains(event.getType())) {
			event.setResult(Result.DENY);
		}
		else {
			logger.info("<< ! JKS ! >> Permitted init event {}", event.getType().name());
		}
	}
}

This logic voids most of the world, but despite the onInitMapGen event, I still gee some structures generating, most notably mineshafts and ocean monuments, and I think at one point I might have seen a floating village garden, though I could be recalling an old test. I also see stray water and lava pillars. These seem logically inconsistent with the above behavior.

On a separate note, do I need to check isRemote on the onInitMapGen, or is it implicitly not remote? Unsure how to grab the world from the event. Also, is there a way to change some of this logic to only take effect when in the overworld? That onInitMapGen seems like it might make a check like that tricky.

All the best and thanks for taking the time to take a look at this. Let me know if more is needed.
jks

Link to comment
Share on other sites

  • Curle locked this topic
Guest
This topic is now closed to further replies.

Announcements



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • A friend found this code, but I don't know where. It seems to be very outdated, maybe from 1.12? and so uses TextureManager$loadTexture and TextureManager$deleteTexture which both don't seem to exist anymore. It also uses Minecraft.getMinecraft().mcDataDir.getCanonicalPath() which I replaced with the resource location of my texture .getPath()? Not sure if thats entirely correct. String textureName = "entitytest.png"; File textureFile = null; try { textureFile = new File(Minecraft.getMinecraft().mcDataDir.getCanonicalPath(), textureName); } catch (Exception ex) { } if (textureFile != null && textureFile.exists()) { ResourceLocation MODEL_TEXTURE = Resources.OTHER_TESTMODEL_CUSTOM; TextureManager texturemanager = Minecraft.getMinecraft().getTextureManager(); texturemanager.deleteTexture(MODEL_TEXTURE); Object object = new ThreadDownloadImageData(textureFile, null, MODEL_TEXTURE, new ImageBufferDownload()); texturemanager.loadTexture(MODEL_TEXTURE, (ITextureObject)object); return true; } else { return false; }   Then I've been trying to go through the source code of the reload resource packs from minecraft, to see if I can "cache" some data and simply reload some textures and swap them out, but I can't seem to figure out where exactly its "loading" the texture files and such. Minecraft$reloadResourcePacks(bool) seems to be mainly controlling the loading screen, and using this.resourcePackRepository.reload(); which is PackRepository$reload(), but that function seems to be using this absolute confusion of a line List<String> list = this.selected.stream().map(Pack::getId).collect(ImmutableList.toImmutableList()); and then this.discoverAvailable() and this.rebuildSelected. The rebuild selected seemed promising, but it seems to just be going through each pack and doing this to them? pack.getDefaultPosition().insert(list, pack, Functions.identity(), false); e.g. putting them into a list of packs and returning that into this.selected? Where do the textures actually get baked/loaded/whatever? Any info on how Minecraft reloads resource packs or how the texture manager works would be appreciated!
    • This might be a long shot , but do you remember how you fixed that?
    • Yeah, I'll start with the ones I added last night.  Wasn't crashing until today and wasn't crashing at all yesterday (+past few days since removing Cupboard), so deductive reasoning says it's likeliest to be one of the new ones.  A few horse armor mods and a corn-based add-on to Farmer's Delight, the latter which I hope to keep - I could do without the horse armor mods if necessary.  Let me try a few things and we'll see. 
    • Add crash-reports with sites like https://mclo.gs/ Add this mod: https://www.curseforge.com/minecraft/mc-mods/packet-fixer/files/5416165
  • Topics

×
×
  • Create New...

Important Information

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