Fix network sync of custom datapack registries.

Add gametest to verify that it functions.
This commit is contained in:
LexManos committed 2024-08-05 13:30:14 -07:00
1 parent 28e55b2843
commit 4995902bc0
6 files changed
+159 -30

No files matched your search

@@ -5,33 +5,40 @@
package net.minecraftforge.registries;
import com.google.common.collect.ImmutableMap;
import net.minecraft.core.Registry;
import net.minecraft.core.RegistrySynchronization;
import net.minecraft.resources.RegistryDataLoader;
import net.minecraft.resources.ResourceKey;
import org.jetbrains.annotations.ApiStatus;
import java.util.*;
import java.util.stream.Stream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Supplier;
@ApiStatus.Internal
public final class DataPackRegistriesHooks {
private DataPackRegistriesHooks() {} // utility class
private static final Map<ResourceKey<? extends Registry<?>>, RegistryDataLoader.RegistryData<?>> NETWORKABLE_REGISTRIES = new LinkedHashMap<>();
// Mutable views of vanilla registries
private static final List<RegistryDataLoader.RegistryData<?>> SYNCHRONIZED_REGISTRIES = new ArrayList<>();
private static final List<RegistryDataLoader.RegistryData<?>> WORLDGEN_REGISTRIES = new ArrayList<>();
private static final Set<ResourceKey<? extends Registry<?>>> SYNCED_CUSTOM_REGISTRIES = new HashSet<>();
private static final Set<ResourceKey<? extends Registry<?>>> SYNCED_CUSTOM_REGISTRIES_VIEW = Collections.unmodifiableSet(SYNCED_CUSTOM_REGISTRIES);
private static final Set<ResourceKey<? extends Registry<?>>> NETWORKABLE_REGISTRIES = new HashSet<>();
// Out custom registries, things we need to make sure the client has
private static final Set<ResourceKey<? extends Registry<?>>> SYNCHRONIZED_REGISTRIES_CUSTOM = new HashSet<>();
private static final Set<ResourceKey<? extends Registry<?>>> SYNCHRONIZED_REGISTRIESD_CUSTOM_VIEW = Collections.unmodifiableSet(SYNCHRONIZED_REGISTRIES_CUSTOM);
/* Internal forge hook for retaining mutable access to RegistryAccess's codec registry when it bootstraps. */
public static Map<ResourceKey<? extends Registry<?>>, RegistryDataLoader.RegistryData<?>> grabNetworkableRegistries(ImmutableMap.Builder<ResourceKey<? extends Registry<?>>, RegistryDataLoader.RegistryData<?>> builder) {
if (!StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE).getCallerClass().equals(RegistrySynchronization.class))
throw new IllegalCallerException("Attempted to call DataPackRegistriesHooks#grabNetworkableRegistries!");
NETWORKABLE_REGISTRIES.forEach(builder::put);
NETWORKABLE_REGISTRIES.clear();
NETWORKABLE_REGISTRIES.putAll(builder.build());
return Collections.unmodifiableMap(NETWORKABLE_REGISTRIES);
public static List<RegistryDataLoader.RegistryData<?>> grabSynchronizedRegistries(RegistryDataLoader.RegistryData<?>... vanilla) {
if (!StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE).getCallerClass().equals(RegistryDataLoader.class))
throw new IllegalCallerException("Attempted to call DataPackRegistriesHooks#grabSynchronizedRegistries!");
for (var reg : vanilla)
SYNCHRONIZED_REGISTRIES.add(reg);
return Collections.unmodifiableList(SYNCHRONIZED_REGISTRIES);
}
/* Internal forge method, registers a datapack registry codec and folder. */
@@ -39,25 +46,12 @@ public final class DataPackRegistriesHooks {
RegistryDataLoader.RegistryData<T> loaderData = data.loaderData();
WORLDGEN_REGISTRIES.add(loaderData);
if (data.networkCodec() != null) {
SYNCED_CUSTOM_REGISTRIES.add(loaderData.key());
NETWORKABLE_REGISTRIES.put(loaderData.key(), new RegistryDataLoader.RegistryData<>(loaderData.key(), data.networkCodec(), false));
NETWORKABLE_REGISTRIES.add(loaderData.key());
SYNCHRONIZED_REGISTRIES_CUSTOM.add(loaderData.key());
SYNCHRONIZED_REGISTRIES.add(new RegistryDataLoader.RegistryData<>(loaderData.key(), data.networkCodec(), false));
}
}
/**
* {@return An unmodifiable view of the list of datapack registries}.
* These registries are loaded from per-world datapacks on server startup.
*/
@Deprecated // Use RegistryDataLoader#WORLDGEN_REGISTRIES instead
public static List<RegistryDataLoader.RegistryData<?>> getDataPackRegistries() {
return Collections.unmodifiableList(WORLDGEN_REGISTRIES);
}
@Deprecated // Use RegistryDataLoader#WORLDGEN_REGISTRIES instead
public static Stream<RegistryDataLoader.RegistryData<?>> getDataPackRegistriesWithDimensions() {
return WORLDGEN_REGISTRIES.stream();
}
/**
* Captures a mutable view of {@link RegistryDataLoader#WORLDGEN_REGISTRIES} so that we can register modded entries during the registry event.
* All uses should use that field instead of this class.
@@ -71,12 +65,27 @@ public final class DataPackRegistriesHooks {
return Collections.unmodifiableList(WORLDGEN_REGISTRIES);
}
/**
* Captures a mutable view of {@link RegistrySynchronization#NETWORKABLE_REGISTRIES} so that we can register modded entries during the registry event.
* All users should use that field instead of this class.
*
* @param vanilla Supplier for the default vanilla values
* @return An unmodifiable set of networksable registry names
*/
public static Set<ResourceKey<? extends Registry<?>>> grabNetworkableRegistries(Supplier<Set<ResourceKey<? extends Registry<?>>>> vanilla) {
if (!StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE).getCallerClass().equals(RegistrySynchronization.class))
throw new IllegalCallerException("Attempted to call DataPackRegistriesHooks#grabNetworkableRegistries!");
NETWORKABLE_REGISTRIES.addAll(vanilla.get());
return Collections.unmodifiableSet(NETWORKABLE_REGISTRIES);
}
/**
* {@return An unmodifiable view of the set of synced non-vanilla datapack registry IDs}
* Clients must have each of a server's synced datapack registries to be able to connect to that server;
* vanilla clients therefore cannot connect if this list is non-empty on the server.
*/
public static Set<ResourceKey<? extends Registry<?>>> getSyncedCustomRegistries() {
return SYNCED_CUSTOM_REGISTRIES_VIEW;
return SYNCHRONIZED_REGISTRIESD_CUSTOM_VIEW;
}
}