From 14c0ce9d3dda9b698639acda6fe739c26c994210 Mon Sep 17 00:00:00 2001 From: Samu Date: Mon, 9 Feb 2026 13:49:39 +0100 Subject: [PATCH 01/10] Environment attribute API for adding custom attribute layers --- fabric-environment-attributes-v0/build.gradle | 11 +++ .../attribute/v0/AttributeLayerPosition.java | 48 ++++++++++++ .../v0/EnvironmentAttributeEvents.java | 64 ++++++++++++++++ .../EnvironmentAttributeEventsImpl.java | 55 ++++++++++++++ .../EnvironmentAttributeSystemMixin.java | 71 ++++++++++++++++++ .../fabric-environment-attributes-v0/icon.png | Bin 0 -> 1555 bytes ...bric-environment-attributes-v0.mixins.json | 14 ++++ .../src/main/resources/fabric.mod.json | 31 ++++++++ .../FabricEnvironmentAttributesTest.java | 37 +++++++++ .../src/testmod/resources/fabric.mod.json | 19 +++++ ...FabricEnvironmentAttributesClientTest.java | 69 +++++++++++++++++ gradle.properties | 1 + settings.gradle | 1 + 13 files changed, 421 insertions(+) create mode 100644 fabric-environment-attributes-v0/build.gradle create mode 100644 fabric-environment-attributes-v0/src/main/java/net/fabricmc/fabric/api/environment/attribute/v0/AttributeLayerPosition.java create mode 100644 fabric-environment-attributes-v0/src/main/java/net/fabricmc/fabric/api/environment/attribute/v0/EnvironmentAttributeEvents.java create mode 100644 fabric-environment-attributes-v0/src/main/java/net/fabricmc/fabric/impl/environment/attribute/EnvironmentAttributeEventsImpl.java create mode 100644 fabric-environment-attributes-v0/src/main/java/net/fabricmc/fabric/mixin/environment/attribute/EnvironmentAttributeSystemMixin.java create mode 100644 fabric-environment-attributes-v0/src/main/resources/assets/fabric-environment-attributes-v0/icon.png create mode 100644 fabric-environment-attributes-v0/src/main/resources/fabric-environment-attributes-v0.mixins.json create mode 100644 fabric-environment-attributes-v0/src/main/resources/fabric.mod.json create mode 100644 fabric-environment-attributes-v0/src/testmod/java/net/fabricmc/fabric/test/environment/attribute/FabricEnvironmentAttributesTest.java create mode 100644 fabric-environment-attributes-v0/src/testmod/resources/fabric.mod.json create mode 100644 fabric-environment-attributes-v0/src/testmodClient/java/net/fabricmc/fabric/test/environment/attribute/client/FabricEnvironmentAttributesClientTest.java diff --git a/fabric-environment-attributes-v0/build.gradle b/fabric-environment-attributes-v0/build.gradle new file mode 100644 index 00000000000..8bfe314df96 --- /dev/null +++ b/fabric-environment-attributes-v0/build.gradle @@ -0,0 +1,11 @@ +version = getSubprojectVersion(project) + +moduleDependencies(project, [ + 'fabric-api-base', + 'fabric-lifecycle-events-v1' +]) + +testDependencies(project, [ + ':fabric-resource-loader-v1', + ':fabric-client-gametest-api-v1' +]) diff --git a/fabric-environment-attributes-v0/src/main/java/net/fabricmc/fabric/api/environment/attribute/v0/AttributeLayerPosition.java b/fabric-environment-attributes-v0/src/main/java/net/fabricmc/fabric/api/environment/attribute/v0/AttributeLayerPosition.java new file mode 100644 index 00000000000..cbbf7cc1659 --- /dev/null +++ b/fabric-environment-attributes-v0/src/main/java/net/fabricmc/fabric/api/environment/attribute/v0/AttributeLayerPosition.java @@ -0,0 +1,48 @@ +/* + * 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.environment.attribute.v0; + +/** + * Positions at which environment attribute layers can be inserted. Each position is associated with an event in + * {@link EnvironmentAttributeEvents}. The enum is ordered by in which order Minecraft adds its default layers. + */ +public enum AttributeLayerPosition { + /** + * The position before all vanilla layers. + */ + BEFORE_ALL, + + /** + * The position between dimension and biome layers. + */ + BETWEEN_DIMENSION_AND_BIOMES, + + /** + * The position between biome and timeline layers. + */ + BETWEEN_BIOMES_AND_TIMELINES, + + /** + * The position between timeline and weather layers. + */ + BETWEEN_TIMELINES_AND_WEATHER, + + /** + * The position after all vanilla layers. + */ + AFTER_ALL +} diff --git a/fabric-environment-attributes-v0/src/main/java/net/fabricmc/fabric/api/environment/attribute/v0/EnvironmentAttributeEvents.java b/fabric-environment-attributes-v0/src/main/java/net/fabricmc/fabric/api/environment/attribute/v0/EnvironmentAttributeEvents.java new file mode 100644 index 00000000000..8fb8f0b4729 --- /dev/null +++ b/fabric-environment-attributes-v0/src/main/java/net/fabricmc/fabric/api/environment/attribute/v0/EnvironmentAttributeEvents.java @@ -0,0 +1,64 @@ +/* + * 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.environment.attribute.v0; + +import net.minecraft.world.attribute.EnvironmentAttributeSystem; +import net.minecraft.world.level.Level; + +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.impl.environment.attribute.EnvironmentAttributeEventsImpl; + +/** + * Events related to environment attributes. + */ +public class EnvironmentAttributeEvents { + /** + * Returns the {@link InsertLayers} event for the given {@link AttributeLayerPosition}. This event allows inserting + * extra attribute layers at that position during the environment attribute setup for a {@link Level}. By default, + * Minecraft adds layers for the dimension, then for biomes, then for timelines and lastly for weather. The event + * returned by this method is triggered before, in between and after each of these vanilla layers, depending on the + * selected position, in the following manner: + * + * @param position The position at which you want to insert attribute layers. + * @return The event to listen for layer setup. + */ + public static Event insertLayersEvent(AttributeLayerPosition position) { + return EnvironmentAttributeEventsImpl.getOrCreateInsertLayersEvent(position); + } + + /** + * Callback for events returned from {@link #insertLayersEvent}. + */ + public interface InsertLayers { + /** + * Insert custom attribute layers into the {@link EnvironmentAttributeSystem.Builder}. + * @param systemBuilder The environment attribute system builder to modify. + * @param level The level for which the attribute system is built. + */ + void insertAttributeLayers(EnvironmentAttributeSystem.Builder systemBuilder, Level level); + } +} diff --git a/fabric-environment-attributes-v0/src/main/java/net/fabricmc/fabric/impl/environment/attribute/EnvironmentAttributeEventsImpl.java b/fabric-environment-attributes-v0/src/main/java/net/fabricmc/fabric/impl/environment/attribute/EnvironmentAttributeEventsImpl.java new file mode 100644 index 00000000000..f93960f5f81 --- /dev/null +++ b/fabric-environment-attributes-v0/src/main/java/net/fabricmc/fabric/impl/environment/attribute/EnvironmentAttributeEventsImpl.java @@ -0,0 +1,55 @@ +/* + * 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.impl.environment.attribute; + +import java.util.EnumMap; +import java.util.Map; + +import org.jspecify.annotations.NonNull; + +import net.minecraft.world.attribute.EnvironmentAttributeSystem; +import net.minecraft.world.level.Level; + +import net.fabricmc.fabric.api.environment.attribute.v0.AttributeLayerPosition; +import net.fabricmc.fabric.api.environment.attribute.v0.EnvironmentAttributeEvents; +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; + +public class EnvironmentAttributeEventsImpl { + private static final Map> POSITION_EVENT_MAP = new EnumMap<>(AttributeLayerPosition.class); + + @NonNull + public static Event getOrCreateInsertLayersEvent(AttributeLayerPosition position) { + return POSITION_EVENT_MAP.computeIfAbsent(position, (p -> createInsertEvent())); + } + + public static void insertLayers(AttributeLayerPosition position, EnvironmentAttributeSystem.Builder systemBuilder, Level level) { + Event event = POSITION_EVENT_MAP.get(position); + + if (event != null) { + event.invoker().insertAttributeLayers(systemBuilder, level); + } + } + + private static Event createInsertEvent() { + return EventFactory.createArrayBacked(EnvironmentAttributeEvents.InsertLayers.class, callbacks -> (systemBuilder, level) -> { + for (EnvironmentAttributeEvents.InsertLayers callback : callbacks) { + callback.insertAttributeLayers(systemBuilder, level); + } + }); + } +} diff --git a/fabric-environment-attributes-v0/src/main/java/net/fabricmc/fabric/mixin/environment/attribute/EnvironmentAttributeSystemMixin.java b/fabric-environment-attributes-v0/src/main/java/net/fabricmc/fabric/mixin/environment/attribute/EnvironmentAttributeSystemMixin.java new file mode 100644 index 00000000000..01f6bfe52de --- /dev/null +++ b/fabric-environment-attributes-v0/src/main/java/net/fabricmc/fabric/mixin/environment/attribute/EnvironmentAttributeSystemMixin.java @@ -0,0 +1,71 @@ +/* + * 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.mixin.environment.attribute; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.world.attribute.EnvironmentAttributeSystem; +import net.minecraft.world.level.Level; + +import net.fabricmc.fabric.api.environment.attribute.v0.AttributeLayerPosition; +import net.fabricmc.fabric.impl.environment.attribute.EnvironmentAttributeEventsImpl; + +@Mixin(EnvironmentAttributeSystem.class) +public class EnvironmentAttributeSystemMixin { + @Inject( + method = "addDefaultLayers", + at = @At(value = "HEAD") + ) + private static void addLayersBeforeAll(EnvironmentAttributeSystem.Builder builder, Level level, CallbackInfo ci) { + EnvironmentAttributeEventsImpl.insertLayers(AttributeLayerPosition.BEFORE_ALL, builder, level); + } + + @Inject( + method = "addDefaultLayers", + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/attribute/EnvironmentAttributeSystem;addBiomeLayer(Lnet/minecraft/world/attribute/EnvironmentAttributeSystem$Builder;Lnet/minecraft/core/HolderLookup;Lnet/minecraft/world/level/biome/BiomeManager;)V") + ) + private static void addLayersAfterDimension(EnvironmentAttributeSystem.Builder builder, Level level, CallbackInfo ci) { + EnvironmentAttributeEventsImpl.insertLayers(AttributeLayerPosition.BETWEEN_DIMENSION_AND_BIOMES, builder, level); + } + + @Inject( + method = "addDefaultLayers", + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;dimensionType()Lnet/minecraft/world/level/dimension/DimensionType;") + ) + private static void addLayersAfterBiomes(EnvironmentAttributeSystem.Builder builder, Level level, CallbackInfo ci) { + EnvironmentAttributeEventsImpl.insertLayers(AttributeLayerPosition.BETWEEN_BIOMES_AND_TIMELINES, builder, level); + } + + @Inject( + method = "addDefaultLayers", + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;canHaveWeather()Z") + ) + private static void addLayersAfterTimelines(EnvironmentAttributeSystem.Builder builder, Level level, CallbackInfo ci) { + EnvironmentAttributeEventsImpl.insertLayers(AttributeLayerPosition.BETWEEN_TIMELINES_AND_WEATHER, builder, level); + } + + @Inject( + method = "addDefaultLayers", + at = @At(value = "TAIL") + ) + private static void addLayersAfterAll(EnvironmentAttributeSystem.Builder builder, Level level, CallbackInfo ci) { + EnvironmentAttributeEventsImpl.insertLayers(AttributeLayerPosition.AFTER_ALL, builder, level); + } +} diff --git a/fabric-environment-attributes-v0/src/main/resources/assets/fabric-environment-attributes-v0/icon.png b/fabric-environment-attributes-v0/src/main/resources/assets/fabric-environment-attributes-v0/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..12c4531de92fe0544a0e15347f84381c132a7feb GIT binary patch literal 1555 zcmbVMONbmr817YeS0`Bvm<_8$sdPkC($if%&o0utJLwrS1L<{`3}loX(o5`x6Ep1Z4+am|^rTyU-RHPnPe)^ld+*!=$4&3I z>W!eGA48bhNyDT~k_>H^p*imGQs^3Zl?0$k+Loj8KVQ7W1ItwT6B%97U5#|C^1vg< z2P<_vSjCFTFD-(@Az}nJ2@DY0UB^eE$`5%FTSvzt4~CFnRpkqjLeS8wK%*W3nPgVL zFfD_el7v}Fk<*8OEWw;8R1=sseC60TqKJ9em~hy zC8^gIp`s|FB#W{vFofW*JAn}jj(>2%P$WL~EH|*I10qJFN!J3EXO@m!u-%x}@yB6e z0TV;R6=70}Tp9vR9OK+IuRBz3Vv%%-O`O1ISQum74h^W^p?^aii~pp6g;v*N9S^m| zwqq53Q0g%^#sPUK+OMy>M63~?u6dZ0dd$p&kvA^VJYodYt5e#YJXCdJGSIZ>Ve;Um z6P9DrzW?%$JEUj?MCBv70A&GY>oAKlX#{hElt+>@g6hlcrFNcIG_C5bC_#`dML=rKZ5X)F-wenaX=`<9S6l@7;C1a*r zFpYEBk-O}Ek>a%|3nur?|9Ss4&tg?*bRU@~s?8{UP}%a?!>*63=Qw$Dyy{wDm@&w} zQ6;E6j#7Y_{P@^<utq@Kv^7o)Nrxg!46%b{#X ziBI6HZ$!(uVX;lz@`%IwoW~m4((?!2X3g;ZO0iH6ziV#JEKKiv@r~aK;fD%m+`qeP zqj!gUd>JIZzIXQGa=BdwQ+vS+TaVp2d4HjC{TKZ1T^OEP^h*yupZ((7eYf^3ZRqE( zWln<`?)nV)~_M|=0.18.4", + "minecraft": ">=1.16-rc.3", + "fabric-api-base": "*" + }, + "description": "Fabric Environment Attributes API.", + "mixins": [ + "fabric-environment-attributes-v0.mixins.json" + ], + "custom": { + "fabric-api:module-lifecycle": "stable" + } +} diff --git a/fabric-environment-attributes-v0/src/testmod/java/net/fabricmc/fabric/test/environment/attribute/FabricEnvironmentAttributesTest.java b/fabric-environment-attributes-v0/src/testmod/java/net/fabricmc/fabric/test/environment/attribute/FabricEnvironmentAttributesTest.java new file mode 100644 index 00000000000..1d7427a8994 --- /dev/null +++ b/fabric-environment-attributes-v0/src/testmod/java/net/fabricmc/fabric/test/environment/attribute/FabricEnvironmentAttributesTest.java @@ -0,0 +1,37 @@ +/* + * 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.test.environment.attribute; + +import net.minecraft.core.Registry; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.Identifier; +import net.minecraft.world.attribute.AttributeTypes; +import net.minecraft.world.attribute.EnvironmentAttribute; + +import net.fabricmc.api.ModInitializer; + +public class FabricEnvironmentAttributesTest implements ModInitializer { + public static final EnvironmentAttribute TEST_COLOR = EnvironmentAttribute.builder(AttributeTypes.RGB_COLOR) + .defaultValue(0xFFFFFF) + .syncable() + .build(); + + @Override + public void onInitialize() { + Registry.register(BuiltInRegistries.ENVIRONMENT_ATTRIBUTE, Identifier.fromNamespaceAndPath("fabric_environment_attributes", "test_color"), TEST_COLOR); + } +} diff --git a/fabric-environment-attributes-v0/src/testmod/resources/fabric.mod.json b/fabric-environment-attributes-v0/src/testmod/resources/fabric.mod.json new file mode 100644 index 00000000000..897dd1bb2a7 --- /dev/null +++ b/fabric-environment-attributes-v0/src/testmod/resources/fabric.mod.json @@ -0,0 +1,19 @@ +{ + "schemaVersion": 1, + "id": "fabric-environment-attributes-v0-testmod", + "name": "Fabric Environment Attributes (v0) Test Mod", + "version": "1.0.0", + "environment": "*", + "license": "Apache-2.0", + "depends": { + "fabric-environment-attributes-v0": "*" + }, + "entrypoints": { + "main": [ + "net.fabricmc.fabric.test.environment.attribute.FabricEnvironmentAttributesTest" + ], + "fabric-client-gametest": [ + "net.fabricmc.fabric.test.environment.attribute.client.FabricEnvironmentAttributesClientTest" + ] + } +} diff --git a/fabric-environment-attributes-v0/src/testmodClient/java/net/fabricmc/fabric/test/environment/attribute/client/FabricEnvironmentAttributesClientTest.java b/fabric-environment-attributes-v0/src/testmodClient/java/net/fabricmc/fabric/test/environment/attribute/client/FabricEnvironmentAttributesClientTest.java new file mode 100644 index 00000000000..91552bc8195 --- /dev/null +++ b/fabric-environment-attributes-v0/src/testmodClient/java/net/fabricmc/fabric/test/environment/attribute/client/FabricEnvironmentAttributesClientTest.java @@ -0,0 +1,69 @@ +/* + * 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.test.environment.attribute.client; + +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.attribute.EnvironmentAttributes; +import net.minecraft.world.level.Level; + +import net.fabricmc.fabric.api.client.gametest.v1.FabricClientGameTest; +import net.fabricmc.fabric.api.client.gametest.v1.context.ClientGameTestContext; +import net.fabricmc.fabric.api.client.gametest.v1.context.TestSingleplayerContext; +import net.fabricmc.fabric.api.environment.attribute.v0.AttributeLayerPosition; +import net.fabricmc.fabric.api.environment.attribute.v0.EnvironmentAttributeEvents; +import net.fabricmc.fabric.test.environment.attribute.FabricEnvironmentAttributesTest; + +public class FabricEnvironmentAttributesClientTest implements FabricClientGameTest { + public static final int TEST_COLOR = 0xFFFF00FF; + + @Override + public void runTest(ClientGameTestContext context) { + EnvironmentAttributeEvents.insertLayersEvent(AttributeLayerPosition.BEFORE_ALL).register((systemBuilder, level) -> { + // Test color is not overridden in any way, we should see the layer + systemBuilder.addConstantLayer(FabricEnvironmentAttributesTest.TEST_COLOR, base -> TEST_COLOR); + + // Cloud color is overridden in overworld dimension, we should not see it + systemBuilder.addConstantLayer(EnvironmentAttributes.CLOUD_COLOR, base -> TEST_COLOR); + }); + + EnvironmentAttributeEvents.insertLayersEvent(AttributeLayerPosition.AFTER_ALL).register((systemBuilder, level) -> { + systemBuilder.addConstantLayer(EnvironmentAttributes.SKY_COLOR, base -> TEST_COLOR); + }); + + try (TestSingleplayerContext spContext = context.worldBuilder().create()) { + spContext.getServer().runOnServer(server -> { + ServerLevel overworld = server.getLevel(Level.OVERWORLD); + int testColor = overworld.environmentAttributes().getValue(FabricEnvironmentAttributesTest.TEST_COLOR, BlockPos.ZERO); + int cloudColor = overworld.environmentAttributes().getValue(EnvironmentAttributes.CLOUD_COLOR, BlockPos.ZERO); + int skyColor = overworld.environmentAttributes().getValue(EnvironmentAttributes.SKY_COLOR, BlockPos.ZERO); + + if (testColor != TEST_COLOR) { + throw new AssertionError("Expected test color to be (%d) but was (%d)".formatted(TEST_COLOR, testColor)); + } + + if (cloudColor == TEST_COLOR) { + throw new AssertionError("Expected cloud color to not be (%d), but it was".formatted(TEST_COLOR)); + } + + if (skyColor != TEST_COLOR) { + throw new AssertionError("Expected sky color to be (%d) but was (%d)".formatted(TEST_COLOR, skyColor)); + } + }); + } + } +} diff --git a/gradle.properties b/gradle.properties index 8a8b11b2f5c..7f479645fe9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,6 +25,7 @@ fabric-data-generation-api-v1-version=24.0.9 fabric-debug-api-v1-version=1.0.0 fabric-dimensions-v1-version=5.1.1 fabric-entity-events-v1-version=5.0.0 +fabric-environment-attributes-v0-version=1.0.0 fabric-events-interaction-v0-version=5.1.4 fabric-game-rule-api-v1-version=4.0.3 fabric-gametest-api-v1-version=4.0.6 diff --git a/settings.gradle b/settings.gradle index 8e249715bc4..edb0db1b8f6 100644 --- a/settings.gradle +++ b/settings.gradle @@ -40,6 +40,7 @@ include 'fabric-data-generation-api-v1' include 'fabric-debug-api-v1' include 'fabric-dimensions-v1' include 'fabric-entity-events-v1' +include 'fabric-environment-attributes-v0' include 'fabric-events-interaction-v0' include 'fabric-game-rule-api-v1' include 'fabric-gametest-api-v1' From 02d8b0305f1e9ac821c9a45ee8b734f7ab1b7864 Mon Sep 17 00:00:00 2001 From: Samu Date: Mon, 9 Feb 2026 15:01:26 +0100 Subject: [PATCH 02/10] Change v0 into v1 --- .../build.gradle | 0 .../attribute/v1}/AttributeLayerPosition.java | 2 +- .../attribute/v1}/EnvironmentAttributeEvents.java | 2 +- .../attribute/EnvironmentAttributeEventsImpl.java | 4 ++-- .../attribute/EnvironmentAttributeSystemMixin.java | 2 +- .../fabric-environment-attributes-v1}/icon.png | Bin .../fabric-environment-attributes-v1.mixins.json | 0 .../src/main/resources/fabric.mod.json | 8 ++++---- .../attribute/FabricEnvironmentAttributesTest.java | 0 .../src/testmod/resources/fabric.mod.json | 6 +++--- .../FabricEnvironmentAttributesClientTest.java | 4 ++-- gradle.properties | 2 +- settings.gradle | 2 +- 13 files changed, 16 insertions(+), 16 deletions(-) rename {fabric-environment-attributes-v0 => fabric-environment-attributes-v1}/build.gradle (100%) rename {fabric-environment-attributes-v0/src/main/java/net/fabricmc/fabric/api/environment/attribute/v0 => fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1}/AttributeLayerPosition.java (95%) rename {fabric-environment-attributes-v0/src/main/java/net/fabricmc/fabric/api/environment/attribute/v0 => fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1}/EnvironmentAttributeEvents.java (98%) rename {fabric-environment-attributes-v0 => fabric-environment-attributes-v1}/src/main/java/net/fabricmc/fabric/impl/environment/attribute/EnvironmentAttributeEventsImpl.java (94%) rename {fabric-environment-attributes-v0 => fabric-environment-attributes-v1}/src/main/java/net/fabricmc/fabric/mixin/environment/attribute/EnvironmentAttributeSystemMixin.java (97%) rename {fabric-environment-attributes-v0/src/main/resources/assets/fabric-environment-attributes-v0 => fabric-environment-attributes-v1/src/main/resources/assets/fabric-environment-attributes-v1}/icon.png (100%) rename fabric-environment-attributes-v0/src/main/resources/fabric-environment-attributes-v0.mixins.json => fabric-environment-attributes-v1/src/main/resources/fabric-environment-attributes-v1.mixins.json (100%) rename {fabric-environment-attributes-v0 => fabric-environment-attributes-v1}/src/main/resources/fabric.mod.json (74%) rename {fabric-environment-attributes-v0 => fabric-environment-attributes-v1}/src/testmod/java/net/fabricmc/fabric/test/environment/attribute/FabricEnvironmentAttributesTest.java (100%) rename {fabric-environment-attributes-v0 => fabric-environment-attributes-v1}/src/testmod/resources/fabric.mod.json (71%) rename {fabric-environment-attributes-v0 => fabric-environment-attributes-v1}/src/testmodClient/java/net/fabricmc/fabric/test/environment/attribute/client/FabricEnvironmentAttributesClientTest.java (96%) diff --git a/fabric-environment-attributes-v0/build.gradle b/fabric-environment-attributes-v1/build.gradle similarity index 100% rename from fabric-environment-attributes-v0/build.gradle rename to fabric-environment-attributes-v1/build.gradle diff --git a/fabric-environment-attributes-v0/src/main/java/net/fabricmc/fabric/api/environment/attribute/v0/AttributeLayerPosition.java b/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/AttributeLayerPosition.java similarity index 95% rename from fabric-environment-attributes-v0/src/main/java/net/fabricmc/fabric/api/environment/attribute/v0/AttributeLayerPosition.java rename to fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/AttributeLayerPosition.java index cbbf7cc1659..0a004a86d05 100644 --- a/fabric-environment-attributes-v0/src/main/java/net/fabricmc/fabric/api/environment/attribute/v0/AttributeLayerPosition.java +++ b/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/AttributeLayerPosition.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package net.fabricmc.fabric.api.environment.attribute.v0; +package net.fabricmc.fabric.api.environment.attribute.v1; /** * Positions at which environment attribute layers can be inserted. Each position is associated with an event in diff --git a/fabric-environment-attributes-v0/src/main/java/net/fabricmc/fabric/api/environment/attribute/v0/EnvironmentAttributeEvents.java b/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/EnvironmentAttributeEvents.java similarity index 98% rename from fabric-environment-attributes-v0/src/main/java/net/fabricmc/fabric/api/environment/attribute/v0/EnvironmentAttributeEvents.java rename to fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/EnvironmentAttributeEvents.java index 8fb8f0b4729..6738a0cb673 100644 --- a/fabric-environment-attributes-v0/src/main/java/net/fabricmc/fabric/api/environment/attribute/v0/EnvironmentAttributeEvents.java +++ b/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/EnvironmentAttributeEvents.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package net.fabricmc.fabric.api.environment.attribute.v0; +package net.fabricmc.fabric.api.environment.attribute.v1; import net.minecraft.world.attribute.EnvironmentAttributeSystem; import net.minecraft.world.level.Level; diff --git a/fabric-environment-attributes-v0/src/main/java/net/fabricmc/fabric/impl/environment/attribute/EnvironmentAttributeEventsImpl.java b/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/impl/environment/attribute/EnvironmentAttributeEventsImpl.java similarity index 94% rename from fabric-environment-attributes-v0/src/main/java/net/fabricmc/fabric/impl/environment/attribute/EnvironmentAttributeEventsImpl.java rename to fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/impl/environment/attribute/EnvironmentAttributeEventsImpl.java index f93960f5f81..7f3f255ac05 100644 --- a/fabric-environment-attributes-v0/src/main/java/net/fabricmc/fabric/impl/environment/attribute/EnvironmentAttributeEventsImpl.java +++ b/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/impl/environment/attribute/EnvironmentAttributeEventsImpl.java @@ -24,8 +24,8 @@ import net.minecraft.world.attribute.EnvironmentAttributeSystem; import net.minecraft.world.level.Level; -import net.fabricmc.fabric.api.environment.attribute.v0.AttributeLayerPosition; -import net.fabricmc.fabric.api.environment.attribute.v0.EnvironmentAttributeEvents; +import net.fabricmc.fabric.api.environment.attribute.v1.AttributeLayerPosition; +import net.fabricmc.fabric.api.environment.attribute.v1.EnvironmentAttributeEvents; import net.fabricmc.fabric.api.event.Event; import net.fabricmc.fabric.api.event.EventFactory; diff --git a/fabric-environment-attributes-v0/src/main/java/net/fabricmc/fabric/mixin/environment/attribute/EnvironmentAttributeSystemMixin.java b/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/mixin/environment/attribute/EnvironmentAttributeSystemMixin.java similarity index 97% rename from fabric-environment-attributes-v0/src/main/java/net/fabricmc/fabric/mixin/environment/attribute/EnvironmentAttributeSystemMixin.java rename to fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/mixin/environment/attribute/EnvironmentAttributeSystemMixin.java index 01f6bfe52de..3244ba41130 100644 --- a/fabric-environment-attributes-v0/src/main/java/net/fabricmc/fabric/mixin/environment/attribute/EnvironmentAttributeSystemMixin.java +++ b/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/mixin/environment/attribute/EnvironmentAttributeSystemMixin.java @@ -24,7 +24,7 @@ import net.minecraft.world.attribute.EnvironmentAttributeSystem; import net.minecraft.world.level.Level; -import net.fabricmc.fabric.api.environment.attribute.v0.AttributeLayerPosition; +import net.fabricmc.fabric.api.environment.attribute.v1.AttributeLayerPosition; import net.fabricmc.fabric.impl.environment.attribute.EnvironmentAttributeEventsImpl; @Mixin(EnvironmentAttributeSystem.class) diff --git a/fabric-environment-attributes-v0/src/main/resources/assets/fabric-environment-attributes-v0/icon.png b/fabric-environment-attributes-v1/src/main/resources/assets/fabric-environment-attributes-v1/icon.png similarity index 100% rename from fabric-environment-attributes-v0/src/main/resources/assets/fabric-environment-attributes-v0/icon.png rename to fabric-environment-attributes-v1/src/main/resources/assets/fabric-environment-attributes-v1/icon.png diff --git a/fabric-environment-attributes-v0/src/main/resources/fabric-environment-attributes-v0.mixins.json b/fabric-environment-attributes-v1/src/main/resources/fabric-environment-attributes-v1.mixins.json similarity index 100% rename from fabric-environment-attributes-v0/src/main/resources/fabric-environment-attributes-v0.mixins.json rename to fabric-environment-attributes-v1/src/main/resources/fabric-environment-attributes-v1.mixins.json diff --git a/fabric-environment-attributes-v0/src/main/resources/fabric.mod.json b/fabric-environment-attributes-v1/src/main/resources/fabric.mod.json similarity index 74% rename from fabric-environment-attributes-v0/src/main/resources/fabric.mod.json rename to fabric-environment-attributes-v1/src/main/resources/fabric.mod.json index b68ab5279dc..23d53115601 100644 --- a/fabric-environment-attributes-v0/src/main/resources/fabric.mod.json +++ b/fabric-environment-attributes-v1/src/main/resources/fabric.mod.json @@ -1,10 +1,10 @@ { "schemaVersion": 1, - "id": "fabric-environment-attributes-v0", - "name": "Fabric Environment Attributes API (v0)", + "id": "fabric-environment-attributes-v1", + "name": "Fabric Environment Attributes API (v1)", "version": "${version}", "license": "Apache-2.0", - "icon": "assets/fabric-environment-attributes-v0/icon.png", + "icon": "assets/fabric-environment-attributes-v1/icon.png", "contact" : { "homepage": "https://fabricmc.net", "irc": "irc://irc.esper.net:6667/fabric", @@ -23,7 +23,7 @@ }, "description": "Fabric Environment Attributes API.", "mixins": [ - "fabric-environment-attributes-v0.mixins.json" + "fabric-environment-attributes-v1.mixins.json" ], "custom": { "fabric-api:module-lifecycle": "stable" diff --git a/fabric-environment-attributes-v0/src/testmod/java/net/fabricmc/fabric/test/environment/attribute/FabricEnvironmentAttributesTest.java b/fabric-environment-attributes-v1/src/testmod/java/net/fabricmc/fabric/test/environment/attribute/FabricEnvironmentAttributesTest.java similarity index 100% rename from fabric-environment-attributes-v0/src/testmod/java/net/fabricmc/fabric/test/environment/attribute/FabricEnvironmentAttributesTest.java rename to fabric-environment-attributes-v1/src/testmod/java/net/fabricmc/fabric/test/environment/attribute/FabricEnvironmentAttributesTest.java diff --git a/fabric-environment-attributes-v0/src/testmod/resources/fabric.mod.json b/fabric-environment-attributes-v1/src/testmod/resources/fabric.mod.json similarity index 71% rename from fabric-environment-attributes-v0/src/testmod/resources/fabric.mod.json rename to fabric-environment-attributes-v1/src/testmod/resources/fabric.mod.json index 897dd1bb2a7..843bcd0f1d1 100644 --- a/fabric-environment-attributes-v0/src/testmod/resources/fabric.mod.json +++ b/fabric-environment-attributes-v1/src/testmod/resources/fabric.mod.json @@ -1,12 +1,12 @@ { "schemaVersion": 1, - "id": "fabric-environment-attributes-v0-testmod", - "name": "Fabric Environment Attributes (v0) Test Mod", + "id": "fabric-environment-attributes-v1-testmod", + "name": "Fabric Environment Attributes (v1) Test Mod", "version": "1.0.0", "environment": "*", "license": "Apache-2.0", "depends": { - "fabric-environment-attributes-v0": "*" + "fabric-environment-attributes-v1": "*" }, "entrypoints": { "main": [ diff --git a/fabric-environment-attributes-v0/src/testmodClient/java/net/fabricmc/fabric/test/environment/attribute/client/FabricEnvironmentAttributesClientTest.java b/fabric-environment-attributes-v1/src/testmodClient/java/net/fabricmc/fabric/test/environment/attribute/client/FabricEnvironmentAttributesClientTest.java similarity index 96% rename from fabric-environment-attributes-v0/src/testmodClient/java/net/fabricmc/fabric/test/environment/attribute/client/FabricEnvironmentAttributesClientTest.java rename to fabric-environment-attributes-v1/src/testmodClient/java/net/fabricmc/fabric/test/environment/attribute/client/FabricEnvironmentAttributesClientTest.java index 91552bc8195..743609670d2 100644 --- a/fabric-environment-attributes-v0/src/testmodClient/java/net/fabricmc/fabric/test/environment/attribute/client/FabricEnvironmentAttributesClientTest.java +++ b/fabric-environment-attributes-v1/src/testmodClient/java/net/fabricmc/fabric/test/environment/attribute/client/FabricEnvironmentAttributesClientTest.java @@ -24,8 +24,8 @@ import net.fabricmc.fabric.api.client.gametest.v1.FabricClientGameTest; import net.fabricmc.fabric.api.client.gametest.v1.context.ClientGameTestContext; import net.fabricmc.fabric.api.client.gametest.v1.context.TestSingleplayerContext; -import net.fabricmc.fabric.api.environment.attribute.v0.AttributeLayerPosition; -import net.fabricmc.fabric.api.environment.attribute.v0.EnvironmentAttributeEvents; +import net.fabricmc.fabric.api.environment.attribute.v1.AttributeLayerPosition; +import net.fabricmc.fabric.api.environment.attribute.v1.EnvironmentAttributeEvents; import net.fabricmc.fabric.test.environment.attribute.FabricEnvironmentAttributesTest; public class FabricEnvironmentAttributesClientTest implements FabricClientGameTest { diff --git a/gradle.properties b/gradle.properties index 7f479645fe9..1a3509bdeca 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,7 +25,7 @@ fabric-data-generation-api-v1-version=24.0.9 fabric-debug-api-v1-version=1.0.0 fabric-dimensions-v1-version=5.1.1 fabric-entity-events-v1-version=5.0.0 -fabric-environment-attributes-v0-version=1.0.0 +fabric-environment-attributes-v1-version=1.0.0 fabric-events-interaction-v0-version=5.1.4 fabric-game-rule-api-v1-version=4.0.3 fabric-gametest-api-v1-version=4.0.6 diff --git a/settings.gradle b/settings.gradle index edb0db1b8f6..042b4bb7640 100644 --- a/settings.gradle +++ b/settings.gradle @@ -40,7 +40,7 @@ include 'fabric-data-generation-api-v1' include 'fabric-debug-api-v1' include 'fabric-dimensions-v1' include 'fabric-entity-events-v1' -include 'fabric-environment-attributes-v0' +include 'fabric-environment-attributes-v1' include 'fabric-events-interaction-v0' include 'fabric-game-rule-api-v1' include 'fabric-gametest-api-v1' From d05868b7ad3cf285786e44cc727f2480618b126d Mon Sep 17 00:00:00 2001 From: Samu Date: Tue, 10 Feb 2026 22:11:40 +0100 Subject: [PATCH 03/10] Replace events with proper sortable registry. --- .../attribute/v1/AttributeLayerPosition.java | 48 --- .../attribute/v1/AttributeLayerProvider.java | 84 ++++++ .../attribute/v1/AttributeLayerRegistry.java | 50 ++++ .../v1/EnvironmentAttributeEvents.java | 64 ---- .../attribute/AttributeLayerRegistryImpl.java | 274 ++++++++++++++++++ .../EnvironmentAttributeEventsImpl.java | 55 ---- .../EnvironmentAttributeSystemMixin.java | 15 +- ...FabricEnvironmentAttributesClientTest.java | 15 +- 8 files changed, 426 insertions(+), 179 deletions(-) delete mode 100644 fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/AttributeLayerPosition.java create mode 100644 fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/AttributeLayerProvider.java create mode 100644 fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/AttributeLayerRegistry.java delete mode 100644 fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/EnvironmentAttributeEvents.java create mode 100644 fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/impl/environment/attribute/AttributeLayerRegistryImpl.java delete mode 100644 fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/impl/environment/attribute/EnvironmentAttributeEventsImpl.java diff --git a/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/AttributeLayerPosition.java b/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/AttributeLayerPosition.java deleted file mode 100644 index 0a004a86d05..00000000000 --- a/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/AttributeLayerPosition.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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.environment.attribute.v1; - -/** - * Positions at which environment attribute layers can be inserted. Each position is associated with an event in - * {@link EnvironmentAttributeEvents}. The enum is ordered by in which order Minecraft adds its default layers. - */ -public enum AttributeLayerPosition { - /** - * The position before all vanilla layers. - */ - BEFORE_ALL, - - /** - * The position between dimension and biome layers. - */ - BETWEEN_DIMENSION_AND_BIOMES, - - /** - * The position between biome and timeline layers. - */ - BETWEEN_BIOMES_AND_TIMELINES, - - /** - * The position between timeline and weather layers. - */ - BETWEEN_TIMELINES_AND_WEATHER, - - /** - * The position after all vanilla layers. - */ - AFTER_ALL -} diff --git a/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/AttributeLayerProvider.java b/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/AttributeLayerProvider.java new file mode 100644 index 00000000000..422ab0f7686 --- /dev/null +++ b/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/AttributeLayerProvider.java @@ -0,0 +1,84 @@ +/* + * 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.environment.attribute.v1; + +import net.minecraft.resources.Identifier; +import net.minecraft.world.attribute.EnvironmentAttributeLayer; +import net.minecraft.world.attribute.EnvironmentAttributeSystem; +import net.minecraft.world.level.Level; + +/** + * Provides {@link EnvironmentAttributeLayer}s to an {@link EnvironmentAttributeSystem}. You may register custom + * {@link AttributeLayerProvider} implementations using {@link AttributeLayerRegistry#registerLayerProvider}. + * + *

+ * Attribute layers can be ordered relative to vanilla's layers or other modded layers using + * {@link AttributeLayerRegistry#addLayerOrdering}. The order defines which layers override which other layers: layers + * that come first in the ordering are overriden by layers that come later in the ordering. For example, in vanilla, + * biome layers come after dimension layers, since biome-local attributes override dimension-global attributes. + *

+ * + *

+ * Minecraft adds layers in four phases: dimension-global attributes, then biome-local attributes, then + * timeline-interpolated attributes, and finally some hardcoded weather attributes. Each of these phases, as well modded + * layer providers, are associated with an identifier that can be sorted against. + *

+ */ +public interface AttributeLayerProvider { + /** + * Identifier associated to vanilla's dimension attribute layers. + */ + Identifier DIMENSION = Identifier.withDefaultNamespace("dimensions"); + + /** + * Identifier associated to vanilla's biome attribute layers. + */ + Identifier BIOMES = Identifier.withDefaultNamespace("biomes"); + + /** + * Identifier associated to vanilla's timeline attribute layers. + */ + Identifier TIMELINES = Identifier.withDefaultNamespace("timelines"); + + /** + * Identifier associated to vanilla's weather attribute layers. + */ + Identifier WEATHER = Identifier.withDefaultNamespace("weather"); + + /** + * The identifier associated to the first vanilla phase. Currently, that is {@link #DIMENSION}. + * This constant exists purely for compatibility: if Minecraft ever adds another layer before its dimension phase, + * then this constant is updated. + */ + Identifier FIRST_VANILLA_PHASE = DIMENSION; + + /** + * The identifier associated to the last vanilla phase. Currently, that is {@link #WEATHER}. + * This constant exists purely for compatibility: if Minecraft ever adds another layer after its weather phase, + * then this constant is updated. + */ + Identifier LAST_VANILLA_PHASE = WEATHER; + + /** + * Called to add attribute layers to an {@link EnvironmentAttributeSystem.Builder} for the given {@link Level}. + * This is called both on the client and on the server for every {@link Level} that is created. + * + * @param systemBuilder The {@link EnvironmentAttributeSystem.Builder} to add layers to. + * @param level The {@link Level} that the environment attribute system is being created for. + */ + void addAttributeLayers(EnvironmentAttributeSystem.Builder systemBuilder, Level level); +} diff --git a/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/AttributeLayerRegistry.java b/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/AttributeLayerRegistry.java new file mode 100644 index 00000000000..bda6521402a --- /dev/null +++ b/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/AttributeLayerRegistry.java @@ -0,0 +1,50 @@ +/* + * 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.environment.attribute.v1; + +import org.jspecify.annotations.NullMarked; + +import net.minecraft.resources.Identifier; + +import net.fabricmc.fabric.impl.environment.attribute.AttributeLayerRegistryImpl; + +@NullMarked +public class AttributeLayerRegistry { + /** + * Register a {@link AttributeLayerProvider}. If a layer with the given identifier already exists, an exception + * is thrown. + * + * @param id The identifier of the layer provider. This can be ordered against by other layer providers. + * @param layer The layer provider to register. + */ + public static void registerLayerProvider(Identifier id, AttributeLayerProvider layer) { + AttributeLayerRegistryImpl.registerLayerProvider(id, layer); + } + + /** + * Declares that the layer provider with the first identifier should activate before the layer provider with the + * second identifier. Unless this causes a cyclic dependency, the two layer providers are guaranteed to activate in + * said order. You may use this to order your layer provider against vanilla phases using any of the constants in + * {@link AttributeLayerProvider}. If both layer identifiers are the same, then an exception is thrown. + * + * @param firstLayer The ID of the layer that should activate earlier. + * @param secondLayer The ID of the layer that should activate later. + */ + public static void addLayerOrdering(Identifier firstLayer, Identifier secondLayer) { + AttributeLayerRegistryImpl.addLayerOrdering(firstLayer, secondLayer); + } +} diff --git a/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/EnvironmentAttributeEvents.java b/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/EnvironmentAttributeEvents.java deleted file mode 100644 index 6738a0cb673..00000000000 --- a/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/EnvironmentAttributeEvents.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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.environment.attribute.v1; - -import net.minecraft.world.attribute.EnvironmentAttributeSystem; -import net.minecraft.world.level.Level; - -import net.fabricmc.fabric.api.event.Event; -import net.fabricmc.fabric.impl.environment.attribute.EnvironmentAttributeEventsImpl; - -/** - * Events related to environment attributes. - */ -public class EnvironmentAttributeEvents { - /** - * Returns the {@link InsertLayers} event for the given {@link AttributeLayerPosition}. This event allows inserting - * extra attribute layers at that position during the environment attribute setup for a {@link Level}. By default, - * Minecraft adds layers for the dimension, then for biomes, then for timelines and lastly for weather. The event - * returned by this method is triggered before, in between and after each of these vanilla layers, depending on the - * selected position, in the following manner: - *
    - *
  • Event for {@link AttributeLayerPosition#BEFORE_ALL} is triggered.
  • - *
  • Minecraft adds the layer for dimension type attribute configurations.
  • - *
  • Event for {@link AttributeLayerPosition#BETWEEN_DIMENSION_AND_BIOMES} is triggered.
  • - *
  • Minecraft adds the layer for biome attribute configurations.
  • - *
  • Event for {@link AttributeLayerPosition#BETWEEN_BIOMES_AND_TIMELINES} is triggered.
  • - *
  • Minecraft adds the layer for timeline attribute animations.
  • - *
  • Event for {@link AttributeLayerPosition#BETWEEN_TIMELINES_AND_WEATHER} is triggered.
  • - *
  • Minecraft adds the layer for some hardcoded weather attribute overrides.
  • - *
  • Event for {@link AttributeLayerPosition#AFTER_ALL} is triggered.
  • - *
- * @param position The position at which you want to insert attribute layers. - * @return The event to listen for layer setup. - */ - public static Event insertLayersEvent(AttributeLayerPosition position) { - return EnvironmentAttributeEventsImpl.getOrCreateInsertLayersEvent(position); - } - - /** - * Callback for events returned from {@link #insertLayersEvent}. - */ - public interface InsertLayers { - /** - * Insert custom attribute layers into the {@link EnvironmentAttributeSystem.Builder}. - * @param systemBuilder The environment attribute system builder to modify. - * @param level The level for which the attribute system is built. - */ - void insertAttributeLayers(EnvironmentAttributeSystem.Builder systemBuilder, Level level); - } -} diff --git a/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/impl/environment/attribute/AttributeLayerRegistryImpl.java b/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/impl/environment/attribute/AttributeLayerRegistryImpl.java new file mode 100644 index 00000000000..0433e2107c6 --- /dev/null +++ b/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/impl/environment/attribute/AttributeLayerRegistryImpl.java @@ -0,0 +1,274 @@ +/* + * 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.impl.environment.attribute; + +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import net.minecraft.resources.Identifier; +import net.minecraft.world.attribute.EnvironmentAttributeSystem; +import net.minecraft.world.level.Level; + +import net.fabricmc.fabric.api.environment.attribute.v1.AttributeLayerProvider; +import net.fabricmc.fabric.impl.base.toposort.NodeSorting; +import net.fabricmc.fabric.impl.base.toposort.SortableNode; + +public class AttributeLayerRegistryImpl { + // Markes for each vanilla phase. Used to ensure vanilla ordering remains the same. + private static final Map MARKERS = Map.copyOf(Stream.of(VanillaLayerMarker.values()) + .collect(Collectors.toMap(marker -> marker.id, marker -> marker))); + + private static final Map LAYER_MAP = new HashMap<>(); + private static final Set DEPENDENCIES = new HashSet<>(); + + // Lock used to ensure thread safety. + private static final Object LOCK = new Object(); + + // As long as this is true, we skip sorting and inserting layers all together. + // Becomes false once a modded layer is registered. + private static volatile boolean hasOnlyVanillaLayers; + + // As long as this is true, the ordering in the fields below is valid. + // Becomes false once a modded layer is registered or once a depencency order is added. + private static volatile boolean orderValid; + + // Layers that should go before vanilla layers. + private static final List FIRST_PHASES = new ArrayList<>(); + + // Layers that should go in between or after vanilla layers. + private static final Map> AFTER_VANILLA_PHASES = new EnumMap<>(VanillaLayerMarker.class); + + static { + // Initialize sorted phase lists + for (VanillaLayerMarker layer : VanillaLayerMarker.values()) { + AFTER_VANILLA_PHASES.put(layer, new ArrayList<>()); + } + + // Register vanilla ordering + registerLayerProvider(AttributeLayerProvider.DIMENSION, VanillaLayerMarker.DIMENSION); + registerLayerProvider(AttributeLayerProvider.BIOMES, VanillaLayerMarker.BIOMES); + registerLayerProvider(AttributeLayerProvider.TIMELINES, VanillaLayerMarker.TIMELINES); + registerLayerProvider(AttributeLayerProvider.WEATHER, VanillaLayerMarker.WEATHER); + + addLayerOrdering(AttributeLayerProvider.DIMENSION, AttributeLayerProvider.BIOMES); + addLayerOrdering(AttributeLayerProvider.BIOMES, AttributeLayerProvider.TIMELINES); + addLayerOrdering(AttributeLayerProvider.TIMELINES, AttributeLayerProvider.WEATHER); + + // Validate cache + hasOnlyVanillaLayers = true; // Set to true here because registerLayerProvider used above sets it to false + orderValid = true; // Vanilla layers are not included in sorted phase lists + } + + public static void registerLayerProvider(Identifier id, AttributeLayerProvider layer) { + Objects.requireNonNull(id, "The layer identifier should not be null."); + Objects.requireNonNull(layer, "The layer should not be null."); + + if (LAYER_MAP.containsKey(id)) { + throw new IllegalArgumentException("Layer with ID %s was already registered.".formatted(id)); + } + + synchronized (LOCK) { + LAYER_MAP.put(id, layer); + orderValid = false; + hasOnlyVanillaLayers = false; + } + } + + public static void addLayerOrdering(Identifier firstLayer, Identifier secondLayer) { + Objects.requireNonNull(firstLayer, "The first layer identifier should not be null."); + Objects.requireNonNull(secondLayer, "The second layer identifier should not be null."); + + if (firstLayer.equals(secondLayer)) { + throw new IllegalArgumentException("Tried to add a layer that depends on itself."); + } + + synchronized (LOCK) { + if (DEPENDENCIES.add(new Dependency(firstLayer, secondLayer))) { + // Adding a dependency only affects order if both IDs are associated with registered layers. + // Dependencies with missing registrations are simply ignored during sorting. + + if (LAYER_MAP.containsKey(firstLayer) && LAYER_MAP.containsKey(secondLayer)) { + orderValid = false; + } + } + } + } + + private static void addLayers(List providers, EnvironmentAttributeSystem.Builder systemBuilder, Level level) { + synchronized (LOCK) { + for (AttributeLayerProvider provider : providers) { + provider.addAttributeLayers(systemBuilder, level); + } + } + } + + public static void addPreEverythingLayers(EnvironmentAttributeSystem.Builder systemBuilder, Level level) { + if (!hasOnlyVanillaLayers) { + sortIfNeeded(); + addLayers(FIRST_PHASES, systemBuilder, level); + } + } + + public static void addPostDimensionLayers(EnvironmentAttributeSystem.Builder systemBuilder, Level level) { + if (!hasOnlyVanillaLayers) { + sortIfNeeded(); + addLayers(AFTER_VANILLA_PHASES.get(VanillaLayerMarker.DIMENSION), systemBuilder, level); + } + } + + public static void addPostBiomesLayers(EnvironmentAttributeSystem.Builder systemBuilder, Level level) { + if (!hasOnlyVanillaLayers) { + sortIfNeeded(); + addLayers(AFTER_VANILLA_PHASES.get(VanillaLayerMarker.BIOMES), systemBuilder, level); + } + } + + public static void addPostTimelinesLayers(EnvironmentAttributeSystem.Builder systemBuilder, Level level) { + if (!hasOnlyVanillaLayers) { + sortIfNeeded(); + addLayers(AFTER_VANILLA_PHASES.get(VanillaLayerMarker.TIMELINES), systemBuilder, level); + } + } + + public static void addPostWeatherLayers(EnvironmentAttributeSystem.Builder systemBuilder, Level level) { + if (!hasOnlyVanillaLayers) { + sortIfNeeded(); + addLayers(AFTER_VANILLA_PHASES.get(VanillaLayerMarker.WEATHER), systemBuilder, level); + } + } + + private static void sortIfNeeded() { + Map layers; + + // Collect sorting data from registry + synchronized (LOCK) { + if (orderValid) { + return; + } + + layers = new HashMap<>(); + + for (Map.Entry entry : LAYER_MAP.entrySet()) { + layers.put(entry.getKey(), new Layer(entry.getKey(), entry.getValue())); + } + + for (Dependency dependency : DEPENDENCIES) { + Layer firstLayer = layers.get(dependency.firstLayer()); + Layer secondLayer = layers.get(dependency.secondLayer()); + + if (firstLayer != null && secondLayer != null) { + Layer.link(firstLayer, secondLayer); + } + } + } + + // Sort layers + List sorted = new ArrayList<>(layers.values()); + NodeSorting.sort(sorted, "environment attribute layers", AttributeLayerRegistryImpl::compareIds); + + // Categorize layer providers into vanilla phases + synchronized (LOCK) { + FIRST_PHASES.clear(); + AFTER_VANILLA_PHASES.forEach((_, list) -> list.clear()); + + List phase = FIRST_PHASES; + + for (Layer layer : sorted) { + AttributeLayerProvider provider = layer.provider; + + if (provider instanceof VanillaLayerMarker marker) { + phase = AFTER_VANILLA_PHASES.get(marker); + } else { + phase.add(provider); + } + } + } + } + + // Tiebreaker: put vanilla layers before others, and otherwise sort by lexicographic ordering + // This also makes sure that layers that were not tied to vanilla ordering will come last in the ordering + private static int compareIds(Layer a, Layer b) { + Identifier idA = a.id; + Identifier idB = b.id; + + VanillaLayerMarker markerA = MARKERS.get(idA); + VanillaLayerMarker markerB = MARKERS.get(idB); + + // If both are vanilla layers, ensure they remain the same order as defined by Minecraft + if (markerA != null && markerB != null) { + return markerA.compareTo(markerB); + } + + // If one of them is a vanilla layer and the other is not, then put the vanilla layer first + if (markerA != null) { + return -1; + } + + if (markerB != null) { + return 1; + } + + // Otherwise just mess with the mod devs that like their mod IDs to start with an A + return idA.compareTo(idB); + } + + // Markers for vanilla layers. It's important that these enum constants stay in the order that vanilla layers should appear, + // since this order will be used to fix dependency cycles (and we don't want a dependency cycle to mess up the order). + private enum VanillaLayerMarker implements AttributeLayerProvider { + DIMENSION(AttributeLayerProvider.DIMENSION), + BIOMES(AttributeLayerProvider.BIOMES), + TIMELINES(AttributeLayerProvider.TIMELINES), + WEATHER(AttributeLayerProvider.WEATHER); + + final Identifier id; + + VanillaLayerMarker(Identifier id) { + this.id = id; + } + + @Override + public void addAttributeLayers(EnvironmentAttributeSystem.Builder systemBuilder, Level level) { + // N/A, done through mixin + } + } + + private static class Layer extends SortableNode { + private final Identifier id; + private final AttributeLayerProvider provider; + + private Layer(Identifier id, AttributeLayerProvider provider) { + this.id = id; + this.provider = provider; + } + + @Override + protected String getDescription() { + return id.toString(); + } + } + + private record Dependency(Identifier firstLayer, Identifier secondLayer) { + } +} diff --git a/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/impl/environment/attribute/EnvironmentAttributeEventsImpl.java b/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/impl/environment/attribute/EnvironmentAttributeEventsImpl.java deleted file mode 100644 index 7f3f255ac05..00000000000 --- a/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/impl/environment/attribute/EnvironmentAttributeEventsImpl.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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.impl.environment.attribute; - -import java.util.EnumMap; -import java.util.Map; - -import org.jspecify.annotations.NonNull; - -import net.minecraft.world.attribute.EnvironmentAttributeSystem; -import net.minecraft.world.level.Level; - -import net.fabricmc.fabric.api.environment.attribute.v1.AttributeLayerPosition; -import net.fabricmc.fabric.api.environment.attribute.v1.EnvironmentAttributeEvents; -import net.fabricmc.fabric.api.event.Event; -import net.fabricmc.fabric.api.event.EventFactory; - -public class EnvironmentAttributeEventsImpl { - private static final Map> POSITION_EVENT_MAP = new EnumMap<>(AttributeLayerPosition.class); - - @NonNull - public static Event getOrCreateInsertLayersEvent(AttributeLayerPosition position) { - return POSITION_EVENT_MAP.computeIfAbsent(position, (p -> createInsertEvent())); - } - - public static void insertLayers(AttributeLayerPosition position, EnvironmentAttributeSystem.Builder systemBuilder, Level level) { - Event event = POSITION_EVENT_MAP.get(position); - - if (event != null) { - event.invoker().insertAttributeLayers(systemBuilder, level); - } - } - - private static Event createInsertEvent() { - return EventFactory.createArrayBacked(EnvironmentAttributeEvents.InsertLayers.class, callbacks -> (systemBuilder, level) -> { - for (EnvironmentAttributeEvents.InsertLayers callback : callbacks) { - callback.insertAttributeLayers(systemBuilder, level); - } - }); - } -} diff --git a/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/mixin/environment/attribute/EnvironmentAttributeSystemMixin.java b/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/mixin/environment/attribute/EnvironmentAttributeSystemMixin.java index 3244ba41130..2afd529e377 100644 --- a/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/mixin/environment/attribute/EnvironmentAttributeSystemMixin.java +++ b/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/mixin/environment/attribute/EnvironmentAttributeSystemMixin.java @@ -24,8 +24,7 @@ import net.minecraft.world.attribute.EnvironmentAttributeSystem; import net.minecraft.world.level.Level; -import net.fabricmc.fabric.api.environment.attribute.v1.AttributeLayerPosition; -import net.fabricmc.fabric.impl.environment.attribute.EnvironmentAttributeEventsImpl; +import net.fabricmc.fabric.impl.environment.attribute.AttributeLayerRegistryImpl; @Mixin(EnvironmentAttributeSystem.class) public class EnvironmentAttributeSystemMixin { @@ -34,7 +33,7 @@ public class EnvironmentAttributeSystemMixin { at = @At(value = "HEAD") ) private static void addLayersBeforeAll(EnvironmentAttributeSystem.Builder builder, Level level, CallbackInfo ci) { - EnvironmentAttributeEventsImpl.insertLayers(AttributeLayerPosition.BEFORE_ALL, builder, level); + AttributeLayerRegistryImpl.addPreEverythingLayers(builder, level); } @Inject( @@ -42,7 +41,7 @@ private static void addLayersBeforeAll(EnvironmentAttributeSystem.Builder builde at = @At(value = "INVOKE", target = "Lnet/minecraft/world/attribute/EnvironmentAttributeSystem;addBiomeLayer(Lnet/minecraft/world/attribute/EnvironmentAttributeSystem$Builder;Lnet/minecraft/core/HolderLookup;Lnet/minecraft/world/level/biome/BiomeManager;)V") ) private static void addLayersAfterDimension(EnvironmentAttributeSystem.Builder builder, Level level, CallbackInfo ci) { - EnvironmentAttributeEventsImpl.insertLayers(AttributeLayerPosition.BETWEEN_DIMENSION_AND_BIOMES, builder, level); + AttributeLayerRegistryImpl.addPostDimensionLayers(builder, level); } @Inject( @@ -50,7 +49,7 @@ private static void addLayersAfterDimension(EnvironmentAttributeSystem.Builder b at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;dimensionType()Lnet/minecraft/world/level/dimension/DimensionType;") ) private static void addLayersAfterBiomes(EnvironmentAttributeSystem.Builder builder, Level level, CallbackInfo ci) { - EnvironmentAttributeEventsImpl.insertLayers(AttributeLayerPosition.BETWEEN_BIOMES_AND_TIMELINES, builder, level); + AttributeLayerRegistryImpl.addPostBiomesLayers(builder, level); } @Inject( @@ -58,14 +57,14 @@ private static void addLayersAfterBiomes(EnvironmentAttributeSystem.Builder buil at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;canHaveWeather()Z") ) private static void addLayersAfterTimelines(EnvironmentAttributeSystem.Builder builder, Level level, CallbackInfo ci) { - EnvironmentAttributeEventsImpl.insertLayers(AttributeLayerPosition.BETWEEN_TIMELINES_AND_WEATHER, builder, level); + AttributeLayerRegistryImpl.addPostTimelinesLayers(builder, level); } @Inject( method = "addDefaultLayers", at = @At(value = "TAIL") ) - private static void addLayersAfterAll(EnvironmentAttributeSystem.Builder builder, Level level, CallbackInfo ci) { - EnvironmentAttributeEventsImpl.insertLayers(AttributeLayerPosition.AFTER_ALL, builder, level); + private static void addLayersAfterWeather(EnvironmentAttributeSystem.Builder builder, Level level, CallbackInfo ci) { + AttributeLayerRegistryImpl.addPostWeatherLayers(builder, level); } } diff --git a/fabric-environment-attributes-v1/src/testmodClient/java/net/fabricmc/fabric/test/environment/attribute/client/FabricEnvironmentAttributesClientTest.java b/fabric-environment-attributes-v1/src/testmodClient/java/net/fabricmc/fabric/test/environment/attribute/client/FabricEnvironmentAttributesClientTest.java index 743609670d2..c74845bd149 100644 --- a/fabric-environment-attributes-v1/src/testmodClient/java/net/fabricmc/fabric/test/environment/attribute/client/FabricEnvironmentAttributesClientTest.java +++ b/fabric-environment-attributes-v1/src/testmodClient/java/net/fabricmc/fabric/test/environment/attribute/client/FabricEnvironmentAttributesClientTest.java @@ -17,6 +17,7 @@ package net.fabricmc.fabric.test.environment.attribute.client; import net.minecraft.core.BlockPos; +import net.minecraft.resources.Identifier; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.attribute.EnvironmentAttributes; import net.minecraft.world.level.Level; @@ -24,16 +25,19 @@ import net.fabricmc.fabric.api.client.gametest.v1.FabricClientGameTest; import net.fabricmc.fabric.api.client.gametest.v1.context.ClientGameTestContext; import net.fabricmc.fabric.api.client.gametest.v1.context.TestSingleplayerContext; -import net.fabricmc.fabric.api.environment.attribute.v1.AttributeLayerPosition; -import net.fabricmc.fabric.api.environment.attribute.v1.EnvironmentAttributeEvents; +import net.fabricmc.fabric.api.environment.attribute.v1.AttributeLayerProvider; +import net.fabricmc.fabric.api.environment.attribute.v1.AttributeLayerRegistry; import net.fabricmc.fabric.test.environment.attribute.FabricEnvironmentAttributesTest; public class FabricEnvironmentAttributesClientTest implements FabricClientGameTest { public static final int TEST_COLOR = 0xFFFF00FF; + private static final Identifier BEFORE_ALL = Identifier.fromNamespaceAndPath("fabric", "before_all"); + private static final Identifier AFTER_ALL = Identifier.fromNamespaceAndPath("fabric", "after_all"); + @Override public void runTest(ClientGameTestContext context) { - EnvironmentAttributeEvents.insertLayersEvent(AttributeLayerPosition.BEFORE_ALL).register((systemBuilder, level) -> { + AttributeLayerRegistry.registerLayerProvider(BEFORE_ALL, (systemBuilder, level) -> { // Test color is not overridden in any way, we should see the layer systemBuilder.addConstantLayer(FabricEnvironmentAttributesTest.TEST_COLOR, base -> TEST_COLOR); @@ -41,10 +45,13 @@ public void runTest(ClientGameTestContext context) { systemBuilder.addConstantLayer(EnvironmentAttributes.CLOUD_COLOR, base -> TEST_COLOR); }); - EnvironmentAttributeEvents.insertLayersEvent(AttributeLayerPosition.AFTER_ALL).register((systemBuilder, level) -> { + AttributeLayerRegistry.registerLayerProvider(AFTER_ALL, (systemBuilder, level) -> { systemBuilder.addConstantLayer(EnvironmentAttributes.SKY_COLOR, base -> TEST_COLOR); }); + AttributeLayerRegistry.addLayerOrdering(BEFORE_ALL, AttributeLayerProvider.FIRST_VANILLA_PHASE); + AttributeLayerRegistry.addLayerOrdering(AttributeLayerProvider.LAST_VANILLA_PHASE, AFTER_ALL); + try (TestSingleplayerContext spContext = context.worldBuilder().create()) { spContext.getServer().runOnServer(server -> { ServerLevel overworld = server.getLevel(Level.OVERWORLD); From 14e89bcc54b93fb607ca0709ac8efff2ec9e1c35 Mon Sep 17 00:00:00 2001 From: Samu Date: Tue, 3 Mar 2026 14:03:57 +0100 Subject: [PATCH 04/10] Be more consistent with terms used in docs and code --- .../attribute/v1/AttributeLayerProvider.java | 93 ++++++++++++++----- .../attribute/v1/AttributeLayerRegistry.java | 18 ++-- .../attribute/AttributeLayerRegistryImpl.java | 12 +-- ...FabricEnvironmentAttributesClientTest.java | 4 +- 4 files changed, 90 insertions(+), 37 deletions(-) diff --git a/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/AttributeLayerProvider.java b/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/AttributeLayerProvider.java index 422ab0f7686..b90236af362 100644 --- a/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/AttributeLayerProvider.java +++ b/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/AttributeLayerProvider.java @@ -23,59 +23,108 @@ /** * Provides {@link EnvironmentAttributeLayer}s to an {@link EnvironmentAttributeSystem}. You may register custom - * {@link AttributeLayerProvider} implementations using {@link AttributeLayerRegistry#registerLayerProvider}. + * {@link AttributeLayerProvider} implementations using {@link AttributeLayerRegistry#registerLayerProvider}. Using + * {@link AttributeLayerProvider}, you can implement custom logic for modify and overriding attributes, based on + * things like weather, location or time. You can set restrictions on when your layer provider should apply in relation + * to vanilla providers or other modded providers using {@link AttributeLayerRegistry#addProviderOrdering} + * + *

Background

* *

- * Attribute layers can be ordered relative to vanilla's layers or other modded layers using - * {@link AttributeLayerRegistry#addLayerOrdering}. The order defines which layers override which other layers: layers - * that come first in the ordering are overriden by layers that come later in the ordering. For example, in vanilla, - * biome layers come after dimension layers, since biome-local attributes override dimension-global attributes. + * The {@link EnvironmentAttributeSystem} assigns zero or more layers to every environment attribute. A layer here is + * represented by a {@link EnvironmentAttributeLayer}. Layers modify or + * override the value of an environment attribute by some implementation-specific logic. In vanilla Minecraft, defining an + * environment attribute in a dimension type, biome or timeline will cause a layer for that attribute to be added that + * modifies the attribute accordingly. *

* *

- * Minecraft adds layers in four phases: dimension-global attributes, then biome-local attributes, then - * timeline-interpolated attributes, and finally some hardcoded weather attributes. Each of these phases, as well modded - * layer providers, are associated with an identifier that can be sorted against. + * Minecraft creates an {@link EnvironmentAttributeSystem} for each {@link Level}, both on the client and the server, + * and adds layers to this system through four different providers: + *

    + *
  1. Dimension type overrides: a layer is added for each attribute defined in the dimension type of the {@link Level}.
  2. + *
  3. Biome overrides: if one or more biomes define an attribute, a layer is added for that attribute that alters the + * attribute throughout different biomes.
  4. + *
  5. Timeline overrides: if one or more timelines define an attribute, a layer isadded for that attribute that alters + * the attribute according to how the timeline defines it.
  6. + *
  7. Weather overrides: if the {@link Level} {@linkplain Level#canHaveWeather() has weather}, Minecraft defines some + * hardcoded weather layers for weather for some attributes.
  8. + *
+ * Each layer is given the value outputted by the previous layer, and must modify or replace + * this value based on some context parameters. The first layer is given the default value of the attribute. + *

+ * + *

Adding modded layers

+ * + *

+ * As mentioned, the {@link AttributeLayerProvider} allows you to add modded layers to environment attributes during + * the creation of the {@link EnvironmentAttributeSystem}. Every provider is associated to an {@link Identifier}, + * including vanilla's providers (despite that vanilla's providers are not implemented as separate classes). + * As order matters, attribute layers can be ordered relative to vanilla's layers or other modded layers using + * {@link AttributeLayerRegistry#addProviderOrdering}. *

+ * + *

+ * Depending on the type of {@link EnvironmentAttributeLayer}, Minecraft caches values of environment attributes. Minecraft + * allows three different types of layers: + *

    + *
  • {@linkplain EnvironmentAttributeLayer.Constant Constant layers}: these modify the value in a context-independent + * manner. Minecraft uses these for dimensions and expects them to be constant - do not depend on external variables + * when implementing constant layers. If an attribute has only constant layers, the attribute value is simply cached and + * never recomputed again. Minecraft uses constant layers to provide a dimension's attribute values.
  • + *
  • {@linkplain EnvironmentAttributeLayer.Positional Positional layers}: these modify the value based on a position + * in the world. If a positional layer is added to an attribute, Minecraft will recompute the value every time. + * Minecraft uses positional layers for biome interpolated attribute values. Note that environment attributes can be + * sampled without a position. In this case, positional layers are completely ignored.
  • + *
  • {@linkplain EnvironmentAttributeLayer.TimeBased Time based layers}: these modify the value based on time. + * Minecraft will cache the value per tick, so that if it is sampled multiple times per tick, it is only evaluated once. + * Minecraft uses time based layers for timelines and weather.
  • + *
+ * It is important that modded implementations take into account the constraints of different layer types, otherwise + * they may not work properly. + *

+ * */ public interface AttributeLayerProvider { /** - * Identifier associated to vanilla's dimension attribute layers. + * Identifier associated to vanilla's dimension attribute layer provider. */ - Identifier DIMENSION = Identifier.withDefaultNamespace("dimensions"); + Identifier DIMENSIONS = Identifier.withDefaultNamespace("dimensions"); /** - * Identifier associated to vanilla's biome attribute layers. + * Identifier associated to vanilla's biome attribute layer provider. */ Identifier BIOMES = Identifier.withDefaultNamespace("biomes"); /** - * Identifier associated to vanilla's timeline attribute layers. + * Identifier associated to vanilla's timeline attribute layer provider. */ Identifier TIMELINES = Identifier.withDefaultNamespace("timelines"); /** - * Identifier associated to vanilla's weather attribute layers. + * Identifier associated to vanilla's weather attribute layer provider. */ Identifier WEATHER = Identifier.withDefaultNamespace("weather"); /** - * The identifier associated to the first vanilla phase. Currently, that is {@link #DIMENSION}. - * This constant exists purely for compatibility: if Minecraft ever adds another layer before its dimension phase, - * then this constant is updated. + * The identifier associated to the first vanilla provider. Currently, this is an alias for {@link #DIMENSIONS}. + * This constant exists purely for compatibility: if Minecraft ever adds another provider before its dimension provider, + * then this constant is updated so that mods can guarantee that their layer provider activates before all + * vanilla providers. */ - Identifier FIRST_VANILLA_PHASE = DIMENSION; + Identifier FIRST_VANILLA_PROVIDER = DIMENSIONS; /** - * The identifier associated to the last vanilla phase. Currently, that is {@link #WEATHER}. - * This constant exists purely for compatibility: if Minecraft ever adds another layer after its weather phase, - * then this constant is updated. + * The identifier associated to the last vanilla provider. Currently, this is an alias for {@link #WEATHER}. + * This constant exists purely for compatibility: if Minecraft ever adds another provider after its weather provider, + * then this constant is updated so that mods can guarantee that their layer provider activates after all + * vanilla providers. */ - Identifier LAST_VANILLA_PHASE = WEATHER; + Identifier LAST_VANILLA_PROVIDER = WEATHER; /** * Called to add attribute layers to an {@link EnvironmentAttributeSystem.Builder} for the given {@link Level}. - * This is called both on the client and on the server for every {@link Level} that is created. + * This is called both on the client and on the server each time a {@link Level} is initialized. * * @param systemBuilder The {@link EnvironmentAttributeSystem.Builder} to add layers to. * @param level The {@link Level} that the environment attribute system is being created for. diff --git a/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/AttributeLayerRegistry.java b/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/AttributeLayerRegistry.java index bda6521402a..37ec784cf76 100644 --- a/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/AttributeLayerRegistry.java +++ b/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/AttributeLayerRegistry.java @@ -22,13 +22,17 @@ import net.fabricmc.fabric.impl.environment.attribute.AttributeLayerRegistryImpl; +/** + * Utility class allowing you to register and reorder {@link AttributeLayerProvider}s. + */ @NullMarked public class AttributeLayerRegistry { /** - * Register a {@link AttributeLayerProvider}. If a layer with the given identifier already exists, an exception + * Register a {@link AttributeLayerProvider}. If a layer provider with the given identifier already exists, an exception * is thrown. * - * @param id The identifier of the layer provider. This can be ordered against by other layer providers. + * @param id The identifier of the layer provider. This identifier can be used to set an ordering via + * {@link #addProviderOrdering}. . * @param layer The layer provider to register. */ public static void registerLayerProvider(Identifier id, AttributeLayerProvider layer) { @@ -38,13 +42,13 @@ public static void registerLayerProvider(Identifier id, AttributeLayerProvider l /** * Declares that the layer provider with the first identifier should activate before the layer provider with the * second identifier. Unless this causes a cyclic dependency, the two layer providers are guaranteed to activate in - * said order. You may use this to order your layer provider against vanilla phases using any of the constants in + * said order. You may use this to order your layer provider against vanilla layer providers using any of the constants in * {@link AttributeLayerProvider}. If both layer identifiers are the same, then an exception is thrown. * - * @param firstLayer The ID of the layer that should activate earlier. - * @param secondLayer The ID of the layer that should activate later. + * @param firstLayer The ID of the layer provider that should activate earlier. + * @param secondLayer The ID of the layer provider that should activate later. */ - public static void addLayerOrdering(Identifier firstLayer, Identifier secondLayer) { - AttributeLayerRegistryImpl.addLayerOrdering(firstLayer, secondLayer); + public static void addProviderOrdering(Identifier firstLayer, Identifier secondLayer) { + AttributeLayerRegistryImpl.addProviderOrdering(firstLayer, secondLayer); } } diff --git a/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/impl/environment/attribute/AttributeLayerRegistryImpl.java b/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/impl/environment/attribute/AttributeLayerRegistryImpl.java index 0433e2107c6..a5c0db69668 100644 --- a/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/impl/environment/attribute/AttributeLayerRegistryImpl.java +++ b/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/impl/environment/attribute/AttributeLayerRegistryImpl.java @@ -67,14 +67,14 @@ public class AttributeLayerRegistryImpl { } // Register vanilla ordering - registerLayerProvider(AttributeLayerProvider.DIMENSION, VanillaLayerMarker.DIMENSION); + registerLayerProvider(AttributeLayerProvider.DIMENSIONS, VanillaLayerMarker.DIMENSION); registerLayerProvider(AttributeLayerProvider.BIOMES, VanillaLayerMarker.BIOMES); registerLayerProvider(AttributeLayerProvider.TIMELINES, VanillaLayerMarker.TIMELINES); registerLayerProvider(AttributeLayerProvider.WEATHER, VanillaLayerMarker.WEATHER); - addLayerOrdering(AttributeLayerProvider.DIMENSION, AttributeLayerProvider.BIOMES); - addLayerOrdering(AttributeLayerProvider.BIOMES, AttributeLayerProvider.TIMELINES); - addLayerOrdering(AttributeLayerProvider.TIMELINES, AttributeLayerProvider.WEATHER); + addProviderOrdering(AttributeLayerProvider.DIMENSIONS, AttributeLayerProvider.BIOMES); + addProviderOrdering(AttributeLayerProvider.BIOMES, AttributeLayerProvider.TIMELINES); + addProviderOrdering(AttributeLayerProvider.TIMELINES, AttributeLayerProvider.WEATHER); // Validate cache hasOnlyVanillaLayers = true; // Set to true here because registerLayerProvider used above sets it to false @@ -96,7 +96,7 @@ public static void registerLayerProvider(Identifier id, AttributeLayerProvider l } } - public static void addLayerOrdering(Identifier firstLayer, Identifier secondLayer) { + public static void addProviderOrdering(Identifier firstLayer, Identifier secondLayer) { Objects.requireNonNull(firstLayer, "The first layer identifier should not be null."); Objects.requireNonNull(secondLayer, "The second layer identifier should not be null."); @@ -237,7 +237,7 @@ private static int compareIds(Layer a, Layer b) { // Markers for vanilla layers. It's important that these enum constants stay in the order that vanilla layers should appear, // since this order will be used to fix dependency cycles (and we don't want a dependency cycle to mess up the order). private enum VanillaLayerMarker implements AttributeLayerProvider { - DIMENSION(AttributeLayerProvider.DIMENSION), + DIMENSION(AttributeLayerProvider.DIMENSIONS), BIOMES(AttributeLayerProvider.BIOMES), TIMELINES(AttributeLayerProvider.TIMELINES), WEATHER(AttributeLayerProvider.WEATHER); diff --git a/fabric-environment-attributes-v1/src/testmodClient/java/net/fabricmc/fabric/test/environment/attribute/client/FabricEnvironmentAttributesClientTest.java b/fabric-environment-attributes-v1/src/testmodClient/java/net/fabricmc/fabric/test/environment/attribute/client/FabricEnvironmentAttributesClientTest.java index c74845bd149..6d3db5cb032 100644 --- a/fabric-environment-attributes-v1/src/testmodClient/java/net/fabricmc/fabric/test/environment/attribute/client/FabricEnvironmentAttributesClientTest.java +++ b/fabric-environment-attributes-v1/src/testmodClient/java/net/fabricmc/fabric/test/environment/attribute/client/FabricEnvironmentAttributesClientTest.java @@ -49,8 +49,8 @@ public void runTest(ClientGameTestContext context) { systemBuilder.addConstantLayer(EnvironmentAttributes.SKY_COLOR, base -> TEST_COLOR); }); - AttributeLayerRegistry.addLayerOrdering(BEFORE_ALL, AttributeLayerProvider.FIRST_VANILLA_PHASE); - AttributeLayerRegistry.addLayerOrdering(AttributeLayerProvider.LAST_VANILLA_PHASE, AFTER_ALL); + AttributeLayerRegistry.addProviderOrdering(BEFORE_ALL, AttributeLayerProvider.FIRST_VANILLA_PROVIDER); + AttributeLayerRegistry.addProviderOrdering(AttributeLayerProvider.LAST_VANILLA_PROVIDER, AFTER_ALL); try (TestSingleplayerContext spContext = context.worldBuilder().create()) { spContext.getServer().runOnServer(server -> { From 250d6d69e4bb7200b43c6c014745ab231205c3c2 Mon Sep 17 00:00:00 2001 From: Samu Date: Tue, 3 Mar 2026 14:27:08 +0100 Subject: [PATCH 05/10] Fix javadoc errors --- .../attribute/v1/AttributeLayerProvider.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/AttributeLayerProvider.java b/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/AttributeLayerProvider.java index b90236af362..1ab25ff907b 100644 --- a/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/AttributeLayerProvider.java +++ b/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/AttributeLayerProvider.java @@ -28,7 +28,7 @@ * things like weather, location or time. You can set restrictions on when your layer provider should apply in relation * to vanilla providers or other modded providers using {@link AttributeLayerRegistry#addProviderOrdering} * - *

Background

+ *

Background

* *

* The {@link EnvironmentAttributeSystem} assigns zero or more layers to every environment attribute. A layer here is @@ -41,6 +41,8 @@ *

* Minecraft creates an {@link EnvironmentAttributeSystem} for each {@link Level}, both on the client and the server, * and adds layers to this system through four different providers: + *

+ * *
    *
  1. Dimension type overrides: a layer is added for each attribute defined in the dimension type of the {@link Level}.
  2. *
  3. Biome overrides: if one or more biomes define an attribute, a layer is added for that attribute that alters the @@ -50,11 +52,13 @@ *
  4. Weather overrides: if the {@link Level} {@linkplain Level#canHaveWeather() has weather}, Minecraft defines some * hardcoded weather layers for weather for some attributes.
  5. *
+ * + *

* Each layer is given the value outputted by the previous layer, and must modify or replace * this value based on some context parameters. The first layer is given the default value of the attribute. *

* - *

Adding modded layers

+ *

Adding modded layers

* *

* As mentioned, the {@link AttributeLayerProvider} allows you to add modded layers to environment attributes during @@ -67,6 +71,8 @@ *

* Depending on the type of {@link EnvironmentAttributeLayer}, Minecraft caches values of environment attributes. Minecraft * allows three different types of layers: + *

+ * *
    *
  • {@linkplain EnvironmentAttributeLayer.Constant Constant layers}: these modify the value in a context-independent * manner. Minecraft uses these for dimensions and expects them to be constant - do not depend on external variables @@ -80,6 +86,8 @@ * Minecraft will cache the value per tick, so that if it is sampled multiple times per tick, it is only evaluated once. * Minecraft uses time based layers for timelines and weather.
  • *
+ * + *

* It is important that modded implementations take into account the constraints of different layer types, otherwise * they may not work properly. *

From 66ebdd3dda695330070f9a76a3c5632fbde53a6a Mon Sep 17 00:00:00 2001 From: Samu Date: Tue, 3 Mar 2026 14:33:34 +0100 Subject: [PATCH 06/10] Add a small essential comment in the docs about the nature of layers --- .../api/environment/attribute/v1/AttributeLayerProvider.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/AttributeLayerProvider.java b/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/AttributeLayerProvider.java index 1ab25ff907b..2d88f98fe87 100644 --- a/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/AttributeLayerProvider.java +++ b/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/AttributeLayerProvider.java @@ -35,7 +35,8 @@ * represented by a {@link EnvironmentAttributeLayer}. Layers modify or * override the value of an environment attribute by some implementation-specific logic. In vanilla Minecraft, defining an * environment attribute in a dimension type, biome or timeline will cause a layer for that attribute to be added that - * modifies the attribute accordingly. + * modifies the attribute accordingly. Note that each attribute has its own stack of layers: layers apply to individual + * attributes, not to the system as a whole. *

* *

From ece2392d0601677daa56ab0017842b652e6f4886 Mon Sep 17 00:00:00 2001 From: Samu Date: Mon, 9 Mar 2026 13:37:00 +0100 Subject: [PATCH 07/10] Make implementation naming match API naming --- .../attribute/v1/AttributeLayerRegistry.java | 18 +-- .../attribute/AttributeLayerRegistryImpl.java | 108 +++++++++--------- 2 files changed, 63 insertions(+), 63 deletions(-) diff --git a/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/AttributeLayerRegistry.java b/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/AttributeLayerRegistry.java index 37ec784cf76..1734baeeb02 100644 --- a/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/AttributeLayerRegistry.java +++ b/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/AttributeLayerRegistry.java @@ -31,12 +31,12 @@ public class AttributeLayerRegistry { * Register a {@link AttributeLayerProvider}. If a layer provider with the given identifier already exists, an exception * is thrown. * - * @param id The identifier of the layer provider. This identifier can be used to set an ordering via - * {@link #addProviderOrdering}. . - * @param layer The layer provider to register. + * @param id The identifier of the layer provider. This identifier can be used to set an ordering via + * {@link #addProviderOrdering}. . + * @param provider The layer provider to register. */ - public static void registerLayerProvider(Identifier id, AttributeLayerProvider layer) { - AttributeLayerRegistryImpl.registerLayerProvider(id, layer); + public static void registerLayerProvider(Identifier id, AttributeLayerProvider provider) { + AttributeLayerRegistryImpl.registerLayerProvider(id, provider); } /** @@ -45,10 +45,10 @@ public static void registerLayerProvider(Identifier id, AttributeLayerProvider l * said order. You may use this to order your layer provider against vanilla layer providers using any of the constants in * {@link AttributeLayerProvider}. If both layer identifiers are the same, then an exception is thrown. * - * @param firstLayer The ID of the layer provider that should activate earlier. - * @param secondLayer The ID of the layer provider that should activate later. + * @param firstProvider The ID of the layer provider that should activate earlier. + * @param secondProvider The ID of the layer provider that should activate later. */ - public static void addProviderOrdering(Identifier firstLayer, Identifier secondLayer) { - AttributeLayerRegistryImpl.addProviderOrdering(firstLayer, secondLayer); + public static void addProviderOrdering(Identifier firstProvider, Identifier secondProvider) { + AttributeLayerRegistryImpl.addProviderOrdering(firstProvider, secondProvider); } } diff --git a/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/impl/environment/attribute/AttributeLayerRegistryImpl.java b/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/impl/environment/attribute/AttributeLayerRegistryImpl.java index a5c0db69668..f0940618c55 100644 --- a/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/impl/environment/attribute/AttributeLayerRegistryImpl.java +++ b/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/impl/environment/attribute/AttributeLayerRegistryImpl.java @@ -40,24 +40,24 @@ public class AttributeLayerRegistryImpl { private static final Map MARKERS = Map.copyOf(Stream.of(VanillaLayerMarker.values()) .collect(Collectors.toMap(marker -> marker.id, marker -> marker))); - private static final Map LAYER_MAP = new HashMap<>(); + private static final Map PROVIDER_MAP = new HashMap<>(); private static final Set DEPENDENCIES = new HashSet<>(); // Lock used to ensure thread safety. private static final Object LOCK = new Object(); - // As long as this is true, we skip sorting and inserting layers all together. - // Becomes false once a modded layer is registered. - private static volatile boolean hasOnlyVanillaLayers; + // As long as this is true, we skip sorting and inserting providers all together. + // Becomes false once a modded provider is registered. + private static volatile boolean hasOnlyVanillaMarkers; // As long as this is true, the ordering in the fields below is valid. - // Becomes false once a modded layer is registered or once a depencency order is added. + // Becomes false once a modded provider is registered or once a depencency order is added. private static volatile boolean orderValid; - // Layers that should go before vanilla layers. + // Layers that should go before vanilla providers. private static final List FIRST_PHASES = new ArrayList<>(); - // Layers that should go in between or after vanilla layers. + // Layers that should go in between or after vanilla providers. private static final Map> AFTER_VANILLA_PHASES = new EnumMap<>(VanillaLayerMarker.class); static { @@ -77,46 +77,46 @@ public class AttributeLayerRegistryImpl { addProviderOrdering(AttributeLayerProvider.TIMELINES, AttributeLayerProvider.WEATHER); // Validate cache - hasOnlyVanillaLayers = true; // Set to true here because registerLayerProvider used above sets it to false - orderValid = true; // Vanilla layers are not included in sorted phase lists + hasOnlyVanillaMarkers = true; // Set to true here because registerLayerProvider used above sets it to false + orderValid = true; // Vanilla provider are not included in sorted phase lists } - public static void registerLayerProvider(Identifier id, AttributeLayerProvider layer) { + public static void registerLayerProvider(Identifier id, AttributeLayerProvider provider) { Objects.requireNonNull(id, "The layer identifier should not be null."); - Objects.requireNonNull(layer, "The layer should not be null."); + Objects.requireNonNull(provider, "The provider should not be null."); - if (LAYER_MAP.containsKey(id)) { + if (PROVIDER_MAP.containsKey(id)) { throw new IllegalArgumentException("Layer with ID %s was already registered.".formatted(id)); } synchronized (LOCK) { - LAYER_MAP.put(id, layer); + PROVIDER_MAP.put(id, provider); orderValid = false; - hasOnlyVanillaLayers = false; + hasOnlyVanillaMarkers = false; } } - public static void addProviderOrdering(Identifier firstLayer, Identifier secondLayer) { - Objects.requireNonNull(firstLayer, "The first layer identifier should not be null."); - Objects.requireNonNull(secondLayer, "The second layer identifier should not be null."); + public static void addProviderOrdering(Identifier firstProvider, Identifier secondProvider) { + Objects.requireNonNull(firstProvider, "The first provider identifier should not be null."); + Objects.requireNonNull(secondProvider, "The second provider identifier should not be null."); - if (firstLayer.equals(secondLayer)) { - throw new IllegalArgumentException("Tried to add a layer that depends on itself."); + if (firstProvider.equals(secondProvider)) { + throw new IllegalArgumentException("Tried to make a provider depend on itself."); } synchronized (LOCK) { - if (DEPENDENCIES.add(new Dependency(firstLayer, secondLayer))) { - // Adding a dependency only affects order if both IDs are associated with registered layers. + if (DEPENDENCIES.add(new Dependency(firstProvider, secondProvider))) { + // Adding a dependency only affects order if both IDs are associated with registered providers. // Dependencies with missing registrations are simply ignored during sorting. - if (LAYER_MAP.containsKey(firstLayer) && LAYER_MAP.containsKey(secondLayer)) { + if (PROVIDER_MAP.containsKey(firstProvider) && PROVIDER_MAP.containsKey(secondProvider)) { orderValid = false; } } } } - private static void addLayers(List providers, EnvironmentAttributeSystem.Builder systemBuilder, Level level) { + private static void insertModdedLayers(List providers, EnvironmentAttributeSystem.Builder systemBuilder, Level level) { synchronized (LOCK) { for (AttributeLayerProvider provider : providers) { provider.addAttributeLayers(systemBuilder, level); @@ -125,42 +125,42 @@ private static void addLayers(List providers, Environmen } public static void addPreEverythingLayers(EnvironmentAttributeSystem.Builder systemBuilder, Level level) { - if (!hasOnlyVanillaLayers) { + if (!hasOnlyVanillaMarkers) { sortIfNeeded(); - addLayers(FIRST_PHASES, systemBuilder, level); + insertModdedLayers(FIRST_PHASES, systemBuilder, level); } } public static void addPostDimensionLayers(EnvironmentAttributeSystem.Builder systemBuilder, Level level) { - if (!hasOnlyVanillaLayers) { + if (!hasOnlyVanillaMarkers) { sortIfNeeded(); - addLayers(AFTER_VANILLA_PHASES.get(VanillaLayerMarker.DIMENSION), systemBuilder, level); + insertModdedLayers(AFTER_VANILLA_PHASES.get(VanillaLayerMarker.DIMENSION), systemBuilder, level); } } public static void addPostBiomesLayers(EnvironmentAttributeSystem.Builder systemBuilder, Level level) { - if (!hasOnlyVanillaLayers) { + if (!hasOnlyVanillaMarkers) { sortIfNeeded(); - addLayers(AFTER_VANILLA_PHASES.get(VanillaLayerMarker.BIOMES), systemBuilder, level); + insertModdedLayers(AFTER_VANILLA_PHASES.get(VanillaLayerMarker.BIOMES), systemBuilder, level); } } public static void addPostTimelinesLayers(EnvironmentAttributeSystem.Builder systemBuilder, Level level) { - if (!hasOnlyVanillaLayers) { + if (!hasOnlyVanillaMarkers) { sortIfNeeded(); - addLayers(AFTER_VANILLA_PHASES.get(VanillaLayerMarker.TIMELINES), systemBuilder, level); + insertModdedLayers(AFTER_VANILLA_PHASES.get(VanillaLayerMarker.TIMELINES), systemBuilder, level); } } public static void addPostWeatherLayers(EnvironmentAttributeSystem.Builder systemBuilder, Level level) { - if (!hasOnlyVanillaLayers) { + if (!hasOnlyVanillaMarkers) { sortIfNeeded(); - addLayers(AFTER_VANILLA_PHASES.get(VanillaLayerMarker.WEATHER), systemBuilder, level); + insertModdedLayers(AFTER_VANILLA_PHASES.get(VanillaLayerMarker.WEATHER), systemBuilder, level); } } private static void sortIfNeeded() { - Map layers; + Map providersById; // Collect sorting data from registry synchronized (LOCK) { @@ -168,25 +168,25 @@ private static void sortIfNeeded() { return; } - layers = new HashMap<>(); + providersById = new HashMap<>(); - for (Map.Entry entry : LAYER_MAP.entrySet()) { - layers.put(entry.getKey(), new Layer(entry.getKey(), entry.getValue())); + for (Map.Entry entry : PROVIDER_MAP.entrySet()) { + providersById.put(entry.getKey(), new LayerProvider(entry.getKey(), entry.getValue())); } for (Dependency dependency : DEPENDENCIES) { - Layer firstLayer = layers.get(dependency.firstLayer()); - Layer secondLayer = layers.get(dependency.secondLayer()); + LayerProvider firstLayerProvider = providersById.get(dependency.first()); + LayerProvider secondLayerProvider = providersById.get(dependency.second()); - if (firstLayer != null && secondLayer != null) { - Layer.link(firstLayer, secondLayer); + if (firstLayerProvider != null && secondLayerProvider != null) { + LayerProvider.link(firstLayerProvider, secondLayerProvider); } } } - // Sort layers - List sorted = new ArrayList<>(layers.values()); - NodeSorting.sort(sorted, "environment attribute layers", AttributeLayerRegistryImpl::compareIds); + // Sort providers + List sorted = new ArrayList<>(providersById.values()); + NodeSorting.sort(sorted, "environment attribute providers", AttributeLayerRegistryImpl::compareIds); // Categorize layer providers into vanilla phases synchronized (LOCK) { @@ -195,8 +195,8 @@ private static void sortIfNeeded() { List phase = FIRST_PHASES; - for (Layer layer : sorted) { - AttributeLayerProvider provider = layer.provider; + for (LayerProvider layerProvider : sorted) { + AttributeLayerProvider provider = layerProvider.provider; if (provider instanceof VanillaLayerMarker marker) { phase = AFTER_VANILLA_PHASES.get(marker); @@ -207,16 +207,16 @@ private static void sortIfNeeded() { } } - // Tiebreaker: put vanilla layers before others, and otherwise sort by lexicographic ordering - // This also makes sure that layers that were not tied to vanilla ordering will come last in the ordering - private static int compareIds(Layer a, Layer b) { + // Tiebreaker: put vanilla providers before others, and otherwise sort by lexicographic ordering + // This also makes sure that providers that were not tied to vanilla ordering will come last in the ordering + private static int compareIds(LayerProvider a, LayerProvider b) { Identifier idA = a.id; Identifier idB = b.id; VanillaLayerMarker markerA = MARKERS.get(idA); VanillaLayerMarker markerB = MARKERS.get(idB); - // If both are vanilla layers, ensure they remain the same order as defined by Minecraft + // If both are vanilla providers, ensure they remain the same order as defined by Minecraft if (markerA != null && markerB != null) { return markerA.compareTo(markerB); } @@ -234,7 +234,7 @@ private static int compareIds(Layer a, Layer b) { return idA.compareTo(idB); } - // Markers for vanilla layers. It's important that these enum constants stay in the order that vanilla layers should appear, + // Markers for vanilla providers. It's important that these enum constants stay in the order that vanilla providers should appear, // since this order will be used to fix dependency cycles (and we don't want a dependency cycle to mess up the order). private enum VanillaLayerMarker implements AttributeLayerProvider { DIMENSION(AttributeLayerProvider.DIMENSIONS), @@ -254,11 +254,11 @@ public void addAttributeLayers(EnvironmentAttributeSystem.Builder systemBuilder, } } - private static class Layer extends SortableNode { + private static class LayerProvider extends SortableNode { private final Identifier id; private final AttributeLayerProvider provider; - private Layer(Identifier id, AttributeLayerProvider provider) { + private LayerProvider(Identifier id, AttributeLayerProvider provider) { this.id = id; this.provider = provider; } @@ -269,6 +269,6 @@ protected String getDescription() { } } - private record Dependency(Identifier firstLayer, Identifier secondLayer) { + private record Dependency(Identifier first, Identifier second) { } } From 9af08dec391b13c967628dfbd3834f269d19b3a5 Mon Sep 17 00:00:00 2001 From: Samu Date: Mon, 9 Mar 2026 13:51:49 +0100 Subject: [PATCH 08/10] Change module name to match convention --- .../build.gradle | 0 .../attribute/v1/AttributeLayerProvider.java | 0 .../attribute/v1/AttributeLayerRegistry.java | 0 .../attribute/AttributeLayerRegistryImpl.java | 0 .../attribute/EnvironmentAttributeSystemMixin.java | 0 .../fabric-environment-attribute-api-v1}/icon.png | Bin .../fabric-environment-attribute-api-v1.mixins.json | 0 .../src/main/resources/fabric.mod.json | 10 +++++----- .../attribute/FabricEnvironmentAttributesTest.java | 0 .../src/testmod/resources/fabric.mod.json | 0 .../FabricEnvironmentAttributesClientTest.java | 0 gradle.properties | 2 +- settings.gradle | 2 +- 13 files changed, 7 insertions(+), 7 deletions(-) rename {fabric-environment-attributes-v1 => fabric-environment-attribute-api-v1}/build.gradle (100%) rename {fabric-environment-attributes-v1 => fabric-environment-attribute-api-v1}/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/AttributeLayerProvider.java (100%) rename {fabric-environment-attributes-v1 => fabric-environment-attribute-api-v1}/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/AttributeLayerRegistry.java (100%) rename {fabric-environment-attributes-v1 => fabric-environment-attribute-api-v1}/src/main/java/net/fabricmc/fabric/impl/environment/attribute/AttributeLayerRegistryImpl.java (100%) rename {fabric-environment-attributes-v1 => fabric-environment-attribute-api-v1}/src/main/java/net/fabricmc/fabric/mixin/environment/attribute/EnvironmentAttributeSystemMixin.java (100%) rename {fabric-environment-attributes-v1/src/main/resources/assets/fabric-environment-attributes-v1 => fabric-environment-attribute-api-v1/src/main/resources/assets/fabric-environment-attribute-api-v1}/icon.png (100%) rename fabric-environment-attributes-v1/src/main/resources/fabric-environment-attributes-v1.mixins.json => fabric-environment-attribute-api-v1/src/main/resources/fabric-environment-attribute-api-v1.mixins.json (100%) rename {fabric-environment-attributes-v1 => fabric-environment-attribute-api-v1}/src/main/resources/fabric.mod.json (66%) rename {fabric-environment-attributes-v1 => fabric-environment-attribute-api-v1}/src/testmod/java/net/fabricmc/fabric/test/environment/attribute/FabricEnvironmentAttributesTest.java (100%) rename {fabric-environment-attributes-v1 => fabric-environment-attribute-api-v1}/src/testmod/resources/fabric.mod.json (100%) rename {fabric-environment-attributes-v1 => fabric-environment-attribute-api-v1}/src/testmodClient/java/net/fabricmc/fabric/test/environment/attribute/client/FabricEnvironmentAttributesClientTest.java (100%) diff --git a/fabric-environment-attributes-v1/build.gradle b/fabric-environment-attribute-api-v1/build.gradle similarity index 100% rename from fabric-environment-attributes-v1/build.gradle rename to fabric-environment-attribute-api-v1/build.gradle diff --git a/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/AttributeLayerProvider.java b/fabric-environment-attribute-api-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/AttributeLayerProvider.java similarity index 100% rename from fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/AttributeLayerProvider.java rename to fabric-environment-attribute-api-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/AttributeLayerProvider.java diff --git a/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/AttributeLayerRegistry.java b/fabric-environment-attribute-api-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/AttributeLayerRegistry.java similarity index 100% rename from fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/AttributeLayerRegistry.java rename to fabric-environment-attribute-api-v1/src/main/java/net/fabricmc/fabric/api/environment/attribute/v1/AttributeLayerRegistry.java diff --git a/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/impl/environment/attribute/AttributeLayerRegistryImpl.java b/fabric-environment-attribute-api-v1/src/main/java/net/fabricmc/fabric/impl/environment/attribute/AttributeLayerRegistryImpl.java similarity index 100% rename from fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/impl/environment/attribute/AttributeLayerRegistryImpl.java rename to fabric-environment-attribute-api-v1/src/main/java/net/fabricmc/fabric/impl/environment/attribute/AttributeLayerRegistryImpl.java diff --git a/fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/mixin/environment/attribute/EnvironmentAttributeSystemMixin.java b/fabric-environment-attribute-api-v1/src/main/java/net/fabricmc/fabric/mixin/environment/attribute/EnvironmentAttributeSystemMixin.java similarity index 100% rename from fabric-environment-attributes-v1/src/main/java/net/fabricmc/fabric/mixin/environment/attribute/EnvironmentAttributeSystemMixin.java rename to fabric-environment-attribute-api-v1/src/main/java/net/fabricmc/fabric/mixin/environment/attribute/EnvironmentAttributeSystemMixin.java diff --git a/fabric-environment-attributes-v1/src/main/resources/assets/fabric-environment-attributes-v1/icon.png b/fabric-environment-attribute-api-v1/src/main/resources/assets/fabric-environment-attribute-api-v1/icon.png similarity index 100% rename from fabric-environment-attributes-v1/src/main/resources/assets/fabric-environment-attributes-v1/icon.png rename to fabric-environment-attribute-api-v1/src/main/resources/assets/fabric-environment-attribute-api-v1/icon.png diff --git a/fabric-environment-attributes-v1/src/main/resources/fabric-environment-attributes-v1.mixins.json b/fabric-environment-attribute-api-v1/src/main/resources/fabric-environment-attribute-api-v1.mixins.json similarity index 100% rename from fabric-environment-attributes-v1/src/main/resources/fabric-environment-attributes-v1.mixins.json rename to fabric-environment-attribute-api-v1/src/main/resources/fabric-environment-attribute-api-v1.mixins.json diff --git a/fabric-environment-attributes-v1/src/main/resources/fabric.mod.json b/fabric-environment-attribute-api-v1/src/main/resources/fabric.mod.json similarity index 66% rename from fabric-environment-attributes-v1/src/main/resources/fabric.mod.json rename to fabric-environment-attribute-api-v1/src/main/resources/fabric.mod.json index 23d53115601..85b906d7b3b 100644 --- a/fabric-environment-attributes-v1/src/main/resources/fabric.mod.json +++ b/fabric-environment-attribute-api-v1/src/main/resources/fabric.mod.json @@ -1,10 +1,10 @@ { "schemaVersion": 1, - "id": "fabric-environment-attributes-v1", - "name": "Fabric Environment Attributes API (v1)", + "id": "fabric-environment-attribute-api-v1", + "name": "Fabric Environment Attribute API (v1)", "version": "${version}", "license": "Apache-2.0", - "icon": "assets/fabric-environment-attributes-v1/icon.png", + "icon": "assets/fabric-environment-attribute-api-v1/icon.png", "contact" : { "homepage": "https://fabricmc.net", "irc": "irc://irc.esper.net:6667/fabric", @@ -21,9 +21,9 @@ "minecraft": ">=1.16-rc.3", "fabric-api-base": "*" }, - "description": "Fabric Environment Attributes API.", + "description": "Fabric Environment Attribute API.", "mixins": [ - "fabric-environment-attributes-v1.mixins.json" + "fabric-environment-attribute-api-v1.mixins.json" ], "custom": { "fabric-api:module-lifecycle": "stable" diff --git a/fabric-environment-attributes-v1/src/testmod/java/net/fabricmc/fabric/test/environment/attribute/FabricEnvironmentAttributesTest.java b/fabric-environment-attribute-api-v1/src/testmod/java/net/fabricmc/fabric/test/environment/attribute/FabricEnvironmentAttributesTest.java similarity index 100% rename from fabric-environment-attributes-v1/src/testmod/java/net/fabricmc/fabric/test/environment/attribute/FabricEnvironmentAttributesTest.java rename to fabric-environment-attribute-api-v1/src/testmod/java/net/fabricmc/fabric/test/environment/attribute/FabricEnvironmentAttributesTest.java diff --git a/fabric-environment-attributes-v1/src/testmod/resources/fabric.mod.json b/fabric-environment-attribute-api-v1/src/testmod/resources/fabric.mod.json similarity index 100% rename from fabric-environment-attributes-v1/src/testmod/resources/fabric.mod.json rename to fabric-environment-attribute-api-v1/src/testmod/resources/fabric.mod.json diff --git a/fabric-environment-attributes-v1/src/testmodClient/java/net/fabricmc/fabric/test/environment/attribute/client/FabricEnvironmentAttributesClientTest.java b/fabric-environment-attribute-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/environment/attribute/client/FabricEnvironmentAttributesClientTest.java similarity index 100% rename from fabric-environment-attributes-v1/src/testmodClient/java/net/fabricmc/fabric/test/environment/attribute/client/FabricEnvironmentAttributesClientTest.java rename to fabric-environment-attribute-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/environment/attribute/client/FabricEnvironmentAttributesClientTest.java diff --git a/gradle.properties b/gradle.properties index 4052a2c0ac4..40c69c09037 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,7 +25,7 @@ fabric-data-generation-api-v1-version=24.0.13 fabric-debug-api-v1-version=1.0.0 fabric-dimensions-v1-version=5.1.2 fabric-entity-events-v1-version=5.0.1 -fabric-environment-attributes-v1-version=1.0.0 +fabric-environment-attribute-api-v1-version=1.0.0 fabric-events-interaction-v0-version=5.1.7 fabric-game-rule-api-v1-version=4.0.3 fabric-gametest-api-v1-version=4.0.9 diff --git a/settings.gradle b/settings.gradle index b02d9271188..b19e42f0d47 100644 --- a/settings.gradle +++ b/settings.gradle @@ -40,7 +40,7 @@ include 'fabric-data-generation-api-v1' include 'fabric-debug-api-v1' include 'fabric-dimensions-v1' include 'fabric-entity-events-v1' -include 'fabric-environment-attributes-v1' +include 'fabric-environment-attribute-api-v1' include 'fabric-events-interaction-v0' include 'fabric-game-rule-api-v1' include 'fabric-gametest-api-v1' From f0fc207941168880a71398e2b4a5c001b34e9362 Mon Sep 17 00:00:00 2001 From: Samu Date: Mon, 9 Mar 2026 14:07:48 +0100 Subject: [PATCH 09/10] Fix environment attribute api dependencies --- fabric-environment-attribute-api-v1/build.gradle | 3 +-- .../src/main/resources/fabric.mod.json | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/fabric-environment-attribute-api-v1/build.gradle b/fabric-environment-attribute-api-v1/build.gradle index 8bfe314df96..1c4e0279f2f 100644 --- a/fabric-environment-attribute-api-v1/build.gradle +++ b/fabric-environment-attribute-api-v1/build.gradle @@ -1,8 +1,7 @@ version = getSubprojectVersion(project) moduleDependencies(project, [ - 'fabric-api-base', - 'fabric-lifecycle-events-v1' + 'fabric-api-base' ]) testDependencies(project, [ diff --git a/fabric-environment-attribute-api-v1/src/main/resources/fabric.mod.json b/fabric-environment-attribute-api-v1/src/main/resources/fabric.mod.json index 85b906d7b3b..c6870a8ca0b 100644 --- a/fabric-environment-attribute-api-v1/src/main/resources/fabric.mod.json +++ b/fabric-environment-attribute-api-v1/src/main/resources/fabric.mod.json @@ -18,7 +18,7 @@ }, "depends": { "fabricloader": ">=0.18.4", - "minecraft": ">=1.16-rc.3", + "minecraft": ">=1.21.11-rc1", "fabric-api-base": "*" }, "description": "Fabric Environment Attribute API.", From 6fa1af77a58aaac80609c53a850a884d4263f87a Mon Sep 17 00:00:00 2001 From: Samu Date: Mon, 9 Mar 2026 14:21:14 +0100 Subject: [PATCH 10/10] Fix test mod dependency --- .../attribute/FabricEnvironmentAttributesTest.java | 2 +- .../src/testmod/resources/fabric.mod.json | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/fabric-environment-attribute-api-v1/src/testmod/java/net/fabricmc/fabric/test/environment/attribute/FabricEnvironmentAttributesTest.java b/fabric-environment-attribute-api-v1/src/testmod/java/net/fabricmc/fabric/test/environment/attribute/FabricEnvironmentAttributesTest.java index 1d7427a8994..5f12f9a109d 100644 --- a/fabric-environment-attribute-api-v1/src/testmod/java/net/fabricmc/fabric/test/environment/attribute/FabricEnvironmentAttributesTest.java +++ b/fabric-environment-attribute-api-v1/src/testmod/java/net/fabricmc/fabric/test/environment/attribute/FabricEnvironmentAttributesTest.java @@ -32,6 +32,6 @@ public class FabricEnvironmentAttributesTest implements ModInitializer { @Override public void onInitialize() { - Registry.register(BuiltInRegistries.ENVIRONMENT_ATTRIBUTE, Identifier.fromNamespaceAndPath("fabric_environment_attributes", "test_color"), TEST_COLOR); + Registry.register(BuiltInRegistries.ENVIRONMENT_ATTRIBUTE, Identifier.fromNamespaceAndPath("fabric", "test_color"), TEST_COLOR); } } diff --git a/fabric-environment-attribute-api-v1/src/testmod/resources/fabric.mod.json b/fabric-environment-attribute-api-v1/src/testmod/resources/fabric.mod.json index 843bcd0f1d1..90bf83a1cdd 100644 --- a/fabric-environment-attribute-api-v1/src/testmod/resources/fabric.mod.json +++ b/fabric-environment-attribute-api-v1/src/testmod/resources/fabric.mod.json @@ -1,12 +1,12 @@ { "schemaVersion": 1, - "id": "fabric-environment-attributes-v1-testmod", - "name": "Fabric Environment Attributes (v1) Test Mod", + "id": "fabric-environment-attribute-api-v1-testmod", + "name": "Fabric Environment Attribute API (v1) Test Mod", "version": "1.0.0", "environment": "*", "license": "Apache-2.0", "depends": { - "fabric-environment-attributes-v1": "*" + "fabric-environment-attribute-api-v1": "*" }, "entrypoints": { "main": [