Last active
February 25, 2022 21:42
-
-
Save Commoble/ac7d7b57c9cbbfcae310c4ab110c3cc0 to your computer and use it in GitHub Desktop.
Custom Dimensions and How You Go In Them in Minecraft Forge 1.14 and 1.15
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
WHAT ARE WE WORKING WITH | |
--Dimension, DimensionType, ServerWorld | |
-- There exists a 1:1:1 relationship between each of these, e.g. there will be one DimensionType instance | |
and one Dimension instance for a given ServerWorld, and those DimensionType and Dimension instances will only be | |
used on that worldserver | |
--ServerWorld | |
-- The server-specific version of the World, which holds all the block and chunk data, entities, tile entities, etc.\ | |
for a given dimension. You won't be making these yourself or extending the class, but you'll need to find and use the | |
ServerWorld for your Dimension to teleport the player there. | |
--Dimension | |
-- This one was called WorldProvider in 1.12 and earlier. It's mostly the same, and defines most of the properties | |
of your dimension. You will be extending this class. | |
--DimensionType | |
-- A DimensionType instance is essentially just a ResourceLocation with an optional PacketBuffer stapled to it. | |
DimensionType instances are used to generate and identify Dimension instances; | |
again, there's a one-to-one relationship here | |
-- You won't be extending this class; you use the DimensionManager to generate instances for you from that | |
ResourceLocation and an optional packetbuffer via DimensionManager.registerDimension | |
--ModDimension | |
-- Forge wrapper around the vanilla dimension framework. Responsible for generating the Dimension instance | |
for a given DimensionType. This is also able to pass extra data to the Dimension instance to tweak the | |
properties of your dimension as needed. You may have one ModDimension instance being responsible for | |
many dimensions. You will be extending this class. | |
THE FUNDAMENTAL DIMENSION PIPELINE | |
-- Extend these classes: | |
-- public class YourModDimension extends ModDimension | |
-- public class YourDimension extends Dimension | |
-- Register an instance of YourModDimension in the ModDimension registry event to make | |
an ObjectHolder-friendly instance (optional) | |
-- in the RegisterDimensionEvent FORGE event, call DimensionManager.registerDimension with your YourModDimension | |
instance and a ResourceLocation to get a DimensionType instance for that ResourceLocation | |
(you can optionally give it a PacketBuffer with extra data for your YourDimension as well | |
-- your ModDimension defines a factory that uses a DimensionType instance to generate an instance of YourDimension | |
(if you registered the DimensionType with a data packet, you have access to that data here and can tweak your | |
YourDimension instance as needed) | |
-- finally, your YourDimension instance is responsible for defining all the physical and visual | |
properties of your dimension. In particular, it defines the ChunkGenerator that generates chunks for | |
your dimension. | |
-- To summarize: | |
*DimensionManager uses ResourceLocation + ModDimension instance + PacketBuffer to generate DimensionType instance | |
*ModDimension instance uses DimensionType instance to generate Dimension instance | |
*Dimension instance defines the ChunkGenerator and other things that determine what your dimension's world has in it | |
WHAT ELSE DO WE WANT | |
-we probably also want at least one Biome, a ChunkGenerator, and maybe some Feature/Placements for the biome | |
HOW DO I REGISTER THESE THINGS | |
-Start with the ModDimension: | |
**/ | |
// ModDimensions are a Forge wrapper around the vanilla dimension framework; if you intend to have a variety of dimensions | |
// with the same worldgen behaviour but different variations or pseudoseeds, you can use one ModDimension to dole out Dimensions | |
@EventBusSubscriber(modid = "yourmodid", bus = Bus.MOD) | |
public class ModDimensionRegistrar | |
{ | |
@ObjectHolder("yourmodid:yourdimension") | |
public static final ModDimension YOUR_MOD_DIMENSION = null; | |
@SubscribeEvent | |
public static void onDimensionRegistryEvent(RegistryEvent.Register<ModDimension> event) | |
{ | |
event.getRegistry().register(new YourModDimension().setRegistryName("yourmodid:yourdimension"); | |
} | |
} | |
public class YourModDimension extends ModDimension | |
{ | |
@Override | |
public BiFunction<World, DimensionType, ? extends Dimension> getFactory() | |
{ | |
return YourDimension::new; | |
} | |
} | |
// You can see the ModDimension must implement a method that returns a Dimension based on a World and a DimensionType, | |
// so we'll need a Dimension as well | |
// Dimension is essentially the old WorldProvider from 1.12, with the caveat that they must be unique per world/level | |
// --(you can use one ModDimension for multiple very similar worlds/levels if you need that sort of thing) | |
public class YourDimension extends Dimension | |
{ | |
public YourDimension(World worldIn, DimensionType typeIn) | |
{ | |
super(worldIn, typeIn); | |
} | |
@Override | |
public ChunkGenerator<?> createChunkGenerator() | |
{ | |
// your Chunk Generator tells your dimension what to put in each chunk | |
// it's important but also complicated | |
// check out the vanilla chunkgenerators to try to see how they work | |
} | |
// there's a bunch of things from Dimension you'll need to override; | |
// if you're familiar with 1.12 WorldProviders | |
// then they'll all look very similar, we'll ignore them here for brevity's sake | |
} | |
// we'll also need a DimensionType registered | |
// note that this event fires on the FORGE bus, not the MOD bus | |
@EventBusSubscriber(modid="yourmodid", bus=Bus.FORGE) | |
public class CommonForgeEventHandler | |
{ | |
public static final ResourceLocation DIMENSION_TYPE_RL = new ResourceLocation("yourmodid", "yourdimension"); | |
@SubscribeEvent | |
public static void onRegisterDimensionsEvent(RegisterDimensionsEvent event) | |
{ | |
// the first argument here is a resource location for your dimension type | |
// the second argument here is the ModDimension that your DimensionType uses | |
// the third argument here is an optional PacketBuffer with extra data you want to pass | |
// to your DimensionType, which is in turn passed to your Dimension | |
// which allows you to define properties of your Dimension when you register this | |
// the fourth argument determines skylight for some reason | |
// we'll also need to add a check to prevent the dimension from being registered more than once | |
if (DimensionType.byName(DIMENSION_TYPE_RL) == null) | |
{ | |
DimensionManager.registerDimension(DIMENSION_TYPE_RL, ModDimensionRegistrar.YOUR_MOD_DIMENSION, null, true); | |
} | |
// this returns a DimensionType for your ResourceLocation; alternatively you can also retrieve the dimensiontype with | |
// DimensionType.byName(ResourceLocation) | |
} | |
} | |
// the following block is no longer relevant as of forge build 1.14.4-28.1.35; | |
// the recommended forge build for minecraft 1.14 is still 28.1.0, so this will remain here for now | |
/** | |
IMPORTANT SIDE NOTE FOR FORGE BUILDS 28.1.0 through 28.1.34 | |
Forge apparently doesn't properly sync dimensions to the client | |
https://github.com/MinecraftForge/MinecraftForge/issues/6147 | |
Cryptic Mushroom's Midnight mod has a handshake packet that fixes this licensed under GPL 3 | |
https://github.com/Cryptic-Mushroom/The-Midnight/blob/f33d483012e07107c238af96dd9940ccab555cc4/src/main/java/com/mushroom/midnight/common/registry/MidnightDimensions.java | |
**/ | |
// HOW TO GET TO YOUR DIMENSION | |
public static void teleportPlayer(ServerPlayerEntity player, DimensionType destinationType, BlockPos destinationPos) | |
{ | |
ServerWorld nextWorld = player.getServer().getWorld(destinationType); | |
nextWorld.getChunk(destinationPos); // make sure the chunk is loaded | |
player.teleport(nextWorld, destinationPos.getX(), destinationPos.getY(), destinationPos.getZ(), player.rotationYaw, player.rotationPitch); | |
} | |
// TODO | |
// putting stuff inside your dimension |
Maybe just a note to define all the terminology up front at the top of the gist:
DimensionType
: Unique handle to a world. There is oneWorldServer
for eachDimensionType
. EachDimensionType
has a string ID likeminecraft:overworld
, that replaces the old int world ids. The name is a bad one since it's not a type, it's a unique handle.Dimension
: Implements a lot of logic for each dimension like the horizon height, sky color, etc. Used to be calledWorldProvider
. There's one per world just likeDimensionType
, but these have no name/ID and thus aren't uniquely identifiable.ModDimension
: Forge class, a template to create newDimension
. There need not be a 1:1 correspondence between this and worlds/DimensionType
s.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
L79: That won't work. When you save the world and reload it, that line will throw an error: duplicate key.
You have to check to see if your dim is already registered first:
https://github.com/Draco18s/ReasonableRealism/blob/1.14.4/src/main/java/com/draco18s/industry/ExpandedIndustry.java#L175