Registry API to create modded registries, close #21

This commit is contained in:
shedaniel
2021-01-25 11:09:20 +08:00
parent 5d4a779d05
commit a4beace95c
12 changed files with 249 additions and 30 deletions

View File

@@ -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

View File

@@ -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> {
}

View File

@@ -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> {
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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 {
}

View File

@@ -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,
}

View File

@@ -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> {

View File

@@ -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> {
}

View File

@@ -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;
}
}

View File

@@ -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();

View File

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