-
Notifications
You must be signed in to change notification settings - Fork 29
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Support for re-creating persistent worlds #33
Comments
+1 for implementing an API for listing and opening previously created dimensions |
Is there a known way of determining what mods created specific dimensions? Perhaps reading from the registry for what dimensions were registered by what mods? |
@Aareon I don't think that there is an official API for listing dimensions created by fantasy yet. |
Alternatively you could also read the registry entries of the dimension registry and filter by identifier. However, you cannot get the DynamicRegistryManager registryManager = server.getCombinedDynamicRegistries().getCombinedRegistryManager();
Registry<DimensionOptions> dimensionRegistry = registryManager.get(RegistryKeys.DIMENSION);
// iterate all registered dimensions
for (RegistryKey<DimensionOptions> key : dimensionsRegistry.getKeys()) {
Identifier id = key.getValue();
// filter the dimension by mod namespace
if (id.getNamespace().equals("target_mod_id")) {
// do something with it, e.g. get the world
RegistryKey<World> wKey = RegistryKey.of(RegistryKeys.WORLD, id);
ServerWorld world = server.getWorld(wKey);
}
} However, this requires that each mod uses an unique namespace to distinguish the worlds by mod. |
Just from looking, this seems like exactly what I'm looking for. Luckily I don't think I need the RuntimeWorldHandle in my case, as I just want to check what namespaces have been registered so that I can blacklist those namespaces from use in my mod. Here's how I go about creating my private static int jumpToDimension(ServerCommandSource source, String namespace, String name) {
MinecraftServer server = source.getServer();
ServerPlayerEntity player = Objects.requireNonNull(source.getPlayer());
Fantasy fantasy = Fantasy.get(server);
Identifier dimensionId = new Identifier(namespace, name);
RegistryKey<World> dimensionKey = RegistryKey.of(RegistryKeys.WORLD, dimensionId);
if (!DimensionUtility.doesDimensionExist(server, dimensionKey)) {
source.sendFeedback(() -> Text.literal("Dimension §6%s§r:§c%s§r does not exist".formatted(namespace, name)), false);
return 1;
}
RuntimeWorldHandle worldHandle = fantasy.getOrOpenPersistentWorld(dimensionId, DimensionUtility.createStandardVoidConfig(server));
player.teleport(worldHandle.asWorld(), player.getX(), player.getY() + 1.5, player.getZ(), player.getYaw(), player.getPitch());
LOGGER.info("Teleported player %s to %s,%s,%s".formatted(player.getName().getString(), player.getX(), player.getY(), player.getZ()));
source.sendFeedback(() -> Text.literal("Teleported to dimension: §6%s§r:§c%s§r".formatted(namespace, name)), true);
return 0;
}
public static boolean doesDimensionExist(MinecraftServer server, RegistryKey<World> dimensionKey) {
try {
ServerWorld world = server.getWorld(dimensionKey);
if (world != null) {
return true; // Dimension exists
}
} catch (NullPointerException | IllegalArgumentException e) {
// Dimension does not exist or other error occurred
return false;
}
return false;
} I think your extension should help me append new protected namespaces after world initialization to my |
The problem
Currently, if you want to load a previously created persistent world, you have to use
Fantasy::getOrOpenPersistentWorld
.The method obviously requires you to pass a dimension type and chunk generator via a
RuntimeWorldConfig
.If you created the world with a custom generator, you will have to memorize it somehow.
That creates an unnecessary overhead for the developer IMO.
Use case
I personally create worlds for minigames in single player.
Often, I change the generator options, such as the dimension type or the chunk generator in the level.dat.
On my minigame server, I copy the level save into the dimensions directory, every time the game starts.
I would like to load the map as dimension using the fantasy library.
Then, I have to re-create the generator options by hand in Java, for each individual map.
In my case, an API would surely be helpful.
Potential solution
I think there should be an API method on the
Fantasy
class, such asopenPersistentWorld(Identifier)
in order to open worlds inside thedimensions/
directory of the currently loaded save.The method needs to somehow re-construct the
RuntimeWorldConfig
, the world was created with.For this to work, fantasy would also need to save the config/the generator data to disk on persistent world creation.
Implementation details
My proposal would be to check whether there is a
level.dat
file in the directory of the dimension that should be loaded.If it exists, the code from
net.minecraft.world.level.storage.LevelStorage#createLevelDataParser
can be used to parse it.This way, users could also put worlds they created in singleplayer / another world into the dimensions folder of the desired save (my use case).
As for writing the
level.dat
, one could usenet.minecraft.world.level.storage.LevelStorage.Session#backupLevelDataFile()
.Maybe there are even better ways to save and load the world data, I am not sure...
Sample implementation
I implemented the
level.dat
parsing and config re-creation as proof of concept in one of my libraries.If you like the approach, I would be happy to create a pull request providing the feature to fantasy.
Please let me know, if the concept / the implementation is to your liking.
I am still working on the
leve.dat
creation when creating a persistent world. So it can only be tested with other saves ATM.The text was updated successfully, but these errors were encountered: