From a4beace95cde5a4e5680ce128582cf40dbdc6fb9 Mon Sep 17 00:00:00 2001 From: shedaniel Date: Mon, 25 Jan 2021 11:09:20 +0800 Subject: [PATCH] Registry API to create modded registries, close #21 --- build.gradle | 4 +- .../core/AbstractRecipeSerializer.java | 2 +- .../architectury/core/RegistryEntry.java | 26 ++++++ .../architectury/registry/Registries.java | 18 +++- .../registry/registries/RegistryBuilder.java | 42 ++++++++++ .../registry/registries/RegistryOption.java | 23 ++++++ .../registries/StandardRegistryOption.java | 31 +++++++ .../registry/fabric/RegistriesImpl.java | 37 +++++++++ ...erializer.java => MixinRegistryEntry.java} | 6 +- .../plugin/forge/ArchitecturyMixinPlugin.java | 6 +- .../registry/forge/RegistriesImpl.java | 82 +++++++++++++++---- .../main/resources/architectury.mixins.json | 2 +- 12 files changed, 249 insertions(+), 30 deletions(-) create mode 100644 common/src/main/java/me/shedaniel/architectury/core/RegistryEntry.java create mode 100644 common/src/main/java/me/shedaniel/architectury/registry/registries/RegistryBuilder.java create mode 100644 common/src/main/java/me/shedaniel/architectury/registry/registries/RegistryOption.java create mode 100644 common/src/main/java/me/shedaniel/architectury/registry/registries/StandardRegistryOption.java rename forge/src/main/java/me/shedaniel/architectury/mixin/forge/{MixinAbstractRecipeSerializer.java => MixinRegistryEntry.java} (86%) diff --git a/build.gradle b/build.gradle index fddfe4ac..bf8f47dc 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ plugins { - id "architectury-plugin" version "2.0.57" - id "forgified-fabric-loom" version "0.6.49" apply false + id "architectury-plugin" version "2.0.59" + id "forgified-fabric-loom" version "0.6.53" apply false id "org.cadixdev.licenser" version "0.5.0" id "com.jfrog.bintray" version "1.8.4" id "com.matthewprenger.cursegradle" version "1.4.0" apply false diff --git a/common/src/main/java/me/shedaniel/architectury/core/AbstractRecipeSerializer.java b/common/src/main/java/me/shedaniel/architectury/core/AbstractRecipeSerializer.java index bdde8377..d67f9d92 100644 --- a/common/src/main/java/me/shedaniel/architectury/core/AbstractRecipeSerializer.java +++ b/common/src/main/java/me/shedaniel/architectury/core/AbstractRecipeSerializer.java @@ -25,5 +25,5 @@ import net.minecraft.world.item.crafting.RecipeSerializer; /** * The equivalent of {@link RecipeSerializer} to use in common that has forge registry entries extended. */ -public abstract class AbstractRecipeSerializer> implements RecipeSerializer { +public abstract class AbstractRecipeSerializer> extends RegistryEntry implements RecipeSerializer { } diff --git a/common/src/main/java/me/shedaniel/architectury/core/RegistryEntry.java b/common/src/main/java/me/shedaniel/architectury/core/RegistryEntry.java new file mode 100644 index 00000000..77cd8e1d --- /dev/null +++ b/common/src/main/java/me/shedaniel/architectury/core/RegistryEntry.java @@ -0,0 +1,26 @@ +/* + * This file is part of architectury. + * Copyright (C) 2020, 2021 shedaniel + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package me.shedaniel.architectury.core; + +/** + * An entry in registries, will extend {@code ForgeRegistryEntry} on forge. + */ +public class RegistryEntry { +} diff --git a/common/src/main/java/me/shedaniel/architectury/registry/Registries.java b/common/src/main/java/me/shedaniel/architectury/registry/Registries.java index 9ce5d9a6..60377776 100644 --- a/common/src/main/java/me/shedaniel/architectury/registry/Registries.java +++ b/common/src/main/java/me/shedaniel/architectury/registry/Registries.java @@ -20,9 +20,12 @@ package me.shedaniel.architectury.registry; import me.shedaniel.architectury.annotations.ExpectPlatform; +import me.shedaniel.architectury.core.RegistryEntry; +import me.shedaniel.architectury.registry.registries.RegistryBuilder; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Map; @@ -36,6 +39,7 @@ public final class Registries { private final RegistryProvider provider; private final String modId; + @NotNull public static Registries get(String modId) { return REGISTRIES.computeIfAbsent(modId, Registries::new); } @@ -45,15 +49,24 @@ public final class Registries { this.modId = modId; } + @NotNull public Registry get(ResourceKey> key) { return this.provider.get(key); } + @NotNull @Deprecated public Registry get(net.minecraft.core.Registry registry) { return this.provider.get(registry); } + @NotNull + @SafeVarargs + public final > RegistryBuilder builder(ResourceLocation registryId, T... typeGetter) { + if (typeGetter.length != 0) throw new IllegalStateException("array must be empty!"); + return this.provider.builder((Class) typeGetter.getClass().getComponentType(), registryId); + } + /** * Forge: If the object is {@code IForgeRegistryEntry}, use `getRegistryName`, else null * Fabric: Use registry @@ -79,8 +92,8 @@ public final class Registries { * Forge: If the object is {@code IForgeRegistryEntry}, use `getRegistryName`, else null * Fabric: null */ - @Deprecated @Nullable + @Deprecated public static ResourceLocation getRegistryName(T object) { return getId(object, (ResourceKey>) null); } @@ -90,6 +103,7 @@ public final class Registries { throw new AssertionError(); } + @NotNull public String getModId() { return modId; } @@ -100,5 +114,7 @@ public final class Registries { @Deprecated Registry get(net.minecraft.core.Registry registry); + + > RegistryBuilder builder(Class type, ResourceLocation registryId); } } diff --git a/common/src/main/java/me/shedaniel/architectury/registry/registries/RegistryBuilder.java b/common/src/main/java/me/shedaniel/architectury/registry/registries/RegistryBuilder.java new file mode 100644 index 00000000..9f2df633 --- /dev/null +++ b/common/src/main/java/me/shedaniel/architectury/registry/registries/RegistryBuilder.java @@ -0,0 +1,42 @@ +/* + * This file is part of architectury. + * Copyright (C) 2020, 2021 shedaniel + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package me.shedaniel.architectury.registry.registries; + +import me.shedaniel.architectury.core.RegistryEntry; +import me.shedaniel.architectury.registry.Registry; +import org.jetbrains.annotations.NotNull; + +public interface RegistryBuilder> { + @NotNull + Registry build(); + + @NotNull + RegistryBuilder option(@NotNull RegistryOption option); + + @NotNull + default RegistryBuilder saveToDisc() { + return option(StandardRegistryOption.SAVE_TO_DISC); + } + + @NotNull + default RegistryBuilder syncToClients() { + return option(StandardRegistryOption.SYNC_TO_CLIENTS); + } +} \ No newline at end of file diff --git a/common/src/main/java/me/shedaniel/architectury/registry/registries/RegistryOption.java b/common/src/main/java/me/shedaniel/architectury/registry/registries/RegistryOption.java new file mode 100644 index 00000000..8b7bebb5 --- /dev/null +++ b/common/src/main/java/me/shedaniel/architectury/registry/registries/RegistryOption.java @@ -0,0 +1,23 @@ +/* + * This file is part of architectury. + * Copyright (C) 2020, 2021 shedaniel + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package me.shedaniel.architectury.registry.registries; + +public interface RegistryOption { +} diff --git a/common/src/main/java/me/shedaniel/architectury/registry/registries/StandardRegistryOption.java b/common/src/main/java/me/shedaniel/architectury/registry/registries/StandardRegistryOption.java new file mode 100644 index 00000000..34783086 --- /dev/null +++ b/common/src/main/java/me/shedaniel/architectury/registry/registries/StandardRegistryOption.java @@ -0,0 +1,31 @@ +/* + * This file is part of architectury. + * Copyright (C) 2020, 2021 shedaniel + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package me.shedaniel.architectury.registry.registries; + +public enum StandardRegistryOption implements RegistryOption { + /** + * Denote that the registry should save to disc and persist. Defaulted false. + */ + SAVE_TO_DISC, + /** + * Denote that the registry should sync its contents to clients. Defaulted false. + */ + SYNC_TO_CLIENTS, +} diff --git a/fabric/src/main/java/me/shedaniel/architectury/registry/fabric/RegistriesImpl.java b/fabric/src/main/java/me/shedaniel/architectury/registry/fabric/RegistriesImpl.java index d2218150..2287adb8 100644 --- a/fabric/src/main/java/me/shedaniel/architectury/registry/fabric/RegistriesImpl.java +++ b/fabric/src/main/java/me/shedaniel/architectury/registry/fabric/RegistriesImpl.java @@ -20,9 +20,16 @@ package me.shedaniel.architectury.registry.fabric; import com.google.common.base.Objects; +import me.shedaniel.architectury.core.RegistryEntry; import me.shedaniel.architectury.registry.Registries; import me.shedaniel.architectury.registry.Registry; import me.shedaniel.architectury.registry.RegistrySupplier; +import me.shedaniel.architectury.registry.registries.RegistryBuilder; +import me.shedaniel.architectury.registry.registries.RegistryOption; +import me.shedaniel.architectury.registry.registries.StandardRegistryOption; +import net.fabricmc.fabric.api.event.registry.FabricRegistryBuilder; +import net.fabricmc.fabric.api.event.registry.RegistryAttribute; +import net.minecraft.core.MappedRegistry; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.util.LazyLoadedValue; @@ -64,6 +71,36 @@ public class RegistriesImpl { public Registry get(net.minecraft.core.Registry registry) { return new RegistryImpl<>(registry); } + + @Override + @NotNull + public > RegistryBuilder builder(Class type, ResourceLocation registryId) { + return new RegistryBuilderWrapper<>(FabricRegistryBuilder.createSimple(type, registryId)); + } + } + + public static class RegistryBuilderWrapper> implements RegistryBuilder { + @NotNull + private FabricRegistryBuilder> builder; + + public RegistryBuilderWrapper(@NotNull FabricRegistryBuilder> builder) { + this.builder = builder; + } + + @Override + public @NotNull Registry build() { + return RegistryProviderImpl.INSTANCE.get(builder.buildAndRegister()); + } + + @Override + public @NotNull RegistryBuilder option(@NotNull RegistryOption option) { + if (option == StandardRegistryOption.SAVE_TO_DISC) { + this.builder.attribute(RegistryAttribute.PERSISTED); + } else if (option == StandardRegistryOption.SYNC_TO_CLIENTS) { + this.builder.attribute(RegistryAttribute.SYNCED); + } + return this; + } } public static class RegistryImpl implements Registry { diff --git a/forge/src/main/java/me/shedaniel/architectury/mixin/forge/MixinAbstractRecipeSerializer.java b/forge/src/main/java/me/shedaniel/architectury/mixin/forge/MixinRegistryEntry.java similarity index 86% rename from forge/src/main/java/me/shedaniel/architectury/mixin/forge/MixinAbstractRecipeSerializer.java rename to forge/src/main/java/me/shedaniel/architectury/mixin/forge/MixinRegistryEntry.java index 06b44783..8d675a1b 100644 --- a/forge/src/main/java/me/shedaniel/architectury/mixin/forge/MixinAbstractRecipeSerializer.java +++ b/forge/src/main/java/me/shedaniel/architectury/mixin/forge/MixinRegistryEntry.java @@ -19,9 +19,9 @@ package me.shedaniel.architectury.mixin.forge; -import me.shedaniel.architectury.core.AbstractRecipeSerializer; +import me.shedaniel.architectury.core.RegistryEntry; import org.spongepowered.asm.mixin.Mixin; -@Mixin(AbstractRecipeSerializer.class) -public class MixinAbstractRecipeSerializer { +@Mixin(RegistryEntry.class) +public class MixinRegistryEntry { } diff --git a/forge/src/main/java/me/shedaniel/architectury/plugin/forge/ArchitecturyMixinPlugin.java b/forge/src/main/java/me/shedaniel/architectury/plugin/forge/ArchitecturyMixinPlugin.java index 25b01e1d..4f9aec57 100644 --- a/forge/src/main/java/me/shedaniel/architectury/plugin/forge/ArchitecturyMixinPlugin.java +++ b/forge/src/main/java/me/shedaniel/architectury/plugin/forge/ArchitecturyMixinPlugin.java @@ -61,7 +61,7 @@ public class ArchitecturyMixinPlugin implements IMixinConfigPlugin { public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { // Inject our own sugar switch (mixinClassName) { - case "me.shedaniel.architectury.mixin.forge.MixinAbstractRecipeSerializer": + case "me.shedaniel.architectury.mixin.forge.MixinRegistryEntry": targetClass.superName = "net/minecraftforge/registries/ForgeRegistryEntry"; for (MethodNode method : targetClass.methods) { if (Objects.equals(method.name, "")) { @@ -77,9 +77,7 @@ public class ArchitecturyMixinPlugin implements IMixinConfigPlugin { } } String recipeSerializer = targetClass.interfaces.get(0); - if (targetClass.signature != null) { - targetClass.signature = targetClass.signature.replace("Ljava/lang/Object;", "Lnet/minecraftforge/registries/ForgeRegistryEntry;>"); - } + targetClass.signature = ";>Lnet/minecraftforge/registries/ForgeRegistryEntry;"; break; } } diff --git a/forge/src/main/java/me/shedaniel/architectury/registry/forge/RegistriesImpl.java b/forge/src/main/java/me/shedaniel/architectury/registry/forge/RegistriesImpl.java index 7ac31e48..cb2f06d1 100644 --- a/forge/src/main/java/me/shedaniel/architectury/registry/forge/RegistriesImpl.java +++ b/forge/src/main/java/me/shedaniel/architectury/registry/forge/RegistriesImpl.java @@ -22,10 +22,14 @@ package me.shedaniel.architectury.registry.forge; import com.google.common.base.Objects; import com.google.common.collect.HashBasedTable; import com.google.common.collect.Table; +import me.shedaniel.architectury.core.RegistryEntry; import me.shedaniel.architectury.platform.forge.EventBuses; import me.shedaniel.architectury.registry.Registries; import me.shedaniel.architectury.registry.Registry; import me.shedaniel.architectury.registry.RegistrySupplier; +import me.shedaniel.architectury.registry.registries.RegistryBuilder; +import me.shedaniel.architectury.registry.registries.RegistryOption; +import me.shedaniel.architectury.registry.registries.StandardRegistryOption; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.util.LazyLoadedValue; @@ -76,7 +80,11 @@ public class RegistriesImpl { @Override public Registry get(ResourceKey> registryKey) { - return new ForgeBackedRegistryImpl<>(registry, (IForgeRegistry) RegistryManager.ACTIVE.getRegistry(registryKey.location())); + return get(RegistryManager.ACTIVE.getRegistry(registryKey.location())); + } + + public Registry get(IForgeRegistry registry) { + return new ForgeBackedRegistryImpl<>(this.registry, registry); } @Override @@ -84,6 +92,13 @@ public class RegistriesImpl { return new VanillaBackedRegistryImpl<>(registry); } + @Override + public > RegistryBuilder builder(Class type, ResourceLocation registryId) { + return new RegistryBuilderWrapper<>(this, new net.minecraftforge.registries.RegistryBuilder<>() + .setName(registryId) + .setType((Class) type)); + } + public class EventListener { @SubscribeEvent public void handleEvent(RegistryEvent.Register event) { @@ -101,6 +116,37 @@ public class RegistriesImpl { } } + public static class RegistryBuilderWrapper> implements RegistryBuilder { + @NotNull + private final RegistryProviderImpl provider; + @NotNull + private final net.minecraftforge.registries.RegistryBuilder builder; + private boolean saveToDisk = false; + private boolean syncToClients = false; + + public RegistryBuilderWrapper(@NotNull RegistryProviderImpl provider, @NotNull net.minecraftforge.registries.RegistryBuilder builder) { + this.provider = provider; + this.builder = builder; + } + + @Override + public @NotNull Registry build() { + if (!syncToClients) builder.disableSync(); + if (!saveToDisk) builder.disableSaving(); + return provider.get(builder.create()); + } + + @Override + public @NotNull RegistryBuilder option(@NotNull RegistryOption option) { + if (option == StandardRegistryOption.SAVE_TO_DISC) { + this.saveToDisk = true; + } else if (option == StandardRegistryOption.SYNC_TO_CLIENTS) { + this.syncToClients = true; + } + return this; + } + } + public static class VanillaBackedRegistryImpl implements Registry { private net.minecraft.core.Registry delegate; @@ -121,22 +167,22 @@ public class RegistriesImpl { public @NotNull ResourceLocation getId() { return id; } - + @Override public boolean isPresent() { return contains(id); } - + @Override public T get() { return value.get(); } - + @Override public int hashCode() { return Objects.hashCode(getRegistryId(), getId()); } - + @Override public boolean equals(Object obj) { if (this == obj) return true; @@ -144,7 +190,7 @@ public class RegistriesImpl { RegistrySupplier other = (RegistrySupplier) obj; return other.getRegistryId().equals(getRegistryId()) && other.getId().equals(getId()); } - + @Override public String toString() { return getRegistryId().toString() + "@" + id.toString(); @@ -223,27 +269,27 @@ public class RegistriesImpl { public @NotNull ResourceLocation getRegistryId() { return delegate.getRegistryName(); } - + @Override public @NotNull ResourceLocation getId() { return id; } - + @Override public boolean isPresent() { return contains(id); } - + @Override public T get() { return value.get(); } - + @Override public int hashCode() { return Objects.hashCode(getRegistryId(), getId()); } - + @Override public boolean equals(Object obj) { if (this == obj) return true; @@ -251,7 +297,7 @@ public class RegistriesImpl { RegistrySupplier other = (RegistrySupplier) obj; return other.getRegistryId().equals(getRegistryId()) && other.getId().equals(getId()); } - + @Override public String toString() { return getRegistryId().toString() + "@" + id.toString(); @@ -268,27 +314,27 @@ public class RegistriesImpl { public @NotNull ResourceLocation getRegistryId() { return delegate.getRegistryName(); } - + @Override public @NotNull ResourceLocation getId() { return registryObject.getId(); } - + @Override public boolean isPresent() { return registryObject.isPresent(); } - + @Override public T get() { return (T) registryObject.get(); } - + @Override public int hashCode() { return Objects.hashCode(getRegistryId(), getId()); } - + @Override public boolean equals(Object obj) { if (this == obj) return true; @@ -296,7 +342,7 @@ public class RegistriesImpl { RegistrySupplier other = (RegistrySupplier) obj; return other.getRegistryId().equals(getRegistryId()) && other.getId().equals(getId()); } - + @Override public String toString() { return getRegistryId().toString() + "@" + id.toString(); diff --git a/forge/src/main/resources/architectury.mixins.json b/forge/src/main/resources/architectury.mixins.json index 8408592c..af3e3799 100644 --- a/forge/src/main/resources/architectury.mixins.json +++ b/forge/src/main/resources/architectury.mixins.json @@ -7,7 +7,7 @@ "client": [ ], "mixins": [ - "BiomeGenerationSettingsBuilderAccessor", "MixinAbstractRecipeSerializer", "MixinBlockEntity", "MixinBlockEntityExtension", + "BiomeGenerationSettingsBuilderAccessor", "MixinRegistryEntry", "MixinBlockEntity", "MixinBlockEntityExtension", "MobSpawnSettingsBuilderAccessor" ], "injectors": {