|
| 1 | +# Fantasy |
| 2 | +Fantasy is a library that allows for dimensions to be created and destroyed at runtime on the server. |
| 3 | +It supports both temporary dimensions which do not get saved, as well as persistent dimensions which can be safely used across server restarts. |
| 4 | + |
| 5 | +## Using |
| 6 | + |
| 7 | +### Adding to Gradle |
| 8 | +To add Fantasy to your Gradle project, add the Nucleoid Maven repository and Fantasy dependency. |
| 9 | +`FANTASY_VERSION` should be replaced with the latest version from [Maven](https://maven.nucleoid.xyz/xyz/nucleoid/fantasy). |
| 10 | +```gradle |
| 11 | +repositories { |
| 12 | + maven { url = 'https://maven.nucleoid.xyz/' } |
| 13 | +} |
| 14 | +
|
| 15 | +dependencies { |
| 16 | + // ... |
| 17 | + modImplementation 'xyz.nucleoid:fantasy:FANTASY_VERSION' |
| 18 | +} |
| 19 | +``` |
| 20 | + |
| 21 | +### Creating Runtime Dimensions |
| 22 | +All access to Fantasy's APIs goes through the `Fantasy` object, which can be acquired given a `MinecraftServer` instance. |
| 23 | + |
| 24 | +```java |
| 25 | +Fantasy fantasy = Fantasy.get(server); |
| 26 | +// ... |
| 27 | +``` |
| 28 | + |
| 29 | +All dimensions created with Fantasy must be set up through a `RuntimeWorldConfig`. |
| 30 | +This specifies how the dimension should be created, involving a dimension type, seed, chunk generator, and so on. |
| 31 | + |
| 32 | +For example, we could create a config like such: |
| 33 | +```java |
| 34 | +RuntimeWorldConfig worldConfig = new RuntimeWorldConfig() |
| 35 | + .setDimensionType(DimensionType.OVERWORLD_REGISTRY_KEY) |
| 36 | + .setDifficulty(Difficulty.HARD) |
| 37 | + .setGameRule(GameRules.DO_DAYLIGHT_CYCLE, false) |
| 38 | + .setGenerator(server.getOverworld().getChunkManager().getChunkGenerator()) |
| 39 | + .setSeed(1234L); |
| 40 | +``` |
| 41 | + |
| 42 | +Values such as difficulty, game rules, and weather can all be configured per-world. |
| 43 | + |
| 44 | +#### Creating a temporary dimension |
| 45 | +Once we have a runtime world config, creating a temporary dimension is simple: |
| 46 | +```java |
| 47 | +CompletableFuture<RuntimeWorldHandle> future = fantasy.openTemporaryWorld(worldConfig); |
| 48 | +future.thenAccept(worldHandle -> { |
| 49 | + // when the temporary world is created, set a block |
| 50 | + ServerWorld world = worldHandle.asWorld(); |
| 51 | + world.setBlockState(BlockPos.ORIGIN, Blocks.STONE.getDefaultState()); |
| 52 | + |
| 53 | + // we don't need the world anymore, delete it! |
| 54 | + worldHandle.delete(); |
| 55 | +}); |
| 56 | +``` |
| 57 | +Explicit deletion is not strictly required for temporary worlds: they will be automatically cleaned up when the server exits. |
| 58 | +However, it is generally a good idea to delete old worlds if they're not in use anymore. |
| 59 | + |
| 60 | +#### Creating a persistent dimension |
| 61 | +Persistent dimensions work along very similar lines to temporary dimensions: |
| 62 | + |
| 63 | +```java |
| 64 | +CompletableFuture<RuntimeWorldHandle> future = fantasy.getOrOpenPersistentWorld(new Identifier("foo", "bar"), config); |
| 65 | +future.thenAccept(worldHandle -> { |
| 66 | + // when the persistent world is created, set a block |
| 67 | + ServerWorld world = worldHandle.asWorld(); |
| 68 | + world.setBlockState(BlockPos.ORIGIN, Blocks.STONE.getDefaultState()); |
| 69 | +}); |
| 70 | +``` |
| 71 | + |
| 72 | +The main difference involves the addition of an `Identifier` parameter which much be specified to name your dimension uniquely. |
| 73 | + |
| 74 | +Another **very important note** with persistent dimensions is that `getOrOpenPersistentWorld` must be called to re-initialize |
| 75 | +the dimension after a game restart! Fantasy will not restore the dimension by itself- it only makes sure that the world data |
| 76 | +sticks around. This means, if you have a custom persistent dimension, you need to keep track of it and all its needed |
| 77 | +data such that it can be reconstructed by calling `getOrOpenPersistentWorld` again with the same identifier. |
0 commit comments