瀏覽代碼

Registry API to create modded registries, close #21

shedaniel 4 年之前
父節點
當前提交
a4beace95c

+ 2 - 2
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

+ 1 - 1
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<T extends Recipe<?>> implements RecipeSerializer<T> {
+public abstract class AbstractRecipeSerializer<T extends Recipe<?>> extends RegistryEntry<T> implements RecipeSerializer<T> {
 }

+ 26 - 0
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<T> {
+}

+ 17 - 1
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 <T> Registry<T> get(ResourceKey<net.minecraft.core.Registry<T>> key) {
         return this.provider.get(key);
     }
     
+    @NotNull
     @Deprecated
     public <T> Registry<T> get(net.minecraft.core.Registry<T> registry) {
         return this.provider.get(registry);
     }
     
+    @NotNull
+    @SafeVarargs
+    public final <T extends RegistryEntry<T>> RegistryBuilder<T> builder(ResourceLocation registryId, T... typeGetter) {
+        if (typeGetter.length != 0) throw new IllegalStateException("array must be empty!");
+        return this.provider.builder((Class<T>) 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 <T> ResourceLocation getRegistryName(T object) {
         return getId(object, (ResourceKey<net.minecraft.core.Registry<T>>) 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
         <T> Registry<T> get(net.minecraft.core.Registry<T> registry);
+        
+        <T extends RegistryEntry<T>> RegistryBuilder<T> builder(Class<T> type, ResourceLocation registryId);
     }
 }

+ 42 - 0
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<T extends RegistryEntry<T>> {
+    @NotNull
+    Registry<T> build();
+    
+    @NotNull
+    RegistryBuilder<T> option(@NotNull RegistryOption option);
+    
+    @NotNull
+    default RegistryBuilder<T> saveToDisc() {
+        return option(StandardRegistryOption.SAVE_TO_DISC);
+    }
+    
+    @NotNull
+    default RegistryBuilder<T> syncToClients() {
+        return option(StandardRegistryOption.SYNC_TO_CLIENTS);
+    }
+}

+ 23 - 0
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 {
+}

+ 31 - 0
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,
+}

+ 37 - 0
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 <T> Registry<T> get(net.minecraft.core.Registry<T> registry) {
             return new RegistryImpl<>(registry);
         }
+        
+        @Override
+        @NotNull
+        public <T extends RegistryEntry<T>> RegistryBuilder<T> builder(Class<T> type, ResourceLocation registryId) {
+            return new RegistryBuilderWrapper<>(FabricRegistryBuilder.createSimple(type, registryId));
+        }
+    }
+    
+    public static class RegistryBuilderWrapper<T extends RegistryEntry<T>> implements RegistryBuilder<T> {
+        @NotNull
+        private FabricRegistryBuilder<T, MappedRegistry<T>> builder;
+        
+        public RegistryBuilderWrapper(@NotNull FabricRegistryBuilder<T, MappedRegistry<T>> builder) {
+            this.builder = builder;
+        }
+        
+        @Override
+        public @NotNull Registry<T> build() {
+            return RegistryProviderImpl.INSTANCE.get(builder.buildAndRegister());
+        }
+        
+        @Override
+        public @NotNull RegistryBuilder<T> 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<T> implements Registry<T> {

+ 3 - 3
forge/src/main/java/me/shedaniel/architectury/mixin/forge/MixinAbstractRecipeSerializer.java → 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<T> {
 }

+ 2 - 4
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, "<init>")) {
@@ -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<L" + recipeSerializer + "<*>;>");
-                }
+                targetClass.signature = "<T::Lnet/minecraftforge/registries/IForgeRegistryEntry<TT;>;>Lnet/minecraftforge/registries/ForgeRegistryEntry<TT;>;";
                 break;
         }
     }

+ 64 - 18
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 <T> Registry<T> get(ResourceKey<net.minecraft.core.Registry<T>> registryKey) {
-            return new ForgeBackedRegistryImpl<>(registry, (IForgeRegistry) RegistryManager.ACTIVE.getRegistry(registryKey.location()));
+            return get(RegistryManager.ACTIVE.getRegistry(registryKey.location()));
+        }
+    
+        public <T> Registry<T> get(IForgeRegistry registry) {
+            return new ForgeBackedRegistryImpl<>(this.registry, registry);
         }
         
         @Override
@@ -84,6 +92,13 @@ public class RegistriesImpl {
             return new VanillaBackedRegistryImpl<>(registry);
         }
         
+        @Override
+        public <T extends RegistryEntry<T>> RegistryBuilder<T> builder(Class<T> 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<T extends RegistryEntry<T>> implements RegistryBuilder<T> {
+        @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<T> build() {
+            if (!syncToClients) builder.disableSync();
+            if (!saveToDisk) builder.disableSaving();
+            return provider.get(builder.create());
+        }
+        
+        @Override
+        public @NotNull RegistryBuilder<T> 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<T> implements Registry<T> {
         private net.minecraft.core.Registry<T> 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();

+ 1 - 1
forge/src/main/resources/architectury.mixins.json

@@ -7,7 +7,7 @@
   "client": [
   ],
   "mixins": [
-    "BiomeGenerationSettingsBuilderAccessor", "MixinAbstractRecipeSerializer", "MixinBlockEntity", "MixinBlockEntityExtension",
+    "BiomeGenerationSettingsBuilderAccessor", "MixinRegistryEntry", "MixinBlockEntity", "MixinBlockEntityExtension",
     "MobSpawnSettingsBuilderAccessor"
   ],
   "injectors": {