Create icon indicating copy to clipboard operation
Create copied to clipboard

[1.21.1] Processing Recipe Rework

Open RaymondBlaze opened this issue 7 months ago • 10 comments

Fixes #8048.

Overview

This PR reworked the Processing Recipe system in order to:

  • Better adapt the Codec/StreamCodec based RecipeSerializer system in 1.21.1
  • Remove unavailable recipe id context from ProcessingRecipe and ProcessingRecipeParams, the recipe id is no longer retrievable upon deserialization so recipes should not ask for its own id upon construction.
  • Decouple AllRecipeTypes from ProcessingRecipe so addons can create their own processing recipe types
  • Make ProcessingRecipe generic and ProcessingRecipeParams extensible so ProcessingRecipe with more context (like ItemApplicationRecipe) can be created without having to injecting extra context to the base ProcessingRecipeParams.

Usage

To create a custom ProcessingRecipe with custom ProcessingRecipeParams, take ItemApplicationRecipe as an example:

  1. Create a custom ProcessingRecipeParams class: ItemApplicationRecipeParams, add your own field (boolean keepHeldItem) to it;
  2. Create a MapCodec for the params class by grouping a MapCodec with all fields in ProcessingRecipeParams handled and your own field MapCodecs, the prior can be created from ProcessingRecipeParams.codec(Supplier<P>):
public static MapCodec<ItemApplicationRecipeParams> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
		codec(ItemApplicationRecipeParams::new).forGetter(Function.identity()),
		Codec.BOOL.optionalFieldOf("keep_held_item", false).forGetter(ItemApplicationRecipeParams::keepHeldItem)
	).apply(instance, (params, keepHeldItem) -> {
		params.keepHeldItem = keepHeldItem;
		return params;
	}));
  1. Override the encode and decode methods for network (de)serialization, and create a StreamCodec for the params class using ProcessingRecipeParams.streamCodec(Supplier<P>):
public static StreamCodec<RegistryFriendlyByteBuf, ItemApplicationRecipeParams> STREAM_CODEC = streamCodec(ItemApplicationRecipeParams::new);

	@Override
	protected void encode(RegistryFriendlyByteBuf buffer) {
		super.encode(buffer);
		ByteBufCodecs.BOOL.encode(buffer, keepHeldItem);
	}

	@Override
	protected void decode(RegistryFriendlyByteBuf buffer) {
		super.decode(buffer);
		keepHeldItem = ByteBufCodecs.BOOL.decode(buffer);
	}
  1. Create the recipe's MapCodec and StreamCodec from the params', using MapCodec#xmap and StreamCodec#map, and create your own RecipeSerializer with them.
  2. Create the recipe's builder, extending ProcessingRecipeBuilder, you may optionally specify a generic factory interface for input if you wish to use the params for multiple recipes so they can share the builder class:
@FunctionalInterface
public interface Factory<R extends ItemApplicationRecipe> extends ProcessingRecipe.Factory<ItemApplicationRecipeParams, R> {
	R create(ItemApplicationRecipeParams params);
}

public static class Builder<R extends ItemApplicationRecipe> extends ProcessingRecipeBuilder<ItemApplicationRecipeParams, R, Builder<R>> {
	public Builder(Factory<R> factory, ResourceLocation recipeId) {
		super(factory, recipeId);
	}

	@Override
	protected ItemApplicationRecipeParams createParams() {
		return new ItemApplicationRecipeParams();
	}

	@Override
	public Builder<R> self() {
		return this;
	}

	public Builder<R> toolNotConsumed() {
		params.keepHeldItem = true;
		return this;
	}
}
  1. You may now register the recipe's IRecipeTypeInfo, and use the recipe builder in datagen.

RaymondBlaze avatar Mar 14 '25 12:03 RaymondBlaze