diff --git a/src/main/java/com/gregtechceu/gtceu/GTCEu.java b/src/main/java/com/gregtechceu/gtceu/GTCEu.java index e7b1de43d39..221f9d8c1d9 100644 --- a/src/main/java/com/gregtechceu/gtceu/GTCEu.java +++ b/src/main/java/com/gregtechceu/gtceu/GTCEu.java @@ -34,6 +34,22 @@ public class GTCEu { public static final Path GTCEU_FOLDER = getGameDir().resolve("gtceu"); + /** + * Only used for datafixers. Bump whenever a block changes id, save data layout changes, etc.
+ * Should be bumped up to the next multiple of 10 the first time it is bumped after a release, then by 1 for each + * subsequent change. + * + *

+ * Example versions: + *

+ */ + public static final int GT_DATA_VERSION = 10; + public GTCEu() { GTCEu.init(); GTCEuAPI.instance = this; @@ -96,7 +112,7 @@ public static boolean isDataGen() { /** * A friendly reminder that the server instance is populated on the server side only, so null/side check it! - * + * * @return the current minecraft server instance */ public static MinecraftServer getMinecraftServer() { @@ -113,7 +129,7 @@ public static boolean isModLoaded(String modId) { /** * For async stuff use this, otherwise use {@link GTCEu isClientSide} - * + * * @return if the current thread is the client thread */ public static boolean isClientThread() { @@ -123,7 +139,7 @@ public static boolean isClientThread() { /** * @return if the game is the PHYSICAL client, e.g. not a dedicated server. * @apiNote Do not use this to check if you're currently on the server thread for side-specific actions! - * It does NOT work for that. Use {@link #isClientThread()} instead. + * It does NOT work for that. Use {@link #isClientThread()} instead. * @see #isClientThread() */ public static boolean isClientSide() { @@ -132,9 +148,9 @@ public static boolean isClientSide() { /** * This check isn't the same for client and server! - * + * * @return if it's safe to access the current instance {@link net.minecraft.world.level.Level Level} on client or if - * it's safe to access any level on server. + * it's safe to access any level on server. */ public static boolean canGetServerLevel() { if (isClientSide()) { diff --git a/src/main/java/com/gregtechceu/gtceu/api/data/tag/TagPrefix.java b/src/main/java/com/gregtechceu/gtceu/api/data/tag/TagPrefix.java index c438c7e0167..0bfad34f0c0 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/data/tag/TagPrefix.java +++ b/src/main/java/com/gregtechceu/gtceu/api/data/tag/TagPrefix.java @@ -203,7 +203,7 @@ public boolean isEmpty() { .requiresCorrectToolForDrops().strength(4.5F, 9.0F), new ResourceLocation("block/end_stone"), true, false, true); - public static final TagPrefix rawOre = new TagPrefix("raw", true) + public static final TagPrefix rawOre = new TagPrefix("raw") .idPattern("raw_%s") .defaultTagPath("raw_materials/%s") .unformattedTagPath("raw_materials") @@ -983,8 +983,6 @@ public record BlockProperties(Supplier> renderType, @Getter @Setter private String idPattern; - @Getter - public final boolean invertedName; protected final List tags = new ArrayList<>(); @Setter @@ -1050,13 +1048,8 @@ public record BlockProperties(Supplier> renderType, protected final Set> miningToolTag = new HashSet<>(); public TagPrefix(String name) { - this(name, false); - } - - public TagPrefix(String name, boolean invertedName) { this.name = name; this.idPattern = "%s_" + getLowerCaseName(); - this.invertedName = invertedName; this.langValue = "%s " + FormattingUtil.toEnglishName(getLowerCaseName()); PREFIXES.put(name, this); } diff --git a/src/main/java/com/gregtechceu/gtceu/api/datafixer/DataFixHelper.java b/src/main/java/com/gregtechceu/gtceu/api/datafixer/DataFixHelper.java new file mode 100644 index 00000000000..bac8ad46a6b --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/api/datafixer/DataFixHelper.java @@ -0,0 +1,90 @@ +package com.gregtechceu.gtceu.api.datafixer; + +import com.gregtechceu.gtceu.GTCEu; +import com.gregtechceu.gtceu.common.data.datafixer.GTDataFixers; + +import com.mojang.datafixers.DSL; +import com.mojang.datafixers.DataFixUtils; +import com.mojang.datafixers.schemas.Schema; +import com.mojang.serialization.Dynamic; + +import net.minecraft.SharedConstants; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.util.datafix.DataFixers; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.*; + +@ApiStatus.Internal +public abstract class DataFixHelper { + + public static final String GT_DATA_VERSION_TAG = "GTCEu_DataVersion"; + public static final Logger LOGGER = LogManager.getLogger("GTCEu/DFU"); + + // region updating + + public static Dynamic updateToCurrentVersion(DSL.TypeReference type, Dynamic dynamic) { + return update(type, dynamic, getGTDataVersion(dynamic), GTCEu.GT_DATA_VERSION); + } + + public static Dynamic update(DSL.TypeReference type, Dynamic dynamic, int version, int newVersion) { + if (GTDataFixers.getDataFixer() == null) { + return dynamic; + } + return GTDataFixers.getDataFixer().update(type, dynamic, version, newVersion); + } + + public static CompoundTag updateToCurrentVersion(DSL.TypeReference dataFixTypes, CompoundTag tag) { + return update(dataFixTypes, tag, getGTDataVersion(tag), GTCEu.GT_DATA_VERSION); + } + + public static CompoundTag update(DSL.TypeReference dataFixTypes, CompoundTag tag, int version, int newVersion) { + return (CompoundTag) update(dataFixTypes, new Dynamic<>(NbtOps.INSTANCE, tag), version, newVersion).getValue(); + } + + // endregion + + // region data version handling + + public static CompoundTag addGTDataVersion(CompoundTag tag) { + if (GTDataFixers.getDataFixer() != null) { + tag.putInt(GT_DATA_VERSION_TAG, GTCEu.GT_DATA_VERSION); + } + + return tag; + } + + @Contract(pure = true) + @Range(from = 0, to = Integer.MAX_VALUE) + public static int getGTDataVersion(Dynamic dynamic) { + return getGTDataVersion(dynamic, -1); + } + + @Contract(pure = true) + @Range(from = 0, to = Integer.MAX_VALUE) + public static int getGTDataVersion(Dynamic dynamic, int defaultValue) { + return dynamic.get(GT_DATA_VERSION_TAG).asInt(defaultValue); + } + + @Contract(pure = true) + @Range(from = 0, to = Integer.MAX_VALUE) + public static int getGTDataVersion(CompoundTag tag) { + return getGTDataVersion(tag, -1); + } + + @Contract(pure = true) + @Range(from = 0, to = Integer.MAX_VALUE) + public static int getGTDataVersion(CompoundTag tag, int defaultValue) { + return tag.contains(GT_DATA_VERSION_TAG, CompoundTag.TAG_ANY_NUMERIC) ? tag.getInt(GT_DATA_VERSION_TAG) : + defaultValue; + } + + // endregion + + public static Schema getLatestVanillaSchema() { + int vanillaDataVersion = SharedConstants.getCurrentVersion().getDataVersion().getVersion(); + return DataFixers.getDataFixer().getSchema(DataFixUtils.makeKey(vanillaDataVersion)); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/api/datafixer/EmptyDataFixer.java b/src/main/java/com/gregtechceu/gtceu/api/datafixer/EmptyDataFixer.java new file mode 100644 index 00000000000..ab3f38955ef --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/api/datafixer/EmptyDataFixer.java @@ -0,0 +1,88 @@ +package com.gregtechceu.gtceu.api.datafixer; + +import com.mojang.datafixers.DSL; +import com.mojang.datafixers.DataFixer; +import com.mojang.datafixers.schemas.Schema; +import com.mojang.datafixers.types.Type; +import com.mojang.datafixers.types.templates.TypeTemplate; +import com.mojang.serialization.Dynamic; +import it.unimi.dsi.fastutil.objects.Object2ObjectMaps; +import org.jetbrains.annotations.Range; + +import java.util.Map; +import java.util.function.Supplier; + +class EmptyDataFixer implements DataFixer { + + static final EmptyDataFixer INSTANCE = new EmptyDataFixer(); + + private final Schema schema = new EmptySchema(0); + + private EmptyDataFixer() {} + + @Override + public Dynamic update(DSL.TypeReference type, Dynamic input, int version, int newVersion) { + return input; + } + + @Override + public Schema getSchema(int key) { + return this.schema; + } + + /* + * Copyright 2022 QuiltMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + /** + * Represents an empty {@link Schema}, having no parent and containing no type definitions. + */ + static final class EmptySchema extends Schema { + + /** + * Constructs an empty schema. + * + * @param versionKey the data version key + */ + EmptySchema(@Range(from = 0, to = Integer.MAX_VALUE) int versionKey) { + super(versionKey, null); + } + + // all of these methods refer to this.parent without checking if its null + @Override + public void registerTypes(Schema schema, Map> entityTypes, + Map> blockEntityTypes) {} + + @Override + public Map> registerEntities(Schema schema) { + return Map.of(); + } + + @Override + public Map> registerBlockEntities(Schema schema) { + return Map.of(); + } + + // Ensure the schema stays empty. + @Override + public void registerType(boolean recursive, DSL.TypeReference type, Supplier template) { + throw new UnsupportedOperationException(); + } + + @Override + protected Map> buildTypes() { + return Object2ObjectMaps.emptyMap(); + } + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/api/datafixer/LazyDataFixer.java b/src/main/java/com/gregtechceu/gtceu/api/datafixer/LazyDataFixer.java new file mode 100644 index 00000000000..0d36eb500a8 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/api/datafixer/LazyDataFixer.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2023 embeddedt + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.gregtechceu.gtceu.api.datafixer; + +import com.gregtechceu.gtceu.GTCEu; + +import com.mojang.datafixers.DSL; +import com.mojang.datafixers.DataFixer; +import com.mojang.datafixers.schemas.Schema; +import com.mojang.serialization.Dynamic; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Supplier; + +/** + * Original from + * ModernFix + */ +public class LazyDataFixer implements DataFixer { + private @Nullable DataFixer backingDataFixer; + private final Supplier<@Nullable DataFixer> dfuSupplier; + + public LazyDataFixer(Supplier<@Nullable DataFixer> dfuSupplier) { + this.backingDataFixer = null; + this.dfuSupplier = dfuSupplier; + } + + private DataFixer getDataFixer() { + synchronized(this) { + if (this.backingDataFixer == null) { + GTCEu.LOGGER.info("Instantiating GTCEu Data Fixers"); + this.backingDataFixer = this.dfuSupplier.get(); + } + if (this.backingDataFixer == null) { + this.backingDataFixer = EmptyDataFixer.INSTANCE; + } + } + + return this.backingDataFixer; + } + + public Dynamic update(DSL.TypeReference type, Dynamic input, int version, int newVersion) { + return version >= newVersion ? input : this.getDataFixer().update(type, input, version, newVersion); + } + + public Schema getSchema(int key) { + return this.getDataFixer().getSchema(key); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/api/datafixer/fixes/ToolBehaviorFix.java b/src/main/java/com/gregtechceu/gtceu/api/datafixer/fixes/ToolBehaviorFix.java new file mode 100644 index 00000000000..c90a13f48e2 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/api/datafixer/fixes/ToolBehaviorFix.java @@ -0,0 +1,30 @@ +package com.gregtechceu.gtceu.api.datafixer.fixes; + +import com.mojang.datafixers.schemas.Schema; +import com.mojang.serialization.Dynamic; +import net.minecraft.util.datafix.fixes.ItemStackTagFix; + +public abstract class ToolBehaviorFix extends ItemStackTagFix { + + private final String behaviorId; + private final String newBehaviorId; + + public ToolBehaviorFix(Schema outputSchema, String name, String behaviorId) { + this(outputSchema, name, behaviorId, behaviorId); + } + + public ToolBehaviorFix(Schema outputSchema, String name, String behaviorId, String newBehaviorId) { + super(outputSchema, name, itemId -> true); + this.behaviorId = behaviorId; + this.newBehaviorId = newBehaviorId; + } + + @Override + protected final Dynamic fixItemStackTag(Dynamic tag) { + Dynamic behavior = tag.remove(behaviorId); + behavior = fixBehavior(behavior); + return tag.set(newBehaviorId, behavior); + } + + protected abstract Dynamic fixBehavior(Dynamic tag); +} diff --git a/src/main/java/com/gregtechceu/gtceu/api/datafixer/fixes/package-info.java b/src/main/java/com/gregtechceu/gtceu/api/datafixer/fixes/package-info.java new file mode 100644 index 00000000000..cb13d6c5af8 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/api/datafixer/fixes/package-info.java @@ -0,0 +1,4 @@ +@NotNullByDefault +package com.gregtechceu.gtceu.api.datafixer.fixes; + +import org.jetbrains.annotations.NotNullByDefault; diff --git a/src/main/java/com/gregtechceu/gtceu/api/datafixer/package-info.java b/src/main/java/com/gregtechceu/gtceu/api/datafixer/package-info.java new file mode 100644 index 00000000000..66651429d10 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/api/datafixer/package-info.java @@ -0,0 +1,4 @@ +@NotNullByDefault +package com.gregtechceu.gtceu.api.datafixer; + +import org.jetbrains.annotations.NotNullByDefault; diff --git a/src/main/java/com/gregtechceu/gtceu/api/datafixer/types/ExtraDSL.java b/src/main/java/com/gregtechceu/gtceu/api/datafixer/types/ExtraDSL.java new file mode 100644 index 00000000000..bee671c6777 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/api/datafixer/types/ExtraDSL.java @@ -0,0 +1,453 @@ +package com.gregtechceu.gtceu.api.datafixer.types; + +import com.mojang.datafixers.types.Type; +import com.mojang.datafixers.types.templates.TypeTemplate; +import com.mojang.datafixers.util.Either; +import com.mojang.datafixers.util.Pair; +import com.mojang.datafixers.util.Unit; +import com.mojang.serialization.Dynamic; + +import static com.mojang.datafixers.DSL.*; + +// spotless:off +public interface ExtraDSL { + + static TypeTemplate fields( + final String name1, final TypeTemplate element1, + final String name2, final TypeTemplate element2, + final String name3, final TypeTemplate element3, + final String name4, final TypeTemplate element4, + final String name5, final TypeTemplate element5, + final String name6, final TypeTemplate element6 + ) { + return and( + field(name1, element1), + field(name2, element2), + field(name3, element3), + field(name4, element4), + field(name5, element5), + field(name6, element6) + ); + } + + static Type>> fields(final String name, final Type element) { + return and( + field(name, element), + remainderType() + ); + } + + static Type>>> fields( + final String name1, final Type element1, + final String name2, final Type element2 + ) { + return and( + field(name1, element1), + field(name2, element2), + remainderType() + ); + } + + static Type>>>> fields( + final String name1, final Type element1, + final String name2, final Type element2, + final String name3, final Type element3 + ) { + return and( + field(name1, element1), + field(name2, element2), + field(name3, element3), + remainderType() + ); + } + + static Type>>>>> fields( + final String name1, final Type element1, + final String name2, final Type element2, + final String name3, final Type element3, + final String name4, final Type element4 + ) { + return and( + field(name1, element1), + field(name2, element2), + field(name3, element3), + fields( + name4, element4 + ) + ); + } + + static Type>>>>>> fields( + final String name1, final Type element1, + final String name2, final Type element2, + final String name3, final Type element3, + final String name4, final Type element4, + final String name5, final Type element5 + ) { + return and( + field(name1, element1), + field(name2, element2), + field(name3, element3), + fields( + name4, element4, + name5, element5 + ) + ); + } + + static Type>>>>>>> fields( + final String name1, final Type element1, + final String name2, final Type element2, + final String name3, final Type element3, + final String name4, final Type element4, + final String name5, final Type element5, + final String name6, final Type element6 + ) { + return and( + field(name1, element1), + field(name2, element2), + field(name3, element3), + fields( + name4, element4, + name5, element5, + name6, element6 + ) + ); + } + + static Type> fields( + final String name, final Type element, + final Type rest + ) { + return and( + field(name, element), + rest + ); + } + + static Type>> fields( + final String name1, final Type element1, + final String name2, final Type element2, + final Type rest + ) { + return and( + field(name1, element1), + field(name2, element2), + rest + ); + } + + static Type>>> fields( + final String name1, final Type element1, + final String name2, final Type element2, + final String name3, final Type element3, + final Type rest + ) { + return and( + field(name1, element1), + field(name2, element2), + field(name3, element3), + rest + ); + } + + static Type>>>> fields( + final String name1, final Type element1, + final String name2, final Type element2, + final String name3, final Type element3, + final String name4, final Type element4, + final Type rest + ) { + return fields( + name1, element1, + name2, element2, + name3, element3, + fields( + name4, element4, + rest + ) + ); + } + + static Type>>>>> fields( + final String name1, final Type element1, + final String name2, final Type element2, + final String name3, final Type element3, + final String name4, final Type element4, + final String name5, final Type element5, + final Type rest + ) { + return fields( + name1, element1, + name2, element2, + name3, element3, + fields( + name4, element4, + name5, element5, + rest + ) + ); + } + + static Type>>>>>> fields( + final String name1, final Type element1, + final String name2, final Type element2, + final String name3, final Type element3, + final String name4, final Type element4, + final String name5, final Type element5, + final String name6, final Type element6, + final Type rest + ) { + return fields( + name1, element1, + name2, element2, + name3, element3, + fields( + name4, element4, + name5, element5, + name6, element6, + rest + ) + ); + } + + static TypeTemplate optionalFields( + final String name1, final TypeTemplate element1, + final String name2, final TypeTemplate element2, + final String name3, final TypeTemplate element3, + final String name4, final TypeTemplate element4, + final String name5, final TypeTemplate element5, + final String name6, final TypeTemplate element6 + ) { + return allWithRemainder( + optional(field(name1, element1)), + optional(field(name2, element2)), + optional(field(name3, element3)), + optional(field(name4, element4)), + optional(field(name5, element5)), + optional(field(name6, element6)) + ); + } + + static TypeTemplate optionalFields( + final String name1, final TypeTemplate element1, + final String name2, final TypeTemplate element2, + final String name3, final TypeTemplate element3, + final String name4, final TypeTemplate element4, + final String name5, final TypeTemplate element5, + final String name6, final TypeTemplate element6, + final String name7, final TypeTemplate element7 + ) { + return allWithRemainder( + optional(field(name1, element1)), + optional(field(name2, element2)), + optional(field(name3, element3)), + optional(field(name4, element4)), + optional(field(name5, element5)), + optional(field(name6, element6)), + optional(field(name7, element7)) + ); + } + + static TypeTemplate optionalFields( + final String name1, final TypeTemplate element1, + final String name2, final TypeTemplate element2, + final String name3, final TypeTemplate element3, + final String name4, final TypeTemplate element4, + final String name5, final TypeTemplate element5, + final String name6, final TypeTemplate element6, + final TypeTemplate rest + ) { + return and( + optional(field(name1, element1)), + optional(field(name2, element2)), + optional(field(name3, element3)), + optional(field(name4, element4)), + optional(field(name5, element5)), + optional(field(name6, element6)), + rest + ); + } + + static Type, Dynamic>> optionalFields(final String name, final Type element) { + return and( + optional(field(name, element)), + remainderType() + ); + } + + static Type, Pair, Dynamic>>> optionalFields( + final String name1, final Type element1, + final String name2, final Type element2 + ) { + return and( + optional(field(name1, element1)), + optional(field(name2, element2)), + remainderType() + ); + } + + static Type, Pair, Pair, Dynamic>>>> optionalFields( + final String name1, final Type element1, + final String name2, final Type element2, + final String name3, final Type element3 + ) { + return and( + optional(field(name1, element1)), + optional(field(name2, element2)), + optional(field(name3, element3)), + remainderType() + ); + } + + static Type, Pair, Pair, Pair, Dynamic>>>>> optionalFields( + final String name1, final Type element1, + final String name2, final Type element2, + final String name3, final Type element3, + final String name4, final Type element4 + ) { + return and( + optional(field(name1, element1)), + optional(field(name2, element2)), + optional(field(name3, element3)), + optionalFields( + name4, element4 + ) + ); + } + + static Type, Pair, Pair, Pair, Pair, Dynamic>>>>>> optionalFields( + final String name1, final Type element1, + final String name2, final Type element2, + final String name3, final Type element3, + final String name4, final Type element4, + final String name5, final Type element5 + ) { + return and( + optional(field(name1, element1)), + optional(field(name2, element2)), + optional(field(name3, element3)), + optionalFields( + name4, element4, + name5, element5 + ) + ); + } + + static Type, Pair, Pair, Pair, Pair, Pair, Dynamic>>>>>>> optionalFields( + final String name1, final Type element1, + final String name2, final Type element2, + final String name3, final Type element3, + final String name4, final Type element4, + final String name5, final Type element5, + final String name6, final Type element6 + ) { + return and( + optional(field(name1, element1)), + optional(field(name2, element2)), + optional(field(name3, element3)), + optionalFields( + name4, element4, + name5, element5, + name6, element6 + ) + ); + } + + static Type, G>> optionalFields( + final String name, final Type element, + final Type rest + ) { + return and( + optional(field(name, element)), + rest + ); + } + + static Type, Pair, H>>> optionalFields( + final String name1, final Type element1, + final String name2, final Type element2, + final Type rest + ) { + return and( + optional(field(name1, element1)), + optional(field(name2, element2)), + rest + ); + } + + static Type, Pair, Pair, I>>>> optionalFields( + final String name1, final Type element1, + final String name2, final Type element2, + final String name3, final Type element3, + final Type rest + ) { + return and( + optional(field(name1, element1)), + optional(field(name2, element2)), + optional(field(name3, element3)), + rest + ); + } + + static Type, Pair, Pair, Pair, J>>>>> optionalFields( + final String name1, final Type element1, + final String name2, final Type element2, + final String name3, final Type element3, + final String name4, final Type element4, + final Type rest + ) { + return optionalFields( + name1, element1, + name2, element2, + name3, element3, + optionalFields( + name4, element4, + rest + ) + ); + } + + static Type, Pair, Pair, Pair, Pair, K>>>>>> optionalFields( + final String name1, final Type element1, + final String name2, final Type element2, + final String name3, final Type element3, + final String name4, final Type element4, + final String name5, final Type element5, + final Type rest + ) { + return optionalFields( + name1, element1, + name2, element2, + name3, element3, + optionalFields( + name4, element4, + name5, element5, + rest + ) + ); + } + + static Type, Pair, Pair, Pair, Pair, Pair, L>>>>>>> optionalFields( + final String name1, final Type element1, + final String name2, final Type element2, + final String name3, final Type element3, + final String name4, final Type element4, + final String name5, final Type element5, + final String name6, final Type element6, + final Type rest + ) { + return optionalFields( + name1, element1, + name2, element2, + name3, element3, + optionalFields( + name4, element4, + name5, element5, + name6, element6, + rest + ) + ); + } +} +// spotless:on diff --git a/src/main/java/com/gregtechceu/gtceu/api/machine/MetaMachine.java b/src/main/java/com/gregtechceu/gtceu/api/machine/MetaMachine.java index b7c9731b56f..cf5924bcd45 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/machine/MetaMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/api/machine/MetaMachine.java @@ -155,12 +155,6 @@ public MetaMachine(BlockEntityCreationInfo info) { // ***** Machine Lifecycle ******// ////////////////////////////////////// - @Override - public void load(CompoundTag tag) { - TagCompatibilityFixer.fixMachineAutoOutputTag(tag); - super.load(tag); - } - /** * Called when this machine is loaded.
* On the server side, the entire world may not be loaded when this method is called.
diff --git a/src/main/java/com/gregtechceu/gtceu/common/CommonEventListener.java b/src/main/java/com/gregtechceu/gtceu/common/CommonEventListener.java index 354ff71ba48..e438c72aa06 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/CommonEventListener.java +++ b/src/main/java/com/gregtechceu/gtceu/common/CommonEventListener.java @@ -19,12 +19,10 @@ import com.gregtechceu.gtceu.api.data.chemical.material.stack.MaterialStack; import com.gregtechceu.gtceu.api.data.medicalcondition.MedicalCondition; import com.gregtechceu.gtceu.api.data.medicalcondition.Symptom; -import com.gregtechceu.gtceu.api.data.tag.TagPrefix; import com.gregtechceu.gtceu.api.fluids.FluidBuilder; import com.gregtechceu.gtceu.api.fluids.FluidState; import com.gregtechceu.gtceu.api.fluids.store.FluidStorageKeys; import com.gregtechceu.gtceu.api.item.armor.ArmorComponentItem; -import com.gregtechceu.gtceu.api.item.tool.GTToolType; import com.gregtechceu.gtceu.api.machine.MetaMachine; import com.gregtechceu.gtceu.api.misc.virtualregistry.VirtualEnderRegistry; import com.gregtechceu.gtceu.api.pattern.MultiblockWorldSavedData; @@ -38,7 +36,6 @@ import com.gregtechceu.gtceu.common.commands.MedicalConditionCommands; import com.gregtechceu.gtceu.common.cosmetics.GTCapes; import com.gregtechceu.gtceu.common.data.*; -import com.gregtechceu.gtceu.common.data.machines.GTAEMachines; import com.gregtechceu.gtceu.common.fluid.potion.BottleItemFluidHandler; import com.gregtechceu.gtceu.common.fluid.potion.PotionItemFluidHandler; import com.gregtechceu.gtceu.common.item.armor.IJetpack; @@ -64,9 +61,7 @@ import com.gregtechceu.gtceu.integration.map.cache.server.ServerCache; import com.gregtechceu.gtceu.utils.TaskHandler; -import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; -import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.Difficulty; @@ -78,13 +73,11 @@ import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.monster.Zombie; import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.item.PotionItem; import net.minecraft.world.item.enchantment.EnchantmentHelper; import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraftforge.common.ForgeMod; import net.minecraftforge.common.capabilities.ForgeCapabilities; @@ -104,17 +97,10 @@ import net.minecraftforge.fml.LogicalSide; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.items.IItemHandler; -import net.minecraftforge.registries.MissingMappingsEvent; -import com.tterrag.registrate.util.entry.BlockEntry; -import com.tterrag.registrate.util.entry.ItemEntry; import org.jetbrains.annotations.NotNull; import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import static com.gregtechceu.gtceu.utils.FormattingUtil.toLowerCaseUnderscore; @Mod.EventBusSubscriber(modid = GTCEu.MOD_ID, bus = Mod.EventBusSubscriber.Bus.FORGE) public class CommonEventListener { @@ -583,164 +569,4 @@ public static void addAlloyBlastProperty(@NotNull Material material) { private static boolean isMaterialStackFluidOnly(@NotNull MaterialStack ms) { return !ms.material().hasProperty(PropertyKey.DUST) && ms.material().hasProperty(PropertyKey.FLUID); } - - @SubscribeEvent - public static void remapIds(MissingMappingsEvent event) { - event.getMappings(Registries.BLOCK, GTCEu.MOD_ID).forEach(mapping -> { - if (mapping.getKey().equals(GTCEu.id("tungstensteel_coil_block"))) { - mapping.remap(GTBlocks.COIL_RTMALLOY.get()); - } - if (mapping.getKey().equals(GTCEu.id("steam_miner"))) { - mapping.remap(GTMachines.STEAM_MINER.first().getBlock()); - } - }); - event.getMappings(Registries.ITEM, GTCEu.MOD_ID).forEach(mapping -> { - if (mapping.getKey().equals(GTCEu.id("tungstensteel_coil_block"))) { - mapping.remap(GTBlocks.COIL_RTMALLOY.get().asItem()); - } - if (mapping.getKey().equals(GTCEu.id("steam_miner"))) { - mapping.remap(GTMachines.STEAM_MINER.first().getItem()); - } - if (mapping.getKey().equals(GTCEu.id("tungstensteel_fluid_cell"))) { - mapping.remap(GTItems.FLUID_CELL_LARGE_TUNGSTEN_STEEL.get().asItem()); - } - if (mapping.getKey().equals(GTCEu.id("avanced_nanomuscle_chestplate"))) { - mapping.remap(GTItems.NANO_CHESTPLATE_ADVANCED.get()); - } - String path = mapping.getKey().getPath(); - if (path.matches("[lhi]v_.+_wirecutter")) { - String suffix = "_wirecutter"; - String typeString = path.substring(0, 2) + suffix; // [lhi]v_wirecutter -- tooltype name - String matString = path.substring(3, path.length() - suffix.length()); // material name - - GTToolType type = GTToolType.getTypes().get(typeString); - Material material = GTMaterials.get(matString); - if (type == null || material.isNull()) { - mapping.warn(); - return; - } - var tool = GTMaterialItems.TOOL_ITEMS.get(material, type); - if (tool == null) { - mapping.warn(); - return; - } - mapping.remap(tool.asItem()); - } - }); - event.getMappings(Registries.BLOCK_ENTITY_TYPE, GTCEu.MOD_ID).forEach(mapping -> { - if (mapping.getKey().equals(GTCEu.id("steam_miner"))) { - mapping.remap(GTMachines.STEAM_MINER.first().getBlockEntityType()); - } - }); - - event.getMappings(Registries.BLOCK, "gregiceng").forEach(mapping -> { - String path = mapping.getKey().getPath(); - switch (path) { - case "stocking_bus", "adv_stocking_bus" -> mapping - .remap(GTAEMachines.STOCKING_IMPORT_BUS_ME.getBlock()); - case "stocking_hatch", "adv_stocking_hatch" -> mapping - .remap(GTAEMachines.STOCKING_IMPORT_HATCH_ME.getBlock()); - case "crafting_io_buffer" -> mapping.remap(GTAEMachines.ME_PATTERN_BUFFER.getBlock()); - case "crafting_io_slave" -> mapping.remap(GTAEMachines.ME_PATTERN_BUFFER_PROXY.getBlock()); - } - if (path.contains("input_buffer")) { - ResourceLocation newName = GTCEu.id(path.replace("input_buffer", "dual_input_hatch")); - if (mapping.getRegistry().containsKey(newName)) { - mapping.remap(mapping.getRegistry().getValue(newName)); - } else { - mapping.remap(GTMachines.DUAL_IMPORT_HATCH[GTValues.LuV].getBlock()); - } - } else if (path.contains("output_buffer")) { - ResourceLocation newName = GTCEu.id(path.replace("output_buffer", "dual_output_hatch")); - if (mapping.getRegistry().containsKey(newName)) { - mapping.remap(mapping.getRegistry().getValue(newName)); - } else { - mapping.remap(GTMachines.DUAL_EXPORT_HATCH[GTValues.LuV].getBlock()); - } - } - }); - event.getMappings(Registries.BLOCK_ENTITY_TYPE, "gregiceng").forEach(mapping -> { - String path = mapping.getKey().getPath(); - switch (path) { - case "stocking_bus", "adv_stocking_bus" -> mapping - .remap(GTAEMachines.STOCKING_IMPORT_BUS_ME.getBlockEntityType()); - case "stocking_hatch", "adv_stocking_hatch" -> mapping - .remap(GTAEMachines.STOCKING_IMPORT_HATCH_ME.getBlockEntityType()); - case "crafting_io_buffer" -> mapping.remap(GTAEMachines.ME_PATTERN_BUFFER.getBlockEntityType()); - case "crafting_io_slave" -> mapping.remap(GTAEMachines.ME_PATTERN_BUFFER_PROXY.getBlockEntityType()); - } - if (path.contains("input_buffer")) { - ResourceLocation newName = GTCEu.id(path.replace("input_buffer", "dual_input_hatch")); - if (mapping.getRegistry().containsKey(newName)) { - mapping.remap(mapping.getRegistry().getValue(newName)); - } else { - mapping.remap(GTMachines.DUAL_IMPORT_HATCH[GTValues.LuV].getBlockEntityType()); - } - } else if (path.contains("output_buffer")) { - ResourceLocation newName = GTCEu.id(path.replace("output_buffer", "dual_output_hatch")); - if (mapping.getRegistry().containsKey(newName)) { - mapping.remap(mapping.getRegistry().getValue(newName)); - } else { - mapping.remap(GTMachines.DUAL_EXPORT_HATCH[GTValues.LuV].getBlockEntityType()); - } - } - }); - event.getMappings(Registries.ITEM, "gregiceng").forEach(mapping -> { - String path = mapping.getKey().getPath(); - switch (path) { - case "stocking_bus", "adv_stocking_bus" -> mapping.remap(GTAEMachines.STOCKING_IMPORT_BUS_ME.getItem()); - case "stocking_hatch", "adv_stocking_hatch" -> mapping - .remap(GTAEMachines.STOCKING_IMPORT_HATCH_ME.getItem()); - case "crafting_io_buffer" -> mapping.remap(GTAEMachines.ME_PATTERN_BUFFER.getItem()); - case "crafting_io_slave" -> mapping.remap(GTAEMachines.ME_PATTERN_BUFFER_PROXY.getItem()); - } - if (path.contains("input_buffer")) { - ResourceLocation newName = GTCEu.id(path.replace("input_buffer", "dual_input_hatch")); - if (mapping.getRegistry().containsKey(newName)) { - mapping.remap(mapping.getRegistry().getValue(newName)); - } else { - mapping.remap(GTMachines.DUAL_IMPORT_HATCH[GTValues.LuV].getItem()); - } - } else if (path.contains("output_buffer")) { - ResourceLocation newName = GTCEu.id(path.replace("output_buffer", "dual_output_hatch")); - if (mapping.getRegistry().containsKey(newName)) { - mapping.remap(mapping.getRegistry().getValue(newName)); - } else { - mapping.remap(GTMachines.DUAL_EXPORT_HATCH[GTValues.LuV].getItem()); - } - } - }); - - for (TagPrefix prefix : TagPrefix.values()) { - String first = prefix.invertedName ? toLowerCaseUnderscore(prefix.name) : "(.+?)"; - String last = prefix.invertedName ? "(.+?)" : toLowerCaseUnderscore(prefix.name); - Pattern idPattern = Pattern.compile(first + "_" + last); - event.getMappings(Registries.BLOCK, GTCEu.MOD_ID).forEach(mapping -> { - Matcher matcher = idPattern.matcher(mapping.getKey().getPath()); - if (matcher.matches()) { - BlockEntry block = GTMaterialBlocks.MATERIAL_BLOCKS.get(prefix, - GTRegistries.MATERIALS.get(GTCEu.id(matcher.group(1)))); - if (block != null && block.isPresent()) { - mapping.remap(block.get()); - } - } - }); - event.getMappings(Registries.ITEM, GTCEu.MOD_ID).forEach(mapping -> { - Matcher matcher = idPattern.matcher(mapping.getKey().getPath()); - if (matcher.matches()) { - BlockEntry block = GTMaterialBlocks.MATERIAL_BLOCKS.get(prefix, - GTRegistries.MATERIALS.get(GTCEu.id(matcher.group(1)))); - if (block != null && block.isPresent()) { - mapping.remap(block.asItem()); - } else { - ItemEntry item = GTMaterialItems.MATERIAL_ITEMS.get(prefix, - GTRegistries.MATERIALS.get(GTCEu.id(matcher.group(1)))); - if (item != null && item.isPresent()) { - mapping.remap(item.asItem()); - } - } - } - }); - } - } } diff --git a/src/main/java/com/gregtechceu/gtceu/common/CommonProxy.java b/src/main/java/com/gregtechceu/gtceu/common/CommonProxy.java index 3f05df69dae..371ef70d1ce 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/CommonProxy.java +++ b/src/main/java/com/gregtechceu/gtceu/common/CommonProxy.java @@ -27,6 +27,7 @@ import com.gregtechceu.gtceu.api.registry.registrate.GTRegistrate; import com.gregtechceu.gtceu.common.data.*; import com.gregtechceu.gtceu.common.data.GTPlaceholders; +import com.gregtechceu.gtceu.common.data.datafixer.GTDataFixers; import com.gregtechceu.gtceu.common.data.machines.GTMachineUtils; import com.gregtechceu.gtceu.common.data.materials.GTFoods; import com.gregtechceu.gtceu.common.item.tool.rotation.CustomBlockRotations; @@ -183,6 +184,8 @@ public static void init() { SyncedKeyMappings.init(); MachineOwner.init(); + GTDataFixers.init(); + FusionReactorMachine.registerFusionTier(GTValues.LuV, " (MKI)"); FusionReactorMachine.registerFusionTier(GTValues.ZPM, " (MKII)"); FusionReactorMachine.registerFusionTier(GTValues.UV, " (MKIII)"); diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/datafixer/GTDataFixers.java b/src/main/java/com/gregtechceu/gtceu/common/data/datafixer/GTDataFixers.java new file mode 100644 index 00000000000..485c87f4553 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/common/data/datafixer/GTDataFixers.java @@ -0,0 +1,150 @@ +package com.gregtechceu.gtceu.common.data.datafixer; + +import com.gregtechceu.gtceu.GTCEu; +import com.gregtechceu.gtceu.api.datafixer.DataFixHelper; +import com.gregtechceu.gtceu.api.datafixer.LazyDataFixer; +import com.gregtechceu.gtceu.common.datafixer.fixes.AutoOutputTraitFix; +import com.gregtechceu.gtceu.common.datafixer.schemas.*; +import com.gregtechceu.gtceu.config.ConfigHolder; + +import net.minecraft.SharedConstants; +import net.minecraft.util.datafix.fixes.*; +import net.minecraft.util.datafix.schemas.NamespacedSchema; + +import com.google.common.util.concurrent.ThreadFactoryBuilder; +import com.mojang.datafixers.DSL; +import com.mojang.datafixers.DataFixUtils; +import com.mojang.datafixers.DataFixer; +import com.mojang.datafixers.DataFixerBuilder; +import com.mojang.datafixers.schemas.Schema; +import lombok.Getter; +import org.jetbrains.annotations.Nullable; + +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.function.BiFunction; +import java.util.function.UnaryOperator; +import java.util.regex.Pattern; + +/** + * Register new datafixers in {@link #addFixers(DataFixerBuilder)}. Remember to bump {@link GTCEu#GT_DATA_VERSION} in + * every PR that changes existing save data and add a schema & fixer for it here. + * + *

+ * For changes that do not change named types or add new (block) entities, use {@link #SAME_NAMESPACED} for the schema. + * Register machines (and other block entities) in a schema overriding {@link Schema#registerBlockEntities}. + * + *

+ *

DO NOT ADD NEW MACHINES TO {@link V0}!! THEY SHOULD BE IN NEW, CORRECTLY VERSIONED, SCHEMAS!!

+ * Reference vanilla schemas for more information on that, examples linked below. Also check how they're used in + * vanilla's {@link net.minecraft.util.datafix.DataFixers DataFixers}.
+ * {@link net.minecraft.util.datafix.schemas.V1460 V1460}, {@link net.minecraft.util.datafix.schemas.V1906 V1906} + * + *

+ * Note how only fields that use other registered types (such as item/fluid stacks) are defined. The same should be + * done for all types. + */ +@SuppressWarnings("SameParameterValue") +public class GTDataFixers { + + private static final BiFunction SAME_NAMESPACED = NamespacedSchema::new; + + @Getter + private static final @Nullable DataFixer dataFixer = createFixer(SharedConstants.DATA_FIX_TYPES_TO_OPTIMIZE); + + public static void init() {} + + private static @Nullable DataFixer createFixer(final Set typesToOptimize) { + if (!ConfigHolder.INSTANCE.compat.doDataFixers) { + return null; + } + + DataFixHelper.LOGGER.info("Registering data fixers"); + + + return new LazyDataFixer(() -> { + try { + DataFixerBuilder builder = new DataFixerBuilder(GTCEu.GT_DATA_VERSION); + addFixers(builder); + + if (typesToOptimize.isEmpty()) { + return builder.buildUnoptimized(); + } else { + Executor executor = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder() + .setNameFormat("GTCEu Datafixer Bootstrap").setDaemon(true).setPriority(1).build()); + return builder.buildOptimized(typesToOptimize, executor); + } + } catch (Exception ex) { + DataFixHelper.LOGGER.warn("Failed to initialize! Either someone stopped DFU from initializing, or this Minecraft build is hosed."); + DataFixHelper.LOGGER.warn("Using no-op implementation."); + DataFixHelper.LOGGER.warn("Full error: ", ex); + + return null; + } + }); + } + + public static void addFixers(DataFixerBuilder builder) { + builder.addSchema(new V0(DataFixUtils.makeKey(0), DataFixHelper.getLatestVanillaSchema())); + + Schema v1 = builder.addSchema(1, V1::new); + createBlockItemRenameFix(builder, v1, "Rename RTM Alloy Coil Block", + createRenamer("tungstensteel_coil_block", "rtm_alloy_coil_block")); + + builder.addFixer(ItemRenameFix.create(v1, "Rename Advanced Nanomuscle Chestplate", + createRenamer("gtceu:avanced_nanomuscle_chestplate", "gtceu:advanced_nanomuscle_chestplate"))); + + createBlockItemRenameFix(builder, v1, "Rename Palladium Substation Casing", + createRenamer("gtceu:palladium_substation", "gtceu:palladium_substation_casing")); + + builder.addFixer(BlockRenameFix.create(v1, "Rename Tungstensteel Fluid Cell", + createRenamer("gtceu:tungstensteel_fluid_cell", "gtceu:tungsten_steel_fluid_cell"))); + + createBlockItemRenameFix(builder, v1, "Rename Low Pressure Steam Miner", + createRenamer("gtceu:steam_miner", "gtceu:lp_steam_miner")); + + builder.addFixer(ItemRenameFix.create(v1, "Rename electric wire cutters", + createRenamer(Pattern.compile("([lhi])v_([a-z0-9/._-]+)_wirecutter"), "$1v_$2_wire_cutter"))); + + // separator + + Schema v10 = builder.addSchema(10, SAME_NAMESPACED); + builder.addFixer(new AutoOutputTraitFix(v10)); + + /* + createBlockItemRenameFix(builder, schemaV11, "U238", + createRenamer(Pattern.compile("gtceu:(.*)uranium_"), "gtceu:$1uranium_238_")); + createBlockItemRenameFix(builder, schemaV11, "Pu239", + createRenamer(Pattern.compile("gtceu:(.*)plutonium_"), "gtceu:$1plutonium_239_")); + createBlockItemRenameFix(builder, schemaV11, "Red Granite", + createRenamer(Pattern.compile("gtceu:(.*)granite_red"), "gtceu:$1red_granite")); + createBlockItemRenameFix(builder, schemaV11, "Tungstensteel", + createRenamer(Pattern.compile("gtceu:(.*)tungstensteel"), "gtceu:$1tungsten_steel")); + + createBlockItemRenameFix(builder, schemaV11, "Raw Oil", + createRenamer(OilVariantsRenameFix.RENAMED_ITEM_IDS)); + */ + } + + private static void createBlockItemRenameFix(DataFixerBuilder builder, Schema schema, String name, + UnaryOperator renamer) { + builder.addFixer(ItemRenameFix.create(schema, name, renamer)); + builder.addFixer(BlockRenameFix.create(schema, name, renamer)); + builder.addFixer(BlockEntityRenameFix.create(schema, name, renamer)); + } + + private static UnaryOperator createRenamer(String oldName, String newName) { + return id -> Objects.equals(NamespacedSchema.ensureNamespaced(id), oldName) ? newName : id; + } + + private static UnaryOperator createRenamer(Map renameMap) { + return id -> renameMap.getOrDefault(NamespacedSchema.ensureNamespaced(id), id); + } + + private static UnaryOperator createRenamer(Pattern check, String replaceWith) { + return id -> check.matcher(NamespacedSchema.ensureNamespaced(id)).replaceAll(replaceWith); + } +} \ No newline at end of file diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/datafixer/GTReferences.java b/src/main/java/com/gregtechceu/gtceu/common/data/datafixer/GTReferences.java new file mode 100644 index 00000000000..16f34303073 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/common/data/datafixer/GTReferences.java @@ -0,0 +1,14 @@ +package com.gregtechceu.gtceu.common.data.datafixer; + +import com.mojang.datafixers.DSL; + +public class GTReferences { + + public static final DSL.TypeReference MATERIAL_STACK = () -> "material_stack"; + public static final DSL.TypeReference MATERIAL_NAME = () -> "material_name"; + + public static final DSL.TypeReference FLUID_STACK = () -> "fluid_stack"; + public static final DSL.TypeReference FLUID_NAME = () -> "fluid_name"; + + public static final DSL.TypeReference FORGE_REGISTRY_DATA = () -> "forge_registry_data"; +} \ No newline at end of file diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/datafixer/package-info.java b/src/main/java/com/gregtechceu/gtceu/common/data/datafixer/package-info.java new file mode 100644 index 00000000000..d3f47b5873d --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/common/data/datafixer/package-info.java @@ -0,0 +1,4 @@ +@NotNullByDefault +package com.gregtechceu.gtceu.common.data.datafixer; + +import org.jetbrains.annotations.NotNullByDefault; diff --git a/src/main/java/com/gregtechceu/gtceu/common/datafixer/fixes/AutoOutputTraitFix.java b/src/main/java/com/gregtechceu/gtceu/common/datafixer/fixes/AutoOutputTraitFix.java new file mode 100644 index 00000000000..b099b9e6747 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/common/datafixer/fixes/AutoOutputTraitFix.java @@ -0,0 +1,48 @@ +package com.gregtechceu.gtceu.common.datafixer.fixes; + +import net.minecraft.util.datafix.fixes.References; + +import com.mojang.datafixers.*; +import com.mojang.datafixers.schemas.Schema; +import com.mojang.serialization.Dynamic; + +import java.util.Map; + +public class AutoOutputTraitFix extends DataFix { + + private static final Map FIELD_RENAMES = Map.of( + "outputFacingItems", "itemOutputDirection", + "outputFacingFluids", "fluidOutputDirection", + "autoOutputItems", "autoOutputItems", + "autoOutputFluids", "autoOutputFluids", + "allowInputFromOutputSideItems", "allowItemInputFromOutputSide", + "allowInputFromOutputSideFluids", "allowFluidInputFromOutputSide" + ); + + public AutoOutputTraitFix(Schema outputSchema) { + super(outputSchema, false); + } + + @Override + protected TypeRewriteRule makeRule() { + return this.fixTypeEverywhereTyped("AutoOutputTraitFix", this.getInputSchema().getType(References.BLOCK_ENTITY), typed -> { + return typed.update(DSL.remainderFinder(), remainder -> { + Dynamic traitValue = remainder.emptyMap(); + for (var entry : FIELD_RENAMES.entrySet()) { + String oldName = entry.getKey(); + String newName = entry.getValue(); + + var oldField = remainder.get(oldName).result(); + if (oldField.isPresent()) { + traitValue = traitValue.set(newName, oldField.get()); + remainder = remainder.remove(oldName); + } + } + + remainder.set("autoOutput", traitValue); + + return remainder; + }); + }); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/common/datafixer/fixes/OilVariantsRenameFix.java b/src/main/java/com/gregtechceu/gtceu/common/datafixer/fixes/OilVariantsRenameFix.java new file mode 100644 index 00000000000..016fc5e7994 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/common/datafixer/fixes/OilVariantsRenameFix.java @@ -0,0 +1,17 @@ +package com.gregtechceu.gtceu.common.datafixer.fixes; + +import com.google.common.collect.ImmutableMap; + +import java.util.Map; + +public class OilVariantsRenameFix { + + public static final Map RENAMED_IDS = ImmutableMap.builder() + .put("gtceu:oil_heavy", "gtceu:heavy_oil") + .put("gtceu:oil_light", "gtceu:light_oil") + .put("gtceu:oil_medium", "gtceu:raw_oil") + .put("gtceu:oil_heavy_bucket", "gtceu:heavy_oil_bucket") + .put("gtceu:oil_light_bucket", "gtceu:light_oil_bucket") + .put("gtceu:oil_medium_bucket", "gtceu:raw_oil_bucket") + .build(); +} diff --git a/src/main/java/com/gregtechceu/gtceu/common/datafixer/fixes/package-info.java b/src/main/java/com/gregtechceu/gtceu/common/datafixer/fixes/package-info.java new file mode 100644 index 00000000000..beb1ec92e54 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/common/datafixer/fixes/package-info.java @@ -0,0 +1,4 @@ +@NotNullByDefault +package com.gregtechceu.gtceu.common.datafixer.fixes; + +import org.jetbrains.annotations.NotNullByDefault; diff --git a/src/main/java/com/gregtechceu/gtceu/common/datafixer/schemas/V0.java b/src/main/java/com/gregtechceu/gtceu/common/datafixer/schemas/V0.java new file mode 100644 index 00000000000..262551fc1da --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/common/datafixer/schemas/V0.java @@ -0,0 +1,501 @@ +package com.gregtechceu.gtceu.common.datafixer.schemas; + +import com.gregtechceu.gtceu.api.GTCEuAPI; +import com.gregtechceu.gtceu.api.GTValues; +import com.gregtechceu.gtceu.api.machine.MachineDefinition; +import com.gregtechceu.gtceu.api.registry.GTRegistries; +import com.gregtechceu.gtceu.common.data.datafixer.GTReferences; + +import com.mojang.datafixers.DSL; +import com.mojang.datafixers.schemas.Schema; +import com.mojang.datafixers.types.templates.TypeTemplate; + +import net.minecraft.util.datafix.fixes.References; +import net.minecraft.util.datafix.schemas.NamespacedSchema; +import net.minecraftforge.fml.loading.LoadingModList; + +import java.util.Locale; +import java.util.Map; +import java.util.function.Supplier; + +import static com.gregtechceu.gtceu.api.GTValues.*; +import static com.gregtechceu.gtceu.common.data.machines.GTMachineUtils.*; +import static com.gregtechceu.gtceu.common.data.machines.GTMachineUtils.ALL_TIERS; +import static com.gregtechceu.gtceu.api.datafixer.types.ExtraDSL.*; +import static com.mojang.datafixers.DSL.*; + +public class V0 extends NamespacedSchema { + + public V0(int versionKey, Schema parent) { + super(versionKey, parent); + } + + // spotless:off + @Override + public void registerTypes(Schema schema, Map> entityTypes, + Map> blockEntityTypes) { + super.registerTypes(schema, entityTypes, blockEntityTypes); + + // add forge registry id map to the level schema + schema.registerType(false, GTReferences.FORGE_REGISTRY_DATA, () -> optionalFields( + "minecraft:block", optionalFields( + "ids", compoundList(References.BLOCK_NAME.in(schema), constType(intType())), + "aliases", compoundList(DSL.constType(namespacedString()), References.BLOCK_NAME.in(schema)) + ), + "minecraft:item", optionalFields( + "ids", compoundList(References.ITEM_NAME.in(schema), constType(intType())), + "aliases", compoundList(DSL.constType(namespacedString()), References.ITEM_NAME.in(schema)) + ), + "minecraft:fluid", optionalFields( + "ids", compoundList(GTReferences.FLUID_NAME.in(schema), constType(intType())), + "aliases", compoundList(DSL.constType(namespacedString()), GTReferences.FLUID_NAME.in(schema)) + ), + "minecraft:entity_type", optionalFields( + "ids", compoundList(References.ENTITY_NAME.in(schema), constType(intType())), + "aliases", compoundList(DSL.constType(namespacedString()), References.ENTITY_NAME.in(schema)) + ) + )); + + + schema.registerType(false, GTReferences.MATERIAL_NAME, () -> constType(namespacedString())); + + schema.registerType(true, GTReferences.FLUID_STACK, () -> optionalFields( + "FluidName", GTReferences.FLUID_NAME.in(schema), + "Tag", remainder() + )); + schema.registerType(false, GTReferences.FLUID_NAME, () -> constType(namespacedString())); + } + + @Override + public Map> registerBlockEntities(Schema schema) { + Map> map = super.registerBlockEntities(schema); + + // region steam + final Supplier steamMachine = () -> optionalFields( + "steamTank", notifiableFluidTank(schema) + ); + final Supplier steamBoiler = () -> optionalFields( + "waterTank", notifiableFluidTank(schema), + steamMachine.get() + ); + registerSteamMachine(schema, map, "steam_solid_boiler", () -> optionalFields( + "fuelHandler", notifiableItemHandler(schema), + "ashHandler", notifiableItemHandler(schema), + steamBoiler.get() + )); + registerSteamMachine(schema, map, "steam_liquid_boiler", () -> optionalFields( + "fuelTank", notifiableFluidTank(schema), + steamBoiler.get() + )); + registerSteamMachine(schema, map, "steam_solar_boiler", steamBoiler); + registerSimpleSteamMachine(schema, map, "extractor"); + registerSimpleSteamMachine(schema, map, "steam_macerator"); + registerSimpleSteamMachine(schema, map, "compressor"); + registerSimpleSteamMachine(schema, map, "forge_hammer"); + registerSimpleSteamMachine(schema, map, "furnace"); + registerSimpleSteamMachine(schema, map, "alloy_smelter"); + registerSimpleSteamMachine(schema, map, "rock_crusher"); + schema.register(map, "steam_miner", () -> optionalFields( + "importItems", notifiableItemHandler(schema), + "exportItems", notifiableItemHandler(schema), + "steamTank", notifiableFluidTank(schema) + )); + // endregion + + // region simple + registerForTiers(schema, map, "machine_hull", DSL::remainder, ALL_TIERS); + registerSimpleMachine(schema, map, "electric_furnace", ELECTRIC_TIERS); + registerSimpleMachine(schema, map, "alloy_smelter", ELECTRIC_TIERS); + registerSimpleMachine(schema, map, "arc_furnace", ELECTRIC_TIERS); + registerSimpleMachine(schema, map, "assembler", ELECTRIC_TIERS); + registerSimpleMachine(schema, map, "autoclave", ELECTRIC_TIERS); + registerSimpleMachine(schema, map, "bender", ELECTRIC_TIERS); + registerSimpleMachine(schema, map, "brewery", ELECTRIC_TIERS); + registerSimpleMachine(schema, map, "canner", ELECTRIC_TIERS); + registerSimpleMachine(schema, map, "centrifuge", ELECTRIC_TIERS); + registerSimpleMachine(schema, map, "chemical_bath", ELECTRIC_TIERS); + registerSimpleMachine(schema, map, "chemical_reactor", ELECTRIC_TIERS); + registerSimpleMachine(schema, map, "compressor", ELECTRIC_TIERS); + registerSimpleMachine(schema, map, "cutter", ELECTRIC_TIERS); + registerSimpleMachine(schema, map, "distillery", ELECTRIC_TIERS); + registerSimpleMachine(schema, map, "electrolyzer", ELECTRIC_TIERS); + registerSimpleMachine(schema, map, "electromagnetic_separator", ELECTRIC_TIERS); + registerSimpleMachine(schema, map, "extractor", ELECTRIC_TIERS); + registerSimpleMachine(schema, map, "extruder", ELECTRIC_TIERS); + registerSimpleMachine(schema, map, "fermenter", ELECTRIC_TIERS); + registerSimpleMachine(schema, map, "fluid_heater", ELECTRIC_TIERS); + registerSimpleMachine(schema, map, "fluid_solidifier", ELECTRIC_TIERS); + registerSimpleMachine(schema, map, "forge_hammer", ELECTRIC_TIERS); + registerSimpleMachine(schema, map, "forming_press", ELECTRIC_TIERS); + registerSimpleMachine(schema, map, "lathe", ELECTRIC_TIERS); + registerSimpleMachine(schema, map, "scanner", ELECTRIC_TIERS); + registerSimpleMachine(schema, map, "mixer", ELECTRIC_TIERS); + registerSimpleMachine(schema, map, "ore_washer", ELECTRIC_TIERS); + registerSimpleMachine(schema, map, "packer", ELECTRIC_TIERS); + registerSimpleMachine(schema, map, "polarizer", ELECTRIC_TIERS); + registerSimpleMachine(schema, map, "laser_engraver", ELECTRIC_TIERS); + registerSimpleMachine(schema, map, "sifter", ELECTRIC_TIERS); + registerSimpleMachine(schema, map, "thermal_centrifuge", ELECTRIC_TIERS); + registerSimpleMachine(schema, map, "wiremill", ELECTRIC_TIERS); + registerSimpleMachine(schema, map, "circuit_assembler", ELECTRIC_TIERS); + registerSimpleMachine(schema, map, "macerator", ELECTRIC_TIERS); + registerSimpleMachine(schema, map, "gas_collector", ELECTRIC_TIERS); + registerSimpleMachine(schema, map, "rock_crusher", ELECTRIC_TIERS); + registerSimpleMachine(schema, map, "air_scrubber", LOW_TIERS); + registerSimpleMachine(schema, map, "combustion", ELECTRIC_TIERS); + registerSimpleMachine(schema, map, "steam_turbine", ELECTRIC_TIERS); + registerSimpleMachine(schema, map, "gas_turbine", ELECTRIC_TIERS); + // endregion + + // region electric + final int[] transformerTiers = GTValues.tiersBetween(ULV, GTCEuAPI.isHighTier() ? OpV : UV); + registerForTiers(schema, map, "transformer_1a", DSL::remainder, transformerTiers); + registerForTiers(schema, map, "transformer_2a", DSL::remainder, transformerTiers); + registerForTiers(schema, map, "transformer_4a", DSL::remainder, transformerTiers); + registerForTiers(schema, map, "transformer_16a", DSL::remainder, transformerTiers); + + registerForTiers(schema, map, "1a_energy_converter", DSL::remainder, ALL_TIERS); + registerForTiers(schema, map, "4a_energy_converter", DSL::remainder, ALL_TIERS); + registerForTiers(schema, map, "8a_energy_converter", DSL::remainder, ALL_TIERS); + registerForTiers(schema, map, "16a_energy_converter", DSL::remainder, ALL_TIERS); + + schema.registerSimple(map, "long_distance_item_pipeline_endpoint"); + schema.registerSimple(map, "long_distance_fluid_pipeline_endpoint"); + schema.registerSimple(map, "long_distance_fluid_pipeline_endpoint"); + + final Supplier batteryBuffer = () -> optionalFields( + "batteryInventory", itemHandler(schema) + ); + registerForTiers(schema, map, "battery_buffer_4x", batteryBuffer, ALL_TIERS); + registerForTiers(schema, map, "battery_buffer_8x", batteryBuffer, ALL_TIERS); + registerForTiers(schema, map, "battery_buffer_16x", batteryBuffer, ALL_TIERS); + registerForTiers(schema, map, "charger_4x", batteryBuffer, ALL_TIERS); + + registerForTiers(schema, map, "pump", () -> optionalFields( + "cache", notifiableFluidTank(schema) + ), LV, MV, HV, EV); + registerForTiers(schema, map, "fisher", () -> optionalFields( + "cache", notifiableItemHandler(schema), + "baitHandler", notifiableItemHandler(schema), + "chargerInventory", itemHandler(schema) + ), LV, MV, HV, EV, IV, LuV); + registerForTiers(schema, map, "block_breaker", () -> optionalFields( + "cache", notifiableItemHandler(schema), + "chargerInventory", itemHandler(schema) + ), LV, MV, HV, EV); + registerSimpleMachine(schema, map, "miner", LV, MV, HV); + registerForTiers(schema, map, "world_accelerator", DSL::remainder, LV, MV, HV, EV, IV, LuV, ZPM, UV); + registerForTiers(schema, map, "item_collector", () -> optionalFields( + "output", notifiableItemHandler(schema), + "chargerInventory", itemHandler(schema), + "filterInventory", itemHandler(schema) + ), LV, MV, HV, EV); + // endregion + + // region storage + final Supplier itemStorage = () -> optionalFields( + "inventory", notifiableItemHandler(schema) + ); + registerForTiers(schema, map, "buffer", () -> optionalFields( + "tank", notifiableFluidTank(schema), + itemStorage.get() + ), LV, MV, HV); + schema.registerSimple(map, "creative_energy"); + schema.registerSimple(map, "creative_computation_provider"); + + final Supplier quantumChest = () -> optionalFields( + "lockedFluid", GTReferences.FLUID_STACK.in(schema), + "stored", GTReferences.FLUID_STACK.in(schema) + ); + final Supplier quantumTank = () -> optionalFields( + "lockedItem", itemHandler(schema), + "stored", References.ITEM_STACK.in(schema) + ); + schema.register(map, "creative_chest", quantumChest); + schema.register(map, "creative_tank", quantumTank); + registerForTiers(schema, map, "super_chest", quantumChest, LOW_TIERS); + registerForTiers(schema, map, "quantum_chest", quantumChest, HIGH_TIERS); + registerForTiers(schema, map, "super_tank", quantumTank, LOW_TIERS); + registerForTiers(schema, map, "quantum_tank", quantumTank, HIGH_TIERS); + + schema.register(map, "wood_crate", itemStorage); + schema.register(map, "bronze_crate", itemStorage); + schema.register(map, "steel_crate", itemStorage); + schema.register(map, "aluminium_crate", itemStorage); + schema.register(map, "stainless_steel_crate", itemStorage); + schema.register(map, "titanium_crate", itemStorage); + schema.register(map, "tungsten_steel_crate", itemStorage); + + final Supplier drum = () -> optionalFields( + "stored", GTReferences.FLUID_STACK.in(schema) + ); + schema.register(map, "wood_drum", drum); + schema.register(map, "bronze_drum", drum); + schema.register(map, "steel_drum", drum); + schema.register(map, "aluminium_drum", drum); + schema.register(map, "stainless_steel_drum", drum); + schema.register(map, "gold_drum", drum); + schema.register(map, "titanium_drum", drum); + schema.register(map, "tungsten_steel_drum", drum); + // endregion + + // region part + final Supplier itemBus = () -> optionalFields( + "circuitInventory", notifiableItemHandler(schema), + itemStorage.get() + ); + registerForTiers(schema, map, "input_bus", itemBus, ALL_TIERS); + registerForTiers(schema, map, "output_bus", itemBus, ALL_TIERS); + final Supplier fluidHatch = () -> optionalFields( + "tank", notifiableFluidTank(schema), + "circuitInventory", notifiableItemHandler(schema) + ); + registerForTiers(schema, map, "input_hatch", fluidHatch, ALL_TIERS); + registerForTiers(schema, map, "input_hatch_4x", fluidHatch, ALL_TIERS); + registerForTiers(schema, map, "input_hatch_9x", fluidHatch, ALL_TIERS); + registerForTiers(schema, map, "output_hatch", fluidHatch, ALL_TIERS); + registerForTiers(schema, map, "output_hatch_4x", fluidHatch, ALL_TIERS); + registerForTiers(schema, map, "output_hatch_9x", fluidHatch, ALL_TIERS); + + registerForTiers(schema, map, "energy_input_hatch", DSL::remainder, ALL_TIERS); + registerForTiers(schema, map, "energy_output_hatch", DSL::remainder, ALL_TIERS); + registerForTiers(schema, map, "energy_input_hatch_4a", DSL::remainder, ALL_TIERS); + registerForTiers(schema, map, "energy_output_hatch_4a", DSL::remainder, ALL_TIERS); + registerForTiers(schema, map, "energy_input_hatch_16a", DSL::remainder, ALL_TIERS); + registerForTiers(schema, map, "energy_output_hatch_16a", DSL::remainder, ALL_TIERS); + registerForTiers(schema, map, "substation_input_hatch_64a", DSL::remainder, ALL_TIERS); + registerForTiers(schema, map, "substation_output_hatch_64a", DSL::remainder, ALL_TIERS); + + registerForTiers(schema, map, "muffler_hatch", itemStorage, ELECTRIC_TIERS); + + schema.register(map, "steam_input_bus", itemBus); + schema.register(map, "steam_output_bus", itemBus); + schema.register(map, "steam_input_hatch", fluidHatch); + schema.registerSimple(map, "coke_oven_hatch"); + schema.register(map, "pump_hatch", fluidHatch); + final Supplier maintenanceHatch = () -> optionalFields( + "itemStackHandler", notifiableItemHandler(schema) + ); + schema.register(map, "maintenance_hatch", maintenanceHatch); + schema.register(map, "configurable_maintenance_hatch", maintenanceHatch); + schema.register(map, "cleaning_maintenance_hatch", maintenanceHatch); + schema.register(map, "auto_maintenance_hatch", maintenanceHatch); + + registerForTiers(schema, map, "item_passthrough_hatch", itemBus, ELECTRIC_TIERS); + registerForTiers(schema, map, "fluid_passthrough_hatch", fluidHatch, ELECTRIC_TIERS); + schema.register(map, "reservoir_hatch", fluidHatch); + final Supplier dualHatch = () -> optionalFields( + "tank", notifiableFluidTank(schema), + itemBus.get() + ); + registerForTiers(schema, map, "dual_input_hatch", dualHatch, DUAL_HATCH_TIERS); + registerForTiers(schema, map, "dual_output_hatch", dualHatch, DUAL_HATCH_TIERS); + + registerForTiers(schema, map, "diode", DSL::remainder, ELECTRIC_TIERS); + registerForTiers(schema, map, "rotor_holder", () -> optionalFields( + "rotorMaterial", GTReferences.MATERIAL_NAME.in(schema), + itemStorage.get() + ), GTValues.tiersBetween(HV, GTCEuAPI.isHighTier() ? OpV : UV)); + + registerForTiers(schema, map, "256a_laser_target_hatch", DSL::remainder, HIGH_TIERS); + registerForTiers(schema, map, "256a_laser_source_hatch", DSL::remainder, HIGH_TIERS); + registerForTiers(schema, map, "1024a_laser_target_hatch", DSL::remainder, HIGH_TIERS); + registerForTiers(schema, map, "1024a_laser_source_hatch", DSL::remainder, HIGH_TIERS); + registerForTiers(schema, map, "4096a_laser_target_hatch", DSL::remainder, HIGH_TIERS); + registerForTiers(schema, map, "4096a_laser_source_hatch", DSL::remainder, HIGH_TIERS); + + schema.registerSimple(map, "monitor"); + schema.registerSimple(map, "advanced_monitor"); + // endregion + + // region multiblock + schema.registerSimple(map, "bronze_large_boiler"); + schema.registerSimple(map, "steel_large_boiler"); + schema.registerSimple(map, "titanium_large_boiler"); + schema.registerSimple(map, "tungstensteel_large_boiler"); + + final Supplier primitiveMachine = () -> optionalFields( + "importItems", notifiableItemHandler(schema), + "exportItems", notifiableItemHandler(schema), + "importFluids", notifiableFluidTank(schema), + "exportFluids", notifiableFluidTank(schema) + ); + schema.register(map, "coke_oven", primitiveMachine); + schema.register(map, "primitive_blast_furnace", primitiveMachine); + + schema.registerSimple(map, "electric_blast_furnace"); + schema.registerSimple(map, "large_chemical_reactor"); + schema.registerSimple(map, "implosion_compressor"); + schema.registerSimple(map, "pyrolyse_oven"); + schema.registerSimple(map, "multi_smelter"); + schema.registerSimple(map, "cracker"); + schema.registerSimple(map, "distillation_tower"); + schema.registerSimple(map, "vacuum_freezer"); + schema.registerSimple(map, "assembly_line"); + schema.registerSimple(map, "primitive_pump"); + schema.registerSimple(map, "steam_grinder"); + schema.registerSimple(map, "steam_oven"); + registerForTiers(schema, map, "fusion_reactor", DSL::remainder, LuV, ZPM, UV); + registerForTiers(schema, map, "fluid_drilling_rig", DSL::remainder, MV, HV, EV); + registerForTiers(schema, map, "large_miner", DSL::remainder, EV, IV, LuV); + schema.registerSimple(map, "cleanroom"); + schema.registerSimple(map, "large_combustion_engine"); + schema.registerSimple(map, "extreme_combustion_engine"); + schema.registerSimple(map, "steam_large_turbine"); + schema.registerSimple(map, "gas_large_turbine"); + schema.registerSimple(map, "plasma_large_turbine"); + schema.registerSimple(map, "active_transformer"); + schema.registerSimple(map, "power_substation"); + registerForTiers(schema, map, "bedrock_ore_miner", DSL::remainder, MV, HV, EV); + schema.registerSimple(map, "wooden_tank_valve"); + schema.registerSimple(map, "wooden_multiblock_tank"); + schema.registerSimple(map, "bronze_tank_valve"); + schema.registerSimple(map, "bronze_multiblock_tank"); + schema.registerSimple(map, "steel_tank_valve"); + schema.registerSimple(map, "steel_multiblock_tank"); + + schema.registerSimple(map, "central_monitor"); + + // region GCYM + registerForTiers(schema, map, "parallel_hatch", DSL::remainder, IV, LuV, ZPM, UV); + schema.registerSimple(map, "large_maceration_tower"); + schema.registerSimple(map, "large_chemical_bath"); + schema.registerSimple(map, "large_centrifuge"); + schema.registerSimple(map, "large_mixer"); + schema.registerSimple(map, "large_electrolyzer"); + schema.registerSimple(map, "large_electromagnet"); + schema.registerSimple(map, "large_packer"); + schema.registerSimple(map, "large_assembler"); + schema.registerSimple(map, "large_circuit_assembler"); + schema.registerSimple(map, "large_arc_smelter"); + schema.registerSimple(map, "large_engraving_laser"); + schema.registerSimple(map, "large_sifting_funnel"); + schema.registerSimple(map, "alloy_blast_smelter"); + schema.registerSimple(map, "large_autoclave"); + schema.registerSimple(map, "large_material_press"); + schema.registerSimple(map, "large_brewer"); + schema.registerSimple(map, "large_cutter"); + schema.registerSimple(map, "large_extractor"); + schema.registerSimple(map, "large_extruder"); + schema.registerSimple(map, "large_solidifier"); + schema.registerSimple(map, "large_wiremill"); + schema.registerSimple(map, "mega_blast_furnace"); // TODO add fixer to rename to "rotary_hearth_furnace" + schema.registerSimple(map, "mega_vacuum_freezer"); // TODO add fixer to rename to "bulk_blast_chiller" + // endregion + // endregion + + // region research + schema.registerSimple(map, "research_station"); + schema.register(map, "object_holder", () -> optionalFields( + "heldItems", notifiableItemHandler(schema) + )); + schema.registerSimple(map, "data_bank"); + schema.registerSimple(map, "network_switch"); + schema.registerSimple(map, "high_performance_computation_array"); + schema.registerSimple(map, "computation_transmitter_hatch"); + schema.registerSimple(map, "computation_receiver_hatch"); + schema.registerSimple(map, "data_transmitter_hatch"); + schema.registerSimple(map, "data_receiver_hatch"); + final Supplier dataAccessHatch = () -> optionalFields( + "importItems", notifiableItemHandler(schema) + ); + schema.register(map, "basic_data_access_hatch", dataAccessHatch); + schema.register(map, "data_access_hatch", dataAccessHatch); + schema.register(map, "advanced_data_access_hatch", dataAccessHatch); + schema.register(map, "creative_data_access_hatch", dataAccessHatch); + schema.registerSimple(map, "hpca_empty_component"); + schema.registerSimple(map, "hpca_computation_component"); + schema.registerSimple(map, "hpca_advanced_computation_component"); + schema.registerSimple(map, "hpca_heat_sink_component"); + schema.registerSimple(map, "hpca_active_cooler_component"); + schema.registerSimple(map, "hpca_bridge_component"); + // endregion + + // region AE2 compat + if (LoadingModList.get().getModFileById(MODID_APPENG) != null) { // only add these if AE2 is loaded + schema.register(map, "me_input_bus", itemBus); + schema.register(map, "me_stocking_input_bus", itemBus); + schema.register(map, "me_output_bus", itemBus); + schema.register(map, "me_input_hatch", fluidHatch); + schema.register(map, "me_stocking_input_hatch", fluidHatch); + schema.register(map, "me_output_hatch", fluidHatch); + schema.register(map, "me_pattern_buffer", () -> optionalFields( + "patternInventory", itemHandler(schema), + "shareInventory", notifiableItemHandler(schema), + "shareTank", notifiableFluidTank(schema), + "internalInventory", list( + fields( + "inventory", list(References.ITEM_STACK.in(schema)), + "fluidInventory", list(GTReferences.FLUID_STACK.in(schema)) + ) + ), + itemBus.get() + )); + schema.registerSimple(map, "me_pattern_buffer_proxy"); + } + // endregion + + // register all remaining machines as very 'plain' types + for (MachineDefinition definition : GTRegistries.MACHINES) { + String id = definition.getId().toString(); + if (!map.containsKey(id)) { + registerSimple(map, id); + } + } + + return map; + } + + @Override + public void register(final Map> map, String name, final Supplier template) { + if (name.indexOf(':') == -1) { + name = "gtceu:" + name; + } + map.put(name, template); + } + + protected static void registerSimpleMachine(Schema schema, Map> map, String name, int... tiers) { + registerForTiers(schema, map, name, () -> optionalFields( + "importItems", notifiableItemHandler(schema), + "exportItems", notifiableItemHandler(schema), + "importFluids", notifiableFluidTank(schema), + "exportFluids", notifiableFluidTank(schema), + "chargerInventory", itemHandler(schema), + "circuitInventory", notifiableItemHandler(schema) + ), tiers); + } + + protected static void registerForTiers(Schema schema, Map> map, + String name, Supplier template, int... tiers) { + for (int tier : tiers) { + schema.register(map, GTValues.VN[tier].toLowerCase(Locale.ROOT) + "_" + name, template); + } + } + + protected static void registerSteamMachine(Schema schema, Map> map, + String name, Supplier template) { + schema.register(map, "lp_%s".formatted(name), template); + schema.register(map, "hp_%s".formatted(name), template); + } + + protected static void registerSimpleSteamMachine(Schema schema, Map> map, String name) { + registerSteamMachine(schema, map, name, () -> optionalFields( + "importItems", notifiableItemHandler(schema), + "exportItems", notifiableItemHandler(schema), + "steamTank", notifiableFluidTank(schema) + )); + } + + protected static TypeTemplate itemHandler(Schema schema) { + return field("Items", list(References.ITEM_STACK.in(schema))); + } + + protected static TypeTemplate notifiableItemHandler(Schema schema) { + return field("storage", itemHandler(schema)); + } + + protected static TypeTemplate notifiableFluidTank(Schema schema) { + return field("storages", list(GTReferences.FLUID_STACK.in(schema))); + } + // spotless:on +} diff --git a/src/main/java/com/gregtechceu/gtceu/common/datafixer/schemas/V1.java b/src/main/java/com/gregtechceu/gtceu/common/datafixer/schemas/V1.java new file mode 100644 index 00000000000..66feec14b07 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/common/datafixer/schemas/V1.java @@ -0,0 +1,28 @@ +package com.gregtechceu.gtceu.common.datafixer.schemas; + +import net.minecraft.util.datafix.schemas.NamespacedSchema; + +import com.mojang.datafixers.schemas.Schema; +import com.mojang.datafixers.types.templates.TypeTemplate; + +import java.util.Map; +import java.util.function.Supplier; + +import static com.gregtechceu.gtceu.common.datafixer.schemas.V0.*; + +public class V1 extends NamespacedSchema { + + public V1(int versionKey, Schema parent) { + super(versionKey, parent); + } + + @Override + public Map> registerBlockEntities(Schema schema) { + Map> map = super.registerBlockEntities(schema); + + map.remove("steam_miner"); + registerSimpleSteamMachine(schema, map, "steam_miner"); + + return map; + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/common/datafixer/schemas/package-info.java b/src/main/java/com/gregtechceu/gtceu/common/datafixer/schemas/package-info.java new file mode 100644 index 00000000000..a5712064fb1 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/common/datafixer/schemas/package-info.java @@ -0,0 +1,4 @@ +@NotNullByDefault +package com.gregtechceu.gtceu.common.datafixer.schemas; + +import org.jetbrains.annotations.NotNullByDefault; diff --git a/src/main/java/com/gregtechceu/gtceu/common/datafixers/TagFixer.java b/src/main/java/com/gregtechceu/gtceu/common/datafixers/TagFixer.java deleted file mode 100644 index 7bf24e1a6a8..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/common/datafixers/TagFixer.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.gregtechceu.gtceu.common.datafixers; - -import com.gregtechceu.gtceu.utils.GTMath; - -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.Tag; - -import java.util.Locale; - -public class TagFixer { - - public static final String[] FLUID_TAGS = { - "currentMilliBucketsPerTick", - "globalTransferSizeMillibuckets", - "minValue", - "maxValue", - }; - - // This is necessary for updating from old versions due to FluidStack long -> int changes - // Any fluid-related long tags need to be turned into int tags - public static void fixFluidTags(CompoundTag tag) { - if (tag.contains("cover", Tag.TAG_COMPOUND)) { - CompoundTag t = tag.getCompound("cover"); - for (String key : t.getAllKeys()) { - var cover = t.getCompound(key); - var id = cover.getCompound("uid").getString("id"); - if ((id.toLowerCase(Locale.ROOT).contains("fluid") || id.toLowerCase(Locale.ROOT).contains("pump"))) { - var data = cover.getCompound("payload").getCompound("d"); - for (String fix_key : FLUID_TAGS) { - if (data.contains(fix_key, Tag.TAG_LONG)) { - var l = data.getLong(fix_key); - data.putInt(fix_key, GTMath.saturatedCast(l)); - } - } - } - } - } - } -} diff --git a/src/main/java/com/gregtechceu/gtceu/config/ConfigHolder.java b/src/main/java/com/gregtechceu/gtceu/config/ConfigHolder.java index 8e617deda31..4ed7710a333 100644 --- a/src/main/java/com/gregtechceu/gtceu/config/ConfigHolder.java +++ b/src/main/java/com/gregtechceu/gtceu/config/ConfigHolder.java @@ -30,6 +30,11 @@ public static void init() { } } + public static ConfigHolder getInstance() { + init(); + return INSTANCE; + } + @Configurable public RecipeConfigs recipes = new RecipeConfigs(); @Configurable @@ -186,6 +191,13 @@ public static class RecipeConfigs { public static class CompatibilityConfigs { + @Configurable + @Configurable.Comment({ "Whether to run datafixers on world load.", + "Do note that mods like ModernFix will interfere with this.", + "Default: true" }) + @Configurable.UpdateRestriction(UpdateRestrictions.MAIN_MENU) + public boolean doDataFixers = true; + @Configurable @Configurable.Comment("Config options regarding GTEU compatibility with other energy systems") public EnergyCompatConfig energy = new EnergyCompatConfig(); diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/datafixer/DataFixTypesMixin.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/datafixer/DataFixTypesMixin.java new file mode 100644 index 00000000000..324c3678592 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/datafixer/DataFixTypesMixin.java @@ -0,0 +1,29 @@ +package com.gregtechceu.gtceu.core.mixins.datafixer; + +import com.gregtechceu.gtceu.api.datafixer.DataFixHelper; +import com.llamalad7.mixinextras.injector.ModifyReturnValue; +import com.mojang.datafixers.DSL; +import com.mojang.serialization.Dynamic; +import net.minecraft.util.datafix.DataFixTypes; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(DataFixTypes.class) +public class DataFixTypesMixin { + + @Shadow + @Final + private DSL.TypeReference type; + + // ModifyReturnValue to inject our fixes *after* vanilla ones + @ModifyReturnValue(method = "update(Lcom/mojang/datafixers/DataFixer;Lcom/mojang/serialization/Dynamic;II)Lcom/mojang/serialization/Dynamic;", + at = @At(value = "RETURN")) + private Dynamic gtceu$injectDataFixers(Dynamic value) { + // skip applying datafixers to options.txt; doing that loads the fixers too early + if ((Object) this == DataFixTypes.OPTIONS) return value; + + return DataFixHelper.updateToCurrentVersion(this.type, value); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/datafixer/ForgeHooksMixin.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/datafixer/ForgeHooksMixin.java new file mode 100644 index 00000000000..12fc7c77953 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/datafixer/ForgeHooksMixin.java @@ -0,0 +1,38 @@ +package com.gregtechceu.gtceu.core.mixins.datafixer; + +import com.gregtechceu.gtceu.GTCEu; +import com.gregtechceu.gtceu.api.datafixer.DataFixHelper; +import com.gregtechceu.gtceu.common.data.datafixer.GTReferences; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtUtils; +import net.minecraftforge.common.ForgeHooks; + +import com.llamalad7.mixinextras.expression.Definition; +import com.llamalad7.mixinextras.expression.Expression; +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +import com.llamalad7.mixinextras.sugar.Local; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(value = ForgeHooks.class, remap = false) +public class ForgeHooksMixin { + + @Definition(id = "CompoundTag", type = CompoundTag.class) + @Definition(id = "fmlData", local = @Local(name = "fmlData", type = CompoundTag.class), remap = false) + @Expression("fmlData = @(new CompoundTag())") + @ModifyExpressionValue(method = "writeAdditionalLevelSaveData", at = @At("MIXINEXTRAS:EXPRESSION")) + private static CompoundTag gtceu$addDataVersions(CompoundTag fmlData) { + return NbtUtils.addCurrentDataVersion(fmlData); + } + + @Definition(id = "tag", local = @Local(type = CompoundTag.class, name = "tag")) + @Definition(id = "getCompound", method = "Lnet/minecraft/nbt/CompoundTag;getCompound(Ljava/lang/String;)Lnet/minecraft/nbt/CompoundTag;", remap = true) + @Expression("tag.getCompound('Registries')") + @ModifyExpressionValue(method = "readAdditionalLevelSaveData", at = @At(value = "MIXINEXTRAS:EXPRESSION")) + private static CompoundTag gtceu$fixRegistriesTag(CompoundTag regs, + @Local(name = "tag") CompoundTag tag) { + int currentVersion = DataFixHelper.getGTDataVersion(tag); + return DataFixHelper.update(GTReferences.FORGE_REGISTRY_DATA, regs, currentVersion, GTCEu.GT_DATA_VERSION); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/datafixer/NbtUtilsMixin.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/datafixer/NbtUtilsMixin.java new file mode 100644 index 00000000000..88f32528aa4 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/datafixer/NbtUtilsMixin.java @@ -0,0 +1,17 @@ +package com.gregtechceu.gtceu.core.mixins.datafixer; + +import com.gregtechceu.gtceu.api.datafixer.DataFixHelper; +import com.llamalad7.mixinextras.injector.ModifyReturnValue; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtUtils; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(NbtUtils.class) +public class NbtUtilsMixin { + + @ModifyReturnValue(method = "addDataVersion", at = @At("RETURN")) + private static CompoundTag gtceu$addGTDataVersion(CompoundTag tag) { + return DataFixHelper.addGTDataVersion(tag); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/utils/data/TagCompatibilityFixer.java b/src/main/java/com/gregtechceu/gtceu/utils/data/TagCompatibilityFixer.java index f6ee9efc56f..0333aa969a2 100644 --- a/src/main/java/com/gregtechceu/gtceu/utils/data/TagCompatibilityFixer.java +++ b/src/main/java/com/gregtechceu/gtceu/utils/data/TagCompatibilityFixer.java @@ -9,25 +9,7 @@ @NoArgsConstructor(access = AccessLevel.PRIVATE) public final class TagCompatibilityFixer { - public static void fixMachineAutoOutputTag(CompoundTag machineTag) { - if (!machineTag.contains("autoOutput")) { - var outputTag = new CompoundTag(); - Tag itemOutputDirection = machineTag.get("outputFacingItems"); - Tag fluidOutputDirection = machineTag.get("outputFacingFluids"); - Tag autoOutputItems = machineTag.get("autoOutputItems"); - Tag autoOutputFluids = machineTag.get("autoOutputFluids"); - Tag allowInputItems = machineTag.get("allowInputFromOutputSideItems"); - Tag allowInputFluids = machineTag.get("allowInputFromOutputSideFluids"); - if (itemOutputDirection != null) outputTag.put("itemOutputDirection", itemOutputDirection); - if (fluidOutputDirection != null) outputTag.put("fluidOutputDirection", fluidOutputDirection); - if (autoOutputItems != null) outputTag.put("autoOutputItems", autoOutputItems); - if (autoOutputFluids != null) outputTag.put("autoOutputFluids", autoOutputFluids); - if (allowInputItems != null) outputTag.put("allowItemInputFromOutputSide", allowInputItems); - if (allowInputFluids != null) outputTag.put("allowFluidInputFromOutputSide", allowInputFluids); - machineTag.put("autoOutput", outputTag); - } - } - + // TODO convert into datafixer public static Tag stripLDLibPayloadWrapper(Tag t) { if (!(t instanceof CompoundTag tag)) return t; if (tag.contains("p") && tag.contains("t")) { diff --git a/src/main/resources/gtceu.mixins.json b/src/main/resources/gtceu.mixins.json index 4d4c326abf7..1088e9c73ba 100644 --- a/src/main/resources/gtceu.mixins.json +++ b/src/main/resources/gtceu.mixins.json @@ -1,6 +1,9 @@ { "required": true, "minVersion": "0.8", + "mixinextras": { + "minVersion": "0.5.0-rc.3" + }, "refmap": "gtceu.refmap.json", "package": "com.gregtechceu.gtceu.core.mixins", "compatibilityLevel": "JAVA_17", @@ -65,6 +68,9 @@ "TagManagerMixin", "TagValueAccessor", "client.ItemEntityMixin", + "datafixer.DataFixTypesMixin", + "datafixer.ForgeHooksMixin", + "datafixer.NbtUtilsMixin", "dev.datagen.FixParallelKeyMappingRegistrationMixin", "dev.test.GameTestRegistryMixin", "emi.EmiRecipeFillerMixin",