Skip to content

Commit d86288d

Browse files
committed
Bridge recipe sync to NeoForge
- Fabric recipes are now synced using Neo's own packet - RecipesReceivedEvent and ClientRecipeSynchronizedEvent will both provide access to all available recipes from both loaders Relates to #288
1 parent 2ef06a0 commit d86288d

7 files changed

Lines changed: 60 additions & 129 deletions

File tree

fabric-recipe-api-v1/src/client/java/net/fabricmc/fabric/impl/recipe/sync/client/RecipeSyncImplClient.java

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -17,53 +17,43 @@
1717
package net.fabricmc.fabric.impl.recipe.sync.client;
1818

1919
import java.util.ArrayList;
20+
import java.util.Collection;
2021
import java.util.Comparator;
2122

22-
import net.minecraft.client.Minecraft;
23-
2423
import net.neoforged.bus.api.IEventBus;
2524
import net.neoforged.fml.common.Mod;
26-
import net.neoforged.neoforge.client.network.event.RegisterClientPayloadHandlersEvent;
27-
import net.neoforged.neoforge.network.handling.IPayloadContext;
25+
import net.neoforged.neoforge.client.event.RecipesReceivedEvent;
26+
import net.neoforged.neoforge.common.NeoForge;
2827
import org.sinytra.fabric.recipe_api.generated.GeneratedEntryPoint;
2928

30-
import net.minecraft.client.player.LocalPlayer;
29+
import net.minecraft.client.Minecraft;
3130
import net.minecraft.world.item.crafting.RecipeHolder;
3231

3332
import net.fabricmc.fabric.api.client.recipe.v1.sync.ClientRecipeSynchronizedEvent;
3433
import net.fabricmc.fabric.api.recipe.v1.sync.SynchronizedRecipes;
35-
import net.fabricmc.fabric.impl.recipe.sync.ClientboundRecipeSyncPayload;
3634
import net.fabricmc.fabric.impl.recipe.sync.SynchronizedRecipesImpl;
3735

