31

I want to create a new world on our Minecraft server, but exploring a new map and generating terrain causes massive lag.

Is there a way to pre generate the chunks (with the default map generator) in a specific radius around the spawn?

I'm looking for a Bukkit plugin or tool I can use on our Linux machine. An offline tool I can run on my local machine is ok, too.

28

In this thread on Reddit, I found a command line script that will generate terrain by repeatedly restarting a server with varying spawn points until the area you specify is filled. This seems like just what you're looking for.

There's also a Bukkit plugin named WorldGenerationControl which can do it on a live server.

  • 1
    for future readers, command line script (gist) doesn't exist and WGC is outdated – dmnc May 8 '13 at 18:03
  • Boo. That's disappointing. – Brant May 8 '13 at 19:04
  • 1
    the command line script is at github.com/DMBuce/mcexplore – glob Mar 14 '15 at 10:50
  • Thank you so much @glob! I needed a script like this that works with modded servers very badly last night. – PatPeter Dec 2 '18 at 18:05
  • The WorldGenerationControl link does not work anymore – haykam Oct 20 '19 at 15:40
7

It's slow, but you can automatically teleport yourself across all the chunks in a specific area of the map to have them generated using Python and the pexpect module (which I've used to send the teleport commands).

First, make a copy of your game data for testing purposes, then open a command prompt at that directory and do the following:

$ virtualenv venv

$ source venv/bin/activate

$ pip install pexpect

Paste this code into teleport-expect.py (adjust playername and the xcoord and zcoord ranges):

#!/usr/bin/python

import sys
import pexpect
import time

# set this to your minecraft username
playername='yourplayername'

child = pexpect.spawn('java -Xms2048M -Xmx2048M -jar minecraft_server.jar nogui')
child.logfile = sys.stdout
child.expect('%s joined the game' % playername)
child.sendline('gamemode 1 %s' % playername)

for xcoord in range(1000000, 1005000, 16):
    for zcoord in range(1000000, 1005000, 16):
        child.sendline('tp %s %i 255 %i' % (playername, xcoord, zcoord))
        child.expect('Teleported %s' % playername)
        # Time between teleports. Smaller value means more stress for the server.
        time.sleep(0.5)
child.sendline('say all done!')

$ python teleport-expect.py

Once the server starts, login to the game. You should see your player automatically being teleported one chunk at a time across the area of interest. Visiting a 5000x5000 area will take multiple hours to run.

It's not a fast way to generate a map, but neat to see the scenery fly by. I mainly wanted to test running the Minecraft server inside a pexpect session. Lots of potential for other automation (say, watching for user-created commands on a vanilla server)!

5

Minecraft Land Generator:

expands your current vanilla (or modded if you have the server mods) world.

http://www.minecraftforum.net/topic/187737-minecraft-land-generator/

3

A totally vanilla way would be to generate a world in singleplayer and explore that manually. This will be a lot of work of course :)

I am not aware of any other methods.

  • 8
    If you do that it's much faster to do so in Creative mode, where you can fly and make maps at any points to keep track of your progress. Filling in a map takes about 10 minutes in flight for ~25 MB of chunks. – badp Oct 12 '11 at 15:54
  • 1
    This can be combined with Single Player Commands' teleport commands to dramatically lower the time needed. – Ben Blank Oct 12 '11 at 16:47
  • 2
    Not sure why this is an answer. OP is obviously looking for a method to automatically, pre-generate his world. Exploring it manually, even with creative mode, is essentially the exact opposite of this. – b1nary.atr0phy Jun 30 '15 at 23:08
2

The WorldBorder plugin for Bukkit lets you set a predefined map size (measured in radius from spawn), and optionally autogenerate the terrain within your borders.

It automatically generates terrain in the background while the server is running. It took about 24 hours to generate my 3000 block radius round world on a quad core server with 4GB allocated to Minecraft. It seemed like memory was the limiting factor - it would chug along faster than Java's GC routines and have to pause periodically to wait for memory to free up again. Forcing a server restart when memory usage got high did speed it up, but in the end I just ignored it and it managed to finish on it's own.

  • 1
    I recommend to use WorldGenerationControl, it is much faster! We combined booth plugins on our server, WorldGenerationControl to generate the world and WorldBorder to keep it in size. – Fox32 Dec 10 '11 at 13:04
  • @Fox32 I'll have to check that out, thanks. – Saiboogu Dec 10 '11 at 22:37
  • WorldBorder plugin is now outdated – dmnc May 8 '13 at 18:04
1

