mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2024-11-14 05:44:52 +00:00
Replace some recipes with a more dynamic system
This adds a new "recipe function" system, that allows transforming the result of a recipe according to some datapack-defined function. Currently, we only provide one function: computercraft:copy_components, which copies components from one of the ingredients to the result. This allows us to replace several of our existing recipes: - Turtle overlay recipes are now defined as a normal shapeless recipe that copies all (non-overlay) components from the input turtle. - Computer conversion recipes (e.g. computer -> turtle, normal -> advanced) copy all components from the input computer to the result. This is more complex (and thus more code), but also a little more flexible, which hopefully is useful for someone :).
This commit is contained in:
parent
d7786ee4b9
commit
a3b07909b0
@ -1,6 +1,7 @@
|
||||
{
|
||||
"type": "computercraft:computer_convert",
|
||||
"type": "computercraft:transform_shaped",
|
||||
"category": "redstone",
|
||||
"function": [{"type": "computercraft:copy_components", "from": {"item": "computercraft:computer_normal"}}],
|
||||
"key": {"#": {"tag": "c:ingots/gold"}, "C": {"item": "computercraft:computer_normal"}},
|
||||
"pattern": ["###", "#C#", "# #"],
|
||||
"result": {"count": 1, "id": "computercraft:computer_advanced"}
|
||||
|
@ -1,6 +1,9 @@
|
||||
{
|
||||
"type": "computercraft:computer_convert",
|
||||
"type": "computercraft:transform_shaped",
|
||||
"category": "redstone",
|
||||
"function": [
|
||||
{"type": "computercraft:copy_components", "from": {"item": "computercraft:pocket_computer_normal"}}
|
||||
],
|
||||
"key": {"#": {"tag": "c:ingots/gold"}, "C": {"item": "computercraft:pocket_computer_normal"}},
|
||||
"pattern": ["###", "#C#", "# #"],
|
||||
"result": {"count": 1, "id": "computercraft:pocket_computer_advanced"}
|
||||
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"type": "computercraft:computer_convert",
|
||||
"type": "computercraft:transform_shaped",
|
||||
"category": "redstone",
|
||||
"function": [{"type": "computercraft:copy_components", "from": {"item": "computercraft:computer_advanced"}}],
|
||||
"key": {
|
||||
"#": {"tag": "c:ingots/gold"},
|
||||
"C": {"item": "computercraft:computer_advanced"},
|
||||
|
@ -1,6 +1,13 @@
|
||||
{
|
||||
"type": "computercraft:turtle_overlay",
|
||||
"type": "computercraft:transform_shapeless",
|
||||
"category": "redstone",
|
||||
"function": [
|
||||
{
|
||||
"type": "computercraft:copy_components",
|
||||
"exclude": ["computercraft:overlay"],
|
||||
"from": {"item": "computercraft:turtle_advanced"}
|
||||
}
|
||||
],
|
||||
"group": "computercraft:turtle_advanced_overlay",
|
||||
"ingredients": [
|
||||
{"tag": "c:dyes/red"},
|
||||
@ -12,6 +19,9 @@
|
||||
{"item": "minecraft:stick"},
|
||||
{"item": "computercraft:turtle_advanced"}
|
||||
],
|
||||
"overlay": "computercraft:block/turtle_rainbow_overlay",
|
||||
"result": {"count": 1, "id": "computercraft:turtle_advanced"}
|
||||
"result": {
|
||||
"components": {"computercraft:overlay": "computercraft:block/turtle_rainbow_overlay"},
|
||||
"count": 1,
|
||||
"id": "computercraft:turtle_advanced"
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,13 @@
|
||||
{
|
||||
"type": "computercraft:turtle_overlay",
|
||||
"type": "computercraft:transform_shapeless",
|
||||
"category": "redstone",
|
||||
"function": [
|
||||
{
|
||||
"type": "computercraft:copy_components",
|
||||
"exclude": ["computercraft:overlay"],
|
||||
"from": {"item": "computercraft:turtle_advanced"}
|
||||
}
|
||||
],
|
||||
"group": "computercraft:turtle_advanced_overlay",
|
||||
"ingredients": [
|
||||
{"tag": "c:dyes/light_blue"},
|
||||
@ -9,6 +16,9 @@
|
||||
{"item": "minecraft:stick"},
|
||||
{"item": "computercraft:turtle_advanced"}
|
||||
],
|
||||
"overlay": "computercraft:block/turtle_trans_overlay",
|
||||
"result": {"count": 1, "id": "computercraft:turtle_advanced"}
|
||||
"result": {
|
||||
"components": {"computercraft:overlay": "computercraft:block/turtle_trans_overlay"},
|
||||
"count": 1,
|
||||
"id": "computercraft:turtle_advanced"
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"type": "computercraft:computer_convert",
|
||||
"type": "computercraft:transform_shaped",
|
||||
"category": "redstone",
|
||||
"function": [{"type": "computercraft:copy_components", "from": {"item": "computercraft:turtle_normal"}}],
|
||||
"key": {
|
||||
"#": {"tag": "c:ingots/gold"},
|
||||
"B": {"tag": "c:storage_blocks/gold"},
|
||||
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"type": "computercraft:computer_convert",
|
||||
"type": "computercraft:transform_shaped",
|
||||
"category": "redstone",
|
||||
"function": [{"type": "computercraft:copy_components", "from": {"item": "computercraft:computer_normal"}}],
|
||||
"key": {
|
||||
"#": {"tag": "c:ingots/iron"},
|
||||
"C": {"item": "computercraft:computer_normal"},
|
||||
|
@ -1,6 +1,13 @@
|
||||
{
|
||||
"type": "computercraft:turtle_overlay",
|
||||
"type": "computercraft:transform_shapeless",
|
||||
"category": "redstone",
|
||||
"function": [
|
||||
{
|
||||
"type": "computercraft:copy_components",
|
||||
"exclude": ["computercraft:overlay"],
|
||||
"from": {"item": "computercraft:turtle_normal"}
|
||||
}
|
||||
],
|
||||
"group": "computercraft:turtle_normal_overlay",
|
||||
"ingredients": [
|
||||
{"tag": "c:dyes/red"},
|
||||
@ -12,6 +19,9 @@
|
||||
{"item": "minecraft:stick"},
|
||||
{"item": "computercraft:turtle_normal"}
|
||||
],
|
||||
"overlay": "computercraft:block/turtle_rainbow_overlay",
|
||||
"result": {"count": 1, "id": "computercraft:turtle_normal"}
|
||||
"result": {
|
||||
"components": {"computercraft:overlay": "computercraft:block/turtle_rainbow_overlay"},
|
||||
"count": 1,
|
||||
"id": "computercraft:turtle_normal"
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,13 @@
|
||||
{
|
||||
"type": "computercraft:turtle_overlay",
|
||||
"type": "computercraft:transform_shapeless",
|
||||
"category": "redstone",
|
||||
"function": [
|
||||
{
|
||||
"type": "computercraft:copy_components",
|
||||
"exclude": ["computercraft:overlay"],
|
||||
"from": {"item": "computercraft:turtle_normal"}
|
||||
}
|
||||
],
|
||||
"group": "computercraft:turtle_normal_overlay",
|
||||
"ingredients": [
|
||||
{"tag": "c:dyes/light_blue"},
|
||||
@ -9,6 +16,9 @@
|
||||
{"item": "minecraft:stick"},
|
||||
{"item": "computercraft:turtle_normal"}
|
||||
],
|
||||
"overlay": "computercraft:block/turtle_trans_overlay",
|
||||
"result": {"count": 1, "id": "computercraft:turtle_normal"}
|
||||
"result": {
|
||||
"components": {"computercraft:overlay": "computercraft:block/turtle_trans_overlay"},
|
||||
"count": 1,
|
||||
"id": "computercraft:turtle_normal"
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,6 @@ import dan200.computercraft.impl.RegistryHelper;
|
||||
import dan200.computercraft.shared.ModRegistry;
|
||||
import dan200.computercraft.shared.common.ClearColourRecipe;
|
||||
import dan200.computercraft.shared.common.ColourableRecipe;
|
||||
import dan200.computercraft.shared.computer.recipe.ComputerConvertRecipe;
|
||||
import dan200.computercraft.shared.media.recipes.DiskRecipe;
|
||||
import dan200.computercraft.shared.media.recipes.PrintoutRecipe;
|
||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||
@ -27,8 +26,10 @@ import dan200.computercraft.shared.pocket.items.PocketComputerItem;
|
||||
import dan200.computercraft.shared.pocket.recipes.PocketComputerUpgradeRecipe;
|
||||
import dan200.computercraft.shared.recipe.ImpostorShapedRecipe;
|
||||
import dan200.computercraft.shared.recipe.ImpostorShapelessRecipe;
|
||||
import dan200.computercraft.shared.recipe.TransformShapedRecipe;
|
||||
import dan200.computercraft.shared.recipe.TransformShapelessRecipe;
|
||||
import dan200.computercraft.shared.recipe.function.CopyComponents;
|
||||
import dan200.computercraft.shared.turtle.items.TurtleItem;
|
||||
import dan200.computercraft.shared.turtle.recipes.TurtleOverlayRecipe;
|
||||
import dan200.computercraft.shared.turtle.recipes.TurtleUpgradeRecipe;
|
||||
import dan200.computercraft.shared.util.ColourUtils;
|
||||
import dan200.computercraft.shared.util.DataComponentUtil;
|
||||
@ -194,16 +195,21 @@ final class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider {
|
||||
}
|
||||
|
||||
private void turtleOverlay(RecipeOutput add, String overlay, Consumer<ShapelessSpecBuilder> build) {
|
||||
var overlayId = new ResourceLocation(ComputerCraftAPI.MOD_ID, "block/" + overlay);
|
||||
|
||||
for (var turtleItem : turtleItems()) {
|
||||
var name = RegistryHelper.getKeyOrThrow(BuiltInRegistries.ITEM, turtleItem);
|
||||
|
||||
var builder = ShapelessSpecBuilder.shapeless(RecipeCategory.REDSTONE, new ItemStack(turtleItem))
|
||||
var builder = ShapelessSpecBuilder
|
||||
.shapeless(RecipeCategory.REDSTONE, DataComponentUtil.createStack(turtleItem, ModRegistry.DataComponents.OVERLAY.get(), overlayId))
|
||||
.group(name.withSuffix("_overlay").toString())
|
||||
.unlockedBy("has_turtle", inventoryChange(turtleItem));
|
||||
build.accept(builder);
|
||||
builder
|
||||
.requires(turtleItem)
|
||||
.build(s -> new TurtleOverlayRecipe(s, new ResourceLocation(ComputerCraftAPI.MOD_ID, "block/" + overlay)))
|
||||
.build(s -> new TransformShapelessRecipe(s, List.of(
|
||||
CopyComponents.builder(turtleItem).exclude(ModRegistry.DataComponents.OVERLAY.get()).build()
|
||||
)))
|
||||
.save(add, name.withSuffix("_overlays/" + overlay));
|
||||
}
|
||||
}
|
||||
@ -251,7 +257,7 @@ final class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider {
|
||||
.define('#', ingredients.goldIngot())
|
||||
.define('C', ModRegistry.Items.COMPUTER_NORMAL.get())
|
||||
.unlockedBy("has_components", inventoryChange(itemPredicate(ModRegistry.Items.COMPUTER_NORMAL.get()), itemPredicate(ingredients.goldIngot())))
|
||||
.build(ComputerConvertRecipe::new)
|
||||
.build(x -> new TransformShapedRecipe(x, List.of(new CopyComponents(ModRegistry.Items.COMPUTER_NORMAL.get()))))
|
||||
.save(add, new ResourceLocation(ComputerCraftAPI.MOD_ID, "computer_advanced_upgrade"));
|
||||
|
||||
ShapedRecipeBuilder
|
||||
@ -274,7 +280,7 @@ final class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider {
|
||||
.define('C', ModRegistry.Items.COMPUTER_NORMAL.get())
|
||||
.define('I', ingredients.woodenChest())
|
||||
.unlockedBy("has_computer", inventoryChange(ModRegistry.Items.COMPUTER_NORMAL.get()))
|
||||
.build(ComputerConvertRecipe::new)
|
||||
.build(x -> new TransformShapedRecipe(x, List.of(new CopyComponents(ModRegistry.Items.COMPUTER_NORMAL.get()))))
|
||||
.save(add);
|
||||
|
||||
ShapedSpecBuilder
|
||||
@ -286,7 +292,7 @@ final class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider {
|
||||
.define('C', ModRegistry.Items.COMPUTER_ADVANCED.get())
|
||||
.define('I', ingredients.woodenChest())
|
||||
.unlockedBy("has_computer", inventoryChange(ModRegistry.Items.COMPUTER_NORMAL.get()))
|
||||
.build(ComputerConvertRecipe::new)
|
||||
.build(x -> new TransformShapedRecipe(x, List.of(new CopyComponents(ModRegistry.Items.COMPUTER_ADVANCED.get()))))
|
||||
.save(add);
|
||||
|
||||
ShapedSpecBuilder
|
||||
@ -298,7 +304,7 @@ final class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider {
|
||||
.define('C', ModRegistry.Items.TURTLE_NORMAL.get())
|
||||
.define('B', ingredients.goldBlock())
|
||||
.unlockedBy("has_components", inventoryChange(itemPredicate(ModRegistry.Items.TURTLE_NORMAL.get()), itemPredicate(ingredients.goldIngot())))
|
||||
.build(ComputerConvertRecipe::new)
|
||||
.build(x -> new TransformShapedRecipe(x, List.of(new CopyComponents(ModRegistry.Items.TURTLE_NORMAL.get()))))
|
||||
.save(add, new ResourceLocation(ComputerCraftAPI.MOD_ID, "turtle_advanced_upgrade"));
|
||||
|
||||
ShapedRecipeBuilder
|
||||
@ -363,7 +369,7 @@ final class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider {
|
||||
.define('#', ingredients.goldIngot())
|
||||
.define('C', ModRegistry.Items.POCKET_COMPUTER_NORMAL.get())
|
||||
.unlockedBy("has_components", inventoryChange(itemPredicate(ModRegistry.Items.POCKET_COMPUTER_NORMAL.get()), itemPredicate(ingredients.goldIngot())))
|
||||
.build(ComputerConvertRecipe::new)
|
||||
.build(x -> new TransformShapedRecipe(x, List.of(new CopyComponents(ModRegistry.Items.POCKET_COMPUTER_NORMAL.get()))))
|
||||
.save(add, new ResourceLocation(ComputerCraftAPI.MOD_ID, "pocket_computer_advanced_upgrade"));
|
||||
|
||||
ShapedRecipeBuilder
|
||||
|
@ -37,7 +37,6 @@ import dan200.computercraft.shared.computer.items.AbstractComputerItem;
|
||||
import dan200.computercraft.shared.computer.items.CommandComputerItem;
|
||||
import dan200.computercraft.shared.computer.items.ComputerItem;
|
||||
import dan200.computercraft.shared.computer.items.ServerComputerReference;
|
||||
import dan200.computercraft.shared.computer.recipe.ComputerConvertRecipe;
|
||||
import dan200.computercraft.shared.config.Config;
|
||||
import dan200.computercraft.shared.data.BlockNamedEntityLootCondition;
|
||||
import dan200.computercraft.shared.data.HasComputerIdLootCondition;
|
||||
@ -71,16 +70,14 @@ import dan200.computercraft.shared.pocket.items.PocketComputerItem;
|
||||
import dan200.computercraft.shared.pocket.peripherals.PocketModem;
|
||||
import dan200.computercraft.shared.pocket.peripherals.PocketSpeaker;
|
||||
import dan200.computercraft.shared.pocket.recipes.PocketComputerUpgradeRecipe;
|
||||
import dan200.computercraft.shared.recipe.CustomShapedRecipe;
|
||||
import dan200.computercraft.shared.recipe.CustomShapelessRecipe;
|
||||
import dan200.computercraft.shared.recipe.ImpostorShapedRecipe;
|
||||
import dan200.computercraft.shared.recipe.ImpostorShapelessRecipe;
|
||||
import dan200.computercraft.shared.recipe.*;
|
||||
import dan200.computercraft.shared.recipe.function.CopyComponents;
|
||||
import dan200.computercraft.shared.recipe.function.RecipeFunction;
|
||||
import dan200.computercraft.shared.turtle.FurnaceRefuelHandler;
|
||||
import dan200.computercraft.shared.turtle.blocks.TurtleBlock;
|
||||
import dan200.computercraft.shared.turtle.blocks.TurtleBlockEntity;
|
||||
import dan200.computercraft.shared.turtle.inventory.TurtleMenu;
|
||||
import dan200.computercraft.shared.turtle.items.TurtleItem;
|
||||
import dan200.computercraft.shared.turtle.recipes.TurtleOverlayRecipe;
|
||||
import dan200.computercraft.shared.turtle.recipes.TurtleUpgradeRecipe;
|
||||
import dan200.computercraft.shared.turtle.upgrades.*;
|
||||
import dan200.computercraft.shared.util.DataComponentUtil;
|
||||
@ -91,14 +88,17 @@ import net.minecraft.commands.synchronization.SingletonArgumentInfo;
|
||||
import net.minecraft.core.cauldron.CauldronInteraction;
|
||||
import net.minecraft.core.component.DataComponentType;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.codec.ByteBufCodecs;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.flag.FeatureFlags;
|
||||
import net.minecraft.world.inventory.MenuType;
|
||||
import net.minecraft.world.item.*;
|
||||
import net.minecraft.world.item.component.DyedItemColor;
|
||||
import net.minecraft.world.item.crafting.CustomRecipe;
|
||||
import net.minecraft.world.item.crafting.Recipe;
|
||||
import net.minecraft.world.item.crafting.RecipeSerializer;
|
||||
import net.minecraft.world.item.crafting.SimpleCraftingRecipeSerializer;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
@ -474,17 +474,32 @@ public final class ModRegistry {
|
||||
return REGISTRY.register(name, () -> new SimpleCraftingRecipeSerializer<>(factory));
|
||||
}
|
||||
|
||||
private static <T extends Recipe<?>> RegistryEntry<RecipeSerializer<T>> register(String name, MapCodec<T> codec, StreamCodec<RegistryFriendlyByteBuf, T> streamCodec) {
|
||||
return REGISTRY.register(name, () -> new BasicRecipeSerialiser<>(codec, streamCodec));
|
||||
}
|
||||
|
||||
public static final RegistryEntry<RecipeSerializer<ImpostorShapedRecipe>> IMPOSTOR_SHAPED = REGISTRY.register("impostor_shaped", () -> CustomShapedRecipe.serialiser(ImpostorShapedRecipe::new));
|
||||
public static final RegistryEntry<RecipeSerializer<ImpostorShapelessRecipe>> IMPOSTOR_SHAPELESS = REGISTRY.register("impostor_shapeless", () -> CustomShapelessRecipe.serialiser(ImpostorShapelessRecipe::new));
|
||||
|
||||
public static final RegistryEntry<RecipeSerializer<TransformShapedRecipe>> TRANSFORM_SHAPED = register("transform_shaped", TransformShapedRecipe.CODEC, TransformShapedRecipe.STREAM_CODEC);
|
||||
public static final RegistryEntry<RecipeSerializer<TransformShapelessRecipe>> TRANSFORM_SHAPELESS = register("transform_shapeless", TransformShapelessRecipe.CODEC, TransformShapelessRecipe.STREAM_CODEC);
|
||||
|
||||
public static final RegistryEntry<SimpleCraftingRecipeSerializer<ColourableRecipe>> DYEABLE_ITEM = simple("colour", ColourableRecipe::new);
|
||||
public static final RegistryEntry<SimpleCraftingRecipeSerializer<ClearColourRecipe>> DYEABLE_ITEM_CLEAR = simple("clear_colour", ClearColourRecipe::new);
|
||||
public static final RegistryEntry<SimpleCraftingRecipeSerializer<TurtleUpgradeRecipe>> TURTLE_UPGRADE = simple("turtle_upgrade", TurtleUpgradeRecipe::new);
|
||||
public static final RegistryEntry<RecipeSerializer<TurtleOverlayRecipe>> TURTLE_OVERLAY = REGISTRY.register("turtle_overlay", TurtleOverlayRecipe::serialiser);
|
||||
public static final RegistryEntry<SimpleCraftingRecipeSerializer<PocketComputerUpgradeRecipe>> POCKET_COMPUTER_UPGRADE = simple("pocket_computer_upgrade", PocketComputerUpgradeRecipe::new);
|
||||
public static final RegistryEntry<SimpleCraftingRecipeSerializer<PrintoutRecipe>> PRINTOUT = simple("printout", PrintoutRecipe::new);
|
||||
public static final RegistryEntry<SimpleCraftingRecipeSerializer<DiskRecipe>> DISK = simple("disk", DiskRecipe::new);
|
||||
public static final RegistryEntry<RecipeSerializer<ComputerConvertRecipe>> COMPUTER_CONVERT = REGISTRY.register("computer_convert", () -> CustomShapedRecipe.serialiser(ComputerConvertRecipe::new));
|
||||
}
|
||||
|
||||
public static class RecipeFunctions {
|
||||
static final RegistrationHelper<RecipeFunction.Type<?>> REGISTRY = PlatformHelper.get().createRegistrationHelper(RecipeFunction.REGISTRY);
|
||||
|
||||
private static <T extends RecipeFunction> RegistryEntry<RecipeFunction.Type<T>> register(String name, MapCodec<T> codec, StreamCodec<RegistryFriendlyByteBuf, T> streamCodec) {
|
||||
return REGISTRY.register(name, () -> new RecipeFunction.Type<>(codec, streamCodec));
|
||||
}
|
||||
|
||||
public static final RegistryEntry<RecipeFunction.Type<CopyComponents>> COPY_COMPONENTS = register("copy_components", CopyComponents.CODEC, CopyComponents.STREAM_CODEC);
|
||||
}
|
||||
|
||||
public static class Permissions {
|
||||
@ -553,6 +568,7 @@ public final class ModRegistry {
|
||||
ArgumentTypes.REGISTRY.register();
|
||||
LootItemConditionTypes.REGISTRY.register();
|
||||
RecipeSerializers.REGISTRY.register();
|
||||
RecipeFunctions.REGISTRY.register();
|
||||
Permissions.REGISTRY.register();
|
||||
CreativeTabs.REGISTRY.register();
|
||||
|
||||
|
@ -1,53 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2018 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.shared.computer.recipe;
|
||||
|
||||
import dan200.computercraft.shared.ModRegistry;
|
||||
import dan200.computercraft.shared.computer.items.AbstractComputerItem;
|
||||
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
|
||||
import dan200.computercraft.shared.recipe.CustomShapedRecipe;
|
||||
import dan200.computercraft.shared.recipe.ShapedRecipeSpec;
|
||||
import net.minecraft.core.HolderLookup;
|
||||
import net.minecraft.world.inventory.CraftingContainer;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.crafting.RecipeSerializer;
|
||||
|
||||
/**
|
||||
* A recipe which converts a computer from one form into another.
|
||||
*/
|
||||
public final class ComputerConvertRecipe extends CustomShapedRecipe {
|
||||
private final Item result;
|
||||
|
||||
public ComputerConvertRecipe(ShapedRecipeSpec recipe) {
|
||||
super(recipe);
|
||||
this.result = recipe.result().getItem();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack assemble(CraftingContainer inventory, HolderLookup.Provider registryAccess) {
|
||||
// Find our computer item and copy the components across.
|
||||
for (var i = 0; i < inventory.getContainerSize(); i++) {
|
||||
var stack = inventory.getItem(i);
|
||||
if (isComputerItem(stack.getItem())) {
|
||||
var newStack = new ItemStack(result);
|
||||
newStack.applyComponents(stack.getComponentsPatch());
|
||||
return newStack;
|
||||
}
|
||||
}
|
||||
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecipeSerializer<ComputerConvertRecipe> getSerializer() {
|
||||
return ModRegistry.RecipeSerializers.COMPUTER_CONVERT.get();
|
||||
}
|
||||
|
||||
private static boolean isComputerItem(Item item) {
|
||||
// TODO: Make this a little more general. Either with a tag, or a predicate on the recipe itself?
|
||||
return item instanceof AbstractComputerItem || item instanceof PocketComputerItem;
|
||||
}
|
||||
}
|
@ -32,7 +32,7 @@ public abstract class CustomShapedRecipe extends ShapedRecipe {
|
||||
public abstract RecipeSerializer<? extends CustomShapedRecipe> getSerializer();
|
||||
|
||||
public static <T extends CustomShapedRecipe> RecipeSerializer<T> serialiser(Function<ShapedRecipeSpec, T> factory) {
|
||||
return new BasicRecipeSerialiser<T>(
|
||||
return new BasicRecipeSerialiser<>(
|
||||
ShapedRecipeSpec.CODEC.xmap(factory, CustomShapedRecipe::toSpec),
|
||||
ShapedRecipeSpec.STREAM_CODEC.map(factory, CustomShapedRecipe::toSpec)
|
||||
);
|
||||
|
@ -0,0 +1,55 @@
|
||||
// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.shared.recipe;
|
||||
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import dan200.computercraft.shared.ModRegistry;
|
||||
import dan200.computercraft.shared.recipe.function.RecipeFunction;
|
||||
import net.minecraft.core.HolderLookup;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.world.inventory.CraftingContainer;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.crafting.RecipeSerializer;
|
||||
import net.minecraft.world.item.crafting.ShapedRecipe;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A {@link ShapedRecipe} that applies a list of {@linkplain RecipeFunction recipe functions}.
|
||||
*/
|
||||
public final class TransformShapedRecipe extends CustomShapedRecipe {
|
||||
public static final MapCodec<TransformShapedRecipe> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
|
||||
ShapedRecipeSpec.CODEC.forGetter(TransformShapedRecipe::toSpec),
|
||||
RecipeFunction.LIST_CODEC.fieldOf("function").forGetter(x -> x.functions)
|
||||
).apply(instance, TransformShapedRecipe::new)
|
||||
);
|
||||
|
||||
public static final StreamCodec<RegistryFriendlyByteBuf, TransformShapedRecipe> STREAM_CODEC = StreamCodec.composite(
|
||||
ShapedRecipeSpec.STREAM_CODEC, TransformShapedRecipe::toSpec,
|
||||
RecipeFunction.LIST_STREAM_CODEC, x -> x.functions,
|
||||
TransformShapedRecipe::new
|
||||
);
|
||||
|
||||
private final List<RecipeFunction> functions;
|
||||
|
||||
public TransformShapedRecipe(ShapedRecipeSpec recipe, List<RecipeFunction> functions) {
|
||||
super(recipe);
|
||||
this.functions = functions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack assemble(CraftingContainer inventory, HolderLookup.Provider registryAccess) {
|
||||
var result = super.assemble(inventory, registryAccess);
|
||||
for (var function : functions) result = function.apply(inventory, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecipeSerializer<TransformShapedRecipe> getSerializer() {
|
||||
return ModRegistry.RecipeSerializers.TRANSFORM_SHAPED.get();
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.shared.recipe;
|
||||
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import dan200.computercraft.shared.ModRegistry;
|
||||
import dan200.computercraft.shared.recipe.function.RecipeFunction;
|
||||
import net.minecraft.core.HolderLookup;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.world.inventory.CraftingContainer;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.crafting.RecipeSerializer;
|
||||
import net.minecraft.world.item.crafting.ShapelessRecipe;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A {@link ShapelessRecipe} that applies a list of {@linkplain RecipeFunction recipe functions}.
|
||||
*/
|
||||
public class TransformShapelessRecipe extends CustomShapelessRecipe {
|
||||
public static final MapCodec<TransformShapelessRecipe> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
|
||||
ShapelessRecipeSpec.CODEC.forGetter(TransformShapelessRecipe::toSpec),
|
||||
RecipeFunction.LIST_CODEC.fieldOf("function").forGetter(x -> x.functions)
|
||||
).apply(instance, TransformShapelessRecipe::new));
|
||||
|
||||
public static final StreamCodec<RegistryFriendlyByteBuf, TransformShapelessRecipe> STREAM_CODEC = StreamCodec.composite(
|
||||
ShapelessRecipeSpec.STREAM_CODEC, CustomShapelessRecipe::toSpec,
|
||||
RecipeFunction.LIST_STREAM_CODEC, x -> x.functions,
|
||||
TransformShapelessRecipe::new
|
||||
);
|
||||
|
||||
private final List<RecipeFunction> functions;
|
||||
|
||||
public TransformShapelessRecipe(ShapelessRecipeSpec spec, List<RecipeFunction> functions) {
|
||||
super(spec);
|
||||
this.functions = functions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack assemble(CraftingContainer inventory, HolderLookup.Provider registryAccess) {
|
||||
var result = super.assemble(inventory, registryAccess);
|
||||
for (var function : functions) result = function.apply(inventory, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecipeSerializer<TransformShapelessRecipe> getSerializer() {
|
||||
return ModRegistry.RecipeSerializers.TRANSFORM_SHAPELESS.get();
|
||||
}
|
||||
}
|
@ -0,0 +1,179 @@
|
||||
// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.shared.recipe.function;
|
||||
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import dan200.computercraft.shared.ModRegistry;
|
||||
import net.minecraft.core.component.DataComponentPatch;
|
||||
import net.minecraft.core.component.DataComponentType;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.codec.ByteBufCodecs;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.world.inventory.CraftingContainer;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.crafting.Ingredient;
|
||||
import net.minecraft.world.level.ItemLike;
|
||||
import net.minecraft.world.level.storage.loot.functions.CopyComponentsFunction;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A {@link RecipeFunction} that copies components from one of the ingredients to the result.
|
||||
* <p>
|
||||
* This has the same behaviour as {@linkplain CopyComponentsFunction}, but operating within the scope of recipes.
|
||||
*/
|
||||
public final class CopyComponents implements RecipeFunction {
|
||||
public static final MapCodec<CopyComponents> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
|
||||
Ingredient.CODEC_NONEMPTY.fieldOf("from").forGetter(x -> x.from),
|
||||
DataComponentType.CODEC.listOf().optionalFieldOf("include").forGetter(x -> x.include),
|
||||
DataComponentType.CODEC.listOf().optionalFieldOf("exclude").forGetter(x -> x.exclude)
|
||||
).apply(instance, CopyComponents::new));
|
||||
|
||||
public static final StreamCodec<RegistryFriendlyByteBuf, CopyComponents> STREAM_CODEC = StreamCodec.composite(
|
||||
Ingredient.CONTENTS_STREAM_CODEC, x -> x.from,
|
||||
ByteBufCodecs.optional(DataComponentType.STREAM_CODEC.apply(ByteBufCodecs.list())), x -> x.include,
|
||||
ByteBufCodecs.optional(DataComponentType.STREAM_CODEC.apply(ByteBufCodecs.list())), x -> x.exclude,
|
||||
CopyComponents::new
|
||||
);
|
||||
|
||||
private final Ingredient from;
|
||||
private final Optional<List<DataComponentType<?>>> include;
|
||||
private final Optional<List<DataComponentType<?>>> exclude;
|
||||
|
||||
private final @Nullable Set<DataComponentType<?>> includeSet;
|
||||
private final @Nullable Set<DataComponentType<?>> excludeSet;
|
||||
|
||||
/**
|
||||
* Create a new {@link CopyComponents} that copies all components from an ingredient.
|
||||
*
|
||||
* @param from The ingredient to copy from.
|
||||
*/
|
||||
public CopyComponents(Ingredient from) {
|
||||
this(from, Optional.empty(), Optional.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link CopyComponents} that copies all components from an ingredient.
|
||||
*
|
||||
* @param from The ingredient to copy from.
|
||||
*/
|
||||
public CopyComponents(ItemLike from) {
|
||||
this(Ingredient.of(from));
|
||||
}
|
||||
|
||||
private CopyComponents(Ingredient from, Optional<List<DataComponentType<?>>> include, Optional<List<DataComponentType<?>>> exclude) {
|
||||
this.from = from;
|
||||
this.include = include.map(List::copyOf);
|
||||
this.exclude = exclude.map(List::copyOf);
|
||||
|
||||
includeSet = include.map(Set::copyOf).orElse(null);
|
||||
excludeSet = exclude.map(Set::copyOf).orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type<?> getType() {
|
||||
return ModRegistry.RecipeFunctions.COPY_COMPONENTS.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack apply(CraftingContainer container, ItemStack result) {
|
||||
for (var item : container.getItems()) {
|
||||
if (from.test(item)) {
|
||||
applyPatch(item.getComponentsPatch(), result);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void applyPatch(DataComponentPatch patch, ItemStack result) {
|
||||
if (includeSet == null && excludeSet == null) {
|
||||
result.applyComponents(patch);
|
||||
return;
|
||||
}
|
||||
|
||||
// Only apply components in the include set (if present) and not in the exclude set (if present).
|
||||
for (var component : patch.entrySet()) {
|
||||
var type = component.getKey();
|
||||
if ((includeSet == null || includeSet.contains(type)) && (excludeSet == null || !excludeSet.contains(type))) {
|
||||
unsafeSetComponent(result, type, component.getValue().orElse(null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T> void unsafeSetComponent(ItemStack stack, DataComponentType<?> type, @Nullable T value) {
|
||||
stack.set((DataComponentType<T>) type, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link CopyComponents} builder, that copies components from an ingredient.
|
||||
*
|
||||
* @param ingredient The ingredient to copy from.
|
||||
* @return The builder.
|
||||
*/
|
||||
public static Builder builder(Ingredient ingredient) {
|
||||
return new Builder(ingredient);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link CopyComponents} builder, that copies components from an ingredient.
|
||||
*
|
||||
* @param ingredient The ingredient to copy from.
|
||||
* @return The builder.
|
||||
*/
|
||||
public static Builder builder(ItemLike ingredient) {
|
||||
return new Builder(Ingredient.of(ingredient));
|
||||
}
|
||||
|
||||
public static final class Builder {
|
||||
private final Ingredient from;
|
||||
private @Nullable List<DataComponentType<?>> include;
|
||||
private @Nullable List<DataComponentType<?>> exclude;
|
||||
|
||||
private Builder(Ingredient from) {
|
||||
this.from = from;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only copy the specified component.
|
||||
*
|
||||
* @param type The component to include.
|
||||
* @return {@code this}, for chaining.
|
||||
*/
|
||||
public Builder include(DataComponentType<?> type) {
|
||||
if (this.include == null) include = new ArrayList<>();
|
||||
include.add(type);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exclude a component from being copied.
|
||||
*
|
||||
* @param type The component to exclude.
|
||||
* @return {@code this}, for chaining.
|
||||
*/
|
||||
public Builder exclude(DataComponentType<?> type) {
|
||||
if (exclude == null) exclude = new ArrayList<>();
|
||||
exclude.add(type);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the resulting {@link CopyComponents} instance.
|
||||
*
|
||||
* @return The constructed {@link CopyComponents} recipe function.
|
||||
*/
|
||||
public CopyComponents build() {
|
||||
return new CopyComponents(from, Optional.ofNullable(include), Optional.ofNullable(exclude));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.shared.recipe.function;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.impl.RegistryHelper;
|
||||
import dan200.computercraft.shared.recipe.TransformShapedRecipe;
|
||||
import dan200.computercraft.shared.recipe.TransformShapelessRecipe;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.codec.ByteBufCodecs;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.inventory.CraftingContainer;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.storage.loot.functions.LootItemFunction;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A function that is applied to the result of a recipe, mutating it in some way. These can be used from within a recipe
|
||||
* JSON file to define basic dynamic recipes, rather than having to fall back to Java.
|
||||
* <p>
|
||||
* For instance, the recipe to convert a normal computer to a turtle, is defined as a basic shaped recipes plus an
|
||||
* additional {@link CopyComponents} function, that copies the id and label from the computer to the turtle.
|
||||
* <p>
|
||||
* The design and implementation of these are very similar to Minecraft's existing {@linkplain LootItemFunction loot
|
||||
* functions}.
|
||||
*
|
||||
* @see TransformShapedRecipe
|
||||
* @see TransformShapelessRecipe
|
||||
*/
|
||||
public interface RecipeFunction {
|
||||
/**
|
||||
* The registry where {@link RecipeFunction}s are registered.
|
||||
*/
|
||||
ResourceKey<Registry<Type<?>>> REGISTRY = ResourceKey.createRegistryKey(new ResourceLocation(ComputerCraftAPI.MOD_ID, "recipe_function"));
|
||||
|
||||
/**
|
||||
* The codec to read and write {@link RecipeFunction}s with.
|
||||
*/
|
||||
Codec<RecipeFunction> CODEC = Codec.lazyInitialized(() -> RegistryHelper.getRegistry(REGISTRY).byNameCodec().dispatch(RecipeFunction::getType, Type::codec));
|
||||
|
||||
/**
|
||||
* A codec for a list of functions.
|
||||
*/
|
||||
Codec<List<RecipeFunction>> LIST_CODEC = CODEC.listOf(1, Integer.MAX_VALUE);
|
||||
|
||||
/**
|
||||
* The {@link StreamCodec} equivalent of {@link #CODEC}.
|
||||
*/
|
||||
StreamCodec<RegistryFriendlyByteBuf, RecipeFunction> STREAM_CODEC = ByteBufCodecs.registry(REGISTRY).dispatch(RecipeFunction::getType, Type::streamCodec);
|
||||
|
||||
/**
|
||||
* The {@link StreamCodec} equivalent of {@link #LIST_CODEC}.
|
||||
*/
|
||||
StreamCodec<RegistryFriendlyByteBuf, List<RecipeFunction>> LIST_STREAM_CODEC = STREAM_CODEC.apply(ByteBufCodecs.list());
|
||||
|
||||
/**
|
||||
* Get the type of this recipe function.
|
||||
*
|
||||
* @return The type of this recipe function.
|
||||
*/
|
||||
Type<?> getType();
|
||||
|
||||
/**
|
||||
* Apply this recipe function, modifying the result item.
|
||||
*
|
||||
* @param container The current crafting container.
|
||||
* @param result The result item to modify. This may be mutated in place.
|
||||
* @return The new result item. This may be {@code result}.
|
||||
*/
|
||||
ItemStack apply(CraftingContainer container, ItemStack result);
|
||||
|
||||
/**
|
||||
* Properties about a type of {@link RecipeFunction}. These are stored in {@linkplain #REGISTRY a Minecraft
|
||||
* registry}, and returned by {@link #getType()}.
|
||||
*
|
||||
* @param codec The codec to read and write this class of recipe functions with.
|
||||
* @param streamCodec The network codec to read and write this class of recipe functions with.
|
||||
* @param <T> The type of recipe function.
|
||||
*/
|
||||
record Type<T extends RecipeFunction>(MapCodec<T> codec, StreamCodec<RegistryFriendlyByteBuf, T> streamCodec) {
|
||||
}
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.shared.turtle.recipes;
|
||||
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import dan200.computercraft.shared.ModRegistry;
|
||||
import dan200.computercraft.shared.recipe.BasicRecipeSerialiser;
|
||||
import dan200.computercraft.shared.recipe.CustomShapelessRecipe;
|
||||
import dan200.computercraft.shared.recipe.ShapelessRecipeSpec;
|
||||
import dan200.computercraft.shared.turtle.items.TurtleItem;
|
||||
import dan200.computercraft.shared.util.DataComponentUtil;
|
||||
import net.minecraft.core.HolderLookup;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.inventory.CraftingContainer;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.crafting.RecipeSerializer;
|
||||
import net.minecraft.world.item.crafting.ShapelessRecipe;
|
||||
|
||||
/**
|
||||
* A {@link ShapelessRecipe} which sets the {@linkplain TurtleItem#getOverlay(ItemStack)} turtle's overlay} instead.
|
||||
*/
|
||||
public class TurtleOverlayRecipe extends CustomShapelessRecipe {
|
||||
private static final MapCodec<TurtleOverlayRecipe> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
|
||||
ShapelessRecipeSpec.CODEC.forGetter(CustomShapelessRecipe::toSpec),
|
||||
ResourceLocation.CODEC.fieldOf("overlay").forGetter(x -> x.overlay)
|
||||
).apply(instance, TurtleOverlayRecipe::new));
|
||||
|
||||
private static final StreamCodec<RegistryFriendlyByteBuf, TurtleOverlayRecipe> STREAM_CODEC = StreamCodec.composite(
|
||||
ShapelessRecipeSpec.STREAM_CODEC, CustomShapelessRecipe::toSpec,
|
||||
ResourceLocation.STREAM_CODEC, x -> x.overlay,
|
||||
TurtleOverlayRecipe::new
|
||||
);
|
||||
|
||||
private final ResourceLocation overlay;
|
||||
|
||||
public TurtleOverlayRecipe(ShapelessRecipeSpec spec, ResourceLocation overlay) {
|
||||
super(spec);
|
||||
this.overlay = overlay;
|
||||
}
|
||||
|
||||
private static ItemStack make(ItemStack stack, ResourceLocation overlay) {
|
||||
return DataComponentUtil.createResult(stack, ModRegistry.DataComponents.OVERLAY.get(), overlay);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack assemble(CraftingContainer inventory, HolderLookup.Provider registryAccess) {
|
||||
for (var i = 0; i < inventory.getContainerSize(); i++) {
|
||||
var stack = inventory.getItem(i);
|
||||
if (stack.getItem() instanceof TurtleItem) return make(stack, overlay);
|
||||
}
|
||||
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecipeSerializer<TurtleOverlayRecipe> getSerializer() {
|
||||
return ModRegistry.RecipeSerializers.TURTLE_OVERLAY.get();
|
||||
}
|
||||
|
||||
public static RecipeSerializer<TurtleOverlayRecipe> serialiser() {
|
||||
return new BasicRecipeSerialiser<>(CODEC, STREAM_CODEC);
|
||||
}
|
||||
}
|
@ -22,12 +22,15 @@ import dan200.computercraft.shared.peripheral.modem.wired.CableBlockEntity;
|
||||
import dan200.computercraft.shared.peripheral.modem.wired.WiredModemFullBlockEntity;
|
||||
import dan200.computercraft.shared.peripheral.modem.wireless.WirelessModemBlockEntity;
|
||||
import dan200.computercraft.shared.platform.FabricConfigFile;
|
||||
import dan200.computercraft.shared.recipe.function.RecipeFunction;
|
||||
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerChunkEvents;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
|
||||
import net.fabricmc.fabric.api.event.player.PlayerBlockBreakEvents;
|
||||
import net.fabricmc.fabric.api.event.player.UseBlockCallback;
|
||||
import net.fabricmc.fabric.api.event.registry.FabricRegistryBuilder;
|
||||
import net.fabricmc.fabric.api.event.registry.RegistryAttribute;
|
||||
import net.fabricmc.fabric.api.itemgroup.v1.ItemGroupEvents;
|
||||
import net.fabricmc.fabric.api.loot.v2.LootTableEvents;
|
||||
import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry;
|
||||
@ -60,6 +63,8 @@ public class ComputerCraft {
|
||||
ServerPlayNetworking.registerGlobalReceiver(type.type(), (packet, player) -> packet.handle(player::player));
|
||||
}
|
||||
|
||||
FabricRegistryBuilder.createSimple(RecipeFunction.REGISTRY).attribute(RegistryAttribute.SYNCED).buildAndRegister();
|
||||
|
||||
ModRegistry.register();
|
||||
ModRegistry.registerMainThread();
|
||||
|
||||
|
@ -30,6 +30,7 @@ import dan200.computercraft.shared.peripheral.modem.wired.CableBlockEntity;
|
||||
import dan200.computercraft.shared.peripheral.modem.wired.WiredModemFullBlockEntity;
|
||||
import dan200.computercraft.shared.peripheral.modem.wireless.WirelessModemBlockEntity;
|
||||
import dan200.computercraft.shared.platform.ForgeConfigFile;
|
||||
import dan200.computercraft.shared.recipe.function.RecipeFunction;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
@ -81,6 +82,7 @@ public final class ComputerCraft {
|
||||
public static void registerRegistries(NewRegistryEvent event) {
|
||||
event.create(new RegistryBuilder<>(ITurtleUpgrade.serialiserRegistryKey()));
|
||||
event.create(new RegistryBuilder<>(IPocketUpgrade.serialiserRegistryKey()));
|
||||
event.create(new RegistryBuilder<>(RecipeFunction.REGISTRY).sync(true));
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
|
Loading…
Reference in New Issue
Block a user