From 14c0ce9d3dda9b698639acda6fe739c26c994210 Mon Sep 17 00:00:00 2001 From: Samu Date: Mon, 9 Feb 2026 13:49:39 +0100 Subject: [PATCH 1/3] 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 2/3] 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 3/3] 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);