From 8e3e8b212057923ee3283fe5e2e480e4c9a77699 Mon Sep 17 00:00:00 2001 From: LexManos Date: Thu, 20 Jan 2022 15:38:55 -0800 Subject: [PATCH] Revert "Hooks to allow registering and managing custom DFU schemes and types. (#8242)" --- .../util/datafix/DataFixers.java.patch | 11 - .../common/ForgeStatesProvider.java | 17 +- .../datafix/ForgeDataFixDelegate.java | 123 ------ .../datafix/ForgeDataFixerBuilder.java | 123 ------ .../ForgeDataFixerDelegateHandler.java | 214 ----------- .../datafix/ForgeDataFixerEventHandler.java | 190 --------- .../minecraftforge/datafix/ForgeSchema.java | 361 ------------------ .../datafix/ConfigureDataFixSchemaEvent.java | 214 ----------- 8 files changed, 2 insertions(+), 1251 deletions(-) delete mode 100644 patches/minecraft/net/minecraft/util/datafix/DataFixers.java.patch delete mode 100644 src/main/java/net/minecraftforge/datafix/ForgeDataFixDelegate.java delete mode 100644 src/main/java/net/minecraftforge/datafix/ForgeDataFixerBuilder.java delete mode 100644 src/main/java/net/minecraftforge/datafix/ForgeDataFixerDelegateHandler.java delete mode 100644 src/main/java/net/minecraftforge/datafix/ForgeDataFixerEventHandler.java delete mode 100644 src/main/java/net/minecraftforge/datafix/ForgeSchema.java delete mode 100644 src/main/java/net/minecraftforge/event/datafix/ConfigureDataFixSchemaEvent.java diff --git a/patches/minecraft/net/minecraft/util/datafix/DataFixers.java.patch b/patches/minecraft/net/minecraft/util/datafix/DataFixers.java.patch deleted file mode 100644 index b073a46f05..0000000000 --- a/patches/minecraft/net/minecraft/util/datafix/DataFixers.java.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/net/minecraft/util/datafix/DataFixers.java -+++ b/net/minecraft/util/datafix/DataFixers.java -@@ -222,7 +_,7 @@ - private static final DataFixer f_14510_ = m_14529_(); - - private static DataFixer m_14529_() { -- DataFixerBuilder datafixerbuilder = new DataFixerBuilder(SharedConstants.m_183709_().getWorldVersion()); -+ DataFixerBuilder datafixerbuilder = new net.minecraftforge.datafix.ForgeDataFixerBuilder(SharedConstants.m_183709_().getWorldVersion()); - m_14513_(datafixerbuilder); - return datafixerbuilder.build(Util.m_183988_()); - } diff --git a/src/main/java/net/minecraftforge/common/ForgeStatesProvider.java b/src/main/java/net/minecraftforge/common/ForgeStatesProvider.java index abef6930c9..5c27bd60fb 100644 --- a/src/main/java/net/minecraftforge/common/ForgeStatesProvider.java +++ b/src/main/java/net/minecraftforge/common/ForgeStatesProvider.java @@ -20,9 +20,7 @@ package net.minecraftforge.common; import net.minecraftforge.common.capabilities.CapabilityManager; -import net.minecraftforge.datafix.ForgeDataFixerEventHandler; import net.minecraftforge.event.RegistryEvent; -import net.minecraftforge.event.datafix.ConfigureDataFixSchemaEvent; import net.minecraftforge.eventbus.api.Event; import net.minecraftforge.fml.*; import net.minecraftforge.fml.event.IModBusEvent; @@ -40,8 +38,7 @@ import java.util.function.Supplier; import java.util.stream.Stream; public class ForgeStatesProvider implements IModStateProvider { - final ModLoadingState SETUP_DFU = ModLoadingState.withTransition("SETUP_DFU", "CONSTRUCT", ModLoadingPhase.GATHER, SerialTransition.forDFU()); - final ModLoadingState CREATE_REGISTRIES = ModLoadingState.withTransition("CREATE_REGISTRIES", "SETUP_DFU", ModLoadingPhase.GATHER, SerialTransition.of(()-> Stream.of(IModStateTransition.EventGenerator.fromFunction(RegistryEvent.NewRegistry::new)))); + final ModLoadingState CREATE_REGISTRIES = ModLoadingState.withTransition("CREATE_REGISTRIES", "CONSTRUCT", ModLoadingPhase.GATHER, SerialTransition.of(()-> Stream.of(IModStateTransition.EventGenerator.fromFunction(RegistryEvent.NewRegistry::new)))); final ModLoadingState OBJECT_HOLDERS = ModLoadingState.withInline("OBJECT_HOLDERS", "CREATE_REGISTRIES", ModLoadingPhase.GATHER, ml-> ObjectHolderRegistry.findObjectHolders()); final ModLoadingState INJECT_CAPABILITIES = ModLoadingState.withInline("INJECT_CAPABILITIES", "OBJECT_HOLDERS", ModLoadingPhase.GATHER, ml-> CapabilityManager.INSTANCE.injectCapabilities(ml.getAllScanData())); final ModLoadingState CUSTOM_TAGS = ModLoadingState.withInline("CUSTOM_TAGS", "INJECT_CAPABILITIES", ModLoadingPhase.GATHER, ml-> GameData.setCustomTagTypesFromRegistries()); @@ -50,23 +47,13 @@ public class ForgeStatesProvider implements IModStateProvider { final ModLoadingState NETLOCK = ModLoadingState.withInline("NETWORK_LOCK", "FREEZE_DATA", ModLoadingPhase.COMPLETE, ml-> NetworkRegistry.lock()); @Override public List getAllStates() { - return List.of(SETUP_DFU, CREATE_REGISTRIES, OBJECT_HOLDERS, INJECT_CAPABILITIES, CUSTOM_TAGS, LOAD_REGISTRIES, FREEZE, NETLOCK); + return List.of(CREATE_REGISTRIES, OBJECT_HOLDERS, INJECT_CAPABILITIES, CUSTOM_TAGS, LOAD_REGISTRIES, FREEZE, NETLOCK); } static record SerialTransition(Supplier>> eventStream, BiFunction, CompletableFuture>> preDispatchHook, BiFunction, CompletableFuture>> postDispatchHook, BiFunction>, CompletableFuture>> finalActivityGenerator) implements IModStateTransition { public static SerialTransition of(Supplier>> eventStream) { return new SerialTransition(eventStream, (t, f)->CompletableFuture.completedFuture(Collections.emptyList()), (t, f)->CompletableFuture.completedFuture(Collections.emptyList()), (e, prev) ->prev.thenApplyAsync(Function.identity(), e)); } - - private static SerialTransition forDFU() { - return new SerialTransition<>( - ForgeDataFixerEventHandler::generateConfigureEvents, - ForgeDataFixerEventHandler::preDispatch, - ForgeDataFixerEventHandler::postDispatch, - ForgeDataFixerEventHandler::rebuildFixer - ); - } - @Override public Supplier>> eventFunctionStream() { return eventStream; diff --git a/src/main/java/net/minecraftforge/datafix/ForgeDataFixDelegate.java b/src/main/java/net/minecraftforge/datafix/ForgeDataFixDelegate.java deleted file mode 100644 index d0fd89a261..0000000000 --- a/src/main/java/net/minecraftforge/datafix/ForgeDataFixDelegate.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Minecraft Forge - * Copyright (c) 2016-2021. - * - * This library 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 version 2.1 - * of the License. - * - * This library 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 library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -package net.minecraftforge.datafix; - -import com.mojang.datafixers.DataFix; -import com.mojang.datafixers.TypeRewriteRule; -import net.minecraftforge.fml.util.ObfuscationReflectionHelper; -import org.jetbrains.annotations.Nullable; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -/** - * This delegate allows for rebuilding of the cached rule, which is needed since it is - * cached in {@link DataFix} and the recompute of schema will need to invalidate this cached - * type rewrite rule. - */ -class ForgeDataFixDelegate extends DataFix -{ - - private static final Method makeRuleMethod = ObfuscationReflectionHelper.findMethod( - DataFix.class, - "makeRule" - ); - - private final DataFix wrapped; - - @Nullable - private TypeRewriteRule wrappedRule; - - ForgeDataFixDelegate(final DataFix wrapped) - { - //We pass in dummy data to the super type. - //However we can not pass in null to the super type for the output schema, since this would cause an NPE. - //Luckily ForgeSchema has this option while preserving the version key. - //So we pass it that, for good measure. - super(new ForgeSchema(wrapped.getVersionKey(), null, null), false); - this.wrapped = wrapped; - } - - @Override - public TypeRewriteRule getRule() - { - //Check if OUR cached rule is available. - if (this.wrappedRule == null) - { - //Not available get a new one. - this.wrappedRule = rebuildRuleReflectively(); - } - - //Cached version available, return it. - return wrappedRule; - } - - /** - * Rebuilds the rule using reflection. - * This is needed since "makeRule" is protected in DataFix. - * And "getRule" returns a potentially cached version, which is explicitly not what we want, - * since that cached version might contain an older invalid schema from before a rebake. - * - * @return The type rewrite rule as defined by "makeRule" in the wrapped DataFix. - */ - private TypeRewriteRule rebuildRuleReflectively() - { - try - { - //Just invoke it via reflection. - final Object candidate = makeRuleMethod.invoke(this.wrapped); - //Check if we have a rule, this is just a security barrier to just crash hard if in the future the schema changes, - //so that this is noted during the initial porting phase. - if (candidate instanceof TypeRewriteRule typeRewriteRule) - { - return typeRewriteRule; - } - - //WTF Who put this here? Who is returning a none TypeRewriteRule from a method that should return it.! - throw new IllegalStateException("Failed to get a rewrite rule. The returned object was not a TypeRewriteRule!"); //Should never be reached. - } - catch (IllegalAccessException | InvocationTargetException e) - { - throw new IllegalStateException("Could not get or invoke makeRule() Method on data fixer!", e); - } - } - - /** - * Allows for resetting of the cached rule. - */ - public void resetRule() - { - this.wrappedRule = null; - } - - /** - * Returns the wrapped datafix originally cached rule. - * Does not rebuild it!. - * - * Is also irrelevant since we are not using this value anyway and is only needed to prevent NPEs in the super class. - * - * @return The value. - */ - @Override - protected TypeRewriteRule makeRule() - { - return wrapped.getRule(); - } -} diff --git a/src/main/java/net/minecraftforge/datafix/ForgeDataFixerBuilder.java b/src/main/java/net/minecraftforge/datafix/ForgeDataFixerBuilder.java deleted file mode 100644 index fc04569e45..0000000000 --- a/src/main/java/net/minecraftforge/datafix/ForgeDataFixerBuilder.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Minecraft Forge - * Copyright (c) 2016-2021. - * - * This library 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 version 2.1 - * of the License. - * - * This library 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 library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -package net.minecraftforge.datafix; - -import com.google.common.collect.Lists; -import com.mojang.datafixers.DataFixUtils; -import com.mojang.datafixers.DataFixer; -import com.mojang.datafixers.DataFixerBuilder; -import com.mojang.datafixers.DataFixerUpper; -import com.mojang.datafixers.DataFix; -import com.mojang.datafixers.schemas.Schema; -import it.unimi.dsi.fastutil.ints.Int2ObjectAVLTreeMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectSortedMap; -import it.unimi.dsi.fastutil.ints.IntAVLTreeSet; -import it.unimi.dsi.fastutil.ints.IntSortedSet; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Executor; -import java.util.function.BiFunction; - -/** - * The purpose of this custom data fixer builder is to gain full control over the datafixer that is in play at runtime. - *

- * This means that schemas become adaptable and that the ruleset can be dynamically rebaked to adapt to the changes mod authors make to the schemas. - *

- * Some methods are carbon copies of the DFU counterpart, but are copied so that we can control the data. - */ -public class ForgeDataFixerBuilder extends DataFixerBuilder -{ - private static final Logger LOGGER = LogManager.getLogger(); - - private final int dataVersion; - private final List allSchemas = new ArrayList<>(); - private final Int2ObjectSortedMap schemas = new Int2ObjectAVLTreeMap<>(); - private final List globalList = Lists.newArrayList(); - private final IntSortedSet fixerVersions = new IntAVLTreeSet(); - - public ForgeDataFixerBuilder(final int dataVersion) - { - super(dataVersion); - this.dataVersion = dataVersion; - } - - @Override - public Schema addSchema(final int version, final int subVersion, final BiFunction factory) - { - final int key = DataFixUtils.makeKey(version, subVersion); - final Schema parent = schemas.isEmpty() ? null : schemas.get(getLowestSchemaSameVersion(schemas, key - 1)); - return addWrappedSchema(factory.apply(key, parent), parent); - } - - @Override - public void addSchema(final Schema schema) - { - final Schema parent = schemas.isEmpty() ? null : schemas.get(getLowestSchemaSameVersion(schemas, schema.getVersionKey() - 1)); - addWrappedSchema(schema, parent); - } - - private ForgeSchema addWrappedSchema(final Schema schema, final Schema parent) - { - final ForgeSchema wrapped = new ForgeSchema(schema.getVersionKey(), parent, schema); - schemas.put(wrapped.getVersionKey(), wrapped); - allSchemas.add(wrapped); - return wrapped; - } - - @Override - public DataFixer build(final Executor executor) - { - return new ForgeDataFixerDelegateHandler(dataVersion, schemas, allSchemas, globalList, executor, fixerVersions); - } - - /** - * CC of the original method in {@link DataFixerUpper}. Is protected so not accessible for us. - * - * @param schemas The schemas to search in. - * @param versionKey The version to find the lowest matching schema for. - * @return The version for the lowest matching schema. - */ - protected static int getLowestSchemaSameVersion(final Int2ObjectSortedMap schemas, final int versionKey) - { - if (versionKey < schemas.firstIntKey()) - { - return schemas.firstIntKey(); - } - return schemas.subMap(0, versionKey + 1).lastIntKey(); - } - - @Override - public void addFixer(final DataFix fix) - { - final int version = DataFixUtils.getVersion(fix.getVersionKey()); - - if (version > dataVersion) - { - LOGGER.warn("Ignored fix registered for version: {} as the DataVersion of the game is: {}", version, dataVersion); - return; - } - - globalList.add(new ForgeDataFixDelegate(fix)); - fixerVersions.add(fix.getVersionKey()); - } -} diff --git a/src/main/java/net/minecraftforge/datafix/ForgeDataFixerDelegateHandler.java b/src/main/java/net/minecraftforge/datafix/ForgeDataFixerDelegateHandler.java deleted file mode 100644 index 4380ef4f9d..0000000000 --- a/src/main/java/net/minecraftforge/datafix/ForgeDataFixerDelegateHandler.java +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Minecraft Forge - * Copyright (c) 2016-2021. - * - * This library 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 version 2.1 - * of the License. - * - * This library 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 library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -package net.minecraftforge.datafix; - -import com.mojang.datafixers.DataFixUtils; -import com.mojang.datafixers.DataFixerUpper; -import com.mojang.datafixers.DataFix; -import com.mojang.datafixers.DSL; -import com.mojang.datafixers.TypeRewriteRule; -import com.mojang.datafixers.schemas.Schema; -import com.mojang.datafixers.types.Type; -import com.mojang.serialization.Dynamic; -import it.unimi.dsi.fastutil.ints.Int2ObjectAVLTreeMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectSortedMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectSortedMaps; -import it.unimi.dsi.fastutil.ints.IntAVLTreeSet; -import it.unimi.dsi.fastutil.ints.IntSortedSet; -import it.unimi.dsi.fastutil.ints.IntSortedSets; -import it.unimi.dsi.fastutil.ints.IntBidirectionalIterator; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executor; - -/** - * A delegate handler which can rebuild a data fixer on the fly. - */ -class ForgeDataFixerDelegateHandler extends DataFixerUpper -{ - private static final Logger LOGGER = LogManager.getLogger(); - - private final int dataVersion; - private final List allSchemas; - private final Int2ObjectSortedMap schemas; - private final List globalList; - private final IntSortedSet fixerVersions; - - private InnerFixer activeFixer; - - ForgeDataFixerDelegateHandler( - final int dataVersion, - final Int2ObjectSortedMap schemas, - final List allSchemas, - final List globalList, - final Executor executor, - final IntSortedSet fixerVersions - ) - { - //Supply dummy data to the super constructor - //We never invoke and method on the super and so this data does not matter. - super(Int2ObjectSortedMaps.emptyMap(), Collections.emptyList(), IntSortedSets.EMPTY_SET); - - //Store the builders input so we can rebuild it later if needed. - this.dataVersion = dataVersion; - this.allSchemas = Collections.unmodifiableList(allSchemas); - this.schemas = schemas; - this.globalList = globalList; - this.fixerVersions = fixerVersions; - - //Rebuild the setup immediately. - rebuildFixer(executor); - } - - public void rebuildFixer(final Executor executor) - { - //Reset our rules, normal vanilla rules (ours too) keep a cache of their schemas - //We can not use that and need to forcefully recompute them. - this.globalList.forEach(ForgeDataFixDelegate::resetRule); - - //All schemas are already reset via the mod event bus as this time. - //Rebuild of those is not needed. - this.activeFixer = new InnerFixer(new Int2ObjectAVLTreeMap(schemas), new ArrayList<>(globalList), new IntAVLTreeSet(fixerVersions)); - - //This section was added to make it easier to debug the rule set at runtime, since it is no longer pre-computed off thread, - //But only on the main thread, at the moment it is needed. - //This basically disables the REWRITE_CACHE prefill and fills it on-demand. - //Although it is mainly used for debugging, it also provides a good way of reducing DFU's memory footprint, when it is not needed. - //Since the following code will compute an update rule from every version to the current for every known type in the schema, - //relating to this version. By default, however this is disabled to preserve vanilla compatibility, since it does do the pre-compute - //to fill up the cache. - //To enable it start the JVM with the system property set to true, -Dforge.datafixer.disablePreCompute=true needs to be added as - //a JVM Launch argument. - if (Boolean.getBoolean("forge.datafixer.disablePreCompute")) - { - LOGGER.warn("The pre-compute of the data fixer rules is disabled, this is not recommended for normal use, but can be useful for debugging or in low-memory situations."); - return; - } - - //Get an iterator for all known versions. - final IntBidirectionalIterator iterator = activeFixer.fixerVersions().iterator(); - while (iterator.hasNext()) - { - //Grab the key. - final int versionKey = iterator.nextInt(); - - //Grab its schema. - final Schema schema = schemas.get(versionKey); - - //For each type in the schema, compute its rewrite rule for the current version. - for (final String typeName : schema.types()) - { - //Schedule the recompute off-thread - CompletableFuture.runAsync(() -> { - //Grab the type. - final Type dataType = schema.getType(() -> typeName); - - //Grab its normal rewrite rule for the given version and our current target version. - final TypeRewriteRule rule = activeFixer.getRule(DataFixUtils.getVersion(versionKey), dataVersion); - - //Optimize the rule to only apply to the given type. - dataType.rewrite(rule, DataFixerUpper.OPTIMIZATION_RULE); - }, executor).exceptionally(e -> { - //Fails. - LOGGER.error("Unable to build datafixers", e); - - //Just kill it, if this fails we have a problem anyway! - Runtime.getRuntime().exit(1); - return null; - }); - } - } - } - - @Override - public Dynamic update( - final DSL.TypeReference type, final Dynamic input, final int version, final int newVersion - ) - { - //Invoke the internal DFU engine. - return activeFixer.update( - type, input, version, newVersion - ); - } - - @Override - public Schema getSchema(final int key) - { - //Grab it from the internal DFU engine. - return activeFixer.getSchema(key); - } - - /** - * Gives access to all known schemas at the point of building of this wrapper. - * - * @return All schemas known to DFU. - */ - public List getAllSchemas() - { - return allSchemas; - } - - /** - * Represents a DFU that gives access to the protected sub methods so data can be properly extracted. - * Delegates all of its method invocations to the super DFU instance. - */ - private static final class InnerFixer extends DataFixerUpper - { - private InnerFixer(final Int2ObjectSortedMap schemas, final List globalList, final IntSortedSet fixerVersions) - { - super(schemas, globalList, fixerVersions); - } - - @Override - public Dynamic update(final DSL.TypeReference type, final Dynamic input, final int version, final int newVersion) - { - return super.update(type, input, version, newVersion); - } - - @Override - public Schema getSchema(final int key) - { - return super.getSchema(key); - } - - @Override - public Type getType(final DSL.TypeReference type, final int version) - { - return super.getType(type, version); - } - - @Override - public TypeRewriteRule getRule(final int version, final int dataVersion) - { - return super.getRule(version, dataVersion); - } - - @Override - public IntSortedSet fixerVersions() - { - return super.fixerVersions(); - } - } -} diff --git a/src/main/java/net/minecraftforge/datafix/ForgeDataFixerEventHandler.java b/src/main/java/net/minecraftforge/datafix/ForgeDataFixerEventHandler.java deleted file mode 100644 index a330fa1118..0000000000 --- a/src/main/java/net/minecraftforge/datafix/ForgeDataFixerEventHandler.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Minecraft Forge - * Copyright (c) 2016-2021. - * - * This library 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 version 2.1 - * of the License. - * - * This library 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 library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -package net.minecraftforge.datafix; - -import com.google.common.collect.Lists; -import com.mojang.datafixers.schemas.Schema; -import net.minecraft.Util; -import net.minecraft.util.datafix.DataFixers; -import net.minecraftforge.event.datafix.ConfigureDataFixSchemaEvent; -import net.minecraftforge.fml.IModStateTransition; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executor; -import java.util.stream.Stream; - -/** - * Event handler utility class for managing the events related to data fixers. - * This particular class is used to handle firing of the parallel mod loading events - * for the DFU setup. - * - * These events are fired immediately after mod construction and before the rest of the game - * loads, even before registries are fired. - * - * THIS CLASS IS FOR INTERNAL USE ONLY! - */ -public class ForgeDataFixerEventHandler -{ - private static final Logger LOGGER = LogManager.getLogger(); - - /** - * Gives access to the list of schemas registered with the data fixers. - * If we are currently running an incompatible version of DFU or somebody messed with it, - * then an empty list is returned. - * - * @return The list of all known schemas to handle. - */ - private static List getAllSchemas() - { - //Check if we are running in a compatible environment. - if (DataFixers.getDataFixer() instanceof ForgeDataFixerDelegateHandler forgeDataFixerDelegateHandler) - { - //Forge DFU wrapper is active, grab its configured schemas. - return forgeDataFixerDelegateHandler.getAllSchemas(); - } - - //Incompatible environment, return an empty list. - return Collections.emptyList(); - } - - /** - * Builder function for creating the events that are fired on start up. - * This returns one generator per schema, and keeps the schema in the order defined. - * - * The generator will always return the same multi-thread capable event reference regardless - * of the passed in mod name. - * - * @return The stream of event generators used to fire one event per mod per schema. - */ - public static Stream> generateConfigureEvents() - { - //Grab the schemas - List schemas = Lists.newArrayList(getAllSchemas()); - //Sort them based on their version key. - schemas.sort(Comparator.comparingInt(Schema::getVersionKey)); - - //Make one event per schema, and return it reference based from the event generator, - //regardless of which mod the generator is invoked for. - return schemas.stream() - .map(ConfigureDataFixSchemaEvent::new) - .map(event -> IModStateTransition.EventGenerator.fromFunction(modContainer -> event)); - } - - /** - * Invoked by the event management system to indicate that we are about the fire an event for the given generator to all mods. - * This is invoked exactly once, and only once, per generator (and as such per event, and schema). - * - * Clears out the current status of the schema by resetting its type definition maps. - * - * @param executor The executor to execute this task on. - * @param eventGenerator The event generator that is about to be executed. - * @return A future that indicates success or failure. - */ - public static CompletableFuture> preDispatch( - final Executor executor, final IModStateTransition.EventGenerator eventGenerator - ) - { - return CompletableFuture.runAsync(() -> { - //Grab the event, with a null container (is reference equals anyways for all containers). - final ConfigureDataFixSchemaEvent event = eventGenerator.apply(null); - - //Log that we are processing that particular event. - LOGGER.debug("Registering DFU Schema updates: {}", event.getSchema().getVersionKey()); - - //Check if we are a compatible schema. - if (event.getSchema() instanceof ForgeSchema forgeSchema) - { - //And reset if needed. - forgeSchema.resetSchema(); - } - }, executor).thenApply(v -> Collections.emptyList()); - } - - /** - * Invoked by the event management system to indicate that it has fired all the events for the given schema. - * This allows us to collect the data from the events and trigger the given schema to rebuild its type map. - * - * @param executor The executor to execute the task on. - * @param eventGenerator The event generator for the event (and thus the schema in question). - * @return The future that indicates success or failure. - */ - public static CompletableFuture> postDispatch( - final Executor executor, final IModStateTransition.EventGenerator eventGenerator - ) - { - return CompletableFuture.runAsync(() -> { - //Grab the event again, with a null container (is reference equals anyways for all containers). - final ConfigureDataFixSchemaEvent event = eventGenerator.apply(null); - - //Notify about the completion of the event firing. - LOGGER.debug("Registered DFU Schema updates: {}", event.getSchema().getVersionKey()); - - //Check for a compatible schema. - if (event.getSchema() instanceof ForgeSchema forgeSchema) - { - //Rebuild the schema with the mod data. - forgeSchema.rebuildSchema( - event.getEntityTypes(), - event.getBlockEntityTypes() - ); - } - }, executor).handle((v, t) -> t != null ? Collections.singletonList(t) : Collections.emptyList()); - } - - /** - * Invoked by the event management system to indicate that it completely fired all events from the event stream. - * This indicates that all the events for all the schemas have been fired and post processed. - * As such we can now safely reconfigure the DFU wrapper so that the new schema configurations are picked - * up by the system. - * - * @param executor The executor to execute the task on. - * @param listCompletableFuture The list of previous failures. - * @return The future which indicates success or failure. - */ - public static CompletableFuture> rebuildFixer( - final Executor executor, final CompletableFuture> listCompletableFuture - ) - { - return listCompletableFuture.whenCompleteAsync((errors, except) -> { - //Check for errors. - if (except != null) - { - //Ouch that failed, log it and escape. - LOGGER.fatal("Detected errors during dfu setup. DFU might not be available.", except); - } - else - { - //Success, check for a compatible DFU instance and then rebuild it. - if (DataFixers.getDataFixer() instanceof ForgeDataFixerDelegateHandler forgeDataFixerDelegateHandler) - { - //Do not do this on the mod executor! - //This will crash the game. - //Rebuild the DFU wrapper on the bootstrap executor - forgeDataFixerDelegateHandler.rebuildFixer(Util.bootstrapExecutor()); - } - } - }, executor); - } -} diff --git a/src/main/java/net/minecraftforge/datafix/ForgeSchema.java b/src/main/java/net/minecraftforge/datafix/ForgeSchema.java deleted file mode 100644 index aa67b54a5e..0000000000 --- a/src/main/java/net/minecraftforge/datafix/ForgeSchema.java +++ /dev/null @@ -1,361 +0,0 @@ -/* - * Minecraft Forge - * Copyright (c) 2016-2021. - * - * This library 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 version 2.1 - * of the License. - * - * This library 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 library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -package net.minecraftforge.datafix; - -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.mojang.datafixers.DSL; -import com.mojang.datafixers.DataFixUtils; -import com.mojang.datafixers.schemas.Schema; -import com.mojang.datafixers.types.Type; -import com.mojang.datafixers.types.families.RecursiveTypeFamily; -import com.mojang.datafixers.types.families.TypeFamily; -import com.mojang.datafixers.types.templates.RecursivePoint; -import com.mojang.datafixers.types.templates.TypeTemplate; - -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.Objects; -import java.util.function.Supplier; - -/** - * A partial carbon copy of the {@link Schema} class. - * But this allows us to delay the setup of the type hierarchy until we need it. - */ -class ForgeSchema extends Schema -{ - //Can not be final, needs to be initialized on the fly! - //Constructor invocation order and the what not! - private Map> TYPE_TEMPLATES = Maps.newConcurrentMap(); - private Map> TYPES; - private Map RECURSIVE_TYPES; - - private final Map> MODDED_ENTITY_TYPES = Maps.newConcurrentMap(); - private final Map> MODDED_BLOCK_ENTITY_TYPES = Maps.newConcurrentMap(); - - //Store some data we can not access later anymore. - private final String name; - private final Schema wrapped; - - ForgeSchema(final int versionKey, final Schema parent, final Schema wrapped) - { - super(versionKey, parent); - if (RECURSIVE_TYPES == null) - { - RECURSIVE_TYPES = Maps.newConcurrentMap(); - } - - if (TYPE_TEMPLATES == null) - { - TYPE_TEMPLATES = Maps.newConcurrentMap(); - } - - this.wrapped = wrapped; - - final int subVersion = DataFixUtils.getSubVersion(versionKey); - name = "V" + DataFixUtils.getVersion(versionKey) + (subVersion == 0 ? "" : "." + subVersion); - - //Now with the vanilla data in the schema, lets build our first version again. - //Yes this executes the type resolve multiple times per schema (but it's not a big deal) - resetSchema(); - rebuildSchema( - Collections.emptyMap(), - Collections.emptyMap() - ); - } - - /** - * Rebuilds the types, with support for the case that no types exists. - * (Which should never happen, but you never know!) - * - * @return The type map. - */ - protected Map> buildTypes() - { - //This is potentially invoked from the super constructor, so our field init code has not run yet. - //Set it to a none null value, so the super type can do its initial construction. - if (RECURSIVE_TYPES == null) - { - RECURSIVE_TYPES = Maps.newConcurrentMap(); - } - - //This is potentially invoked from the super constructor, so our field init code has not run yet. - //Set it to a none null value, so the super type can do its initial construction. - if (TYPE_TEMPLATES == null) - { - TYPE_TEMPLATES = Maps.newConcurrentMap(); - } - - //Result map. - final Map> types = Maps.newConcurrentMap(); - - //All the core templates into which recursion of data is possible. - final List templates = Lists.newArrayList(); - - //Check all recursion types - for (final Map.Entry entry : RECURSIVE_TYPES.entrySet()) - { - //Generate a template for the type. - templates.add(DSL.check(entry.getKey(), entry.getValue(), getTemplate(entry.getKey()))); - } - - //Merge them all together into one root recursive type. - final Optional availableTypeTemplate = templates.stream().reduce(DSL::or); - if (availableTypeTemplate.isEmpty()) - { - //Check for its existence or nuke. - return Maps.newConcurrentMap(); - } - //Build a type family for our recursive types. - final TypeTemplate choice = availableTypeTemplate.get(); - final TypeFamily family = new RecursiveTypeFamily(name, choice); - - //Now process all other known types, taking care of recursion. - for (final String name : TYPE_TEMPLATES.keySet()) - { - final Type type; - final int recurseId = RECURSIVE_TYPES.getOrDefault(name, -1); - if (recurseId != -1) - { - type = family.apply(recurseId); - } - else - { - type = getTemplate(name).apply(family).apply(-1); - } - types.put(name, type); - } - return types; - } - - @Override - public Set types() - { - return TYPES.keySet(); - } - - @Override - public Type getTypeRaw(final DSL.TypeReference type) - { - final String name = type.typeName(); - return TYPES.computeIfAbsent(name, key -> { - throw new IllegalArgumentException("Unknown type: " + name); - }); - } - - @Override - public Type getType(final DSL.TypeReference type) - { - final String name = type.typeName(); - final Type type1 = TYPES.computeIfAbsent(name, key -> { - throw new IllegalArgumentException("Unknown type: " + name); - }); - if (type1 instanceof RecursivePoint.RecursivePointType) - { - return type1.findCheckedType(-1).orElseThrow(() -> new IllegalStateException("Could not find choice type in the recursive type")); - } - return type1; - } - - @Override - public TypeTemplate resolveTemplate(final String name) - { - //This is potentially invoked from the super constructor, so our field init code has not run yet. - //Set it to a none null value, so the super type can do its initial construction. - if (TYPE_TEMPLATES == null) - { - TYPE_TEMPLATES = Maps.newConcurrentMap(); - } - - return TYPE_TEMPLATES.getOrDefault(name, () -> { - throw new IllegalArgumentException("Unknown type: " + name); - }).get(); - } - - @Override - public TypeTemplate id(final String name) - { - //This is potentially invoked from the super constructor, so our field init code has not run yet. - //Set it to a none null value, so the super type can do its initial construction. - if (RECURSIVE_TYPES == null) - { - RECURSIVE_TYPES = Maps.newConcurrentMap(); - } - - final int id = RECURSIVE_TYPES.getOrDefault(name, -1); - if (id != -1) - { - return DSL.id(id); - } - return getTemplate(name); - } - - @Override - public void registerTypes( - final Schema schema, final Map> entityTypes, final Map> blockEntityTypes - ) - { - //This is a bit wonky, in vanilla it suffices to register the types to one single version - //And all newer versions will have this type. - //Due to the way we set up the schemas with events later, that is not possible anymore. - //Modders will need to register their types on all versions that they should exist in, - //not just in the oldest version. - - if (wrapped != null) - { - wrapped.registerTypes(schema, entityTypes, blockEntityTypes); - } - else if (parent != null) - { - parent.registerTypes(schema, entityTypes, blockEntityTypes); - } - } - - @Override - public Map> registerEntities(final Schema schema) - { - //This is a bit wonky, in vanilla it suffices to register the types to one single version - //And all newer versions will have this type. - //Due to the way we set up the schemas with events later, that is not possible anymore. - //Modders will need to register their types on all versions that they should exist in, - //not just in the oldest version. - - if (wrapped != null) - { - return wrapped.registerEntities(schema); - } - if (parent != null) - { - return parent.registerEntities(schema); - } - - return Maps.newHashMap(); - } - - @Override - public Map> registerBlockEntities(final Schema schema) - { - //This is a bit wonky, in vanilla it suffices to register the types to one single version - //And all newer versions will have this type. - //Due to the way we set up the schemas with events later, that is not possible anymore. - //Modders will need to register their types on all versions that they should exist in, - //not just in the oldest version. - - if (wrapped != null) - { - return wrapped.registerBlockEntities(schema); - } - if (parent != null) - { - return parent.registerBlockEntities(schema); - } - - return Maps.newHashMap(); - } - - /** - * Registers a new type to the Schema with its type template. - * - * @param recursive Indicates if the type is potentially recursive. - * @param type The type in question. - * @param template Its template. - */ - @Override - public void registerType(final boolean recursive, final DSL.TypeReference type, final Supplier template) - { - //This is invoked from the super constructor, so our field init code has not run yet. - //Set it to a none null value, so the super type can do its initial construction. - if (TYPE_TEMPLATES == null) - { - TYPE_TEMPLATES = Maps.newConcurrentMap(); - } - - //This is invoked from the super constructor, so our field init code has not run yet. - //Set it to a none null value, so the super type can do its initial construction. - if (RECURSIVE_TYPES == null) - { - RECURSIVE_TYPES = Maps.newConcurrentMap(); - } - - TYPE_TEMPLATES.put(type.typeName(), template); - if (recursive && !RECURSIVE_TYPES.containsKey(type.typeName())) - { - RECURSIVE_TYPES.put(type.typeName(), RECURSIVE_TYPES.size()); - } - } - - /** - * Resets the schema so that the type map can be properly rebuild. - */ - void resetSchema() - { - this.TYPE_TEMPLATES.clear(); - this.TYPES.clear(); - this.RECURSIVE_TYPES.clear(); - this.MODDED_ENTITY_TYPES.clear(); - this.MODDED_BLOCK_ENTITY_TYPES.clear(); - } - - /** - * Rebuilds the schema's type map. - * This also injects custom types for entities and block entities. - * - * @param modEntityTypes The mod entity types to inject. - * @param modBlockEntityTypes The block entity types to inject. - */ - void rebuildSchema( - final Map> modEntityTypes, - final Map> modBlockEntityTypes - ) - { - //First grab the parent's additional modded types, if the parent is compatible. - if (this.parent instanceof ForgeSchema parentForgeSchema) - { - //Compatible parent found, add its modded types. - this.MODDED_ENTITY_TYPES.putAll(parentForgeSchema.MODDED_ENTITY_TYPES); - this.MODDED_BLOCK_ENTITY_TYPES.putAll(parentForgeSchema.MODDED_BLOCK_ENTITY_TYPES); - } - - //Now add our own modded types, and potentially override the data. - this.MODDED_ENTITY_TYPES.putAll(modEntityTypes); - this.MODDED_BLOCK_ENTITY_TYPES.putAll(modBlockEntityTypes); - - //Remove those types from the map, which the event marked for removal. - this.MODDED_ENTITY_TYPES.values().removeIf(Objects::isNull); - this.MODDED_BLOCK_ENTITY_TYPES.values().removeIf(Objects::isNull); - - //Grab the vanilla entities. - final Map> entityTypes = registerEntities(this); - final Map> blockEntityTypes = registerBlockEntities(this); - - //Add all modded entities and block entities. - entityTypes.putAll(this.MODDED_ENTITY_TYPES); - blockEntityTypes.putAll(this.MODDED_BLOCK_ENTITY_TYPES); - - //Re-register them. - registerTypes(this, entityTypes, blockEntityTypes); - - //Build the type map again. - TYPES = buildTypes(); - } -} diff --git a/src/main/java/net/minecraftforge/event/datafix/ConfigureDataFixSchemaEvent.java b/src/main/java/net/minecraftforge/event/datafix/ConfigureDataFixSchemaEvent.java deleted file mode 100644 index 9a9c56810a..0000000000 --- a/src/main/java/net/minecraftforge/event/datafix/ConfigureDataFixSchemaEvent.java +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Minecraft Forge - * Copyright (c) 2016-2021. - * - * This library 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 version 2.1 - * of the License. - * - * This library 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 library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -package net.minecraftforge.event.datafix; - -import com.google.common.collect.Maps; -import com.mojang.datafixers.DSL; -import com.mojang.datafixers.schemas.Schema; -import com.mojang.datafixers.types.templates.TypeTemplate; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.datafix.fixes.References; -import net.minecraftforge.eventbus.api.Event; -import net.minecraftforge.fml.event.IModBusEvent; - -import java.util.Collections; -import java.util.Map; -import java.util.function.Function; -import java.util.function.Supplier; - -/** - * Event fired in parallel on the mod event bus to allow for the modification - * of a DFU Schemas type signature. - * - * If used to register a new entity or block entity to a particular version, - * then this also will need to be registered to all newer versions to persist properly! - * As opposed to vanilla which automatically transfers the entities and block entities from older - * schemas to newer ones, this event does not do that and the modder is on their own to implement this properly. - * - * We suggest instead of checking for version equality to check for a greater or equal version, and to unregister (or override with a newer version) - * when the type changes again in a newer version. - * - * If a DFU touches a vanilla type (like a list of block entities in a chunk), then all the possible variations of that type need to be known, - * in other words, when mojang changes the type signature of a vanilla type, all the mods that touch that type need also to register their types in that schema to persist. - * An example of this is when Mojang moved the block entity list in the chunk during the upgrade from 1.17 to 1.18, any block entity type which is - * not registered to the 1.18 schema will be lost, since the rule considers a not registered block entity type, as a type that got removed from the game. - */ -public class ConfigureDataFixSchemaEvent extends Event implements IModBusEvent -{ - - private final Schema schema; - - private final Map> entityTypes = Maps.newConcurrentMap(); - private final Map> blockEntityTypes = Maps.newConcurrentMap(); - - //Some unmodifiable views of the above maps - private final Map> entityTypesView = Collections.unmodifiableMap(entityTypes); - private final Map> blockEntityTypesView = Collections.unmodifiableMap(blockEntityTypes); - - public ConfigureDataFixSchemaEvent(final Schema schema) - { - this.schema = schema; - } - - /** - * The schema which you can configure. - * - * @return The schema - */ - public Schema getSchema() - { - return schema; - } - - /** - * The version of the schema that is about to be configured. - * - * @return The version. - */ - public int getVersion() - { - return getSchema().getVersionKey(); - } - - /** - * Registers a new simple (catch-all-nbt) block entity to the current schema and all its descendent versions. - * - * @param registryName The registry name of the block entity. - */ - public void registerSimpleBlockEntity(final ResourceLocation registryName) - { - registerBlockEntity(registryName, DSL::remainder); - } - - /** - * Registers a new simple (catch-all-nbt) block entity with an item inventory array on the nbt field with the given name to the current schema and all its descendent versions. - * - * @param registryName The registry name of the block entity. - * @param nbtKey The name of the nbt field to where the item array is located. - */ - public void registerSimpleItemInventory(final ResourceLocation registryName, final String nbtKey) - { - registerBlockEntity(registryName, () -> DSL.optionalFields(nbtKey, DSL.list(References.ITEM_STACK.in(getSchema())))); - } - - /** - * Allows for the custom definition of a new block entity type and registration of it to the current schema and all its descendent versions. - * The function is given the registry name of the block entity type template to produce. - * - * @param registryName The registry name of the block entity type. - * @param template The function to produce the block entity type template. - */ - public void registerBlockEntity(final ResourceLocation registryName, final Function template) - { - registerBlockEntity(registryName, () -> template.apply(registryName.toString())); - } - - /** - * Allows for the custom definition of a new block entity type and registration of it to the current schema and all its descendent versions. - * The supplier is invoked to produce the block entity type template. - * - * @param registryName The registry name of the block entity type. - * @param template The supplier of the type template. - */ - public void registerBlockEntity(final ResourceLocation registryName, final Supplier template) - { - blockEntityTypes.put(registryName.toString(), template); - } - - /** - * Removes an already registered block entity from the current schema and all its descendent versions. - * This allows for the removal of a custom block entity type when it is registered in a parent version and is no longer needed. - * - * @param registryName The registry name of the block entity to remove. - */ - public void removeBlockEntity(final ResourceLocation registryName) - { - blockEntityTypes.put(registryName.toString(), null); - } - - /** - * Registers a new simple (catch-all-nbt) entity to the current schema and all its descendent versions. - * - * @param registryName The registry name of the entity. - */ - public void registerSimpleEntity(final ResourceLocation registryName) - { - registerEntity(registryName, DSL::remainder); - } - - /** - * Allows for the custom definition of a new entity type and registration of it to the current schema and all its descendent versions. - * The function is given the registry name of the entity type template to produce. - * - * @param registryName The registry name of the entity type. - * @param template The function to produce the entity type template. - */ - public void registerEntity(final ResourceLocation registryName, final Function template) - { - registerEntity(registryName, () -> template.apply(registryName.toString())); - } - - /** - * Allows for the custom definition of a new entity type and registration of it to the current schema and all its descendent versions. - * The supplier is invoked to produce the entity type template. - * - * @param registryName The registry name of the entity type. - * @param template The supplier of the type template. - */ - public void registerEntity(final ResourceLocation registryName, final Supplier template) - { - entityTypes.put(registryName.toString(), template); - } - - /** - * Removes an already registered entity from the current schema and all its descendent versions. - * This allows for the removal of a custom entity type when it is registered in a parent version and is no longer needed. - * - * @param registryName The registry name of the entity to remove. - */ - public void removeEntity(final ResourceLocation registryName) - { - entityTypes.put(registryName.toString(), null); - } - - /** - * An unmodifiable map of all registered additional modded block entity types. - * Keys may be mapped to a null value if they are supposed to be removed from the schema and its descendant versions, overriding the - * type specification added in a parent version. - * - * @return The already registered additional modded block entity types. - */ - public Map> getEntityTypes() - { - return entityTypesView; - } - - /** - * An unmodifiable map of all registered additional modded entity types. - * Keys may be mapped to a null value if they are supposed to be removed from the schema and its descendant versions, overriding the - * type specification added in a parent version. - * - * @return The already registered additional modded entity types. - */ - public Map> getBlockEntityTypes() - { - return blockEntityTypesView; - } -}