Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fabric Data Fixer API (v1) #3649

Open
wants to merge 46 commits into
base: 1.21
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
edcde9b
port datafixer api + multiple fixers/mod
Treetrain1 Mar 12, 2024
d9caeb6
Add `DataFixerEvents`
Treetrain1 Mar 12, 2024
8b65e8f
fix style
Treetrain1 Mar 12, 2024
6dad72a
Add data fixer entrypoint
Treetrain1 Mar 12, 2024
82d4bcc
fix style again
Treetrain1 Mar 12, 2024
44db072
Match vanilla entity type builder
Treetrain1 Mar 12, 2024
2376c29
Match vanilla block entity type builder
Treetrain1 Mar 12, 2024
a027458
Remove `DataFixerEvents` in favor of the entrypoint
Treetrain1 Mar 12, 2024
baa4851
Add SchemaRegistry for entrypoint
Treetrain1 Mar 12, 2024
72eda29
mark registry as `final`
Treetrain1 Mar 12, 2024
b510e7e
fix `getModDataVersion` with custom key
Treetrain1 Mar 12, 2024
b4fd97d
fix inconsistency
Treetrain1 Mar 12, 2024
fa44453
add choice type fixes + use custom schema
Treetrain1 Mar 12, 2024
de0f9f1
Merge branch 'refs/heads/1.20.5' into api/datafixerupper
Treetrain1 Mar 12, 2024
f61b197
Prevent block entity breakages.
Treetrain1 Mar 12, 2024
2a2463d
Fix spotless
Treetrain1 Mar 12, 2024
5fa0086
fix mixin remapping
Treetrain1 Mar 12, 2024
9701b60
catch NPE
Treetrain1 Mar 12, 2024
a9a9044
Add `SchemaRegistry#register(Identifier, Function)`
Treetrain1 Mar 12, 2024
f30903c
Remove exception if a mod registers more than 1 fixer
Treetrain1 Mar 13, 2024
57dfec2
(WIP) Use sub versions of latest vanilla schema
Treetrain1 Mar 13, 2024
a3ca9ea
combine mod datafixers into one
Treetrain1 Mar 13, 2024
6db965c
New plan: Modded schema parents
Treetrain1 Mar 27, 2024
51466bc
Merge branch 'refs/heads/1.20.5' into api/datafixerupper-2
Treetrain1 Mar 27, 2024
a8f9f5a
Remove entrypoint
Treetrain1 Mar 27, 2024
7f9a9fc
Merge branch '1.20.5' into api/datafixerupper-2
Treetrain1 Mar 27, 2024
6fb062e
fix key specification in FMJ
Treetrain1 Mar 27, 2024
7f21a87
write todo in testmod
Treetrain1 Mar 27, 2024
54bf384
Merge branch 'refs/heads/1.20.5' into api/datafixerupper-2
Treetrain1 Mar 27, 2024
fa74df7
add isolation test
Treetrain1 Mar 28, 2024
da56a97
run spotless
Treetrain1 Mar 28, 2024
a94e988
Port biome test
Treetrain1 Mar 28, 2024
edc24d1
Add `addBlockStateRenameFix`
Treetrain1 Mar 28, 2024
bafef8b
consistency
Treetrain1 Mar 28, 2024
4ec6809
run spotless
Treetrain1 Mar 28, 2024
85cd529
Only warn if given id is not null
Treetrain1 Mar 28, 2024
1d1cd2e
improve warning + add comment
Treetrain1 Mar 28, 2024
3d0844b
remove `lastVanillaSchema`
Treetrain1 Mar 28, 2024
a23ea14
Revert "Remove entrypoint"
Treetrain1 Mar 30, 2024
4834306
Avoid registering tons of choice type fixes
Treetrain1 Mar 30, 2024
5bdd4ce
Merge remote-tracking branch 'origin/api/datafixerupper-2' into api/d…
Treetrain1 Jun 21, 2024
1924ee6
Merge branch 'refs/heads/1.21' into api/datafixerupper-2
Treetrain1 Jun 21, 2024
dc08fb2
Merge remote-tracking branch 'upstream/1.21' into api/datafixerupper-2
Treetrain1 Jul 11, 2024
5026b33
WIP 1.21 port
Treetrain1 Jul 11, 2024
cdc6895
Resolve conversations
Treetrain1 Jul 11, 2024
6bccbc5
Bypass vanilla version check in chunk deserialization
Treetrain1 Jul 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ allprojects {

spotless {
java {
licenseHeaderFile(rootProject.file("HEADER"))
licenseHeaderFile(rootProject.file("HEADER")).named('default')
removeUnusedImports()
importOrder('java', 'javax', '', 'net.minecraft', 'net.fabricmc')
indentWithTabs()
Expand Down
19 changes: 19 additions & 0 deletions fabric-data-fixer-api-v1/HEADER-PORT
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright (c) 2016-2022 FabricMC
*
* 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.
*
* This file is a modified version of Quilt Standard Libraries,
* authored by QuiltMC.
*/

22 changes: 22 additions & 0 deletions fabric-data-fixer-api-v1/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Fabric Data Fixer API (v1)
For user-facing documentation, please check the Javadoc.

This is a port of data fixer API from QSL, with some internal changes and new methods:

- Unlike QSL, this API saves the data version in a NBT compound `_FabricDataVersions`.
- Current data version can be specified in the `fabric.mod.json` file.
- `FabricDataFixerBuilder#build()` overload that uses bootstrap executor.

Files with ported code are marked with `// From QSL.` comment and a special license header.

## Running the tests
The repository contains three files: `level.dat` and two region files (with chunks trimmed). You can run `gradlew runTestmodServer` to test the updating. If this does not error, the tests passed!

To generate the file (without running the tests), run `gradlew runGenOldSave`, then optionally trim the chunks with NBT editing tools.

The test files contain:

- A chest block with a modded item, at `0, 10, 0` in the overworld
- A modded chest block with a modded item, at `0, 9, 0` in the overworld
- A modded block at `0, 8, 0` in the overworld
- A modded biome at chunk `0, 0` in the End
38 changes: 38 additions & 0 deletions fabric-data-fixer-api-v1/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
archivesBaseName = "fabric-data-fixer-api-v1"
version = getSubprojectVersion(project)

moduleDependencies(project, [
'fabric-api-base',
'fabric-lifecycle-events-v1'
])

testDependencies(project, [
':fabric-biome-api-v1',
':fabric-item-api-v1',
':fabric-object-builder-api-v1'
])

loom {
accessWidenerPath = file('src/main/resources/fabric-data-fixer-api-v1.accesswidener')

runs {
genOldSave {
inherit testmodServer
name "Generate old save"
vmArg "-Dfabric.dataFixerTestMod.genMode=true"

ideConfigGenerated = true
}
}
}

spotless {
java {
/**
* This module contains a code from QSL, and they need a separate license header.
* Code ported from QSL should be marked as "From QSL" in a comment,
* inside the "source" (i.e. not inside header comment).
*/
licenseHeaderFile(project.file("HEADER-PORT")).named('port').onlyIfContentMatches('.*From QSL.*')
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright (c) 2016-2022 FabricMC
*
* 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.
*
* This file is a modified version of Quilt Standard Libraries,
* authored by QuiltMC.
*/

package net.fabricmc.fabric.impl.client.datafixer.v1;

import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;
import net.fabricmc.fabric.impl.datafixer.v1.FabricDataFixesInternals;

public final class ClientFreezer implements ClientModInitializer {
// From QSL.
@Override
public void onInitializeClient() {
ClientLifecycleEvents.CLIENT_STARTED.register((client) -> FabricDataFixesInternals.get().freeze());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* 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.
*/

package net.fabricmc.fabric.api.datafixer.v1;

import com.mojang.datafixers.schemas.Schema;

public interface DataFixerEntrypoint {
void onRegisterBlockEntities(SchemaRegistry registry, Schema schema);

void onRegisterEntities(SchemaRegistry registry, Schema schema);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright (c) 2016-2022 FabricMC
*
* 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.
*
* This file is a modified version of Quilt Standard Libraries,
* authored by QuiltMC.
*/

package net.fabricmc.fabric.api.datafixer.v1;

import java.util.Map;
import java.util.function.Supplier;

import com.mojang.datafixers.DSL;
import com.mojang.datafixers.schemas.Schema;
import com.mojang.datafixers.types.Type;
import com.mojang.datafixers.types.templates.TypeTemplate;
import it.unimi.dsi.fastutil.objects.Object2ObjectMaps;
import org.jetbrains.annotations.Range;

/**
* Represents an empty {@link Schema}, having no parent and containing no type definitions.
*/
public final class EmptySchema extends FirstSchema {
// From QSL.

/**
* Constructs an empty schema.
*
* @param versionKey the data version key
*/
public EmptySchema(@Range(from = 0, to = Integer.MAX_VALUE) int versionKey) {
super(versionKey);
}

// Ensure the schema stays empty.
@Override
public void registerType(boolean recursive, DSL.TypeReference type, Supplier<TypeTemplate> template) {
throw new UnsupportedOperationException();
}

@Override
protected Map<String, Type<?>> buildTypes() {
return Object2ObjectMaps.emptyMap();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
* Copyright (c) 2016-2022 FabricMC
*
* 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.
*
* This file is a modified version of Quilt Standard Libraries,
* authored by QuiltMC.
*/

package net.fabricmc.fabric.api.datafixer.v1;

import java.util.Objects;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.function.Supplier;

import com.mojang.datafixers.DSL;
import com.mojang.datafixers.DataFixerBuilder;
import com.mojang.datafixers.DataFixerUpper;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.Range;

import net.minecraft.util.Util;

import net.fabricmc.fabric.impl.datafixer.v1.FabricDataFixesInternals;
import net.fabricmc.loader.api.ModContainer;

/**
* An extended variant of the {@link DataFixerBuilder} class, which provides an extra method.
*/
public class FabricDataFixerBuilder extends DataFixerBuilder {
// From QSL.
protected final int dataVersion;

/**
* Creates a new {@code FabricDataFixerBuilder}.
*
* @param dataVersion the current data version
*/
public FabricDataFixerBuilder(@Range(from = 0, to = Integer.MAX_VALUE) int dataVersion) {
super(dataVersion);
this.dataVersion = dataVersion;
}

/**
* Creates a new {@code FabricDataFixerBuilder}. This method gets the current version from
* the {@code fabric-data-fixer-api-v1:version} field in the {@code custom} object of
* the {@code fabric.mod.json} file of {@code mod}. To specify the version
* manually, use the other overload.
*
* @param mod the mod container
* @return the data fixer builder
* @throws RuntimeException if the version field does not exist or is not a number
*/
public static FabricDataFixerBuilder create(ModContainer mod) {
Objects.requireNonNull(mod, "mod cannot be null");
int dataVersion = FabricDataFixesInternals.getDataVersionFromMetadata(mod);
return new FabricDataFixerBuilder(dataVersion);
}

/**
* @return the current data version
*/
@Range(from = 0, to = Integer.MAX_VALUE)
public int getDataVersion() {
return this.dataVersion;
}

/**
* Builds the final {@code DataFixer}.
*
* <p>This will build either an {@linkplain #build() unoptimized fixer} or an
* optimized fixer, depending on the vanilla game's settings.
*
* @param types the set of required {@link com.mojang.datafixers.DSL.TypeReference}s, only used if the game is using optimized data fixers
* @param executorGetter the executor supplier, only invoked if the game is using optimized data fixers
* @return the newly built data fixer
*/
@Contract(value = "_, _ -> new")
public DataFixerUpper build(Set<DSL.TypeReference> types, Supplier<Executor> executorGetter) {
Objects.requireNonNull(executorGetter, "executorGetter cannot be null");
return (DataFixerUpper) (types.isEmpty() ? this.build().fixer() : Util.make(() -> {
Result result = this.build();
result.optimize(types, executorGetter.get()).join();
return result.fixer();
}));
}
}
Loading