3836
@Mod(GeneratedEntryPoint.MOD_ID)
3937
public class RecipeSyncImplClient {
38+
4039
public RecipeSyncImplClient(IEventBus bus) {
41-
bus.addListener(RegisterClientPayloadHandlersEvent.class, event -> {
42-
event.register(
43-
ClientboundRecipeSyncPayload.TYPE,
44-
RecipeSyncImplClient::onRecipeSyncPacket
45-
);
46-
});
40+
NeoForge.EVENT_BUS.addListener(RecipesReceivedEvent.class, RecipeSyncImplClient::onNeoRecipesReceives);
4741
}
4842

49-
private static void onRecipeSyncPacket(ClientboundRecipeSyncPayload payload, IPayloadContext context) {
43+
private static void onNeoRecipesReceives(RecipesReceivedEvent event) {
5044
SynchronizedRecipes recipes;
45+
Collection<RecipeHolder<?>> received = event.getRecipeMap().values();
5146

52-
if (!payload.entries().isEmpty()) {
53-
var collectedRecipes = new ArrayList<RecipeHolder<?>>();
54-
55-
for (ClientboundRecipeSyncPayload.Entry entry : payload.entries()) {
56-
collectedRecipes.addAll(entry.recipes());
57-
}
58-
47+
if (!received.isEmpty()) {
48+
var collectedRecipes = new ArrayList<>(received);
5949
// Sort values by id to match ordering with server ones.
6050
collectedRecipes.sort(Comparator.comparing(entry -> entry.id().identifier()));
6151
recipes = SynchronizedRecipesImpl.of(collectedRecipes);
6252
} else {
6353
recipes = SynchronizedRecipesImpl.EMPTY;
6454
}
6555

66-
((SynchronizedClientRecipesSetter) ((LocalPlayer) context.player()).connection.recipes()).fabric_setSynchronizedClientRecipes(recipes);
56+
((SynchronizedClientRecipesSetter) Minecraft.getInstance().player.connection.recipes()).fabric_setSynchronizedClientRecipes(recipes);
6757
ClientRecipeSynchronizedEvent.EVENT.invoker().onRecipesSynchronized(Minecraft.getInstance(), recipes);
6858
}
6959
}

fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/FabricRecipeApiV1.java

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,6 @@
44

55
import com.mojang.datafixers.util.Either;
66
import com.mojang.serialization.Codec;
7-
8-
import net.fabricmc.fabric.impl.recipe.sync.ClientboundRecipeSyncPayload;
9-
10-
import net.fabricmc.fabric.impl.recipe.sync.RecipeSyncImpl;
11-
import net.fabricmc.fabric.impl.recipe.sync.ServerboundSupportedRecipeSerializersPayload;
12-
137
import net.neoforged.bus.api.IEventBus;
148
import net.neoforged.fml.common.Mod;
159
import net.neoforged.neoforge.common.crafting.IngredientType;
@@ -28,6 +22,8 @@
2822
import net.fabricmc.fabric.api.recipe.v1.ingredient.CustomIngredientSerializer;
2923
import net.fabricmc.fabric.api.recipe.v1.sync.RecipeSynchronization;
3024
import net.fabricmc.fabric.impl.recipe.ingredient.compat.NeoCustomIngredientWrapper;
25+
import net.fabricmc.fabric.impl.recipe.sync.RecipeSyncImpl;
26+
import net.fabricmc.fabric.impl.recipe.sync.ServerboundSupportedRecipeSerializersPayload;
3127

3228
@Mod(GeneratedEntryPoint.MOD_ID)
3329
public class FabricRecipeApiV1 {
@@ -41,7 +37,6 @@ public FabricRecipeApiV1(IEventBus bus) {
4137
bus.addListener(RegisterPayloadHandlersEvent.class, event -> {
4238
PayloadRegistrar registrar = event.registrar("1").optional();
4339

44-
registrar.playToClient(ClientboundRecipeSyncPayload.TYPE, ClientboundRecipeSyncPayload.CODEC);
4540
registrar.configurationToServer(
4641
ServerboundSupportedRecipeSerializersPayload.TYPE,
4742
ServerboundSupportedRecipeSerializersPayload.CODEC,

fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/sync/ClientboundRecipeSyncPayload.java

Lines changed: 0 additions & 89 deletions
This file was deleted.

fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/sync/RecipeSyncImpl.java

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,21 @@
1717
package net.fabricmc.fabric.impl.recipe.sync;
1818

1919
import java.util.ArrayList;
20+
import java.util.Collection;
2021
import java.util.Collections;
2122
import java.util.List;
2223
import java.util.Set;
24+
import java.util.stream.Collectors;
2325

2426
import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet;
27+
import net.neoforged.neoforge.network.handling.IPayloadContext;
28+
import net.neoforged.neoforge.network.payload.RecipeContentPayload;
2529

2630
import net.minecraft.core.registries.BuiltInRegistries;
2731
import net.minecraft.resources.Identifier;
32+
import net.minecraft.resources.ResourceKey;
2833
import net.minecraft.server.level.ServerPlayer;
34+
import net.minecraft.world.item.crafting.Recipe;
2935
import net.minecraft.world.item.crafting.RecipeHolder;
3036
import net.minecraft.world.item.crafting.RecipeSerializer;
3137

@@ -34,8 +40,6 @@
3440
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
3541
import net.fabricmc.fabric.mixin.recipe.sync.RecipeManagerAccessor;
3642

37-
import net.neoforged.neoforge.network.handling.IPayloadContext;
38-
3943
public class RecipeSyncImpl implements ModInitializer {
4044
private static final Set<RecipeSerializer<?>> SYNCED_SERIALIZERS = new ReferenceOpenHashSet<>();
4145

@@ -44,7 +48,6 @@ public class RecipeSyncImpl implements ModInitializer {
4448
@Override
4549
public void onInitialize() {
4650
ServerLifecycleEvents.SYNC_DATA_PACK_CONTENTS.addPhaseOrdering(Event.DEFAULT_PHASE, RECIPE_SYNC_EVENT_PHASE);
47-
ServerLifecycleEvents.SYNC_DATA_PACK_CONTENTS.register(RECIPE_SYNC_EVENT_PHASE, RecipeSyncImpl::sendRecipes);
4851
}
4952

5053
public static void onRecipeSyncRequest(ServerboundSupportedRecipeSerializersPayload payload, IPayloadContext context) {
@@ -58,26 +61,38 @@ public static void onRecipeSyncRequest(ServerboundSupportedRecipeSerializersPayl
5861
.fabric_setSyncedRecipeSerializers(set);
5962
}
6063

61-
private static void sendRecipes(ServerPlayer player, boolean exist) {
64+
public static RecipeContentPayload appendSyncedRecipes(RecipeContentPayload payload, ServerPlayer player) {
65+
List<RecipeHolder<?>> combined = new ArrayList<>(payload.recipes());
66+
Collection<ResourceKey<Recipe<?>>> keys = combined.stream()
67+
.map(RecipeHolder::id)
68+
.collect(Collectors.toUnmodifiableSet());
69+
70+
List<RecipeHolder<?>> recipes = getRecipesToSend(player);
71+
for (RecipeHolder<?> recipe : recipes) {
72+
if (!keys.contains(recipe.id())) {
73+
combined.add(recipe);
74+
}
75+
}
76+
77+
return new RecipeContentPayload(payload.recipeTypes(), combined);
78+
}
79+
80+
private static List<RecipeHolder<?>> getRecipesToSend(ServerPlayer player) {
6281
Set<RecipeSerializer<?>> serializers = ((SyncedSerializerAwareConnection) player.connection.getConnection()).fabric_getSyncedRecipeSerializers();
6382

6483
SyncedSerializerAwarePreparedRecipe accessor = (SyncedSerializerAwarePreparedRecipe) ((RecipeManagerAccessor) player.level().recipeAccess()).getRecipes();
6584

66-
var list = new ArrayList<ClientboundRecipeSyncPayload.Entry>();
85+
List<RecipeHolder<?>> list = new ArrayList<>();
6786

6887
for (RecipeSerializer<?> serializer : serializers) {
6988
List<RecipeHolder<?>> recipes = accessor.fabric_getRecipesBySyncedSerializer(serializer);
7089

7190
if (recipes != null && !recipes.isEmpty()) {
72-
list.add(new ClientboundRecipeSyncPayload.Entry(serializer, recipes));
91+
list.addAll(recipes);
7392
}
7493
}
7594

76-
if (list.isEmpty()) {
77-
return;
78-
}
79-
80-
player.connection.send(new ClientboundRecipeSyncPayload(list));
95+
return list;
8196
}
8297

8398
public static void addSynchronizedSerializer(RecipeSerializer<?> serializer) {
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package net.fabricmc.fabric.mixin.recipe.sync;
2+
3+
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
4+
import net.neoforged.neoforge.common.CommonHooks;
5+
import net.neoforged.neoforge.network.payload.RecipeContentPayload;
6+
import org.spongepowered.asm.mixin.Mixin;
7+
import org.spongepowered.asm.mixin.injection.At;
8+
9+
import net.minecraft.server.level.ServerPlayer;
10+
11+
import net.fabricmc.fabric.impl.recipe.sync.RecipeSyncImpl;
12+
13+
@Mixin(CommonHooks.class)
14+
public class CommonHooksMixin {
15+
@ModifyExpressionValue(method = "sendRecipes", at = @At(value = "INVOKE", target = "Lnet/neoforged/neoforge/network/payload/RecipeContentPayload;create(Ljava/util/Collection;Lnet/minecraft/world/item/crafting/RecipeMap;)Lnet/neoforged/neoforge/network/payload/RecipeContentPayload;"))
16+
private static RecipeContentPayload sendRecipes(RecipeContentPayload payload, ServerPlayer player) {
17+
return RecipeSyncImpl.appendSyncedRecipes(payload, player);
18+
}
19+
}

fabric-recipe-api-v1/src/main/resources/fabric-recipe-api-v1.mixins.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"RecipeManagerMixin",
88
"ingredient.IngredientMixin",
99
"ingredient.IngredientCodecsMixin",
10+
"sync.CommonHooksMixin",
1011
"sync.ConnectionMixin",
1112
"sync.RecipeMapMixin",
1213
"sync.RecipeManagerAccessor"

ffapi.gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
implementationVersion=3.2.8
1+
implementationVersion=3.3.0
22

33
versionMc=26.1.2
44
versionNeoForge=26.1.2.76

0 commit comments

Comments
 (0)