Preprocessing Maps

Generate Minecraft worlds by map images!

  1. Via Command Line
  2. Via Data Generators

It’s recommended to preprocess the map image in order to ensure there are no invalid pixel colors and the world will be of the desired scale. The implemented preprocessing algorithms scale a map where each pixel equals one chunk to a map where each pixel equals 4x4 blocks.

To also view a map in the map menu, save the map that shall be displayed at /assets/<namespace>/textures/gui/<map id>.png.

Via Command Line

You can use the mod file as a command line tool to upscale your map image.

usage: java -jar ctgen-0.25.jar -i <arg> -z <arg> -o <arg> [-c <arg>] [-oc]
Tool for upscaling map images so they can be properly read by
the Crafted Terrain Generation Mod (CTGen).
Every image file path must end with ".png"
-i,--input <arg>       Input map image, no alpha supported!
-z,--zones <arg>       directory containing the zones as json files
-o,--output <arg>      Output map image
-c,--corrected <arg>   Optional file to save an image with only the corrected colors
-oc,--only-changed     Works only in addition to --corrected, the corrected image will only show the changed pixel.
Copyright (c) 2024 To_Craft. Licensed under the Crafted License 1.0

For example, you can use the CLI like the following:

java -jar ctgen-1.0.jar -i map.png -o upscaled_map.png -z zones/

The example uses the following file structure:

<dir>
├── ctgen-0.25.jar                      -- The mod file for CTGen
├── map.png                             -- Your input file
├── upscaled_map.png                    -- Will be generated or overwritten if already existing
└── zones                               -- Directory containing the zones files that are also included in the data pack
    ├── zone_a.json
    ├── zone_b.json
    └── zone_c.json

Via Data Generators

You can take a look at ASOS to see how they handle the map upscaling.

In this example, a map at the resource /assets/mymod/textures/gui/my_map.png is parsed and automatically saved as a map with the id mymod:my_map.

Forge:

import java.util.concurrent.CompletableFuture;

@Mod.EventBusSubscriber(modid = MyMod.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD)
public class DataGenerators {
    public static BufferedImage getOriginalMapImage() {
        URL orignalMapUrl = MyMod.class.getResource("/assets/mymod/textures/gui/my_map.png");
        try {
            return ImageIO.read(Objects.requireNonNull(orignalMapUrl));
        } catch (IOException e) {
            throw new RuntimeException("Failed to load biome map located at: " + (orignalMapUrl != null ? orignalMapUrl.getPath() : "invalid location"), e);
        }
    }
    
    @SubscribeEvent
    public static void gatherData(GatherDataEvent event) {
        DataGenerator generator = event.getGenerator();
        PackOutput packOutput = generator.getPackOutput();
        CompletableFuture<HolderLookup.Provider> lookupProvider = event.getLookupProvider();
        
        // World gen maps
        generator.addProvider(true, new MapProvider(getOriginalMapImage(), ResourceLocation.parse("mymod:my_map"), lookupProvider.thenCompose(oProvider -> {
            // this is where you want to extract the list of zones you previously registered
            return new CompletableFuture<List<Zone>>();
        }), packOutput));
    }
}

Fabric:

public final class MyDataGen implements DataGeneratorEntrypoint {
    public static BufferedImage getOriginalMapImage() {
        URL orignalMapUrl = MyMod.class.getResource("/assets/mymod/textures/gui/my_map.png");
        try {
            return ImageIO.read(Objects.requireNonNull(orignalMapUrl));
        } catch (IOException e) {
            throw new RuntimeException("Failed to load biome map located at: " + (orignalMapUrl != null ? orignalMapUrl.getPath() : "invalid location"), e);
        }
    }
    
    @Override
    public void onInitializeDataGenerator(@NotNull FabricDataGenerator generator) {
        FabricDataGenerator.Pack pack = generator.createPack();
        // generate zones here

        // upscale map
        pack.addProvider((output, lookupProvider) -> new MapProvider(getOriginalMapImage(), ResourceLocation.parse("mymod:my_map"), lookupProvider.thenCompose(oProvider -> {
            // this is where you want to extract the list of zones you previously registered
            return new CompletableFuture<List<Zone>>();
        }), output));
    }
}


One more addition to the Map Menu: If you’re a coder and want to redirect the open-map-button, call CTGClient.registerMenu(mapId, (minecraft, packet) -> screen); to provide a custom screen. You can use MapWidget.ofPacket(minecraft, x, y, width, height, packet); to create a new MapWidget with many options to customize it.

Continue with Carvers