PyuTest.register_world = function(options)
  local default_options = {}
  local conf = {}

  for k, v in pairs(options) do
    conf[k] = v
  end

  for k, v in pairs(default_options) do
    if conf[k] == nil then
      conf[k] = v
    end
  end

  if conf.y_max == nil or conf.y_min == nil then
    error("Please supply 'y_max' and 'y_min' to the options table!")
  end

  if conf.name == nil then
    error("Please supply 'name' in the options table!")
  end

  core.register_decoration({
    deco_type = "simple",
    decoration = "pyutest_blocks:bedrock",
    place_on = "group:block",
    sidelen = 80,
    fill_ratio = 10,
    y_min = conf.y_max,
    y_max = conf.y_max,
    flags = "force_placement"
  })

  core.register_decoration({
    deco_type = "simple",
    decoration = "pyutest_blocks:bedrock",
    place_on = "group:block",
    sidelen = 80,
    fill_ratio = 10,
    y_min = conf.y_min,
    y_max = conf.y_min,
    flags = "force_placement"
  })

  local World = {
    name = conf.name,
    y_max = conf.y_max,
    y_min = conf.y_min,
    biome_names = {}
  }

  function World:register_biome(name, type, opts, overworld)
    local b = true
    if overworld then
      b = false
    end

    local newname = conf.name .. "-" .. name

    opts["_pyutest_sky_type"] = opts["_pyutest_sky_type"] or conf.sky_type or "plain"
    opts["_pyutest_sky_base_color"] = opts["_pyutest_sky_base_color"] or conf.sky_color or "#000000"

    PyuTest.register_overworld_biome(newname, type, PyuTest.util.tableconcat(opts, {
      depth_top = opts.depth_top or 0,
      depth_filler = opts.depth_filler or 0,
      y_max = opts.y_max or conf.y_max,
      y_min = opts.y_min or conf.y_min,
      node_water = opts.node_water or "air",
      node_river_water = opts.node_water or "air",
      node_cave_liquid = opts.node_water or "air",
    }), b)

    self.biome_names[#self.biome_names + 1] = newname
    return name
  end

  function World:register_ore(o)
    core.register_ore(PyuTest.util.tableconcat(o, {
      y_max = conf.y_max,
      y_min = conf.y_min,
    }))
  end

  function World:register_decoration(o)
    core.register_decoration(PyuTest.util.tableconcat(o, {
      y_max = conf.y_max,
      y_min = conf.y_min
    }))
  end

  function World:create_token(name, world, color, craftitem)
    local average = (conf.y_max + conf.y_min) / 2

    PyuTest.make_item(name, world .. " Token", {
      world_token = 1
    }, "pyutest-world-token.png", {
      color = color,
      stack_max = 16,
      on_use = function(itemstack, user, pointed_thing)
        local pos = user:get_pos()
        local npos = vector.new(pos.x, average, pos.y)
        local range = 1
        itemstack:take_item()

        user:set_pos(npos)
        core.sound_play({ name = "spellbook_action", gain = 1 }, { pos = npos })

        local min = npos - vector.new(range, range, range)
        local max = npos + vector.new(range, range, range)

        local c_air = core.get_content_id("air")
        local c_obsidian = core.get_content_id("pyutest_blocks:obsidian_block")

        local vm = core.get_voxel_manip()
        local emin, emax = vm:read_from_map(min, max)
        local a = VoxelArea:new {
          MinEdge = emin,
          MaxEdge = emax
        }
        local data = vm:get_data()

        local center
        for x = emin.x, emax.x do
          for y = emin.y, emax.y do
            for z = emin.z, emax.z do
              local vi = a:index(x, y, z)

              if data[vi] ~= c_air then
                data[vi] = c_air
              end

              if y == emin.y then
                data[vi] = c_obsidian
              end
            end
          end
        end

        vm:set_data(data)
        vm:write_to_map(true)

        local ax = (emax.x + emin.x) / 2
        local az = (emax.z + emin.z) / 2
        local p = vector.new(ax, emin.y + 1, az)


        core.set_node(p, {
          name = "pyutest_blocks:light"
        })

        user:set_pos(p)

        return itemstack
      end
    })

    core.register_craft({
      output = name,
      recipe = {
        craftitem,
        "pyutest_ores:emerald_shard"
      },
      type = "shapeless"
    })
  end

  return World
end
