Add RegistryAccess for managing Registries

RegistryAccess is independant from CraftServer and
doesn't require one to be created allowing the
org.bukkit.Registry class to be loaded earlier.

== AT ==
public net.minecraft.server.RegistryLayer STATIC_ACCESS
This commit is contained in:
Jake Potrebic
2023-02-27 18:28:39 -08:00
parent 23b8639dbf
commit 239e7a6b37
38 changed files with 930 additions and 214 deletions

View File

@@ -216,11 +216,10 @@ public abstract class CraftParticle<D> implements Keyed {
}
public CraftParticleRegistry(net.minecraft.core.Registry<net.minecraft.core.particles.ParticleType<?>> minecraftRegistry) {
super(CraftParticle.class, minecraftRegistry, null, FieldRename.PARTICLE_TYPE_RENAME);
super(CraftParticle.class, minecraftRegistry, CraftParticleRegistry::createBukkit, FieldRename.PARTICLE_TYPE_RENAME); // Paper - switch to Holder
}
@Override
public CraftParticle<?> createBukkit(NamespacedKey namespacedKey, net.minecraft.core.particles.ParticleType<?> particle) {
public static CraftParticle<?> createBukkit(NamespacedKey namespacedKey, net.minecraft.core.particles.ParticleType<?> particle) { // Paper - idk why this is a separate implementation, just wrap the function
if (particle == null) {
return null;
}

View File

@@ -93,14 +93,41 @@ public class CraftRegistry<B extends Keyed, M> implements Registry<B> {
Preconditions.checkArgument(minecraft != null);
net.minecraft.core.Registry<M> registry = CraftRegistry.getMinecraftRegistry(registryKey);
B bukkit = bukkitRegistry.get(CraftNamespacedKey.fromMinecraft(registry.getResourceKey(minecraft)
.orElseThrow(() -> new IllegalStateException(String.format("Cannot convert '%s' to bukkit representation, since it is not registered.", minecraft))).location()));
// Paper start - support direct Holders
final java.util.Optional<ResourceKey<M>> resourceKey = registry.getResourceKey(minecraft);
if (resourceKey.isEmpty() && bukkitRegistry instanceof final CraftRegistry<?, ?> craftRegistry && craftRegistry.supportsDirectHolders()) {
return ((CraftRegistry<B, M>) registry).convertDirectHolder(Holder.direct(minecraft));
} else if (resourceKey.isEmpty()) {
throw new IllegalStateException(String.format("Cannot convert '%s' to bukkit representation, since it is not registered.", minecraft));
}
final B bukkit = bukkitRegistry.get(CraftNamespacedKey.fromMinecraft(resourceKey.get().location()));
// Paper end - support direct Holders
Preconditions.checkArgument(bukkit != null);
return bukkit;
}
// Paper start - support direct Holders
public static <B extends Keyed, M> B minecraftHolderToBukkit(final Holder<M> minecraft, final Registry<B> bukkitRegistry) {
Preconditions.checkArgument(minecraft != null);
final B bukkit = switch (minecraft) {
case final Holder.Direct<M> direct -> {
if (!(bukkitRegistry instanceof final CraftRegistry<?, ?> craftRegistry) || !craftRegistry.supportsDirectHolders()) {
throw new IllegalArgumentException("Cannot convert direct holder to bukkit representation");
}
yield ((CraftRegistry<B, M>) bukkitRegistry).convertDirectHolder(direct);
}
case final Holder.Reference<M> reference -> bukkitRegistry.get(io.papermc.paper.util.MCUtil.fromResourceKey(reference.key()));
default -> throw new IllegalArgumentException("Unknown holder: " + minecraft);
};
Preconditions.checkArgument(bukkit != null);
return bukkit;
}
// Paper end - support direct Holders
/**
* Usage note: Only use this method to delegate the conversion methods from the individual Craft classes to here.
* Do not use it in other parts of CraftBukkit, use the methods in the respective Craft classes instead.
@@ -116,6 +143,11 @@ public class CraftRegistry<B extends Keyed, M> implements Registry<B> {
public static <B extends Keyed, M> Holder<M> bukkitToMinecraftHolder(B bukkit, ResourceKey<net.minecraft.core.Registry<M>> registryKey) {
Preconditions.checkArgument(bukkit != null);
// Paper start - support direct Holder
if (bukkit instanceof io.papermc.paper.util.Holderable<?>) {
return ((io.papermc.paper.util.Holderable<M>) bukkit).getHolder();
}
// Paper end - support direct Holder
net.minecraft.core.Registry<M> registry = CraftRegistry.getMinecraftRegistry(registryKey);
@@ -127,96 +159,12 @@ public class CraftRegistry<B extends Keyed, M> implements Registry<B> {
+ ", this can happen if a plugin creates its own registry entry with out properly registering it.");
}
/**
* Note: Newly added registries should also be added to RegistriesArgumentProvider in the test package
*
* @param bukkitClass the bukkit class of the registry
* @param registryHolder the minecraft registry holder
* @return the bukkit registry of the provided class
*/
public static <B extends Keyed> Registry<?> createRegistry(Class<? super B> bukkitClass, RegistryAccess registryHolder) {
if (bukkitClass == Art.class) {
return new CraftRegistry<>(Art.class, registryHolder.lookupOrThrow(Registries.PAINTING_VARIANT), CraftArt::new, FieldRename.NONE);
}
if (bukkitClass == Attribute.class) {
return new CraftRegistry<>(Attribute.class, registryHolder.lookupOrThrow(Registries.ATTRIBUTE), CraftAttribute::new, FieldRename.ATTRIBUTE_RENAME);
}
if (bukkitClass == Biome.class) {
return new CraftRegistry<>(Biome.class, registryHolder.lookupOrThrow(Registries.BIOME), CraftBiome::new, FieldRename.BIOME_RENAME);
}
if (bukkitClass == Enchantment.class) {
return new CraftRegistry<>(Enchantment.class, registryHolder.lookupOrThrow(Registries.ENCHANTMENT), CraftEnchantment::new, FieldRename.ENCHANTMENT_RENAME);
}
if (bukkitClass == Fluid.class) {
return new CraftRegistry<>(Fluid.class, registryHolder.lookupOrThrow(Registries.FLUID), CraftFluid::new, FieldRename.NONE);
}
if (bukkitClass == GameEvent.class) {
return new CraftRegistry<>(GameEvent.class, registryHolder.lookupOrThrow(Registries.GAME_EVENT), CraftGameEvent::new, FieldRename.NONE);
}
if (bukkitClass == MusicInstrument.class) {
return new CraftRegistry<>(MusicInstrument.class, registryHolder.lookupOrThrow(Registries.INSTRUMENT), CraftMusicInstrument::new, FieldRename.NONE);
}
if (bukkitClass == MenuType.class) {
return new CraftRegistry<>(MenuType.class, registryHolder.lookupOrThrow(Registries.MENU), CraftMenuType::new, FieldRename.NONE);
}
if (bukkitClass == PotionEffectType.class) {
return new CraftRegistry<>(PotionEffectType.class, registryHolder.lookupOrThrow(Registries.MOB_EFFECT), CraftPotionEffectType::new, FieldRename.NONE);
}
if (bukkitClass == Sound.class) {
return new CraftRegistry<>(Sound.class, registryHolder.lookupOrThrow(Registries.SOUND_EVENT), CraftSound::new, FieldRename.NONE);
}
if (bukkitClass == Structure.class) {
return new CraftRegistry<>(Structure.class, registryHolder.lookupOrThrow(Registries.STRUCTURE), CraftStructure::new, FieldRename.NONE);
}
if (bukkitClass == StructureType.class) {
return new CraftRegistry<>(StructureType.class, registryHolder.lookupOrThrow(Registries.STRUCTURE_TYPE), CraftStructureType::new, FieldRename.NONE);
}
if (bukkitClass == Villager.Type.class) {
return new CraftRegistry<>(Villager.Type.class, registryHolder.lookupOrThrow(Registries.VILLAGER_TYPE), CraftVillager.CraftType::new, FieldRename.NONE);
}
if (bukkitClass == Villager.Profession.class) {
return new CraftRegistry<>(Villager.Profession.class, registryHolder.lookupOrThrow(Registries.VILLAGER_PROFESSION), CraftVillager.CraftProfession::new, FieldRename.NONE);
}
if (bukkitClass == TrimMaterial.class) {
return new CraftRegistry<>(TrimMaterial.class, registryHolder.lookupOrThrow(Registries.TRIM_MATERIAL), CraftTrimMaterial::new, FieldRename.NONE);
}
if (bukkitClass == TrimPattern.class) {
return new CraftRegistry<>(TrimPattern.class, registryHolder.lookupOrThrow(Registries.TRIM_PATTERN), CraftTrimPattern::new, FieldRename.NONE);
}
if (bukkitClass == DamageType.class) {
return new CraftRegistry<>(DamageType.class, registryHolder.lookupOrThrow(Registries.DAMAGE_TYPE), CraftDamageType::new, FieldRename.NONE);
}
if (bukkitClass == JukeboxSong.class) {
return new CraftRegistry<>(JukeboxSong.class, registryHolder.lookupOrThrow(Registries.JUKEBOX_SONG), CraftJukeboxSong::new, FieldRename.NONE);
}
if (bukkitClass == Wolf.Variant.class) {
return new CraftRegistry<>(Wolf.Variant.class, registryHolder.lookupOrThrow(Registries.WOLF_VARIANT), CraftWolf.CraftVariant::new, FieldRename.NONE);
}
if (bukkitClass == BlockType.class) {
return new CraftRegistry<>(BlockType.class, registryHolder.lookupOrThrow(Registries.BLOCK), CraftBlockType::new, FieldRename.NONE);
}
if (bukkitClass == ItemType.class) {
return new CraftRegistry<>(ItemType.class, registryHolder.lookupOrThrow(Registries.ITEM), CraftItemType::new, FieldRename.NONE);
}
if (bukkitClass == Frog.Variant.class) {
return new CraftRegistry<>(Frog.Variant.class, registryHolder.lookupOrThrow(Registries.FROG_VARIANT), CraftFrog.CraftVariant::new, FieldRename.NONE);
}
if (bukkitClass == Cat.Type.class) {
return new CraftRegistry<>(Cat.Type.class, registryHolder.lookupOrThrow(Registries.CAT_VARIANT), CraftCat.CraftType::new, FieldRename.NONE);
}
if (bukkitClass == MapCursor.Type.class) {
return new CraftRegistry<>(MapCursor.Type.class, registryHolder.lookupOrThrow(Registries.MAP_DECORATION_TYPE), CraftMapCursor.CraftType::new, FieldRename.NONE);
}
if (bukkitClass == PatternType.class) {
return new CraftRegistry<>(PatternType.class, registryHolder.lookupOrThrow(Registries.BANNER_PATTERN), CraftPatternType::new, FieldRename.NONE);
}
return null;
}
// Paper - move to PaperRegistries
// Paper - NOTE: As long as all uses of the method below relate to *serialization* via ConfigurationSerializable, it's fine
public static <B extends Keyed> B get(Registry<B> bukkit, NamespacedKey namespacedKey, ApiVersion apiVersion) {
if (bukkit instanceof CraftRegistry<B, ?> craft) {
return craft.get(namespacedKey, apiVersion);
return craft.get(craft.serializationUpdater.apply(namespacedKey, apiVersion)); // Paper
}
if (bukkit instanceof Registry.SimpleRegistry<?> simple) {
@@ -234,23 +182,26 @@ public class CraftRegistry<B extends Keyed, M> implements Registry<B> {
return bukkit.get(namespacedKey);
}
private final Class<? super B> bukkitClass;
private final Class<?> bukkitClass; // Paper - relax preload class
private final Map<NamespacedKey, B> cache = new HashMap<>();
private final net.minecraft.core.Registry<M> minecraftRegistry;
private final BiFunction<NamespacedKey, M, B> minecraftToBukkit;
private final BiFunction<NamespacedKey, ApiVersion, NamespacedKey> updater;
private final io.papermc.paper.registry.entry.RegistryTypeMapper<M, B> minecraftToBukkit; // Paper - switch to Holder
private final BiFunction<NamespacedKey, ApiVersion, NamespacedKey> serializationUpdater; // Paper - rename to make it *clear* what it is *only* for
private boolean init;
public CraftRegistry(Class<? super B> bukkitClass, net.minecraft.core.Registry<M> minecraftRegistry, BiFunction<NamespacedKey, M, B> minecraftToBukkit, BiFunction<NamespacedKey, ApiVersion, NamespacedKey> updater) {
public CraftRegistry(Class<?> bukkitClass, net.minecraft.core.Registry<M> minecraftRegistry, BiFunction<? super NamespacedKey, M, B> minecraftToBukkit, BiFunction<NamespacedKey, ApiVersion, NamespacedKey> serializationUpdater) { // Paper - relax preload class
// Paper start - switch to Holder
this(bukkitClass, minecraftRegistry, new io.papermc.paper.registry.entry.RegistryTypeMapper<>(minecraftToBukkit), serializationUpdater);
}
public CraftRegistry(Class<?> bukkitClass, net.minecraft.core.Registry<M> minecraftRegistry, io.papermc.paper.registry.entry.RegistryTypeMapper<M, B> minecraftToBukkit, BiFunction<NamespacedKey, ApiVersion, NamespacedKey> serializationUpdater) { // Paper - relax preload class
// Paper end - support Holders
this.bukkitClass = bukkitClass;
this.minecraftRegistry = minecraftRegistry;
this.minecraftToBukkit = minecraftToBukkit;
this.updater = updater;
this.serializationUpdater = serializationUpdater;
}
public B get(NamespacedKey namespacedKey, ApiVersion apiVersion) {
return this.get(this.updater.apply(namespacedKey, apiVersion));
}
// Paper - inline into CraftRegistry#get(Registry, NamespacedKey, ApiVersion) above
@Override
public B get(NamespacedKey namespacedKey) {
@@ -280,7 +231,7 @@ public class CraftRegistry<B extends Keyed, M> implements Registry<B> {
return this.get(namespacedKey);
}
B bukkit = this.createBukkit(namespacedKey, this.minecraftRegistry.getOptional(CraftNamespacedKey.toMinecraft(namespacedKey)).orElse(null));
B bukkit = this.createBukkit(namespacedKey, this.minecraftRegistry.get(CraftNamespacedKey.toMinecraft(namespacedKey)).orElse(null)); // Paper - switch to Holder
if (bukkit == null) {
return null;
}
@@ -311,11 +262,21 @@ public class CraftRegistry<B extends Keyed, M> implements Registry<B> {
return this.stream().iterator();
}
public B createBukkit(NamespacedKey namespacedKey, M minecraft) {
public B createBukkit(NamespacedKey namespacedKey, Holder<M> minecraft) { // Paper - switch to Holder
if (minecraft == null) {
return null;
}
return this.minecraftToBukkit.apply(namespacedKey, minecraft);
return this.minecraftToBukkit.createBukkit(namespacedKey, minecraft); // Paper - switch to Holder
}
// Paper start - support Direct Holders
public boolean supportsDirectHolders() {
return this.minecraftToBukkit.supportsDirectHolders();
}
public B convertDirectHolder(Holder<M> holder) {
return this.minecraftToBukkit.convertDirectHolder(holder);
}
// Paper end - support Direct Holders
}

View File

@@ -284,7 +284,7 @@ public final class CraftServer implements Server {
protected final DedicatedServer console;
protected final DedicatedPlayerList playerList;
private final Map<String, World> worlds = new LinkedHashMap<String, World>();
private final Map<Class<?>, Registry<?>> registries = new HashMap<>();
// private final Map<Class<?>, Registry<?>> registries = new HashMap<>(); // Paper - replace with RegistryAccess
private YamlConfiguration configuration;
private YamlConfiguration commandsConfiguration;
private final Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));
@@ -431,6 +431,7 @@ public final class CraftServer implements Server {
}
private void loadCompatibilities() {
if (true) return; // Paper - Big nope
ConfigurationSection compatibilities = this.configuration.getConfigurationSection("settings.compatibility");
if (compatibilities == null) {
this.activeCompatibilities = Collections.emptySet();
@@ -2754,7 +2755,7 @@ public final class CraftServer implements Server {
@Override
public <T extends Keyed> Registry<T> getRegistry(Class<T> aClass) {
return (Registry<T>) this.registries.computeIfAbsent(aClass, key -> CraftRegistry.createRegistry(aClass, this.console.registryAccess()));
return io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(aClass); // Paper - replace with RegistryAccess
}
@Deprecated

View File

@@ -51,11 +51,14 @@ public class FieldRename {
};
}
@RequireCompatibility("allow-old-keys-in-registry")
public static <T extends Keyed> T get(Registry<T> registry, NamespacedKey namespacedKey) {
// We don't have version-specific changes, so just use current, and don't inject a version
return CraftRegistry.get(registry, namespacedKey, ApiVersion.CURRENT);
}
// Paper start - absolutely not, having this as an expectation for plugin developers opens a huge
// can of worms in the future, especially if mojang comes back and reuses some old key
//@RequireCompatibility("allow-old-keys-in-registry")
//public static <T extends Keyed> T get(Registry<T> registry, NamespacedKey namespacedKey) {
// // We don't have version-specific changes, so just use current, and don't inject a version
// return CraftRegistry.get(registry, namespacedKey, ApiVersion.CURRENT);
//}
// Paper end
// PatternType
private static final FieldRenameData PATTERN_TYPE_DATA = FieldRenameData.Builder.newBuilder()

View File

@@ -220,20 +220,10 @@ public class Commodore {
public byte[] convert(byte[] b, final String pluginName, final ApiVersion pluginVersion, final Set<String> activeCompatibilities) {
final boolean modern = pluginVersion.isNewerThanOrSameAs(ApiVersion.FLATTENING);
final boolean enumCompatibility = pluginVersion.isOlderThanOrSameAs(ApiVersion.getOrCreateVersion("1.20.6")) && activeCompatibilities.contains("enum-compatibility-mode");
ClassReader cr = new ClassReader(b);
ClassWriter cw = new ClassWriter(cr, 0);
List<String> methodEnumSignatures = Commodore.getMethodSignatures(b);
Multimap<String, String> enumLessToEnum = HashMultimap.create();
for (String method : methodEnumSignatures) {
enumLessToEnum.put(method.replace("Ljava/lang/Enum;", "Ljava/lang/Object;"), method);
}
ClassVisitor visitor = cw;
if (enumCompatibility) {
visitor = new LimitedClassRemapper(cw, new SimpleRemapper(Commodore.ENUM_RENAMES));
}
visitor = io.papermc.paper.pluginremap.reflect.ReflectionRemapper.visitor(visitor); // Paper
cr.accept(new ClassRemapper(new ClassVisitor(Opcodes.ASM9, visitor) {
@@ -300,15 +290,6 @@ public class Commodore {
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
if (enumCompatibility && (access & Opcodes.ACC_SYNTHETIC) != 0 && (access & Opcodes.ACC_BRIDGE) != 0 && desc.contains("Ljava/lang/Object;")) {
// SPIGOT-7820: Do not use object method if enum method is present
// The object method does only redirect to the enum method
Collection<String> result = enumLessToEnum.get(desc.replace("Ljava/lang/Enum;", "Ljava/lang/Object;") + " " + name);
if (result.size() == 2) {
name = name + "_BUKKIT_UNUSED";
}
}
return new MethodVisitor(this.api, super.visitMethod(access, name, desc, signature, exceptions)) {
// Paper start - Plugin rewrites
@Override