Hey @kbar,
Thank you for reaching out to us and pointing out the missing documentation. I will fix that. In the mean time I would recommend having a look at the Gradient and Field Sampling example in the migration guide, as I did explain the principal changes there.
In short, extraData is the means with which sampling has been made const. Before, sampling did change the field instance, now the to be mutated data has been separated out into that 'extra data', and you get your extraData when initializing the sampling. In the example I covered Sample, but things translate directly to DirectSample.
Cheers,
Ferdinand
Code from the migration guide:
  iferr_scope;
 
  // #field is a #FieldObject sampled by the #BaseObject #effector. See the full example for details.
 
  // The input location we want to sample and the output data. We are only interested in sampling
  // FIELDSAMPLE_FLAG::VALUE, i.e., the field influence value of the field at point x.
  FieldInput inputs(Vector(0, 50, 0));
  FieldOutput outputs;
  outputs.Resize(inputs.GetCount(), FIELDSAMPLE_FLAG::VALUE) iferr_return;
  FieldOutputBlock outputBlock = outputs.GetBlock();
 
  // Create the field info for sampling the sample data #inputs for the caller #effector.
  const FieldInfo info = FieldInfo::Create(effector, inputs, FIELDSAMPLE_FLAG::VALUE) iferr_return;
 
  // Sample the field. In 2024.0 we now must pass on the extra data generated by the sampling 
  // initialization so that #field can remain const for this operation.
  maxon::GenericData extraData = field->InitSampling(info) iferr_return;
  field->Sample(inputs, outputBlock, info, extraData, FIELDOBJECTSAMPLE_FLAG::NONE) iferr_return;
 
  // Iterate over the output values.
  for (const maxon::Float value : outputBlock._value)
    ApplicationOutput("Sampled value: @", value);
 
  field->FreeSampling(info, extraData);