A better way of doing this now, is to grab yourself a copy of mcedit from http://www.mcedit.net/ and open up your world with that. download a copy of the minecraft server jar (as the one that comes with MCedit is from 1.5.2) and place it in \ServerJarStorage\release . make sure that the jar is called "minecraft_server.jar" Then just use the Chunk generator tool to generate new chunks of an existing map. Or you could use mcedit to generate a complately new map.

1

enter image description here

#!/usr/bin/python

import sys
import pexpect
import time

# set this to your minecraft username
playername='yourplayername'

child = pexpect.spawn('java -Xms2048M -Xmx2048M -jar minecraft_server.jar nogui')
child.logfile = sys.stdout
child.expect('%s joined the game' % playername)
child.sendline('gamemode 1 %s' % playername)

for xcoord in range(1000000, 1005000, 16):
    for zcoord in range(1000000, 1005000, 16):
        child.sendline('tp %s %i 255 %i' % (playername, xcoord, zcoord))
        child.expect('Teleported %s' % playername)
        # Time between teleports. Smaller value means more stress for the server.
        time.sleep(0.5)
child.sendline('say all done!')
0

Here is a version, inspired by the pexpect one above.

To run, use Python 3 and have click installed (maybe in a virtual environment). Then, find help in the command line:

$ python explore.py --help
Usage: explore.py [OPTIONS]

  Travel your minecraft world

Options:
  -p, --player TEXT     Set this a a logged in minecraft player name
  -s, --start TEXT      Starting point x:z
  -r, --radius INTEGER  Width of the world you want generated
  --help                Show this message and exit.

Starting from a point, it will teleport a player in an outward spiral by step until a certain width is attained.

The code below presumes your world is running in a docker image. Edit the run_mc_command function to fit your hosting.

It is slow: Generating a 1000x1000 world is (1000/16)^2 = 3906 teleports at minimum half a second each.

Here is the code:

#!/usr/bin/python

from subprocess import run

from itertools import cycle, count

import click


@click.command()
@click.option("-p", "--player",
              help="Set this a a logged in minecraft player name")
@click.option("-s", "--start",
              help="Starting point x:z",
              default="0:0")
@click.option("-r", "--radius",
              help="Width of the world you want generated",
              default=5000)
def main(player: str, start: str, radius):
    """Travel your minecraft world"""
    start = start.split(":", 2)
    parsed_start = float(start[0]), float(start[1])

    click.echo("Exploring world")
    click.echo(f"  Puppeteering {player!s}")
    click.echo(f"  Starting from {parsed_start!s}")
    click.echo(f"  Until reached {radius!s} meters radius (square, of course)")
    explore(player, parsed_start, float(radius))


def explore(player: str, start: tuple, width: float, step: float = 16) -> None:
    """
    Travel you minecaft world

    Args:
        player: A logged in player will be teleported.  This is its playername.
        start: Starting coordinate (x, z).
        width: Width of the square you want explored.
        step: Length of jumps.  Defaults to 16 minecraft blocks.
    """
    run_mc_command(f"gamemode creative {player!s}")
    for position in walk_spiral(start, step):
        run_mc_command(f"tp {player!s} {position[0]!s} 255 {position[1]!s}")
        distance = position[0] - start[0], position[1] - start[1]
        if distance[0] > width:
            break


def run_mc_command(command: str) -> None:
    """
    Run a Minecraft console command..

    Here you can customize base on where you world is hosted.  This
    implementation use the itzg/minecraft-server docker image.

    Args:
        command: A Minecraft command, such as "say hello"
    """
    run(
        [
            "docker", "exec", "mc", "rcon-cli",
            command
        ]
    )


def walk_spiral(start: tuple, step: float = 16) -> tuple:
    """
    Generate positions to teleport to.

    This is an infinite generator.

    Args:
        start: Starting position
        step: Length of jumps.

    Yields:
        Position to teleport to in a spiral.
    """
    current_movement_x, current_movement_z = start
    movements = spiral_movements()

    while True:
        yield current_movement_x, current_movement_z
        next_x_movement, next_y_movement = next(movements)
        current_movement_x += next_x_movement * step
        current_movement_z += next_y_movement * step


def spiral_movements():

    def _spiral_distances():
        for steps in count(1):
            for _ in (0, 1):
                yield steps

    def _clockwise_directions():
        left = (-1, 0)
        right = (1, 0)
        up = (0, -1)
        down = (0, 1)
        return cycle((right, down, left, up))

    for distance, direction in zip(_spiral_distances(), _clockwise_directions()):
        for _ in range(distance):
            yield direction


if __name__ == "__main__":
    main()

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.