Bläddra i källkod

Architectury Update
- Cache fractions from -1024 to 1023
- Add BiomeModifications for platform-agnostic biome additions
- Add FluidStackHooksForge to convert architectury FluidStacks to forge FluidStacks
- Migrate to Forge Loom & Update Architect Plugin
- Mark several methods in Mod as NotNull
- Add Env as a replacement for EnvType

shedaniel 4 år sedan
förälder
incheckning
67a1db1ccb
65 ändrade filer med 2260 tillägg och 312 borttagningar
  1. 1 1
      README.md
  2. 7 3
      build.gradle
  3. 3 6
      common/build.gradle
  4. 3 2
      common/src/main/java/me/shedaniel/architectury/event/EventHandler.java
  5. 473 0
      common/src/main/java/me/shedaniel/architectury/hooks/biome/BiomeHooks.java
  6. 71 0
      common/src/main/java/me/shedaniel/architectury/hooks/biome/BiomeProperties.java
  7. 50 0
      common/src/main/java/me/shedaniel/architectury/hooks/biome/ClimateProperties.java
  8. 104 0
      common/src/main/java/me/shedaniel/architectury/hooks/biome/EffectsProperties.java
  9. 61 0
      common/src/main/java/me/shedaniel/architectury/hooks/biome/GenerationProperties.java
  10. 40 0
      common/src/main/java/me/shedaniel/architectury/hooks/biome/SpawnProperties.java
  11. 2 1
      common/src/main/java/me/shedaniel/architectury/networking/NetworkChannel.java
  12. 6 1
      common/src/main/java/me/shedaniel/architectury/networking/NetworkManager.java
  13. 9 3
      common/src/main/java/me/shedaniel/architectury/platform/Mod.java
  14. 7 0
      common/src/main/java/me/shedaniel/architectury/platform/Platform.java
  15. 75 0
      common/src/main/java/me/shedaniel/architectury/registry/BiomeModifications.java
  16. 7 2
      common/src/main/java/me/shedaniel/architectury/registry/Registries.java
  17. 46 0
      common/src/main/java/me/shedaniel/architectury/utils/Env.java
  18. 11 3
      common/src/main/java/me/shedaniel/architectury/utils/EnvExecutor.java
  19. 14 0
      common/src/main/java/me/shedaniel/architectury/utils/Fraction.java
  20. 2 0
      common/src/main/java/me/shedaniel/architectury/utils/GameInstance.java
  21. 0 2
      common/src/main/resources/architectury-common.accessWidener
  22. 41 0
      common/src/main/resources/architectury.accessWidener
  23. 1 1
      common/src/main/resources/fabric.mod.json
  24. 66 3
      fabric/build.gradle
  25. 2 1
      fabric/src/main/java/me/shedaniel/architectury/hooks/fabric/FluidStackHooksImpl.java
  26. 3 2
      fabric/src/main/java/me/shedaniel/architectury/networking/fabric/NetworkManagerImpl.java
  27. 10 5
      fabric/src/main/java/me/shedaniel/architectury/platform/fabric/PlatformImpl.java
  28. 370 0
      fabric/src/main/java/me/shedaniel/architectury/registry/fabric/BiomeModificationsImpl.java
  29. 1 4
      fabric/src/main/java/me/shedaniel/architectury/registry/fabric/RegistriesImpl.java
  30. 2 1
      fabric/src/main/java/me/shedaniel/architectury/utils/fabric/GameInstanceImpl.java
  31. 3 0
      fabric/src/main/resources/fabric.mod.json
  32. 31 58
      forge/build.gradle
  33. 1 0
      forge/gradle.properties
  34. 15 15
      forge/src/main/java/me/shedaniel/architectury/event/forge/EventHandlerImplClient.java
  35. 43 43
      forge/src/main/java/me/shedaniel/architectury/event/forge/EventHandlerImplCommon.java
  36. 0 1
      forge/src/main/java/me/shedaniel/architectury/forge/ArchitecturyForge.java
  37. 1 1
      forge/src/main/java/me/shedaniel/architectury/hooks/forge/DyeColorHooksImpl.java
  38. 1 1
      forge/src/main/java/me/shedaniel/architectury/hooks/forge/EntityHooksImpl.java
  39. 4 4
      forge/src/main/java/me/shedaniel/architectury/hooks/forge/ExplosionHooksImpl.java
  40. 16 0
      forge/src/main/java/me/shedaniel/architectury/hooks/forge/FluidStackHooksForge.java
  41. 14 18
      forge/src/main/java/me/shedaniel/architectury/hooks/forge/FluidStackHooksImpl.java
  42. 1 1
      forge/src/main/java/me/shedaniel/architectury/hooks/forge/ItemEntityHooksImpl.java
  43. 4 4
      forge/src/main/java/me/shedaniel/architectury/hooks/forge/PackRepositoryHooksImpl.java
  44. 3 3
      forge/src/main/java/me/shedaniel/architectury/hooks/forge/PlayerHooksImpl.java
  45. 8 8
      forge/src/main/java/me/shedaniel/architectury/hooks/forge/ScreenHooksImpl.java
  46. 15 0
      forge/src/main/java/me/shedaniel/architectury/mixin/forge/BiomeGenerationSettingsBuilderAccessor.java
  47. 8 0
      forge/src/main/java/me/shedaniel/architectury/mixin/forge/BiomeSpecialEffectsAccessor.java
  48. 25 0
      forge/src/main/java/me/shedaniel/architectury/mixin/forge/MobSpawnSettingsBuilderAccessor.java
  49. 3 3
      forge/src/main/java/me/shedaniel/architectury/networking/forge/ClientNetworkingManager.java
  50. 20 19
      forge/src/main/java/me/shedaniel/architectury/networking/forge/NetworkManagerImpl.java
  51. 10 5
      forge/src/main/java/me/shedaniel/architectury/platform/forge/PlatformImpl.java
  52. 430 0
      forge/src/main/java/me/shedaniel/architectury/registry/forge/BiomeModificationsImpl.java
  53. 5 5
      forge/src/main/java/me/shedaniel/architectury/registry/forge/BlockEntityRenderersImpl.java
  54. 6 6
      forge/src/main/java/me/shedaniel/architectury/registry/forge/BlockPropertiesImpl.java
  55. 10 10
      forge/src/main/java/me/shedaniel/architectury/registry/forge/ColorHandlersImpl.java
  56. 5 5
      forge/src/main/java/me/shedaniel/architectury/registry/forge/CreativeTabsImpl.java
  57. 2 2
      forge/src/main/java/me/shedaniel/architectury/registry/forge/KeyBindingsImpl.java
  58. 36 36
      forge/src/main/java/me/shedaniel/architectury/registry/forge/RegistriesImpl.java
  59. 10 10
      forge/src/main/java/me/shedaniel/architectury/registry/forge/ReloadListenersImpl.java
  60. 5 5
      forge/src/main/java/me/shedaniel/architectury/registry/forge/RenderTypesImpl.java
  61. 6 6
      forge/src/main/java/me/shedaniel/architectury/registry/forge/ToolTypeImpl.java
  62. 17 1
      forge/src/main/resources/META-INF/accesstransformer.cfg
  63. 12 0
      forge/src/main/resources/architectury.mixins.json
  64. 1 1
      gradle.properties
  65. 1 0
      settings.gradle

+ 1 - 1
README.md

@@ -4,7 +4,7 @@ A intermediary api aimed to ease developing multiplatform mods.
 ### What is Architectury
 Architectury is an api to abstract calls to fabric api and forge api as both loader has different implementations of what can be perceived as the same thing.
 
-Architectury updates regularly, with new hooks and features. Currently contains over **60** events hooks, networking abstraction, loader calls abstraction, game registry abstraction and an easy to use @ExpectPlatform annotation.
+Architectury updates regularly, with new hooks and features. Currently contains over **60** events hooks, networking abstraction, loader calls abstraction, game registry abstraction and an easy to use @ExpectPlatform annotation (Only works on static methods).
 
 ### Advantages of Architectury
 - Open sourced

+ 7 - 3
build.gradle

@@ -1,5 +1,5 @@
 plugins {
-    id "architect-plugin" version "1.1.19"
+    id "architect-plugin" version "1.2.28"
     id "org.cadixdev.licenser" version "0.5.0"
     id "com.jfrog.bintray" version "1.8.4"
     id "com.matthewprenger.cursegradle" version "1.4.0" apply false
@@ -7,10 +7,14 @@ plugins {
     id "maven-publish"
 }
 
-architect {
+architectury {
     minecraft = rootProject.minecraft_version
 }
 
+subprojects {
+    apply plugin: "forgified-fabric-loom"
+}
+
 allprojects {
     apply plugin: "java"
     apply plugin: "architect-plugin"
@@ -32,8 +36,8 @@ allprojects {
             year = 2020
         }
 
+        include "*.java"
         exclude "**/NbtType.java"
-        exclude "**/*.accessWidener"
 
         ignoreFailures = true
     }

+ 3 - 6
common/build.gradle

@@ -1,9 +1,6 @@
-plugins {
-    id "fabric-loom"
-}
-
 loom {
-    accessWidener = file("src/main/resources/architectury-common.accessWidener")
+    accessWidener = file("src/main/resources/architectury.accessWidener")
+    silentMojangMappingsLicense()
 }
 
 dependencies {
@@ -15,7 +12,7 @@ dependencies {
     implementation "net.jodah:typetools:0.6.2"
 }
 
-architect {
+architectury {
     common()
 }
 

+ 3 - 2
common/src/main/java/me/shedaniel/architectury/event/EventHandler.java

@@ -21,6 +21,7 @@ package me.shedaniel.architectury.event;
 
 import me.shedaniel.architectury.ExpectPlatform;
 import me.shedaniel.architectury.platform.Platform;
+import me.shedaniel.architectury.utils.Env;
 import net.fabricmc.api.EnvType;
 import net.fabricmc.api.Environment;
 
@@ -32,10 +33,10 @@ public final class EventHandler {
     public static void init() {
         if (initialized) return;
         initialized = true;
-        if (Platform.getEnv() == EnvType.CLIENT)
+        if (Platform.getEnvironment() == Env.CLIENT)
             registerClient();
         registerCommon();
-        if (Platform.getEnv() == EnvType.SERVER)
+        if (Platform.getEnvironment() == Env.SERVER)
             registerServer();
     }
     

+ 473 - 0
common/src/main/java/me/shedaniel/architectury/hooks/biome/BiomeHooks.java

@@ -0,0 +1,473 @@
+/*
+ * This file is part of architectury.
+ * Copyright (C) 2020 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package me.shedaniel.architectury.hooks.biome;
+
+import net.minecraft.sounds.Music;
+import net.minecraft.sounds.SoundEvent;
+import net.minecraft.world.entity.EntityType;
+import net.minecraft.world.entity.MobCategory;
+import net.minecraft.world.level.biome.*;
+import net.minecraft.world.level.biome.Biome.BiomeCategory;
+import net.minecraft.world.level.biome.BiomeSpecialEffects.GrassColorModifier;
+import net.minecraft.world.level.levelgen.GenerationStep;
+import net.minecraft.world.level.levelgen.carver.ConfiguredWorldCarver;
+import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
+import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature;
+import net.minecraft.world.level.levelgen.surfacebuilders.ConfiguredSurfaceBuilder;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.OptionalInt;
+import java.util.function.Supplier;
+
+public final class BiomeHooks {
+    @NotNull
+    public static BiomeProperties getBiomeProperties(Biome biome) {
+        return new BiomeWrapped(biome);
+    }
+    
+    public static class BiomeWrapped implements BiomeProperties {
+        protected final Biome biome;
+        protected final ClimateProperties climateProperties;
+        protected final EffectsProperties effectsProperties;
+        protected final GenerationProperties generationProperties;
+        protected final SpawnProperties spawnProperties;
+        
+        public BiomeWrapped(Biome biome) {
+            this(biome,
+                    new ClimateWrapped(biome),
+                    new EffectsWrapped(biome),
+                    new GenerationSettingsWrapped(biome),
+                    new SpawnSettingsWrapped(biome));
+        }
+        
+        public BiomeWrapped(Biome biome,
+                ClimateProperties climateProperties,
+                EffectsProperties effectsProperties,
+                GenerationProperties generationProperties,
+                SpawnProperties spawnProperties) {
+            this.biome = biome;
+            this.climateProperties = climateProperties;
+            this.effectsProperties = effectsProperties;
+            this.generationProperties = generationProperties;
+            this.spawnProperties = spawnProperties;
+        }
+        
+        @Override
+        @NotNull
+        public ClimateProperties getClimateProperties() {
+            return climateProperties;
+        }
+        
+        @Override
+        @NotNull
+        public EffectsProperties getEffectsProperties() {
+            return effectsProperties;
+        }
+        
+        @NotNull
+        @Override
+        public GenerationProperties getGenerationProperties() {
+            return generationProperties;
+        }
+        
+        @NotNull
+        @Override
+        public SpawnProperties getSpawnProperties() {
+            return spawnProperties;
+        }
+        
+        @Override
+        @NotNull
+        public BiomeCategory getCategory() {
+            return biome.biomeCategory;
+        }
+        
+        @Override
+        public float getDepth() {
+            return biome.depth;
+        }
+        
+        @Override
+        public float getScale() {
+            return biome.scale;
+        }
+    }
+    
+    public static class MutableBiomeWrapped extends BiomeWrapped implements BiomeProperties.Mutable {
+        public MutableBiomeWrapped(Biome biome,
+                GenerationProperties.Mutable generationProperties,
+                SpawnProperties.Mutable spawnProperties) {
+            this(biome,
+                    new ClimateWrapped(biome.climateSettings),
+                    new EffectsWrapped(biome.getSpecialEffects()),
+                    generationProperties,
+                    spawnProperties);
+        }
+        
+        public MutableBiomeWrapped(Biome biome,
+                ClimateProperties.Mutable climateProperties,
+                EffectsProperties.Mutable effectsProperties,
+                GenerationProperties.Mutable generationProperties,
+                SpawnProperties.Mutable spawnProperties) {
+            super(biome,
+                    climateProperties,
+                    effectsProperties,
+                    generationProperties,
+                    spawnProperties);
+        }
+        
+        @Override
+        public @NotNull ClimateProperties.Mutable getClimateProperties() {
+            return (ClimateProperties.Mutable) super.getClimateProperties();
+        }
+        
+        @Override
+        public @NotNull EffectsProperties.Mutable getEffectsProperties() {
+            return (EffectsProperties.Mutable) super.getEffectsProperties();
+        }
+        
+        @Override
+        public @NotNull GenerationProperties.Mutable getGenerationProperties() {
+            return (GenerationProperties.Mutable) super.getGenerationProperties();
+        }
+        
+        @Override
+        public @NotNull SpawnProperties.Mutable getSpawnProperties() {
+            return (SpawnProperties.Mutable) super.getSpawnProperties();
+        }
+        
+        @Override
+        @NotNull
+        public Mutable setCategory(@NotNull BiomeCategory category) {
+            biome.biomeCategory = category;
+            return this;
+        }
+        
+        @Override
+        @NotNull
+        public Mutable setDepth(float depth) {
+            biome.depth = depth;
+            return this;
+        }
+        
+        @Override
+        @NotNull
+        public Mutable setScale(float scale) {
+            biome.scale = scale;
+            return this;
+        }
+    }
+    
+    public static class ClimateWrapped implements ClimateProperties.Mutable {
+        protected final Biome.ClimateSettings climateSettings;
+        
+        public ClimateWrapped(Biome biome) {
+            this(biome.climateSettings);
+        }
+        
+        public ClimateWrapped(Biome.ClimateSettings climateSettings) {
+            this.climateSettings = climateSettings;
+        }
+        
+        @Override
+        @NotNull
+        public Mutable setPrecipitation(@NotNull Biome.Precipitation precipitation) {
+            climateSettings.precipitation = precipitation;
+            return this;
+        }
+        
+        @Override
+        @NotNull
+        public Mutable setTemperature(float temperature) {
+            climateSettings.temperature = temperature;
+            return this;
+        }
+        
+        @Override
+        @NotNull
+        public Mutable setTemperatureModifier(@NotNull Biome.TemperatureModifier temperatureModifier) {
+            climateSettings.temperatureModifier = temperatureModifier;
+            return this;
+        }
+        
+        @Override
+        @NotNull
+        public Mutable setDownfall(float downfall) {
+            climateSettings.downfall = downfall;
+            return this;
+        }
+        
+        @Override
+        @NotNull
+        public Biome.Precipitation getPrecipitation() {
+            return climateSettings.precipitation;
+        }
+        
+        @Override
+        public float getTemperature() {
+            return climateSettings.temperature;
+        }
+        
+        @Override
+        @NotNull
+        public Biome.TemperatureModifier getTemperatureModifier() {
+            return climateSettings.temperatureModifier;
+        }
+        
+        @Override
+        public float getDownfall() {
+            return climateSettings.downfall;
+        }
+    }
+    
+    public static class EffectsWrapped implements EffectsProperties.Mutable {
+        protected final BiomeSpecialEffects effects;
+        
+        public EffectsWrapped(Biome biome) {
+            this(biome.getSpecialEffects());
+        }
+        
+        public EffectsWrapped(BiomeSpecialEffects effects) {
+            this.effects = effects;
+        }
+        
+        @Override
+        @NotNull
+        public EffectsProperties.Mutable setFogColor(int color) {
+            effects.fogColor = color;
+            return this;
+        }
+        
+        @Override
+        @NotNull
+        public EffectsProperties.Mutable setWaterColor(int color) {
+            effects.waterColor = color;
+            return this;
+        }
+        
+        @Override
+        @NotNull
+        public EffectsProperties.Mutable setWaterFogColor(int color) {
+            effects.waterFogColor = color;
+            return this;
+        }
+        
+        @Override
+        @NotNull
+        public EffectsProperties.Mutable setSkyColor(int color) {
+            effects.skyColor = color;
+            return this;
+        }
+        
+        @Override
+        @NotNull
+        public EffectsProperties.Mutable setFoliageColorOverride(@Nullable Integer colorOverride) {
+            effects.foliageColorOverride = Optional.ofNullable(colorOverride);
+            return this;
+        }
+        
+        @Override
+        @NotNull
+        public EffectsProperties.Mutable setGrassColorOverride(@Nullable Integer colorOverride) {
+            effects.grassColorOverride = Optional.ofNullable(colorOverride);
+            return this;
+        }
+        
+        @Override
+        @NotNull
+        public EffectsProperties.Mutable setGrassColorModifier(@NotNull GrassColorModifier modifier) {
+            effects.grassColorModifier = modifier;
+            return this;
+        }
+        
+        @Override
+        @NotNull
+        public EffectsProperties.Mutable setAmbientParticle(@Nullable AmbientParticleSettings settings) {
+            effects.ambientParticleSettings = Optional.ofNullable(settings);
+            return this;
+        }
+        
+        @Override
+        @NotNull
+        public EffectsProperties.Mutable setAmbientLoopSound(@Nullable SoundEvent sound) {
+            effects.ambientLoopSoundEvent = Optional.ofNullable(sound);
+            return this;
+        }
+        
+        @Override
+        @NotNull
+        public EffectsProperties.Mutable setAmbientMoodSound(@Nullable AmbientMoodSettings settings) {
+            effects.ambientMoodSettings = Optional.ofNullable(settings);
+            return this;
+        }
+        
+        @Override
+        @NotNull
+        public EffectsProperties.Mutable setAmbientAdditionsSound(@Nullable AmbientAdditionsSettings settings) {
+            effects.ambientAdditionsSettings = Optional.ofNullable(settings);
+            return this;
+        }
+        
+        @Override
+        @NotNull
+        public EffectsProperties.Mutable setBackgroundMusic(@Nullable Music music) {
+            effects.backgroundMusic = Optional.ofNullable(music);
+            return this;
+        }
+        
+        @Override
+        public int getFogColor() {
+            return effects.fogColor;
+        }
+        
+        @Override
+        public int getWaterColor() {
+            return effects.waterColor;
+        }
+        
+        @Override
+        public int getWaterFogColor() {
+            return effects.waterFogColor;
+        }
+        
+        @Override
+        public int getSkyColor() {
+            return effects.skyColor;
+        }
+        
+        @Override
+        @NotNull
+        public OptionalInt getFoliageColorOverride() {
+            return effects.foliageColorOverride.map(OptionalInt::of).orElseGet(OptionalInt::empty);
+        }
+        
+        @Override
+        @NotNull
+        public OptionalInt getGrassColorOverride() {
+            return effects.grassColorOverride.map(OptionalInt::of).orElseGet(OptionalInt::empty);
+        }
+        
+        @Override
+        @NotNull
+        public GrassColorModifier getGrassColorModifier() {
+            return effects.grassColorModifier;
+        }
+        
+        @Override
+        @NotNull
+        public Optional<AmbientParticleSettings> getAmbientParticle() {
+            return effects.ambientParticleSettings;
+        }
+        
+        @Override
+        @NotNull
+        public Optional<SoundEvent> getAmbientLoopSound() {
+            return effects.ambientLoopSoundEvent;
+        }
+        
+        @Override
+        @NotNull
+        public Optional<AmbientMoodSettings> getAmbientMoodSound() {
+            return effects.ambientMoodSettings;
+        }
+        
+        @Override
+        @NotNull
+        public Optional<AmbientAdditionsSettings> getAmbientAdditionsSound() {
+            return effects.ambientAdditionsSettings;
+        }
+        
+        @Override
+        @NotNull
+        public Optional<Music> getBackgroundMusic() {
+            return effects.backgroundMusic;
+        }
+    }
+    
+    public static class GenerationSettingsWrapped implements GenerationProperties {
+        protected final BiomeGenerationSettings settings;
+        
+        public GenerationSettingsWrapped(Biome biome) {
+            this(biome.getGenerationSettings());
+        }
+        
+        public GenerationSettingsWrapped(BiomeGenerationSettings settings) {
+            this.settings = settings;
+        }
+        
+        @Override
+        public @NotNull Optional<Supplier<ConfiguredSurfaceBuilder<?>>> getSurfaceBuilder() {
+            return Optional.ofNullable(settings.getSurfaceBuilder());
+        }
+        
+        @Override
+        public @NotNull List<Supplier<ConfiguredWorldCarver<?>>> getCarvers(GenerationStep.Carving carving) {
+            return settings.getCarvers(carving);
+        }
+        
+        @Override
+        public @NotNull List<List<Supplier<ConfiguredFeature<?, ?>>>> getFeatures() {
+            return settings.features();
+        }
+        
+        @Override
+        public @NotNull List<Supplier<ConfiguredStructureFeature<?, ?>>> getStructureStarts() {
+            return (List<Supplier<ConfiguredStructureFeature<?, ?>>>) settings.structures();
+        }
+    }
+    
+    public static class SpawnSettingsWrapped implements SpawnProperties {
+        protected final MobSpawnSettings settings;
+        
+        public SpawnSettingsWrapped(Biome biome) {
+            this(biome.getMobSettings());
+        }
+        
+        public SpawnSettingsWrapped(MobSpawnSettings settings) {
+            this.settings = settings;
+        }
+        
+        @Override
+        public float getCreatureProbability() {
+            return this.settings.getCreatureProbability();
+        }
+        
+        @Override
+        @NotNull
+        public Map<MobCategory, List<MobSpawnSettings.SpawnerData>> getSpawners() {
+            return null;
+        }
+        
+        @Override
+        @NotNull
+        public Map<EntityType<?>, MobSpawnSettings.MobSpawnCost> getMobSpawnCosts() {
+            return null;
+        }
+        
+        @Override
+        public boolean isPlayerSpawnFriendly() {
+            return this.settings.playerSpawnFriendly();
+        }
+    }
+}

+ 71 - 0
common/src/main/java/me/shedaniel/architectury/hooks/biome/BiomeProperties.java

@@ -0,0 +1,71 @@
+/*
+ * This file is part of architectury.
+ * Copyright (C) 2020 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package me.shedaniel.architectury.hooks.biome;
+
+import net.minecraft.world.level.biome.Biome.BiomeCategory;
+import org.jetbrains.annotations.NotNull;
+
+public interface BiomeProperties {
+    @NotNull
+    ClimateProperties getClimateProperties();
+    
+    @NotNull
+    EffectsProperties getEffectsProperties();
+    
+    @NotNull
+    GenerationProperties getGenerationProperties();
+    
+    @NotNull
+    SpawnProperties getSpawnProperties();
+    
+    @NotNull
+    BiomeCategory getCategory();
+    
+    float getDepth();
+    
+    float getScale();
+    
+    interface Mutable extends BiomeProperties {
+        @Override
+        @NotNull
+        ClimateProperties.Mutable getClimateProperties();
+        
+        @Override
+        @NotNull
+        EffectsProperties.Mutable getEffectsProperties();
+        
+        @Override
+        @NotNull
+        GenerationProperties.Mutable getGenerationProperties();
+        
+        @Override
+        @NotNull
+        SpawnProperties.Mutable getSpawnProperties();
+        
+        @NotNull
+        Mutable setCategory(@NotNull BiomeCategory category);
+        
+        @NotNull
+        Mutable setDepth(float depth);
+        
+        @NotNull
+        Mutable setScale(float scale);
+    }
+}

+ 50 - 0
common/src/main/java/me/shedaniel/architectury/hooks/biome/ClimateProperties.java

@@ -0,0 +1,50 @@
+/*
+ * This file is part of architectury.
+ * Copyright (C) 2020 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package me.shedaniel.architectury.hooks.biome;
+
+import net.minecraft.world.level.biome.Biome.Precipitation;
+import net.minecraft.world.level.biome.Biome.TemperatureModifier;
+import org.jetbrains.annotations.NotNull;
+
+public interface ClimateProperties {
+    @NotNull
+    Precipitation getPrecipitation();
+    
+    float getTemperature();
+    
+    @NotNull
+    TemperatureModifier getTemperatureModifier();
+    
+    float getDownfall();
+    
+    interface Mutable extends ClimateProperties {
+        @NotNull
+        Mutable setPrecipitation(@NotNull Precipitation precipitation);
+        
+        @NotNull
+        Mutable setTemperature(float temperature);
+        
+        @NotNull
+        Mutable setTemperatureModifier(@NotNull TemperatureModifier temperatureModifier);
+        
+        @NotNull
+        Mutable setDownfall(float downfall);
+    }
+}

+ 104 - 0
common/src/main/java/me/shedaniel/architectury/hooks/biome/EffectsProperties.java

@@ -0,0 +1,104 @@
+/*
+ * This file is part of architectury.
+ * Copyright (C) 2020 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package me.shedaniel.architectury.hooks.biome;
+
+import net.minecraft.sounds.Music;
+import net.minecraft.sounds.SoundEvent;
+import net.minecraft.world.level.biome.AmbientAdditionsSettings;
+import net.minecraft.world.level.biome.AmbientMoodSettings;
+import net.minecraft.world.level.biome.AmbientParticleSettings;
+import net.minecraft.world.level.biome.BiomeSpecialEffects.GrassColorModifier;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Optional;
+import java.util.OptionalInt;
+
+public interface EffectsProperties {
+    int getFogColor();
+    
+    int getWaterColor();
+    
+    int getWaterFogColor();
+    
+    int getSkyColor();
+    
+    @NotNull
+    OptionalInt getFoliageColorOverride();
+    
+    @NotNull
+    OptionalInt getGrassColorOverride();
+    
+    @NotNull
+    GrassColorModifier getGrassColorModifier();
+    
+    @NotNull
+    Optional<AmbientParticleSettings> getAmbientParticle();
+    
+    @NotNull
+    Optional<SoundEvent> getAmbientLoopSound();
+    
+    @NotNull
+    Optional<AmbientMoodSettings> getAmbientMoodSound();
+    
+    @NotNull
+    Optional<AmbientAdditionsSettings> getAmbientAdditionsSound();
+    
+    @NotNull
+    Optional<Music> getBackgroundMusic();
+    
+    interface Mutable  extends EffectsProperties{
+        @NotNull
+        EffectsProperties.Mutable setFogColor(int color);
+        
+        @NotNull
+        EffectsProperties.Mutable setWaterColor(int color);
+        
+        @NotNull
+        EffectsProperties.Mutable setWaterFogColor(int color);
+        
+        @NotNull
+        EffectsProperties.Mutable setSkyColor(int color);
+        
+        @NotNull
+        EffectsProperties.Mutable setFoliageColorOverride(@Nullable Integer colorOverride);
+        
+        @NotNull
+        EffectsProperties.Mutable setGrassColorOverride(@Nullable Integer colorOverride);
+        
+        @NotNull
+        EffectsProperties.Mutable setGrassColorModifier(@NotNull GrassColorModifier modifier);
+        
+        @NotNull
+        EffectsProperties.Mutable setAmbientParticle(@Nullable AmbientParticleSettings settings);
+        
+        @NotNull
+        EffectsProperties.Mutable setAmbientLoopSound(@Nullable SoundEvent sound);
+        
+        @NotNull
+        EffectsProperties.Mutable setAmbientMoodSound(@Nullable AmbientMoodSettings settings);
+        
+        @NotNull
+        EffectsProperties.Mutable setAmbientAdditionsSound(@Nullable AmbientAdditionsSettings settings);
+        
+        @NotNull
+        EffectsProperties.Mutable setBackgroundMusic(@Nullable Music music);
+    }
+}

+ 61 - 0
common/src/main/java/me/shedaniel/architectury/hooks/biome/GenerationProperties.java

@@ -0,0 +1,61 @@
+/*
+ * This file is part of architectury.
+ * Copyright (C) 2020 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package me.shedaniel.architectury.hooks.biome;
+
+import net.minecraft.world.level.levelgen.GenerationStep;
+import net.minecraft.world.level.levelgen.carver.ConfiguredWorldCarver;
+import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
+import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature;
+import net.minecraft.world.level.levelgen.surfacebuilders.ConfiguredSurfaceBuilder;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.function.Supplier;
+
+public interface GenerationProperties {
+    @NotNull
+    Optional<Supplier<ConfiguredSurfaceBuilder<?>>> getSurfaceBuilder();
+    
+    @NotNull
+    List<Supplier<ConfiguredWorldCarver<?>>> getCarvers(GenerationStep.Carving carving);
+    
+    @NotNull
+    List<List<Supplier<ConfiguredFeature<?, ?>>>> getFeatures();
+    
+    @NotNull
+    List<Supplier<ConfiguredStructureFeature<?, ?>>> getStructureStarts();
+    
+    interface Mutable extends GenerationProperties {
+        Mutable setSurfaceBuilder(ConfiguredSurfaceBuilder<?> builder);
+        
+        Mutable addFeature(GenerationStep.Decoration decoration, ConfiguredFeature<?, ?> feature);
+        
+        Mutable addCarver(GenerationStep.Carving carving, ConfiguredWorldCarver<?> feature);
+        
+        Mutable addStructure(ConfiguredStructureFeature<?, ?> feature);
+        
+        Mutable removeFeature(GenerationStep.Decoration decoration, ConfiguredFeature<?, ?> feature);
+        
+        Mutable removeCarver(GenerationStep.Carving carving, ConfiguredWorldCarver<?> feature);
+        
+        Mutable removeStructure(ConfiguredStructureFeature<?, ?> feature);
+    }
+}

+ 40 - 0
common/src/main/java/me/shedaniel/architectury/hooks/biome/SpawnProperties.java

@@ -0,0 +1,40 @@
+package me.shedaniel.architectury.hooks.biome;
+
+import net.minecraft.world.entity.EntityType;
+import net.minecraft.world.entity.MobCategory;
+import net.minecraft.world.level.biome.MobSpawnSettings;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+import java.util.Map;
+import java.util.function.BiPredicate;
+
+public interface SpawnProperties {
+    float getCreatureProbability();
+    
+    @NotNull
+    Map<MobCategory, List<MobSpawnSettings.SpawnerData>> getSpawners();
+    
+    @NotNull
+    Map<EntityType<?>, MobSpawnSettings.MobSpawnCost> getMobSpawnCosts();
+    
+    boolean isPlayerSpawnFriendly();
+    
+    interface Mutable extends SpawnProperties {
+        @NotNull
+        Mutable setCreatureProbability(float probability);
+        
+        Mutable addSpawn(MobCategory category, MobSpawnSettings.SpawnerData data);
+        
+        boolean removeSpawns(BiPredicate<MobCategory, MobSpawnSettings.SpawnerData> predicate);
+        
+        Mutable setSpawnCost(EntityType<?> entityType, MobSpawnSettings.MobSpawnCost cost);
+        
+        Mutable setSpawnCost(EntityType<?> entityType, double mass, double gravityLimit);
+        
+        Mutable clearSpawnCost(EntityType<?> entityType);
+        
+        @NotNull
+        Mutable setPlayerSpawnFriendly(boolean friendly);
+    }
+}

+ 2 - 1
common/src/main/java/me/shedaniel/architectury/networking/NetworkChannel.java

@@ -26,6 +26,7 @@ import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
 import it.unimi.dsi.fastutil.ints.IntSet;
 import me.shedaniel.architectury.networking.NetworkManager.PacketContext;
 import me.shedaniel.architectury.platform.Platform;
+import me.shedaniel.architectury.utils.Env;
 import net.fabricmc.api.EnvType;
 import net.fabricmc.api.Environment;
 import net.minecraft.client.Minecraft;
@@ -78,7 +79,7 @@ public final class NetworkChannel {
         takenIds.add(id);
         ResourceLocation messageId = new ResourceLocation(this.id.getNamespace(), this.id.getPath() + "_" + id);
         if (!side.isPresent() || side.get() == NetworkManager.s2c()) {
-            if (Platform.getEnv() == EnvType.CLIENT) {
+            if (Platform.getEnvironment() == Env.CLIENT) {
                 NetworkManager.registerReceiver(NetworkManager.s2c(), messageId, (buf, context) -> {
                     messageConsumer.accept(decoder.apply(buf), () -> context);
                 });

+ 6 - 1
common/src/main/java/me/shedaniel/architectury/networking/NetworkManager.java

@@ -20,6 +20,7 @@
 package me.shedaniel.architectury.networking;
 
 import me.shedaniel.architectury.ExpectPlatform;
+import me.shedaniel.architectury.utils.Env;
 import net.fabricmc.api.EnvType;
 import net.fabricmc.api.Environment;
 import net.minecraft.client.Minecraft;
@@ -76,8 +77,12 @@ public final class NetworkManager {
         Player getPlayer();
         
         void queue(Runnable runnable);
+    
+        Env getEnvironment();
         
-        EnvType getEnv();
+        default EnvType getEnv() {
+            return getEnvironment().toPlatform();
+        }
     }
     
     public static Side s2c() {

+ 9 - 3
common/src/main/java/me/shedaniel/architectury/platform/Mod.java

@@ -42,6 +42,12 @@ public interface Mod {
     @NotNull
     String getDescription();
     
+    /**
+     * Gets the logo file path of the mod
+     *
+     * @param preferredSize the preferred logo size, only used in fabric
+     * @return the logo file path relative to the file
+     */
     @NotNull
     Optional<String> getLogoFile(int preferredSize);
     
@@ -54,13 +60,13 @@ public interface Mod {
     @Nullable
     Collection<String> getLicense();
     
-    @Nullable
+    @NotNull
     Optional<String> getHomepage();
     
-    @Nullable
+    @NotNull
     Optional<String> getSources();
     
-    @Nullable
+    @NotNull
     Optional<String> getIssueTracker();
     
     @Environment(EnvType.CLIENT)

+ 7 - 0
common/src/main/java/me/shedaniel/architectury/platform/Platform.java

@@ -21,6 +21,7 @@ package me.shedaniel.architectury.platform;
 
 import me.shedaniel.architectury.Architectury;
 import me.shedaniel.architectury.ExpectPlatform;
+import me.shedaniel.architectury.utils.Env;
 import net.fabricmc.api.EnvType;
 import net.minecraft.SharedConstants;
 import org.jetbrains.annotations.NotNull;
@@ -84,6 +85,12 @@ public final class Platform {
         throw new AssertionError();
     }
     
+    @NotNull
+    @ExpectPlatform
+    public static Env getEnvironment() {
+        throw new AssertionError();
+    }
+    
     @NotNull
     @ExpectPlatform
     public static EnvType getEnv() {

+ 75 - 0
common/src/main/java/me/shedaniel/architectury/registry/BiomeModifications.java

@@ -0,0 +1,75 @@
+/*
+ * This file is part of architectury.
+ * Copyright (C) 2020 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package me.shedaniel.architectury.registry;
+
+import com.google.common.base.Predicates;
+import me.shedaniel.architectury.ExpectPlatform;
+import me.shedaniel.architectury.hooks.biome.BiomeProperties;
+import net.minecraft.resources.ResourceLocation;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.function.BiConsumer;
+import java.util.function.Predicate;
+
+public final class BiomeModifications {
+    public static void addProperties(BiConsumer<BiomeContext, BiomeProperties.Mutable> modifier) {
+        BiomeModifications.addProperties(Predicates.alwaysTrue(), modifier);
+    }
+    
+    @ExpectPlatform
+    public static void addProperties(Predicate<BiomeContext> predicate, BiConsumer<BiomeContext, BiomeProperties.Mutable> modifier) {
+        throw new AssertionError();
+    }
+    
+    public static void postProcessProperties(BiConsumer<BiomeContext, BiomeProperties.Mutable> modifier) {
+        BiomeModifications.postProcessProperties(Predicates.alwaysTrue(), modifier);
+    }
+    
+    @ExpectPlatform
+    public static void postProcessProperties(Predicate<BiomeContext> predicate, BiConsumer<BiomeContext, BiomeProperties.Mutable> modifier) {
+        throw new AssertionError();
+    }
+    
+    public static void removeProperties(BiConsumer<BiomeContext, BiomeProperties.Mutable> modifier) {
+        BiomeModifications.removeProperties(Predicates.alwaysTrue(), modifier);
+    }
+    
+    @ExpectPlatform
+    public static void removeProperties(Predicate<BiomeContext> predicate, BiConsumer<BiomeContext, BiomeProperties.Mutable> modifier) {
+        throw new AssertionError();
+    }
+    
+    public static void replaceProperties(BiConsumer<BiomeContext, BiomeProperties.Mutable> modifier) {
+        BiomeModifications.replaceProperties(Predicates.alwaysTrue(), modifier);
+    }
+    
+    @ExpectPlatform
+    public static void replaceProperties(Predicate<BiomeContext> predicate, BiConsumer<BiomeContext, BiomeProperties.Mutable> modifier) {
+        throw new AssertionError();
+    }
+    
+    public interface BiomeContext {
+        @NotNull
+        ResourceLocation getKey();
+        
+        @NotNull
+        BiomeProperties getProperties();
+    }
+}

+ 7 - 2
common/src/main/java/me/shedaniel/architectury/registry/Registries.java

@@ -22,13 +22,17 @@ package me.shedaniel.architectury.registry;
 import me.shedaniel.architectury.ExpectPlatform;
 import net.minecraft.resources.ResourceKey;
 import net.minecraft.resources.ResourceLocation;
+import org.jetbrains.annotations.ApiStatus;
 import org.jetbrains.annotations.Nullable;
 
-import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 
+/**
+ * Platform-agnostic wrapper of minecraft registries, should be used to register content.
+ */
 public final class Registries {
-    private static final Map<String, Registries> REGISTRIES = new HashMap<>();
+    private static final Map<String, Registries> REGISTRIES = new ConcurrentHashMap<>();
     private final RegistryProvider provider;
     
     public static Registries get(String modId) {
@@ -84,6 +88,7 @@ public final class Registries {
         throw new AssertionError();
     }
     
+    @ApiStatus.Internal
     public interface RegistryProvider {
         <T> Registry<T> get(ResourceKey<net.minecraft.core.Registry<T>> key);
         

+ 46 - 0
common/src/main/java/me/shedaniel/architectury/utils/Env.java

@@ -0,0 +1,46 @@
+/*
+ * This file is part of architectury.
+ * Copyright (C) 2020 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package me.shedaniel.architectury.utils;
+
+import net.fabricmc.api.EnvType;
+
+public enum Env {
+    CLIENT,
+    SERVER;
+    
+    /**
+     * Converts platform-specific environment enum to platform-agnostic environment enum.
+     *
+     * @param type the platform-specific environment enum, could be {@link net.fabricmc.api.EnvType} or {@link net.minecraftforge.api.distmarker.Dist}
+     * @return the platform-agnostic environment enum
+     */
+    public static Env fromPlatform(Object type) {
+        return type == EnvType.CLIENT ? CLIENT : type == EnvType.SERVER ? SERVER : null;
+    }
+    
+    /**
+     * Converts platform-agnostic environment enum to platform-specific environment enum.
+     *
+     * @return the platform-specific environment enum, could be {@link net.fabricmc.api.EnvType} or {@link net.minecraftforge.api.distmarker.Dist}
+     */
+    public EnvType toPlatform() {
+        return this == CLIENT ? EnvType.CLIENT : EnvType.SERVER;
+    }
+}

+ 11 - 3
common/src/main/java/me/shedaniel/architectury/utils/EnvExecutor.java

@@ -27,13 +27,21 @@ import java.util.function.Supplier;
 
 public final class EnvExecutor {
     public static void runInEnv(EnvType type, Supplier<Runnable> runnableSupplier) {
-        if (Platform.getEnv() == type) {
+        runInEnv(Env.fromPlatform(type), runnableSupplier);
+    }
+    
+    public static void runInEnv(Env type, Supplier<Runnable> runnableSupplier) {
+        if (Platform.getEnvironment() == type) {
             runnableSupplier.get().run();
         }
     }
     
     public static <T> Optional<T> getInEnv(EnvType type, Supplier<Supplier<T>> runnableSupplier) {
-        if (Platform.getEnv() == type) {
+        return getInEnv(Env.fromPlatform(type), runnableSupplier);
+    }
+    
+    public static <T> Optional<T> getInEnv(Env type, Supplier<Supplier<T>> runnableSupplier) {
+        if (Platform.getEnvironment() == type) {
             return Optional.ofNullable(runnableSupplier.get().get());
         }
         
@@ -41,7 +49,7 @@ public final class EnvExecutor {
     }
     
     public static <T> T getEnvSpecific(Supplier<Supplier<T>> client, Supplier<Supplier<T>> server) {
-        if (Platform.getEnv() == EnvType.CLIENT) {
+        if (Platform.getEnvironment() == Env.CLIENT) {
             return client.get().get();
         } else {
             return server.get().get();

+ 14 - 0
common/src/main/java/me/shedaniel/architectury/utils/Fraction.java

@@ -25,12 +25,19 @@ import org.jetbrains.annotations.NotNull;
 import java.text.DecimalFormat;
 
 public final class Fraction extends Number implements Comparable<Fraction> {
+    private static final Fraction[] SIMPLE_CACHE = new Fraction[2048];
     private static final Fraction ZERO = ofWhole(0);
     private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("###.###");
     private final long numerator;
     private final long denominator;
     private boolean simplified;
     
+    static {
+        for (int i = 0; i < 2048; i++) {
+            SIMPLE_CACHE[i] = new Fraction(i - 1024, 1);
+        }
+    }
+    
     private Fraction(long numerator, long denominator) {
         if (denominator > 0) {
             this.numerator = numerator;
@@ -49,10 +56,17 @@ public final class Fraction extends Number implements Comparable<Fraction> {
     }
     
     public static Fraction ofWhole(long whole) {
+        if (whole >= -1024 && whole < 1024) {
+            return SIMPLE_CACHE[(int) whole + 1024];
+        }
         return new Fraction(whole, 1);
     }
     
     public static Fraction of(long numerator, long denominator) {
+        if (denominator == 1)
+            return ofWhole(numerator);
+        if (denominator == -1)
+            return ofWhole(-numerator);
         return new Fraction(numerator, denominator);
     }
     

+ 2 - 0
common/src/main/java/me/shedaniel/architectury/utils/GameInstance.java

@@ -24,6 +24,7 @@ import net.fabricmc.api.EnvType;
 import net.fabricmc.api.Environment;
 import net.minecraft.client.Minecraft;
 import net.minecraft.server.MinecraftServer;
+import org.jetbrains.annotations.Nullable;
 
 public final class GameInstance {
     @Environment(EnvType.CLIENT)
@@ -31,6 +32,7 @@ public final class GameInstance {
         return Minecraft.getInstance();
     }
     
+    @Nullable
     @ExpectPlatform
     public static MinecraftServer getServer() {
         throw new AssertionError();

+ 0 - 2
common/src/main/resources/architectury-common.accessWidener

@@ -1,2 +0,0 @@
-accessWidener v1 named
-accessible method net/minecraft/world/level/block/state/BlockBehaviour$Properties <init> (Lnet/minecraft/world/level/material/Material;Ljava/util/function/Function;)V

+ 41 - 0
common/src/main/resources/architectury.accessWidener

@@ -0,0 +1,41 @@
+accessWidener v1 named
+accessible method net/minecraft/world/level/block/state/BlockBehaviour$Properties <init> (Lnet/minecraft/world/level/material/Material;Ljava/util/function/Function;)V
+accessible field net/minecraft/world/level/biome/Biome climateSettings Lnet/minecraft/world/level/biome/Biome$ClimateSettings;
+accessible field net/minecraft/world/level/biome/Biome depth F
+mutable field net/minecraft/world/level/biome/Biome depth F
+accessible field net/minecraft/world/level/biome/Biome scale F
+mutable field net/minecraft/world/level/biome/Biome scale F
+accessible field net/minecraft/world/level/biome/Biome biomeCategory Lnet/minecraft/world/level/biome/Biome$BiomeCategory;
+mutable field net/minecraft/world/level/biome/Biome biomeCategory Lnet/minecraft/world/level/biome/Biome$BiomeCategory;
+accessible field net/minecraft/world/level/biome/Biome$ClimateSettings precipitation Lnet/minecraft/world/level/biome/Biome$Precipitation;
+mutable field net/minecraft/world/level/biome/Biome$ClimateSettings precipitation Lnet/minecraft/world/level/biome/Biome$Precipitation;
+accessible field net/minecraft/world/level/biome/Biome$ClimateSettings temperature F
+mutable field net/minecraft/world/level/biome/Biome$ClimateSettings temperature F
+accessible field net/minecraft/world/level/biome/Biome$ClimateSettings temperatureModifier Lnet/minecraft/world/level/biome/Biome$TemperatureModifier;
+mutable field net/minecraft/world/level/biome/Biome$ClimateSettings temperatureModifier Lnet/minecraft/world/level/biome/Biome$TemperatureModifier;
+accessible field net/minecraft/world/level/biome/Biome$ClimateSettings downfall F
+mutable field net/minecraft/world/level/biome/Biome$ClimateSettings downfall F
+accessible field net/minecraft/world/level/biome/BiomeSpecialEffects fogColor I
+mutable field net/minecraft/world/level/biome/BiomeSpecialEffects fogColor I
+accessible field net/minecraft/world/level/biome/BiomeSpecialEffects waterColor I
+mutable field net/minecraft/world/level/biome/BiomeSpecialEffects waterColor I
+accessible field net/minecraft/world/level/biome/BiomeSpecialEffects waterFogColor I
+mutable field net/minecraft/world/level/biome/BiomeSpecialEffects waterFogColor I
+accessible field net/minecraft/world/level/biome/BiomeSpecialEffects skyColor I
+mutable field net/minecraft/world/level/biome/BiomeSpecialEffects skyColor I
+accessible field net/minecraft/world/level/biome/BiomeSpecialEffects foliageColorOverride Ljava/util/Optional;
+mutable field net/minecraft/world/level/biome/BiomeSpecialEffects foliageColorOverride Ljava/util/Optional;
+accessible field net/minecraft/world/level/biome/BiomeSpecialEffects grassColorOverride Ljava/util/Optional;
+mutable field net/minecraft/world/level/biome/BiomeSpecialEffects grassColorOverride Ljava/util/Optional;
+accessible field net/minecraft/world/level/biome/BiomeSpecialEffects grassColorModifier Lnet/minecraft/world/level/biome/BiomeSpecialEffects$GrassColorModifier;
+mutable field net/minecraft/world/level/biome/BiomeSpecialEffects grassColorModifier Lnet/minecraft/world/level/biome/BiomeSpecialEffects$GrassColorModifier;
+accessible field net/minecraft/world/level/biome/BiomeSpecialEffects ambientParticleSettings Ljava/util/Optional;
+mutable field net/minecraft/world/level/biome/BiomeSpecialEffects ambientParticleSettings Ljava/util/Optional;
+accessible field net/minecraft/world/level/biome/BiomeSpecialEffects ambientLoopSoundEvent Ljava/util/Optional;
+mutable field net/minecraft/world/level/biome/BiomeSpecialEffects ambientLoopSoundEvent Ljava/util/Optional;
+accessible field net/minecraft/world/level/biome/BiomeSpecialEffects ambientMoodSettings Ljava/util/Optional;
+mutable field net/minecraft/world/level/biome/BiomeSpecialEffects ambientMoodSettings Ljava/util/Optional;
+accessible field net/minecraft/world/level/biome/BiomeSpecialEffects ambientAdditionsSettings Ljava/util/Optional;
+mutable field net/minecraft/world/level/biome/BiomeSpecialEffects ambientAdditionsSettings Ljava/util/Optional;
+accessible field net/minecraft/world/level/biome/BiomeSpecialEffects backgroundMusic Ljava/util/Optional;
+mutable field net/minecraft/world/level/biome/BiomeSpecialEffects backgroundMusic Ljava/util/Optional;

+ 1 - 1
common/src/main/resources/fabric.mod.json

@@ -3,5 +3,5 @@
   "schemaVersion": 1,
   "id": "architectury-common",
   "version": "0.0.1",
-  "accessWidener": "architectury-common.accessWidener"
+  "accessWidener": "architectury.accessWidener"
 }

+ 66 - 3
fabric/build.gradle

@@ -1,17 +1,27 @@
+import com.github.jengelman.gradle.plugins.shadow.transformers.Transformer
+import com.github.jengelman.gradle.plugins.shadow.transformers.TransformerContext
+import shadow.org.apache.tools.zip.ZipEntry
+import shadow.org.codehaus.plexus.util.IOUtil
+import shadow.org.apache.tools.zip.ZipOutputStream
+
 plugins {
-    id "fabric-loom"
     id "com.github.johnrengelman.shadow" version "5.0.0"
     id "com.matthewprenger.cursegradle"
 }
 
 loom {
     accessWidener(file("src/main/resources/architectury.accessWidener"))
+    silentMojangMappingsLicense()
 }
 
 configurations {
     shadow
 }
 
+architectury {
+    platformSetupLoomIde()
+}
+
 dependencies {
     minecraft("com.mojang:minecraft:${rootProject.architect.minecraft}")
     mappings(minecraft.officialMojangMappings())
@@ -41,13 +51,16 @@ processResources {
 
 shadowJar {
     relocate "net.jodah.typetools", "me.shedaniel.architectury.shadowed.impl.net.jodah.typetools"
+    transform(MergeAccessWidenersTransformer.class) {
+        it.resource = "architectury.accessWidener"
+    }
     configurations = [project.configurations.shadow]
     classifier "shadow"
 }
 
 remapJar {
     dependsOn(shadowJar)
-    input.set(shadowJar.archivePath)
+    input.set(shadowJar.archiveFile)
     archiveClassifier = "fabric"
 }
 
@@ -91,4 +104,54 @@ curseforge {
     }
 }
 
-rootProject.tasks.getByName("curseforgePublish").dependsOn tasks.getByName("curseforge")
+rootProject.tasks.getByName("curseforgePublish").dependsOn tasks.getByName("curseforge")
+
+class MergeAccessWidenersTransformer implements Transformer {
+    String resource
+    ByteArrayOutputStream data
+
+    MergeAccessWidenersTransformer() {
+        data = new ByteArrayOutputStream()
+        data.write("accessWidener v1 named\n".bytes)
+    }
+
+    @Override
+    boolean canTransformResource(FileTreeElement element) {
+        def path = element.relativePath.pathString
+        if (resource != null && resource.equalsIgnoreCase(path)) {
+            return true
+        }
+
+        return false
+    }
+
+    @Override
+    void transform(TransformerContext context) {
+        def lines = context.is.readLines()
+        lines.removeIf { it == "accessWidener v1 named" }
+        IOUtil.copy(lines.join("\n"), data)
+        data.write('\n'.bytes)
+
+        context.is.close()
+    }
+
+    @Override
+    boolean hasTransformedResource() {
+        return data.size() > 0
+    }
+
+    void modifyOutputStream(org.apache.tools.zip.ZipOutputStream jos, boolean preserveFileTimestamps) {
+        throw new AbstractMethodError()
+    }
+
+    @Override
+    void modifyOutputStream(ZipOutputStream os, boolean preserveFileTimestamps) {
+        ZipEntry entry = new ZipEntry(resource)
+        entry.time = TransformerContext.getEntryTimestamp(preserveFileTimestamps, entry.time)
+        os.putNextEntry(entry)
+
+        IOUtil.copy(new ByteArrayInputStream(data.toByteArray()), os)
+        data.reset()
+        data.write('accessWidener v1 named\n'.bytes)
+    }
+}

+ 2 - 1
fabric/src/main/java/me/shedaniel/architectury/hooks/fabric/FluidStackHooksImpl.java

@@ -21,6 +21,7 @@ package me.shedaniel.architectury.hooks.fabric;
 
 import me.shedaniel.architectury.fluid.FluidStack;
 import me.shedaniel.architectury.platform.Platform;
+import me.shedaniel.architectury.utils.Env;
 import me.shedaniel.architectury.utils.Fraction;
 import me.shedaniel.architectury.utils.NbtType;
 import net.fabricmc.api.EnvType;
@@ -38,7 +39,7 @@ import java.util.Objects;
 
 public class FluidStackHooksImpl {
     public static Component getName(FluidStack stack) {
-        if (Platform.getEnv() == EnvType.CLIENT) {
+        if (Platform.getEnvironment() == Env.CLIENT) {
             return getNameClient(stack);
         }
         

+ 3 - 2
fabric/src/main/java/me/shedaniel/architectury/networking/fabric/NetworkManagerImpl.java

@@ -21,6 +21,7 @@ package me.shedaniel.architectury.networking.fabric;
 
 import me.shedaniel.architectury.networking.NetworkManager;
 import me.shedaniel.architectury.networking.NetworkManager.NetworkReceiver;
+import me.shedaniel.architectury.utils.Env;
 import net.fabricmc.api.EnvType;
 import net.fabricmc.api.Environment;
 import net.fabricmc.fabric.api.network.ClientSidePacketRegistry;
@@ -63,8 +64,8 @@ public class NetworkManagerImpl {
             }
             
             @Override
-            public EnvType getEnv() {
-                return context.getPacketEnvironment();
+            public Env getEnvironment() {
+                return Env.fromPlatform(context.getPacketEnvironment());
             }
         };
     }

+ 10 - 5
fabric/src/main/java/me/shedaniel/architectury/platform/fabric/PlatformImpl.java

@@ -20,6 +20,7 @@
 package me.shedaniel.architectury.platform.fabric;
 
 import me.shedaniel.architectury.platform.Mod;
+import me.shedaniel.architectury.utils.Env;
 import net.fabricmc.api.EnvType;
 import net.fabricmc.loader.api.FabricLoader;
 import net.fabricmc.loader.api.ModContainer;
@@ -51,6 +52,10 @@ public class PlatformImpl {
         return getGameFolder().resolve("mods");
     }
     
+    public static Env getEnvironment() {
+        return Env.fromPlatform(getEnv());
+    }
+    
     public static EnvType getEnv() {
         return FabricLoader.getInstance().getEnvironmentType();
     }
@@ -116,31 +121,31 @@ public class PlatformImpl {
         public @NotNull Path getFilePath() {
             return container.getRootPath();
         }
-    
+        
         @Override
         public @NotNull Collection<String> getAuthors() {
             return metadata.getAuthors().stream()
                     .map(Person::getName)
                     .collect(Collectors.toList());
         }
-    
+        
         @Override
         public @Nullable Collection<String> getLicense() {
             return metadata.getLicense();
         }
         
         @Override
-        public @Nullable Optional<String> getHomepage() {
+        public @NotNull Optional<String> getHomepage() {
             return metadata.getContact().get("homepage");
         }
         
         @Override
-        public @Nullable Optional<String> getSources() {
+        public @NotNull Optional<String> getSources() {
             return metadata.getContact().get("issues");
         }
         
         @Override
-        public @Nullable Optional<String> getIssueTracker() {
+        public @NotNull Optional<String> getIssueTracker() {
             return metadata.getContact().get("sources");
         }
         

+ 370 - 0
fabric/src/main/java/me/shedaniel/architectury/registry/fabric/BiomeModificationsImpl.java

@@ -0,0 +1,370 @@
+/*
+ * This file is part of architectury.
+ * Copyright (C) 2020 shedaniel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package me.shedaniel.architectury.registry.fabric;
+
+import com.google.common.base.Predicates;
+import com.google.common.collect.Lists;
+import me.shedaniel.architectury.hooks.biome.*;
+import me.shedaniel.architectury.registry.BiomeModifications.BiomeContext;
+import net.fabricmc.fabric.api.biome.v1.BiomeModification;
+import net.fabricmc.fabric.api.biome.v1.BiomeModificationContext;
+import net.fabricmc.fabric.api.biome.v1.BiomeModificationContext.GenerationSettingsContext;
+import net.fabricmc.fabric.api.biome.v1.BiomeModificationContext.SpawnSettingsContext;
+import net.fabricmc.fabric.api.biome.v1.BiomeSelectionContext;
+import net.fabricmc.fabric.api.biome.v1.ModificationPhase;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.sounds.Music;
+import net.minecraft.sounds.SoundEvent;
+import net.minecraft.world.entity.EntityType;
+import net.minecraft.world.entity.MobCategory;
+import net.minecraft.world.level.biome.*;
+import net.minecraft.world.level.biome.Biome.BiomeCategory;
+import net.minecraft.world.level.biome.Biome.Precipitation;
+import net.minecraft.world.level.biome.Biome.TemperatureModifier;
+import net.minecraft.world.level.biome.BiomeSpecialEffects.GrassColorModifier;
+import net.minecraft.world.level.levelgen.GenerationStep;
+import net.minecraft.world.level.levelgen.carver.ConfiguredWorldCarver;
+import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
+import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature;
+import net.minecraft.world.level.levelgen.surfacebuilders.ConfiguredSurfaceBuilder;
+import org.apache.commons.lang3.tuple.Pair;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.function.BiConsumer;
+import java.util.function.BiPredicate;
+import java.util.function.Predicate;
+
+public class BiomeModificationsImpl {
+    private static final ResourceLocation FABRIC_MODIFICATION = new ResourceLocation("architectury", "fabric_modification");
+    private static final List<Pair<Predicate<BiomeContext>, BiConsumer<BiomeContext, BiomeProperties.Mutable>>> ADDITIONS = Lists.newArrayList();
+    private static final List<Pair<Predicate<BiomeContext>, BiConsumer<BiomeContext, BiomeProperties.Mutable>>> POST_PROCESSING = Lists.newArrayList();
+    private static final List<Pair<Predicate<BiomeContext>, BiConsumer<BiomeContext, BiomeProperties.Mutable>>> REMOVALS = Lists.newArrayList();
+    private static final List<Pair<Predicate<BiomeContext>, BiConsumer<BiomeContext, BiomeProperties.Mutable>>> REPLACEMENTS = Lists.newArrayList();
+    
+    public static void addProperties(Predicate<BiomeContext> predicate, BiConsumer<BiomeContext, BiomeProperties.Mutable> modifier) {
+        ADDITIONS.add(Pair.of(predicate, modifier));
+    }
+    
+    public static void postProcessProperties(Predicate<BiomeContext> predicate, BiConsumer<BiomeContext, BiomeProperties.Mutable> modifier) {
+        ADDITIONS.add(Pair.of(predicate, modifier));
+    }
+    
+    public static void removeProperties(Predicate<BiomeContext> predicate, BiConsumer<BiomeContext, BiomeProperties.Mutable> modifier) {
+        ADDITIONS.add(Pair.of(predicate, modifier));
+    }
+    
+    public static void replaceProperties(Predicate<BiomeContext> predicate, BiConsumer<BiomeContext, BiomeProperties.Mutable> modifier) {
+        ADDITIONS.add(Pair.of(predicate, modifier));
+    }
+    
+    static {
+        BiomeModification modification = net.fabricmc.fabric.api.biome.v1.BiomeModifications.create(FABRIC_MODIFICATION);
+        registerModification(modification,ModificationPhase.ADDITIONS, ADDITIONS);
+        registerModification(modification,ModificationPhase.POST_PROCESSING, POST_PROCESSING);
+        registerModification(modification,ModificationPhase.REMOVALS, REMOVALS);
+        registerModification(modification,ModificationPhase.REPLACEMENTS, REPLACEMENTS);
+    }
+    
+    private static void registerModification( BiomeModification modification, ModificationPhase phase, List<Pair<Predicate<BiomeContext>, BiConsumer<BiomeContext, BiomeProperties.Mutable>>> list ) {
+        modification.add(phase, Predicates.alwaysTrue(), (biomeSelectionContext, biomeModificationContext) -> {
+            BiomeContext biomeContext = wrapSelectionContext(biomeSelectionContext);
+            BiomeProperties.Mutable mutableBiome = wrapMutableBiome(biomeSelectionContext.getBiome(), biomeModificationContext);
+            for (Pair<Predicate<BiomeContext>, BiConsumer<BiomeContext, BiomeProperties.Mutable>> pair : list) {
+                if (pair.getLeft().test(biomeContext)) {
+                    pair.getRight().accept(biomeContext, mutableBiome);
+                }
+            }
+        });
+    }
+    
+    private static BiomeContext wrapSelectionContext(BiomeSelectionContext context) {
+        return new BiomeContext() {
+            BiomeProperties properties = BiomeHooks.getBiomeProperties(context.getBiome());
+            
+            @Override
+            @NotNull
+            public ResourceLocation getKey() {
+                return context.getBiomeKey().location();
+            }
+            
+            @Override
+            @NotNull
+            public BiomeProperties getProperties() {
+                return properties;
+            }
+        };
+    }
+    
+    private static BiomeProperties.Mutable wrapMutableBiome(Biome biome, BiomeModificationContext context) {
+        return new BiomeHooks.MutableBiomeWrapped(
+                biome,
+                wrapWeather(biome, context.getWeather()),
+                wrapEffects(biome, context.getEffects()),
+                new MutableGenerationProperties(biome, context.getGenerationSettings()),
+                new MutableSpawnProperties(biome, context.getSpawnSettings())
+        ) {
+            @Override
+            @NotNull
+            public BiomeProperties.Mutable setCategory(@NotNull BiomeCategory category) {
+                context.setCategory(category);
+                return this;
+            }
+            
+            @Override
+            @NotNull
+            public BiomeProperties.Mutable setDepth(float depth) {
+                context.setDepth(depth);
+                return this;
+            }
+            
+            @Override
+            @NotNull
+            public BiomeProperties.Mutable setScale(float scale) {
+                context.setScale(scale);
+                return this;
+            }
+        };
+    }
+    
+    private static class MutableGenerationProperties extends BiomeHooks.GenerationSettingsWrapped implements GenerationProperties.Mutable {
+        protected final GenerationSettingsContext context;
+        
+        public MutableGenerationProperties(Biome biome, GenerationSettingsContext context) {
+            super(biome);
+            this.context = context;
+        }
+    
+        @Override
+        public Mutable setSurfaceBuilder(ConfiguredSurfaceBuilder<?> builder) {
+            this.context.setBuiltInSurfaceBuilder(builder);
+            return this;
+        }
+    
+        @Override
+        public Mutable addFeature(GenerationStep.Decoration decoration, ConfiguredFeature<?, ?> feature) {
+            this.context.addBuiltInFeature(decoration, feature);
+            return this;
+        }
+    
+        @Override
+        public Mutable addCarver(GenerationStep.Carving carving, ConfiguredWorldCarver<?> feature) {
+            context.addBuiltInCarver(carving, feature);
+            return this;
+        }
+    
+        @Override
+        public Mutable addStructure(ConfiguredStructureFeature<?, ?> feature) {
+            context.addBuiltInStructure(feature);
+            return this;
+        }
+    
+        @Override
+        public Mutable removeFeature(GenerationStep.Decoration decoration, ConfiguredFeature<?, ?> feature) {
+            context.removeBuiltInFeature(decoration, feature);
+            return this;
+        }
+    
+        @Override
+        public Mutable removeCarver(GenerationStep.Carving carving, ConfiguredWorldCarver<?> feature) {
+            context.removeBuiltInCarver(carving, feature);
+            return this;
+        }
+    
+        @Override
+        public Mutable removeStructure(ConfiguredStructureFeature<?, ?> feature) {
+            context.removeBuiltInStructure(feature);
+            return this;
+        }
+    }
+    
+    private static class MutableSpawnProperties extends BiomeHooks.SpawnSettingsWrapped implements SpawnProperties.Mutable {
+        protected final SpawnSettingsContext context;
+    
+        public MutableSpawnProperties(Biome biome, SpawnSettingsContext context) {
+            super(biome);
+            this.context = context;
+        }
+    
+        @Override
+        public @NotNull Mutable setCreatureProbability(float probability) {
+            context.setCreatureSpawnProbability(probability);
+            return this;
+        }
+    
+        @Override
+        public Mutable addSpawn(MobCategory category, MobSpawnSettings.SpawnerData data) {
+            context.addSpawn(category, data);
+            return this;
+        }
+    
+        @Override
+        public boolean removeSpawns(BiPredicate<MobCategory, MobSpawnSettings.SpawnerData> predicate) {
+            return context.removeSpawns(predicate);
+        }
+    
+        @Override
+        public Mutable setSpawnCost(EntityType<?> entityType, MobSpawnSettings.MobSpawnCost cost) {
+            context.setSpawnCost(entityType, cost.getCharge(), cost.getEnergyBudget());
+            return this;
+        }
+    
+        @Override
+        public Mutable setSpawnCost(EntityType<?> entityType, double mass, double gravityLimit) {
+            context.setSpawnCost(entityType, mass, gravityLimit);
+            return this;
+        }
+    
+        @Override
+        public Mutable clearSpawnCost(EntityType<?> entityType) {
+            context.clearSpawnCost(entityType);
+            return this;
+        }
+    
+        @Override
+        public @NotNull Mutable setPlayerSpawnFriendly(boolean friendly) {
+            context.setPlayerSpawnFriendly(friendly);
+            return this;
+        }
+    }
+    
+    private static ClimateProperties.Mutable wrapWeather(Biome biome, BiomeModificationContext.WeatherContext context) {
+        return new BiomeHooks.ClimateWrapped(biome) {
+            @Override
+            @NotNull
+            public ClimateProperties.Mutable setPrecipitation(@NotNull Precipitation precipitation) {
+                context.setPrecipitation(precipitation);
+                return this;
+            }
+            
+            @Override
+            @NotNull
+            public ClimateProperties.Mutable setTemperature(float temperature) {
+                context.setTemperature(temperature);
+                return this;
+            }
+            
+            @Override
+            @NotNull
+            public ClimateProperties.Mutable setTemperatureModifier(@NotNull TemperatureModifier temperatureModifier) {
+                context.setTemperatureModifier(temperatureModifier);
+                return this;
+            }
+            
+            @Override
+            @NotNull
+            public ClimateProperties.Mutable setDownfall(float downfall) {
+                context.setDownfall(downfall);
+                return this;
+            }
+        };
+    }
+    
+    private static EffectsProperties.Mutable wrapEffects(Biome biome, BiomeModificationContext.EffectsContext context) {
+        return new BiomeHooks.EffectsWrapped(biome) {
+            @Override
+            @NotNull
+            public EffectsProperties.Mutable setFogColor(int color) {
+                context.setFogColor(color);
+                return this;
+            }
+            
+            @Override
+            @NotNull
+            public EffectsProperties.Mutable setWaterColor(int color) {
+                context.setWaterColor(color);
+                return this;
+            }
+            
+            @Override
+            @NotNull
+            public EffectsProperties.Mutable setWaterFogColor(int color) {
+                context.setWaterFogColor(color);
+                return this;
+            }
+            
+            @Override
+            @NotNull
+            public EffectsProperties.Mutable setSkyColor(int color) {
+                context.setSkyColor(color);
+                return this;
+            }
+            
+            @Override
+            @NotNull
+            public EffectsProperties.Mutable setFoliageColorOverride(@Nullable Integer colorOverride) {
+                context.setFoliageColor(Optional.ofNullable(colorOverride));
+                return this;
+            }
+            
+            @Override
+            @NotNull
+            public EffectsProperties.Mutable setGrassColorOverride(@Nullable Integer colorOverride) {
+                context.setGrassColor(Optional.ofNullable(colorOverride));
+                return this;
+            }
+            
+            @Override
+            @NotNull
+            public EffectsProperties.Mutable setGrassColorModifier(@NotNull GrassColorModifier modifier) {
+                context.setGrassColorModifier(modifier);
+                return this;
+            }
+            
+            @Override
+            @NotNull
+            public EffectsProperties.Mutable setAmbientParticle(@Nullable AmbientParticleSettings settings) {
+                context.setParticleConfig(Optional.ofNullable(settings));
+                return this;
+            }
+            
+            @Override
+            @NotNull
+            public EffectsProperties.Mutable setAmbientLoopSound(@Nullable SoundEvent sound) {
+                context.setAmbientSound(Optional.ofNullable(sound));
+                return this;
+            }
+            
+            @Override
+            @NotNull
+            public EffectsProperties.Mutable setAmbientMoodSound(@Nullable AmbientMoodSettings settings) {
+                context.setMoodSound(Optional.ofNullable(settings));
+                return this;
+            }
+            
+            @Override
+            @NotNull
+            public EffectsProperties.Mutable setAmbientAdditionsSound(@Nullable AmbientAdditionsSettings settings) {
+                context.setAdditionsSound(Optional.ofNullable(settings));
+                return this;
+            }
+            
+            @Override
+            @NotNull
+            public EffectsProperties.Mutable setBackgroundMusic(@Nullable Music music) {
+                context.setMusic(Optional.ofNullable(music));
+                return this;
+            }
+        };
+    }
+    
+}

+ 1 - 4
fabric/src/main/java/me/shedaniel/architectury/registry/fabric/RegistriesImpl.java

@@ -27,10 +27,7 @@ import net.minecraft.util.LazyLoadedValue;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
+import java.util.*;
 import java.util.function.Supplier;
 
 public class RegistriesImpl {

+ 2 - 1
fabric/src/main/java/me/shedaniel/architectury/utils/fabric/GameInstanceImpl.java

@@ -22,6 +22,7 @@ package me.shedaniel.architectury.utils.fabric;
 import me.shedaniel.architectury.event.EventHandler;
 import me.shedaniel.architectury.event.events.LifecycleEvent;
 import me.shedaniel.architectury.platform.Platform;
+import me.shedaniel.architectury.utils.Env;
 import net.fabricmc.api.EnvType;
 import net.fabricmc.api.Environment;
 import net.minecraft.client.Minecraft;
@@ -33,7 +34,7 @@ public class GameInstanceImpl {
     public static MinecraftServer getServer() {
         MinecraftServer server = null;
         if (GameInstanceImpl.server != null) server = GameInstanceImpl.server;
-        if (Platform.getEnv() == EnvType.CLIENT) {
+        if (Platform.getEnvironment() == Env.CLIENT) {
             server = getServerFromClient();
         }
         return server;

+ 3 - 0
fabric/src/main/resources/fabric.mod.json

@@ -23,5 +23,8 @@
   "accessWidener": "architectury.accessWidener",
   "depends": {
     "minecraft": ">=1.16.4"
+  },
+  "custom": {
+    "modmenu:api": true
   }
 }

+ 31 - 58
forge/build.gradle

@@ -1,93 +1,66 @@
-buildscript {
-    repositories {
-        maven { url "https://files.minecraftforge.net/maven" }
-        jcenter()
-        mavenCentral()
-    }
-    dependencies {
-        classpath(group: "net.minecraftforge.gradle", name: "ForgeGradle", version: "3.+", changing: true)
-    }
-}
-
 plugins {
     id "com.github.johnrengelman.shadow" version "5.0.0"
-    id "eclipse"
     id "com.matthewprenger.cursegradle"
 }
 
-apply plugin: "net.minecraftforge.gradle"
-
-minecraft {
-    mappings(channel: "official", version: rootProject.architect.minecraft)
-    accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg')
-    runs {
-        client {
-            workingDirectory project.file("run")
-            mods {
-                architectury {
-                    source sourceSets.main
-                }
-            }
-        }
-        server {
-            workingDirectory project.file("run")
-            mods {
-                architectury {
-                    source sourceSets.main
-                }
-            }
-        }
-    }
-}
-
-processResources {
-    filesMatching("META-INF/mods.toml") {
-        expand "version": project.version
-    }
-    inputs.property "META-INF/mods.toml", project.version
-}
-
-repositories {
-    jcenter()
-    maven { url "https://files.minecraftforge.net/maven" }
+loom {
+    silentMojangMappingsLicense()
+    mixinConfig = "architectury.mixins.json"
 }
 
 configurations {
     shadow
 }
 
+architectury {
+    platformSetupLoomIde()
+}
+
 dependencies {
-    minecraft("net.minecraftforge:forge:${rootProject.architect.minecraft}-${rootProject.forge_version}")
+    minecraft("com.mojang:minecraft:${rootProject.architect.minecraft}")
+    mappings(minecraft.officialMojangMappings())
+    forge("net.minecraftforge:forge:${rootProject.architect.minecraft}-${rootProject.forge_version}")
     implementation "net.jodah:typetools:0.6.2"
     shadow "net.jodah:typetools:0.6.2"
 
-    compile(project(path: ":common", configuration: "mcpGenerateMod")) {
+    compileOnly(project(path: ":common")) {
+        transitive = false
+    }
+    runtimeOnly(project(path: ":common", configuration: "transformForgeFakeMod")) {
         transitive = false
     }
-    shadow(project(path: ":common", configuration: "mcp")) {
+    shadow(project(path: ":common", configuration: "transformForge")) {
         transitive = false
     }
 }
 
+processResources {
+    filesMatching("META-INF/mods.toml") {
+        expand "version": project.version
+    }
+    inputs.property "META-INF/mods.toml", project.version
+}
+
 shadowJar {
     relocate "net.jodah.typetools", "me.shedaniel.architectury.shadowed.impl.net.jodah.typetools"
     exclude "fabric.mod.json"
+    exclude "architectury-common.accessWidener"
 
     configurations = [project.configurations.shadow]
-    classifier "forge"
+    classifier "shadow"
 }
 
-reobf {
-    shadowJar {}
+remapJar {
+    dependsOn(shadowJar)
+    input.set(shadowJar.archivePath)
+    archiveClassifier = "forge"
 }
 
-build.dependsOn(shadowJar)
-
 publishing {
     publications {
         mavenForge(MavenPublication) {
-            artifact(shadowJar.archivePath) {
-                builtBy shadowJar
+            artifact(remapJar.archivePath) {
+                builtBy build
                 classifier "forge"
             }
         }
@@ -105,7 +78,7 @@ curseforge {
             addGameVersion "1.16.4"
             addGameVersion "Java 8"
             addGameVersion "Forge"
-            mainArtifact(shadowJar.archivePath) {
+            mainArtifact(remapJar.archivePath) {
                 displayName = "[Forge $rootProject.supported_version] v$project.version"
             }
             afterEvaluate {

+ 1 - 0
forge/gradle.properties

@@ -0,0 +1 @@
+loom.forge=true

+ 15 - 15
forge/src/main/java/me/shedaniel/architectury/event/forge/EventHandlerImplClient.java

@@ -28,11 +28,11 @@ import me.shedaniel.architectury.event.events.client.ClientTickEvent;
 import me.shedaniel.architectury.impl.TooltipEventColorContextImpl;
 import me.shedaniel.architectury.impl.TooltipEventPositionContextImpl;
 import net.minecraft.client.Minecraft;
-import net.minecraft.client.gui.IGuiEventListener;
-import net.minecraft.client.world.ClientWorld;
-import net.minecraft.util.ActionResult;
-import net.minecraft.util.ActionResultType;
-import net.minecraft.util.text.ITextComponent;
+import net.minecraft.client.gui.components.events.GuiEventListener;
+import net.minecraft.client.multiplayer.ClientLevel;
+import net.minecraft.network.chat.Component;
+import net.minecraft.world.InteractionResult;
+import net.minecraft.world.InteractionResultHolder;
 import net.minecraftforge.api.distmarker.Dist;
 import net.minecraftforge.api.distmarker.OnlyIn;
 import net.minecraftforge.client.event.*;
@@ -81,14 +81,14 @@ public class EventHandlerImplClient {
     
     @SubscribeEvent
     public static void event(GuiScreenEvent.InitGuiEvent.Pre event) {
-        if (GuiEvent.INIT_PRE.invoker().init(event.getGui(), event.getWidgetList(), (List<IGuiEventListener>) event.getGui().children()) == ActionResultType.FAIL) {
+        if (GuiEvent.INIT_PRE.invoker().init(event.getGui(), event.getWidgetList(), (List<GuiEventListener>) event.getGui().children()) == InteractionResult.FAIL) {
             event.setCanceled(true);
         }
     }
     
     @SubscribeEvent
     public static void event(GuiScreenEvent.InitGuiEvent.Post event) {
-        GuiEvent.INIT_POST.invoker().init(event.getGui(), event.getWidgetList(), (List<IGuiEventListener>) event.getGui().children());
+        GuiEvent.INIT_POST.invoker().init(event.getGui(), event.getWidgetList(), (List<GuiEventListener>) event.getGui().children());
     }
     
     @SubscribeEvent
@@ -99,33 +99,33 @@ public class EventHandlerImplClient {
     
     @SubscribeEvent
     public static void event(net.minecraftforge.client.event.ClientChatEvent event) {
-        ActionResult<String> process = ClientChatEvent.CLIENT.invoker().process(event.getMessage());
+        InteractionResultHolder<String> process = ClientChatEvent.CLIENT.invoker().process(event.getMessage());
         if (process.getObject() != null)
             event.setMessage(process.getObject());
-        if (process.getResult() == ActionResultType.FAIL)
+        if (process.getResult() == InteractionResult.FAIL)
             event.setCanceled(true);
     }
     
     @SubscribeEvent
     public static void event(ClientChatReceivedEvent event) {
-        ActionResult<ITextComponent> process = ClientChatEvent.CLIENT_RECEIVED.invoker().process(event.getType(), event.getMessage(), event.getSenderUUID());
+        InteractionResultHolder<Component> process = ClientChatEvent.CLIENT_RECEIVED.invoker().process(event.getType(), event.getMessage(), event.getSenderUUID());
         if (process.getObject() != null)
             event.setMessage(process.getObject());
-        if (process.getResult() == ActionResultType.FAIL)
+        if (process.getResult() == InteractionResult.FAIL)
             event.setCanceled(true);
     }
     
     @SubscribeEvent
     public static void event(WorldEvent.Save event) {
-        if (event.getWorld() instanceof ClientWorld) {
-            ClientWorld world = (ClientWorld) event.getWorld();
+        if (event.getWorld() instanceof ClientLevel) {
+            ClientLevel world = (ClientLevel) event.getWorld();
             ClientLifecycleEvent.CLIENT_WORLD_LOAD.invoker().act(world);
         }
     }
     
     @SubscribeEvent
     public static void event(GuiScreenEvent.DrawScreenEvent.Pre event) {
-        if (GuiEvent.RENDER_PRE.invoker().render(event.getGui(), event.getMatrixStack(), event.getMouseX(), event.getMouseY(), event.getRenderPartialTicks()) == ActionResultType.FAIL) {
+        if (GuiEvent.RENDER_PRE.invoker().render(event.getGui(), event.getMatrixStack(), event.getMouseX(), event.getMouseY(), event.getRenderPartialTicks()) == InteractionResult.FAIL) {
             event.setCanceled(true);
         }
     }
@@ -155,7 +155,7 @@ public class EventHandlerImplClient {
     
     @SubscribeEvent
     public static void event(RenderTooltipEvent.Pre event) {
-        if (TooltipEvent.RENDER_FORGE_PRE.invoker().renderTooltip(event.getMatrixStack(), event.getLines(), event.getX(), event.getY()) == ActionResultType.FAIL) {
+        if (TooltipEvent.RENDER_FORGE_PRE.invoker().renderTooltip(event.getMatrixStack(), event.getLines(), event.getX(), event.getY()) == InteractionResult.FAIL) {
             event.setCanceled(true);
             return;
         }

+ 43 - 43
forge/src/main/java/me/shedaniel/architectury/event/forge/EventHandlerImplCommon.java

@@ -21,13 +21,13 @@ package me.shedaniel.architectury.event.forge;
 
 import me.shedaniel.architectury.event.events.*;
 import me.shedaniel.architectury.utils.IntValue;
-import net.minecraft.entity.player.ServerPlayerEntity;
-import net.minecraft.item.ItemStack;
-import net.minecraft.util.ActionResult;
-import net.minecraft.util.ActionResultType;
-import net.minecraft.util.text.ITextComponent;
-import net.minecraft.world.World;
-import net.minecraft.world.server.ServerWorld;
+import net.minecraft.network.chat.Component;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.world.InteractionResult;
+import net.minecraft.world.InteractionResultHolder;
+import net.minecraft.world.item.ItemStack;
+import net.minecraft.world.level.Level;
 import net.minecraftforge.event.CommandEvent;
 import net.minecraftforge.event.RegisterCommandsEvent;
 import net.minecraftforge.event.ServerChatEvent;
@@ -67,9 +67,9 @@ public class EventHandlerImplCommon {
     public static void event(WorldTickEvent event) {
         if (event.side == LogicalSide.SERVER) {
             if (event.phase == Phase.START)
-                TickEvent.SERVER_WORLD_PRE.invoker().tick((ServerWorld) event.world);
+                TickEvent.SERVER_WORLD_PRE.invoker().tick((ServerLevel) event.world);
             else if (event.phase == Phase.END)
-                TickEvent.SERVER_WORLD_POST.invoker().tick((ServerWorld) event.world);
+                TickEvent.SERVER_WORLD_POST.invoker().tick((ServerLevel) event.world);
         }
     }
     
@@ -100,23 +100,23 @@ public class EventHandlerImplCommon {
     
     @SubscribeEvent
     public static void event(PlayerLoggedInEvent event) {
-        PlayerEvent.PLAYER_JOIN.invoker().join((ServerPlayerEntity) event.getPlayer());
+        PlayerEvent.PLAYER_JOIN.invoker().join((ServerPlayer) event.getPlayer());
     }
     
     @SubscribeEvent
     public static void event(PlayerLoggedOutEvent event) {
-        PlayerEvent.PLAYER_QUIT.invoker().quit((ServerPlayerEntity) event.getPlayer());
+        PlayerEvent.PLAYER_QUIT.invoker().quit((ServerPlayer) event.getPlayer());
     }
     
     @SubscribeEvent
     public static void event(PlayerRespawnEvent event) {
-        PlayerEvent.PLAYER_RESPAWN.invoker().respawn((ServerPlayerEntity) event.getPlayer(), event.isEndConquered());
+        PlayerEvent.PLAYER_RESPAWN.invoker().respawn((ServerPlayer) event.getPlayer(), event.isEndConquered());
     }
     
     @SubscribeEvent
     public static void event(CommandEvent event) {
         CommandPerformEvent performEvent = new CommandPerformEvent(event.getParseResults(), event.getException());
-        if (CommandPerformEvent.EVENT.invoker().act(performEvent) == ActionResultType.FAIL) {
+        if (CommandPerformEvent.EVENT.invoker().act(performEvent) == InteractionResult.FAIL) {
             event.setCanceled(true);
         }
         event.setParseResults(performEvent.getResults());
@@ -134,61 +134,61 @@ public class EventHandlerImplCommon {
     
     @SubscribeEvent
     public static void event(ServerChatEvent event) {
-        ActionResult<ITextComponent> process = ChatEvent.SERVER.invoker().process(event.getPlayer(), event.getMessage(), event.getComponent());
+        InteractionResultHolder<Component> process = ChatEvent.SERVER.invoker().process(event.getPlayer(), event.getMessage(), event.getComponent());
         if (process.getObject() != null)
             event.setComponent(process.getObject());
-        if (process.getResult() == ActionResultType.FAIL)
+        if (process.getResult() == InteractionResult.FAIL)
             event.setCanceled(true);
     }
     
     @SubscribeEvent
     public static void event(WorldEvent.Load event) {
-        if (event.getWorld() instanceof ServerWorld) {
-            ServerWorld world = (ServerWorld) event.getWorld();
+        if (event.getWorld() instanceof ServerLevel) {
+            ServerLevel world = (ServerLevel) event.getWorld();
             LifecycleEvent.SERVER_WORLD_LOAD.invoker().act(world);
         }
     }
     
     @SubscribeEvent
     public static void event(WorldEvent.Unload event) {
-        if (event.getWorld() instanceof ServerWorld) {
-            ServerWorld world = (ServerWorld) event.getWorld();
+        if (event.getWorld() instanceof ServerLevel) {
+            ServerLevel world = (ServerLevel) event.getWorld();
             LifecycleEvent.SERVER_WORLD_UNLOAD.invoker().act(world);
         }
     }
     
     @SubscribeEvent
     public static void event(WorldEvent.Save event) {
-        if (event.getWorld() instanceof ServerWorld) {
-            ServerWorld world = (ServerWorld) event.getWorld();
+        if (event.getWorld() instanceof ServerLevel) {
+            ServerLevel world = (ServerLevel) event.getWorld();
             LifecycleEvent.SERVER_WORLD_SAVE.invoker().act(world);
         }
     }
     
     @SubscribeEvent
     public static void event(LivingDeathEvent event) {
-        if (EntityEvent.LIVING_DEATH.invoker().die(event.getEntityLiving(), event.getSource()) == ActionResultType.FAIL) {
+        if (EntityEvent.LIVING_DEATH.invoker().die(event.getEntityLiving(), event.getSource()) == InteractionResult.FAIL) {
             event.setCanceled(true);
         }
     }
     
     @SubscribeEvent
     public static void event(AdvancementEvent event) {
-        if (event.getPlayer() instanceof ServerPlayerEntity) {
-            PlayerEvent.PLAYER_ADVANCEMENT.invoker().award((ServerPlayerEntity) event.getPlayer(), event.getAdvancement());
+        if (event.getPlayer() instanceof ServerPlayer) {
+            PlayerEvent.PLAYER_ADVANCEMENT.invoker().award((ServerPlayer) event.getPlayer(), event.getAdvancement());
         }
     }
     
     @SubscribeEvent
     public static void event(Clone event) {
-        if (event.getOriginal() instanceof ServerPlayerEntity && event.getPlayer() instanceof ServerPlayerEntity) {
-            PlayerEvent.PLAYER_CLONE.invoker().clone((ServerPlayerEntity) event.getOriginal(), (ServerPlayerEntity) event.getPlayer(), !event.isWasDeath());
+        if (event.getOriginal() instanceof ServerPlayer && event.getPlayer() instanceof ServerPlayer) {
+            PlayerEvent.PLAYER_CLONE.invoker().clone((ServerPlayer) event.getOriginal(), (ServerPlayer) event.getPlayer(), !event.isWasDeath());
         }
     }
     
     @SubscribeEvent
     public static void event(Start event) {
-        if (ExplosionEvent.PRE.invoker().explode(event.getWorld(), event.getExplosion()) == ActionResultType.FAIL) {
+        if (ExplosionEvent.PRE.invoker().explode(event.getWorld(), event.getExplosion()) == InteractionResult.FAIL) {
             event.setCanceled(true);
         }
     }
@@ -200,14 +200,14 @@ public class EventHandlerImplCommon {
     
     @SubscribeEvent
     public static void event(LivingAttackEvent event) {
-        if (EntityEvent.LIVING_ATTACK.invoker().attack(event.getEntityLiving(), event.getSource(), event.getAmount()) == ActionResultType.FAIL) {
+        if (EntityEvent.LIVING_ATTACK.invoker().attack(event.getEntityLiving(), event.getSource(), event.getAmount()) == InteractionResult.FAIL) {
             event.setCanceled(true);
         }
     }
     
     @SubscribeEvent
     public static void event(EntityJoinWorldEvent event) {
-        if (EntityEvent.ADD.invoker().add(event.getEntity(), event.getWorld()) == ActionResultType.FAIL) {
+        if (EntityEvent.ADD.invoker().add(event.getEntity(), event.getWorld()) == InteractionResult.FAIL) {
             event.setCanceled(true);
         }
     }
@@ -249,8 +249,8 @@ public class EventHandlerImplCommon {
     
     @SubscribeEvent
     public static void event(PlayerInteractEvent.RightClickItem event) {
-        ActionResult<ItemStack> result = InteractionEvent.RIGHT_CLICK_ITEM.invoker().click(event.getPlayer(), event.getHand());
-        if (result.getResult() != ActionResultType.PASS) {
+        InteractionResultHolder<ItemStack> result = InteractionEvent.RIGHT_CLICK_ITEM.invoker().click(event.getPlayer(), event.getHand());
+        if (result.getResult() != InteractionResult.PASS) {
             event.setCanceled(true);
             event.setCancellationResult(result.getResult());
         }
@@ -258,8 +258,8 @@ public class EventHandlerImplCommon {
     
     @SubscribeEvent
     public static void event(PlayerInteractEvent.RightClickBlock event) {
-        ActionResultType result = InteractionEvent.RIGHT_CLICK_BLOCK.invoker().click(event.getPlayer(), event.getHand(), event.getPos(), event.getFace());
-        if (result != ActionResultType.PASS) {
+        InteractionResult result = InteractionEvent.RIGHT_CLICK_BLOCK.invoker().click(event.getPlayer(), event.getHand(), event.getPos(), event.getFace());
+        if (result != InteractionResult.PASS) {
             event.setCanceled(true);
             event.setCancellationResult(result);
             event.setUseBlock(Event.Result.DENY);
@@ -269,8 +269,8 @@ public class EventHandlerImplCommon {
     
     @SubscribeEvent
     public static void event(PlayerInteractEvent.EntityInteract event) {
-        ActionResultType result = InteractionEvent.INTERACT_ENTITY.invoker().interact(event.getPlayer(), event.getTarget(), event.getHand());
-        if (result != ActionResultType.PASS) {
+        InteractionResult result = InteractionEvent.INTERACT_ENTITY.invoker().interact(event.getPlayer(), event.getTarget(), event.getHand());
+        if (result != InteractionResult.PASS) {
             event.setCanceled(true);
             event.setCancellationResult(result);
         }
@@ -278,8 +278,8 @@ public class EventHandlerImplCommon {
     
     @SubscribeEvent
     public static void event(PlayerInteractEvent.LeftClickBlock event) {
-        ActionResultType result = InteractionEvent.LEFT_CLICK_BLOCK.invoker().click(event.getPlayer(), event.getHand(), event.getPos(), event.getFace());
-        if (result != ActionResultType.PASS) {
+        InteractionResult result = InteractionEvent.LEFT_CLICK_BLOCK.invoker().click(event.getPlayer(), event.getHand(), event.getPos(), event.getFace());
+        if (result != InteractionResult.PASS) {
             event.setCanceled(true);
             event.setCancellationResult(result);
             event.setUseBlock(Event.Result.DENY);
@@ -289,8 +289,8 @@ public class EventHandlerImplCommon {
     
     @SubscribeEvent
     public static void event(BlockEvent.BreakEvent event) {
-        if (event.getPlayer() instanceof ServerPlayerEntity && event.getWorld() instanceof World) {
-            ActionResultType result = PlayerEvent.BREAK_BLOCK.invoker().breakBlock((World) event.getWorld(), event.getPos(), event.getState(), (ServerPlayerEntity) event.getPlayer(), new IntValue() {
+        if (event.getPlayer() instanceof ServerPlayer && event.getWorld() instanceof Level) {
+            InteractionResult result = PlayerEvent.BREAK_BLOCK.invoker().breakBlock((Level) event.getWorld(), event.getPos(), event.getState(), (ServerPlayer) event.getPlayer(), new IntValue() {
                 @Override
                 public int getAsInt() {
                     return event.getExpToDrop();
@@ -301,7 +301,7 @@ public class EventHandlerImplCommon {
                     event.setExpToDrop(value);
                 }
             });
-            if (result != ActionResultType.PASS) {
+            if (result != InteractionResult.PASS) {
                 event.setCanceled(true);
             }
         }
@@ -309,9 +309,9 @@ public class EventHandlerImplCommon {
     
     @SubscribeEvent
     public static void event(BlockEvent.EntityPlaceEvent event) {
-        if (event.getWorld() instanceof World) {
-            ActionResultType result = EntityEvent.PLACE_BLOCK.invoker().placeBlock((World) event.getWorld(), event.getPos(), event.getState(), event.getEntity());
-            if (result != ActionResultType.PASS) {
+        if (event.getWorld() instanceof Level) {
+            InteractionResult result = EntityEvent.PLACE_BLOCK.invoker().placeBlock((Level) event.getWorld(), event.getPos(), event.getState(), event.getEntity());
+            if (result != InteractionResult.PASS) {
                 event.setCanceled(true);
             }
         }

+ 0 - 1
forge/src/main/java/me/shedaniel/architectury/forge/ArchitecturyForge.java

@@ -20,7 +20,6 @@
 package me.shedaniel.architectury.forge;
 
 import me.shedaniel.architectury.event.EventHandler;
-import me.shedaniel.architectury.event.events.GuiEvent;
 import me.shedaniel.architectury.platform.forge.EventBuses;
 import net.minecraftforge.fml.common.Mod;
 import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;

+ 1 - 1
forge/src/main/java/me/shedaniel/architectury/hooks/forge/DyeColorHooksImpl.java

@@ -19,7 +19,7 @@
 
 package me.shedaniel.architectury.hooks.forge;
 
-import net.minecraft.item.DyeColor;
+import net.minecraft.world.item.DyeColor;
 
 public class DyeColorHooksImpl {
     public static int getColorValue(DyeColor dyeColor) {

+ 1 - 1
forge/src/main/java/me/shedaniel/architectury/hooks/forge/EntityHooksImpl.java

@@ -19,7 +19,7 @@
 
 package me.shedaniel.architectury.hooks.forge;
 
-import net.minecraft.entity.Entity;
+import net.minecraft.world.entity.Entity;
 
 public class EntityHooksImpl {
     public static String getEncodeId(Entity entity) {

+ 4 - 4
forge/src/main/java/me/shedaniel/architectury/hooks/forge/ExplosionHooksImpl.java

@@ -19,12 +19,12 @@
 
 package me.shedaniel.architectury.hooks.forge;
 
-import net.minecraft.entity.Entity;
-import net.minecraft.util.math.vector.Vector3d;
-import net.minecraft.world.Explosion;
+import net.minecraft.world.entity.Entity;
+import net.minecraft.world.level.Explosion;
+import net.minecraft.world.phys.Vec3;
 
 public class ExplosionHooksImpl {
-    public static Vector3d getPosition(Explosion explosion) {
+    public static Vec3 getPosition(Explosion explosion) {
         return explosion.getPosition();
     }
     

+ 16 - 0
forge/src/main/java/me/shedaniel/architectury/hooks/forge/FluidStackHooksForge.java

@@ -0,0 +1,16 @@
+package me.shedaniel.architectury.hooks.forge;
+
+import me.shedaniel.architectury.fluid.FluidStack;
+import me.shedaniel.architectury.utils.Fraction;
+
+public final class FluidStackHooksForge {
+    private FluidStackHooksForge() {}
+    
+    public static FluidStack fromForge(net.minecraftforge.fluids.FluidStack stack) {
+        return FluidStack.create(stack.getFluid().delegate, Fraction.ofWhole(stack.getAmount()), stack.getTag());
+    }
+    
+    public static net.minecraftforge.fluids.FluidStack toForge(FluidStack stack) {
+        return new net.minecraftforge.fluids.FluidStack(stack.getRawFluid(), stack.getAmount().intValue(), stack.getTag());
+    }
+}

+ 14 - 18
forge/src/main/java/me/shedaniel/architectury/hooks/forge/FluidStackHooksImpl.java

@@ -21,37 +21,33 @@ package me.shedaniel.architectury.hooks.forge;
 
 import me.shedaniel.architectury.fluid.FluidStack;
 import me.shedaniel.architectury.utils.Fraction;
-import net.minecraft.nbt.CompoundNBT;
-import net.minecraft.network.PacketBuffer;
-import net.minecraft.util.text.ITextComponent;
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.network.FriendlyByteBuf;
+import net.minecraft.network.chat.Component;
 
 public class FluidStackHooksImpl {
-    public static ITextComponent getName(FluidStack stack) {
-        return stack.getFluid().getAttributes().getDisplayName(
-                new net.minecraftforge.fluids.FluidStack(stack.getRawFluid(), stack.getAmount().intValue(), stack.getTag()));
+    public static Component getName(FluidStack stack) {
+        return stack.getFluid().getAttributes().getDisplayName(FluidStackHooksForge.toForge(stack));
     }
     
     public static String getTranslationKey(FluidStack stack) {
-        return stack.getFluid().getAttributes().getTranslationKey(
-                new net.minecraftforge.fluids.FluidStack(stack.getRawFluid(), stack.getAmount().intValue(), stack.getTag()));
+        return stack.getFluid().getAttributes().getTranslationKey(FluidStackHooksForge.toForge(stack));
     }
     
-    public static FluidStack read(PacketBuffer buf) {
-        net.minecraftforge.fluids.FluidStack stack = net.minecraftforge.fluids.FluidStack.readFromPacket(buf);
-        return FluidStack.create(stack.getFluid().delegate, Fraction.ofWhole(stack.getAmount()), stack.getTag());
+    public static FluidStack read(FriendlyByteBuf buf) {
+        return FluidStackHooksForge.fromForge(net.minecraftforge.fluids.FluidStack.readFromPacket(buf));
     }
     
-    public static void write(FluidStack stack, PacketBuffer buf) {
-        new net.minecraftforge.fluids.FluidStack(stack.getRawFluid(), stack.getAmount().intValue(), stack.getTag()).writeToPacket(buf);
+    public static void write(FluidStack stack, FriendlyByteBuf buf) {
+        FluidStackHooksForge.toForge(stack).writeToPacket(buf);
     }
     
-    public static FluidStack read(CompoundNBT tag) {
-        net.minecraftforge.fluids.FluidStack stack = net.minecraftforge.fluids.FluidStack.loadFluidStackFromNBT(tag);
-        return FluidStack.create(stack.getFluid().delegate, Fraction.ofWhole(stack.getAmount()), stack.getTag());
+    public static FluidStack read(CompoundTag tag) {
+        return FluidStackHooksForge.fromForge(net.minecraftforge.fluids.FluidStack.loadFluidStackFromNBT(tag));
     }
     
-    public static CompoundNBT write(FluidStack stack, CompoundNBT tag) {
-        return new net.minecraftforge.fluids.FluidStack(stack.getRawFluid(), stack.getAmount().intValue(), stack.getTag()).writeToNBT(tag);
+    public static CompoundTag write(FluidStack stack, CompoundTag tag) {
+        return FluidStackHooksForge.toForge(stack).writeToNBT(tag);
     }
     
     public static Fraction bucketAmount() {

+ 1 - 1
forge/src/main/java/me/shedaniel/architectury/hooks/forge/ItemEntityHooksImpl.java

@@ -20,7 +20,7 @@
 package me.shedaniel.architectury.hooks.forge;
 
 import me.shedaniel.architectury.utils.IntValue;
-import net.minecraft.entity.item.ItemEntity;
+import net.minecraft.world.entity.item.ItemEntity;
 
 public class ItemEntityHooksImpl {
     public static IntValue lifespan(ItemEntity entity) {

+ 4 - 4
forge/src/main/java/me/shedaniel/architectury/hooks/forge/PackRepositoryHooksImpl.java

@@ -19,11 +19,11 @@
 
 package me.shedaniel.architectury.hooks.forge;
 
-import net.minecraft.resources.IPackFinder;
-import net.minecraft.resources.ResourcePackList;
+import net.minecraft.server.packs.repository.PackRepository;
+import net.minecraft.server.packs.repository.RepositorySource;
 
 public class PackRepositoryHooksImpl {
-    public static void addSource(ResourcePackList resourcePackList, IPackFinder iPackFinder) {
-        resourcePackList.addPackFinder(iPackFinder);
+    public static void addSource(PackRepository repository, RepositorySource source) {
+        repository.addPackFinder(source);
     }
 }

+ 3 - 3
forge/src/main/java/me/shedaniel/architectury/hooks/forge/PlayerHooksImpl.java

@@ -19,15 +19,15 @@
 
 package me.shedaniel.architectury.hooks.forge;
 
-import net.minecraft.entity.player.PlayerEntity;
+import net.minecraft.world.entity.player.Player;
 import net.minecraftforge.common.util.FakePlayer;
 
 public class PlayerHooksImpl {
-    public static boolean isFake(PlayerEntity playerEntity) {
+    public static boolean isFake(Player playerEntity) {
         return playerEntity instanceof FakePlayer;
     }
     
-    public static void closeContainer(PlayerEntity playerEntity) {
+    public static void closeContainer(Player playerEntity) {
         playerEntity.closeContainer();
     }
 }

+ 8 - 8
forge/src/main/java/me/shedaniel/architectury/hooks/forge/ScreenHooksImpl.java

@@ -19,30 +19,30 @@
 
 package me.shedaniel.architectury.hooks.forge;
 
-import net.minecraft.client.gui.IGuiEventListener;
-import net.minecraft.client.gui.screen.Screen;
-import net.minecraft.client.gui.widget.Widget;
+import net.minecraft.client.gui.components.AbstractWidget;
+import net.minecraft.client.gui.components.events.GuiEventListener;
+import net.minecraft.client.gui.screens.Screen;
 import net.minecraftforge.fml.common.ObfuscationReflectionHelper;
 
 import java.lang.reflect.InvocationTargetException;
 import java.util.List;
 
 public class ScreenHooksImpl {
-    public static List<Widget> getButtons(Screen screen) {
+    public static List<AbstractWidget> getButtons(Screen screen) {
         return screen.buttons;
     }
     
-    public static <T extends Widget> T addButton(Screen screen, T t) {
+    public static <T extends AbstractWidget> T addButton(Screen screen, T t) {
         try {
-            return (T) ObfuscationReflectionHelper.findMethod(Screen.class, "func_230480_a_", Widget.class).invoke(screen, t);
+            return (T) ObfuscationReflectionHelper.findMethod(Screen.class, "func_230480_a_", AbstractWidget.class).invoke(screen, t);
         } catch (IllegalAccessException | InvocationTargetException e) {
             throw new RuntimeException(e);
         }
     }
     
-    public static <T extends IGuiEventListener> T addChild(Screen screen, T t) {
+    public static <T extends GuiEventListener> T addChild(Screen screen, T t) {
         try {
-            return (T) ObfuscationReflectionHelper.findMethod(Screen.class, "func_230481_d_", IGuiEventListener.class).invoke(screen, t);
+            return (T) ObfuscationReflectionHelper.findMethod(Screen.class, "func_230481_d_", GuiEventListener.class).invoke(screen, t);
         } catch (IllegalAccessException | InvocationTargetException e) {
             throw new RuntimeException(e);
         }

+ 15 - 0
forge/src/main/java/me/shedaniel/architectury/mixin/forge/BiomeGenerationSettingsBuilderAccessor.java

@@ -0,0 +1,15 @@
+package me.shedaniel.architectury.mixin.forge;
+
+import net.minecraft.world.level.biome.BiomeGenerationSettings;
+import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.gen.Accessor;
+
+import java.util.List;
+import java.util.function.Supplier;
+
+@Mixin(BiomeGenerationSettings.Builder.class)
+public interface BiomeGenerationSettingsBuilderAccessor {
+    @Accessor
+    List<List<Supplier<ConfiguredFeature<?, ?>>>> getFeatures();
+}

+ 8 - 0
forge/src/main/java/me/shedaniel/architectury/mixin/forge/BiomeSpecialEffectsAccessor.java

@@ -0,0 +1,8 @@
+package me.shedaniel.architectury.mixin.forge;
+
+import net.minecraft.world.level.biome.BiomeSpecialEffects;
+import org.spongepowered.asm.mixin.Mixin;
+
+@Mixin(BiomeSpecialEffects.class)
+public interface BiomeSpecialEffectsAccessor {
+}

+ 25 - 0
forge/src/main/java/me/shedaniel/architectury/mixin/forge/MobSpawnSettingsBuilderAccessor.java

@@ -0,0 +1,25 @@
+package me.shedaniel.architectury.mixin.forge;
+
+import net.minecraft.world.entity.EntityType;
+import net.minecraft.world.entity.MobCategory;
+import net.minecraft.world.level.biome.MobSpawnSettings;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.gen.Accessor;
+
+import java.util.List;
+import java.util.Map;
+
+@Mixin(MobSpawnSettings.Builder.class)
+public interface MobSpawnSettingsBuilderAccessor {
+    @Accessor
+    Map<EntityType<?>, MobSpawnSettings.MobSpawnCost> getMobSpawnCosts();
+    
+    @Accessor
+    boolean isPlayerCanSpawn();
+    
+    @Accessor
+    void setPlayerCanSpawn(boolean canSpawn);
+    
+    @Accessor
+    Map<MobCategory, List<MobSpawnSettings.SpawnerData>> getSpawners();
+}

+ 3 - 3
forge/src/main/java/me/shedaniel/architectury/networking/forge/ClientNetworkingManager.java

@@ -21,8 +21,8 @@ package me.shedaniel.architectury.networking.forge;
 
 import me.shedaniel.architectury.networking.NetworkManager;
 import net.minecraft.client.Minecraft;
-import net.minecraft.entity.player.PlayerEntity;
-import net.minecraft.util.ResourceLocation;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.world.entity.player.Player;
 import net.minecraftforge.api.distmarker.Dist;
 import net.minecraftforge.api.distmarker.OnlyIn;
 import net.minecraftforge.client.event.ClientPlayerNetworkEvent;
@@ -51,7 +51,7 @@ public class ClientNetworkingManager {
         });
     }
     
-    public static PlayerEntity getClientPlayer() {
+    public static Player getClientPlayer() {
         return Minecraft.getInstance().player;
     }
 }

+ 20 - 19
forge/src/main/java/me/shedaniel/architectury/networking/forge/NetworkManagerImpl.java

@@ -24,11 +24,12 @@ import com.google.common.collect.*;
 import io.netty.buffer.Unpooled;
 import me.shedaniel.architectury.networking.NetworkManager;
 import me.shedaniel.architectury.networking.NetworkManager.NetworkReceiver;
-import net.minecraft.entity.player.PlayerEntity;
-import net.minecraft.entity.player.ServerPlayerEntity;
-import net.minecraft.network.IPacket;
-import net.minecraft.network.PacketBuffer;
-import net.minecraft.util.ResourceLocation;
+import me.shedaniel.architectury.utils.Env;
+import net.minecraft.network.FriendlyByteBuf;
+import net.minecraft.network.protocol.Packet;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.world.entity.player.Player;
 import net.minecraftforge.api.distmarker.Dist;
 import net.minecraftforge.api.distmarker.OnlyIn;
 import net.minecraftforge.common.MinecraftForge;
@@ -55,8 +56,8 @@ public class NetworkManagerImpl {
         }
     }
     
-    public static IPacket<?> toPacket(NetworkManager.Side side, ResourceLocation id, PacketBuffer buffer) {
-        PacketBuffer packetBuffer = new PacketBuffer(Unpooled.buffer());
+    public static Packet<?> toPacket(NetworkManager.Side side, ResourceLocation id, FriendlyByteBuf buffer) {
+        FriendlyByteBuf packetBuffer = new FriendlyByteBuf(Unpooled.buffer());
         packetBuffer.writeResourceLocation(id);
         packetBuffer.writeBytes(buffer);
         return (side == NetworkManager.Side.C2S ? NetworkDirection.PLAY_TO_SERVER : NetworkDirection.PLAY_TO_CLIENT).buildPacket(Pair.of(packetBuffer, 0), CHANNEL_ID).getThis();
@@ -68,14 +69,14 @@ public class NetworkManagerImpl {
     static final Map<ResourceLocation, NetworkReceiver> S2C = Maps.newHashMap();
     static final Map<ResourceLocation, NetworkReceiver> C2S = Maps.newHashMap();
     static final Set<ResourceLocation> serverReceivables = Sets.newHashSet();
-    private static final Multimap<PlayerEntity, ResourceLocation> clientReceivables = Multimaps.newMultimap(Maps.newHashMap(), Sets::newHashSet);
+    private static final Multimap<Player, ResourceLocation> clientReceivables = Multimaps.newMultimap(Maps.newHashMap(), Sets::newHashSet);
     
-    static  {
+    static {
         CHANNEL.addListener(createPacketHandler(NetworkEvent.ClientCustomPayloadEvent.class, C2S));
         
         DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> ClientNetworkingManager::initClient);
         
-        MinecraftForge.EVENT_BUS.<PlayerEvent.PlayerLoggedInEvent>addListener(event -> NetworkManager.sendToPlayer((ServerPlayerEntity) event.getPlayer(), SYNC_IDS, sendSyncPacket(C2S)));
+        MinecraftForge.EVENT_BUS.<PlayerEvent.PlayerLoggedInEvent>addListener(event -> NetworkManager.sendToPlayer((ServerPlayer) event.getPlayer(), SYNC_IDS, sendSyncPacket(C2S)));
         MinecraftForge.EVENT_BUS.<PlayerEvent.PlayerLoggedOutEvent>addListener(event -> clientReceivables.removeAll(event.getPlayer()));
         
         registerC2SReceiver(SYNC_IDS, (buffer, context) -> {
@@ -93,15 +94,15 @@ public class NetworkManagerImpl {
             if (event.getClass() != clazz) return;
             NetworkEvent.Context context = event.getSource().get();
             if (context.getPacketHandled()) return;
-            PacketBuffer buffer = new PacketBuffer(event.getPayload().copy());
+            FriendlyByteBuf buffer = new FriendlyByteBuf(event.getPayload().copy());
             ResourceLocation type = buffer.readResourceLocation();
             NetworkReceiver receiver = map.get(type);
             
             if (receiver != null) {
                 receiver.receive(buffer, new NetworkManager.PacketContext() {
                     @Override
-                    public PlayerEntity getPlayer() {
-                        return getEnv() == Dist.CLIENT ? getClientPlayer() : context.getSender();
+                    public Player getPlayer() {
+                        return getEnvironment() == Env.CLIENT ? getClientPlayer() : context.getSender();
                     }
                     
                     @Override
@@ -110,11 +111,11 @@ public class NetworkManagerImpl {
                     }
                     
                     @Override
-                    public Dist getEnv() {
-                        return context.getDirection().getReceptionSide() == LogicalSide.CLIENT ? Dist.CLIENT : Dist.DEDICATED_SERVER;
+                    public Env getEnvironment() {
+                        return context.getDirection().getReceptionSide() == LogicalSide.CLIENT ? Env.CLIENT : Env.SERVER;
                     }
                     
-                    private PlayerEntity getClientPlayer() {
+                    private Player getClientPlayer() {
                         return DistExecutor.unsafeCallWhenOn(Dist.CLIENT, () -> ClientNetworkingManager::getClientPlayer);
                     }
                 });
@@ -136,13 +137,13 @@ public class NetworkManagerImpl {
         return serverReceivables.contains(id);
     }
     
-    public static boolean canPlayerReceive(ServerPlayerEntity player, ResourceLocation id) {
+    public static boolean canPlayerReceive(ServerPlayer player, ResourceLocation id) {
         return clientReceivables.get(player).contains(id);
     }
     
-    static PacketBuffer sendSyncPacket(Map<ResourceLocation, NetworkReceiver> map) {
+    static FriendlyByteBuf sendSyncPacket(Map<ResourceLocation, NetworkReceiver> map) {
         List<ResourceLocation> availableIds = Lists.newArrayList(map.keySet());
-        PacketBuffer packetBuffer = new PacketBuffer(Unpooled.buffer());
+        FriendlyByteBuf packetBuffer = new FriendlyByteBuf(Unpooled.buffer());
         packetBuffer.writeInt(availableIds.size());
         for (ResourceLocation availableId : availableIds) {
             packetBuffer.writeResourceLocation(availableId);

+ 10 - 5
forge/src/main/java/me/shedaniel/architectury/platform/forge/PlatformImpl.java

@@ -20,6 +20,7 @@
 package me.shedaniel.architectury.platform.forge;
 
 import me.shedaniel.architectury.platform.Mod;
+import me.shedaniel.architectury.utils.Env;
 import net.minecraftforge.api.distmarker.Dist;
 import net.minecraftforge.fml.ExtensionPoint;
 import net.minecraftforge.fml.ModContainer;
@@ -53,6 +54,10 @@ public class PlatformImpl {
         return FMLPaths.MODSDIR.get();
     }
     
+    public static Env getEnvironment() {
+        return Env.fromPlatform(getEnv());
+    }
+    
     public static Dist getEnv() {
         return FMLEnvironment.dist;
     }
@@ -125,32 +130,32 @@ public class PlatformImpl {
         public @NotNull Path getFilePath() {
             return this.info.getOwningFile().getFile().getFilePath();
         }
-    
+        
         @Override
         public @NotNull Collection<String> getAuthors() {
             Optional<String> optional = this.info.getConfigElement("authors")
                     .map(String::valueOf);
             return optional.isPresent() ? Collections.singleton(optional.get()) : Collections.emptyList();
         }
-    
+        
         @Override
         public @Nullable Collection<String> getLicense() {
             return Collections.singleton(this.info.getOwningFile().getLicense());
         }
         
         @Override
-        public @Nullable Optional<String> getHomepage() {
+        public @NotNull Optional<String> getHomepage() {
             return this.info.getConfigElement("displayURL")
                     .map(String::valueOf);
         }
         
         @Override
-        public @Nullable Optional<String> getSources() {
+        public @NotNull Optional<String> getSources() {
             return Optional.empty();
         }
         
         @Override
-        public @Nullable Optional<String> getIssueTracker() {
+        public @NotNull Optional<String> getIssueTracker() {
             return Optional.ofNullable(this.info.getOwningFile().getIssueURL())
                     .map(URL::toString);
         }

+ 430 - 0
forge/src/main/java/me/shedaniel/architectury/registry/forge/BiomeModificationsImpl.java

@@ -0,0 +1,430 @@
+package me.shedaniel.architectury.registry.forge;
+
+import com.google.common.collect.Lists;
+import me.shedaniel.architectury.hooks.biome.*;
+import me.shedaniel.architectury.mixin.forge.BiomeGenerationSettingsBuilderAccessor;
+import me.shedaniel.architectury.mixin.forge.MobSpawnSettingsBuilderAccessor;
+import me.shedaniel.architectury.registry.BiomeModifications.BiomeContext;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.world.entity.EntityType;
+import net.minecraft.world.entity.MobCategory;
+import net.minecraft.world.level.biome.Biome;
+import net.minecraft.world.level.biome.MobSpawnSettings;
+import net.minecraft.world.level.levelgen.GenerationStep;
+import net.minecraft.world.level.levelgen.carver.ConfiguredWorldCarver;
+import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
+import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature;
+import net.minecraft.world.level.levelgen.surfacebuilders.ConfiguredSurfaceBuilder;
+import net.minecraftforge.common.MinecraftForge;
+import net.minecraftforge.common.world.BiomeGenerationSettingsBuilder;
+import net.minecraftforge.common.world.MobSpawnInfoBuilder;
+import net.minecraftforge.event.world.BiomeLoadingEvent;
+import org.apache.commons.lang3.tuple.Pair;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.BiConsumer;
+import java.util.function.BiPredicate;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+
+public class BiomeModificationsImpl {
+    private static final List<Pair<Predicate<BiomeContext>, BiConsumer<BiomeContext, BiomeProperties.Mutable>>> MODIFICATIONS = Lists.newArrayList();
+    
+    public static void addProperties(Predicate<BiomeContext> predicate, BiConsumer<BiomeContext, BiomeProperties.Mutable> modifier) {
+        MODIFICATIONS.add(Pair.of(predicate, modifier));
+    }
+    
+    public static void postProcessProperties(Predicate<BiomeContext> predicate, BiConsumer<BiomeContext, BiomeProperties.Mutable> modifier) {
+        MODIFICATIONS.add(Pair.of(predicate, modifier));
+    }
+    
+    public static void removeProperties(Predicate<BiomeContext> predicate, BiConsumer<BiomeContext, BiomeProperties.Mutable> modifier) {
+        MODIFICATIONS.add(Pair.of(predicate, modifier));
+    }
+    
+    public static void replaceProperties(Predicate<BiomeContext> predicate, BiConsumer<BiomeContext, BiomeProperties.Mutable> modifier) {
+        MODIFICATIONS.add(Pair.of(predicate, modifier));
+    }
+    
+    static {
+        MinecraftForge.EVENT_BUS.<BiomeLoadingEvent>addListener(event -> {
+            BiomeContext biomeContext = wrapSelectionContext(event);
+            BiomeProperties.Mutable mutableBiome = new MutableBiomeWrapped(event);
+            for (Pair<Predicate<BiomeContext>, BiConsumer<BiomeContext, BiomeProperties.Mutable>> pair : MODIFICATIONS) {
+                if (pair.getLeft().test(biomeContext)) {
+                    pair.getRight().accept(biomeContext, mutableBiome);
+                }
+            }
+            MutableClimatePropertiesWrapped climateProperties = (MutableClimatePropertiesWrapped) mutableBiome.getClimateProperties();
+            if (climateProperties.dirty) {
+                event.setClimate(new Biome.ClimateSettings(climateProperties.precipitation,
+                        climateProperties.temperature,
+                        climateProperties.temperatureModifier,
+                        climateProperties.downfall));
+            }
+        });
+    }
+    
+    private static BiomeContext wrapSelectionContext(BiomeLoadingEvent event) {
+        return new BiomeContext() {
+            BiomeProperties properties = new BiomeWrapped(event);
+            
+            @Override
+            @NotNull
+            public ResourceLocation getKey() {
+                return event.getName();
+            }
+            
+            @Override
+            @NotNull
+            public BiomeProperties getProperties() {
+                return properties;
+            }
+        };
+    }
+    
+    public static class BiomeWrapped implements BiomeProperties {
+        protected final BiomeLoadingEvent event;
+        protected final ClimateProperties climateProperties;
+        protected final EffectsProperties effectsProperties;
+        protected final GenerationProperties generationProperties;
+        protected final SpawnProperties spawnProperties;
+        
+        public BiomeWrapped(BiomeLoadingEvent event) {
+            this(event,
+                    new BiomeHooks.ClimateWrapped(event.getClimate()),
+                    new BiomeHooks.EffectsWrapped(event.getEffects()),
+                    new GenerationSettingsBuilderWrapped(event.getGeneration()),
+                    new SpawnSettingsBuilderWrapped(event.getSpawns())
+            );
+        }
+        
+        public BiomeWrapped(BiomeLoadingEvent event, ClimateProperties climateProperties, EffectsProperties effectsProperties, GenerationProperties generationProperties, SpawnProperties spawnProperties) {
+            this.event = event;
+            this.climateProperties = climateProperties;
+            this.effectsProperties = effectsProperties;
+            this.generationProperties = generationProperties;
+            this.spawnProperties = spawnProperties;
+        }
+        
+        @NotNull
+        @Override
+        public ClimateProperties getClimateProperties() {
+            return climateProperties;
+        }
+        
+        @NotNull
+        @Override
+        public EffectsProperties getEffectsProperties() {
+            return effectsProperties;
+        }
+        
+        @NotNull
+        @Override
+        public GenerationProperties getGenerationProperties() {
+            return generationProperties;
+        }
+        
+        @NotNull
+        @Override
+        public SpawnProperties getSpawnProperties() {
+            return spawnProperties;
+        }
+        
+        @Override
+        public Biome.@NotNull BiomeCategory getCategory() {
+            return event.getCategory();
+        }
+        
+        @Override
+        public float getDepth() {
+            return event.getDepth();
+        }
+        
+        @Override
+        public float getScale() {
+            return event.getScale();
+        }
+        
+    }
+    
+    private static class GenerationSettingsBuilderWrapped implements GenerationProperties {
+        protected final BiomeGenerationSettingsBuilder generation;
+        
+        public GenerationSettingsBuilderWrapped(BiomeGenerationSettingsBuilder generation) {this.generation = generation;}
+        
+        @Override
+        public @NotNull Optional<Supplier<ConfiguredSurfaceBuilder<?>>> getSurfaceBuilder() {
+            return generation.getSurfaceBuilder();
+        }
+        
+        @Override
+        public @NotNull List<Supplier<ConfiguredWorldCarver<?>>> getCarvers(GenerationStep.Carving carving) {
+            return generation.getCarvers(carving);
+        }
+        
+        @Override
+        public @NotNull List<List<Supplier<ConfiguredFeature<?, ?>>>> getFeatures() {
+            return ((BiomeGenerationSettingsBuilderAccessor) generation).getFeatures();
+        }
+        
+        @Override
+        public @NotNull List<Supplier<ConfiguredStructureFeature<?, ?>>> getStructureStarts() {
+            return generation.getStructures();
+        }
+        
+    }
+    
+    private static class SpawnSettingsBuilderWrapped implements SpawnProperties {
+        protected final MobSpawnInfoBuilder builder;
+        
+        public SpawnSettingsBuilderWrapped(MobSpawnInfoBuilder builder) {this.builder = builder;}
+        
+        @Override
+        public float getCreatureProbability() {
+            return builder.getProbability();
+        }
+        
+        @Override
+        public @NotNull Map<MobCategory, List<MobSpawnSettings.SpawnerData>> getSpawners() {
+            return ((MobSpawnSettingsBuilderAccessor) builder).getSpawners();
+        }
+        
+        @Override
+        public @NotNull Map<EntityType<?>, MobSpawnSettings.MobSpawnCost> getMobSpawnCosts() {
+            return ((MobSpawnSettingsBuilderAccessor) builder).getMobSpawnCosts();
+        }
+        
+        @Override
+        public boolean isPlayerSpawnFriendly() {
+            return ((MobSpawnSettingsBuilderAccessor) builder).isPlayerCanSpawn();
+        }
+    }
+    
+    public static class MutableBiomeWrapped extends BiomeWrapped implements BiomeProperties.Mutable {
+        public MutableBiomeWrapped(BiomeLoadingEvent event) {
+            super(event,
+                    new MutableClimatePropertiesWrapped(event.getClimate()),
+                    new BiomeHooks.EffectsWrapped(event.getEffects()),
+                    new MutableGenerationSettingsBuilderWrapped(event.getGeneration()),
+                    new MutableSpawnSettingsBuilderWrapped(event.getSpawns())
+            );
+        }
+        
+        @Override
+        public @NotNull ClimateProperties.Mutable getClimateProperties() {
+            return (ClimateProperties.Mutable) super.getClimateProperties();
+        }
+        
+        @Override
+        public @NotNull EffectsProperties.Mutable getEffectsProperties() {
+            return (EffectsProperties.Mutable) super.getEffectsProperties();
+        }
+        
+        @Override
+        public @NotNull GenerationProperties.Mutable getGenerationProperties() {
+            return (GenerationProperties.Mutable) super.getGenerationProperties();
+        }
+        
+        @Override
+        public @NotNull SpawnProperties.Mutable getSpawnProperties() {
+            return (SpawnProperties.Mutable) super.getSpawnProperties();
+        }
+        
+        @Override
+        public @NotNull Mutable setCategory(Biome.@NotNull BiomeCategory category) {
+            event.setCategory(category);
+            return this;
+        }
+        
+        @Override
+        public @NotNull Mutable setDepth(float depth) {
+            event.setDepth(depth);
+            return this;
+        }
+        
+        @Override
+        public @NotNull Mutable setScale(float scale) {
+            event.setScale(scale);
+            return this;
+        }
+    }
+    
+    public static class MutableClimatePropertiesWrapped implements ClimateProperties.Mutable {
+        public Biome.Precipitation precipitation;
+        
+        public float temperature;
+        public Biome.TemperatureModifier temperatureModifier;
+        public float downfall;
+        public boolean dirty;
+        
+        public MutableClimatePropertiesWrapped(Biome.ClimateSettings settings) {
+            this(settings.precipitation,
+                    settings.temperature,
+                    settings.temperatureModifier,
+                    settings.downfall);
+        }
+        
+        public MutableClimatePropertiesWrapped(Biome.Precipitation precipitation, float temperature, Biome.TemperatureModifier temperatureModifier, float downfall) {
+            this.precipitation = precipitation;
+            this.temperature = temperature;
+            this.temperatureModifier = temperatureModifier;
+            this.downfall = downfall;
+        }
+        
+        @NotNull
+        @Override
+        public Biome.Precipitation getPrecipitation() {
+            return precipitation;
+        }
+        
+        @Override
+        public float getTemperature() {
+            return temperature;
+        }
+        
+        @NotNull
+        @Override
+        public Biome.TemperatureModifier getTemperatureModifier() {
+            return temperatureModifier;
+        }
+        
+        @Override
+        public float getDownfall() {
+            return downfall;
+        }
+        
+        @Override
+        public @NotNull Mutable setPrecipitation(Biome.@NotNull Precipitation precipitation) {
+            this.precipitation = precipitation;
+            this.dirty = true;
+            return this;
+        }
+        
+        @Override
+        public @NotNull Mutable setTemperature(float temperature) {
+            this.temperature = temperature;
+            this.dirty = true;
+            return this;
+        }
+        
+        @Override
+        public @NotNull Mutable setTemperatureModifier(Biome.@NotNull TemperatureModifier temperatureModifier) {
+            this.temperatureModifier = temperatureModifier;
+            this.dirty = true;
+            return this;
+        }
+        
+        @Override
+        public @NotNull Mutable setDownfall(float downfall) {
+            this.downfall = downfall;
+            this.dirty = true;
+            return this;
+        }
+        
+    }
+    
+    private static class MutableGenerationSettingsBuilderWrapped extends GenerationSettingsBuilderWrapped implements GenerationProperties.Mutable {
+        public MutableGenerationSettingsBuilderWrapped(BiomeGenerationSettingsBuilder generation) {
+            super(generation);
+        }
+        
+        @Override
+        public Mutable setSurfaceBuilder(ConfiguredSurfaceBuilder<?> builder) {
+            generation.surfaceBuilder(builder);
+            return this;
+        }
+        
+        @Override
+        public Mutable addFeature(GenerationStep.Decoration decoration, ConfiguredFeature<?, ?> feature) {
+            generation.addFeature(decoration, feature);
+            return this;
+        }
+        
+        @Override
+        public Mutable addCarver(GenerationStep.Carving carving, ConfiguredWorldCarver<?> feature) {
+            generation.addCarver(carving, feature);
+            return this;
+        }
+        
+        @Override
+        public Mutable addStructure(ConfiguredStructureFeature<?, ?> feature) {
+            generation.addStructureStart(feature);
+            return this;
+        }
+        
+        @Override
+        public Mutable removeFeature(GenerationStep.Decoration decoration, ConfiguredFeature<?, ?> feature) {
+            generation.getFeatures(decoration).removeIf(supplier -> supplier.get() == feature);
+            return this;
+        }
+        
+        @Override
+        public Mutable removeCarver(GenerationStep.Carving carving, ConfiguredWorldCarver<?> feature) {
+            generation.getCarvers(carving).removeIf(supplier -> supplier.get() == feature);
+            return this;
+        }
+        
+        @Override
+        public Mutable removeStructure(ConfiguredStructureFeature<?, ?> feature) {
+            generation.getStructures().removeIf(supplier -> supplier.get() == feature);
+            return this;
+        }
+    }
+    
+    private static class MutableSpawnSettingsBuilderWrapped extends SpawnSettingsBuilderWrapped implements SpawnProperties.Mutable {
+        public MutableSpawnSettingsBuilderWrapped(MobSpawnInfoBuilder builder) {
+            super(builder);
+        }
+        
+        @Override
+        public @NotNull Mutable setCreatureProbability(float probability) {
+            builder.creatureGenerationProbability(probability);
+            return this;
+        }
+        
+        @Override
+        public Mutable addSpawn(MobCategory category, MobSpawnSettings.SpawnerData data) {
+            builder.addSpawn(category, data);
+            return this;
+        }
+        
+        @Override
+        public boolean removeSpawns(BiPredicate<MobCategory, MobSpawnSettings.SpawnerData> predicate) {
+            boolean removed = false;
+            for (MobCategory type : builder.getSpawnerTypes()) {
+                if (builder.getSpawner(type).removeIf(data -> predicate.test(type, data))) {
+                    removed = true;
+                }
+            }
+            return removed;
+        }
+        
+        @Override
+        public Mutable setSpawnCost(EntityType<?> entityType, MobSpawnSettings.MobSpawnCost cost) {
+            builder.addMobCharge(entityType, cost.getCharge(), cost.getEnergyBudget());
+            return this;
+        }
+        
+        @Override
+        public Mutable setSpawnCost(EntityType<?> entityType, double mass, double gravityLimit) {
+            builder.addMobCharge(entityType, mass, gravityLimit);
+            return this;
+        }
+        
+        @Override
+        public Mutable clearSpawnCost(EntityType<?> entityType) {
+            getMobSpawnCosts().remove(entityType);
+            return this;
+        }
+        
+        @Override
+        public @NotNull Mutable setPlayerSpawnFriendly(boolean friendly) {
+            ((MobSpawnSettingsBuilderAccessor) builder).setPlayerCanSpawn(friendly);
+            return this;
+        }
+    }
+}

+ 5 - 5
forge/src/main/java/me/shedaniel/architectury/registry/forge/BlockEntityRenderersImpl.java

@@ -19,16 +19,16 @@
 
 package me.shedaniel.architectury.registry.forge;
 
-import net.minecraft.client.renderer.tileentity.TileEntityRenderer;
-import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
-import net.minecraft.tileentity.TileEntity;
-import net.minecraft.tileentity.TileEntityType;
+import net.minecraft.client.renderer.blockentity.BlockEntityRenderDispatcher;
+import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
+import net.minecraft.world.level.block.entity.BlockEntity;
+import net.minecraft.world.level.block.entity.BlockEntityType;
 import net.minecraftforge.fml.client.registry.ClientRegistry;
 
 import java.util.function.Function;
 
 public class BlockEntityRenderersImpl {
-    public static <T extends TileEntity> void registerRenderer(TileEntityType<T> type, Function<TileEntityRendererDispatcher, TileEntityRenderer<T>> provider) {
+    public static <T extends BlockEntity> void registerRenderer(BlockEntityType<T> type, Function<BlockEntityRenderDispatcher, BlockEntityRenderer<T>> provider) {
         ClientRegistry.bindTileEntityRenderer(type, provider);
     }
 }

+ 6 - 6
forge/src/main/java/me/shedaniel/architectury/registry/forge/BlockPropertiesImpl.java

@@ -21,10 +21,10 @@ package me.shedaniel.architectury.registry.forge;
 
 import me.shedaniel.architectury.registry.BlockProperties;
 import me.shedaniel.architectury.registry.ToolType;
-import net.minecraft.block.AbstractBlock;
-import net.minecraft.block.BlockState;
-import net.minecraft.block.material.Material;
-import net.minecraft.block.material.MaterialColor;
+import net.minecraft.world.level.block.state.BlockBehaviour;
+import net.minecraft.world.level.block.state.BlockState;
+import net.minecraft.world.level.material.Material;
+import net.minecraft.world.level.material.MaterialColor;
 
 import java.util.function.Function;
 
@@ -37,11 +37,11 @@ public class BlockPropertiesImpl {
         return new Impl(material, function);
     }
     
-    public static BlockProperties copy(AbstractBlock abstractBlock) {
+    public static BlockProperties copy(BlockBehaviour abstractBlock) {
         return copy(abstractBlock.properties);
     }
     
-    public static BlockProperties copy(AbstractBlock.Properties old) {
+    public static BlockProperties copy(BlockBehaviour.Properties old) {
         BlockProperties properties = of(old.material, old.materialColor);
         properties.material = old.material;
         properties.destroyTime = old.destroyTime;

+ 10 - 10
forge/src/main/java/me/shedaniel/architectury/registry/forge/ColorHandlersImpl.java

@@ -20,11 +20,11 @@
 package me.shedaniel.architectury.registry.forge;
 
 import com.google.common.collect.Lists;
-import net.minecraft.block.Block;
 import net.minecraft.client.Minecraft;
-import net.minecraft.client.renderer.color.IBlockColor;
-import net.minecraft.client.renderer.color.IItemColor;
-import net.minecraft.util.IItemProvider;
+import net.minecraft.client.color.block.BlockColor;
+import net.minecraft.client.color.item.ItemColor;
+import net.minecraft.world.level.ItemLike;
+import net.minecraft.world.level.block.Block;
 import net.minecraftforge.client.event.ColorHandlerEvent;
 import net.minecraftforge.common.MinecraftForge;
 import org.apache.commons.lang3.tuple.Pair;
@@ -32,23 +32,23 @@ import org.apache.commons.lang3.tuple.Pair;
 import java.util.List;
 
 public class ColorHandlersImpl {
-    private static final List<Pair<IItemColor, IItemProvider[]>> ITEM_COLORS = Lists.newArrayList();
-    private static final List<Pair<IBlockColor, Block[]>> BLOCK_COLORS = Lists.newArrayList();
+    private static final List<Pair<ItemColor, ItemLike[]>> ITEM_COLORS = Lists.newArrayList();
+    private static final List<Pair<BlockColor, Block[]>> BLOCK_COLORS = Lists.newArrayList();
     
     static {
         MinecraftForge.EVENT_BUS.<ColorHandlerEvent.Item>addListener(event -> {
-            for (Pair<IItemColor, IItemProvider[]> pair : ITEM_COLORS) {
+            for (Pair<ItemColor, ItemLike[]> pair : ITEM_COLORS) {
                 event.getItemColors().register(pair.getLeft(), pair.getRight());
             }
         });
         MinecraftForge.EVENT_BUS.<ColorHandlerEvent.Block>addListener(event -> {
-            for (Pair<IBlockColor, Block[]> pair : BLOCK_COLORS) {
+            for (Pair<BlockColor, Block[]> pair : BLOCK_COLORS) {
                 event.getBlockColors().register(pair.getLeft(), pair.getRight());
             }
         });
     }
     
-    public static void registerItemColors(IItemColor itemColor, IItemProvider... items) {
+    public static void registerItemColors(ItemColor itemColor, ItemLike... items) {
         if (Minecraft.getInstance().getItemColors() == null) {
             ITEM_COLORS.add(Pair.of(itemColor, items));
         } else {
@@ -56,7 +56,7 @@ public class ColorHandlersImpl {
         }
     }
     
-    public static void registerBlockColors(IBlockColor blockColor, Block... blocks) {
+    public static void registerBlockColors(BlockColor blockColor, Block... blocks) {
         if (Minecraft.getInstance().getBlockColors() == null) {
             BLOCK_COLORS.add(Pair.of(blockColor, blocks));
         } else {

+ 5 - 5
forge/src/main/java/me/shedaniel/architectury/registry/forge/CreativeTabsImpl.java

@@ -19,16 +19,16 @@
 
 package me.shedaniel.architectury.registry.forge;
 
-import net.minecraft.item.ItemGroup;
-import net.minecraft.item.ItemStack;
-import net.minecraft.util.ResourceLocation;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.world.item.CreativeModeTab;
+import net.minecraft.world.item.ItemStack;
 
 import javax.annotation.Nonnull;
 import java.util.function.Supplier;
 
 public class CreativeTabsImpl {
-    public static ItemGroup create(ResourceLocation resourceLocation, Supplier<ItemStack> supplier) {
-        return new ItemGroup(String.format("%s.%s", resourceLocation.getNamespace(), resourceLocation.getPath())) {
+    public static CreativeModeTab create(ResourceLocation resourceLocation, Supplier<ItemStack> supplier) {
+        return new CreativeModeTab(String.format("%s.%s", resourceLocation.getNamespace(), resourceLocation.getPath())) {
             @Override
             @Nonnull
             public ItemStack makeIcon() {

+ 2 - 2
forge/src/main/java/me/shedaniel/architectury/registry/forge/KeyBindingsImpl.java

@@ -19,11 +19,11 @@
 
 package me.shedaniel.architectury.registry.forge;
 
-import net.minecraft.client.settings.KeyBinding;
+import net.minecraft.client.KeyMapping;
 import net.minecraftforge.fml.client.registry.ClientRegistry;
 
 public class KeyBindingsImpl {
-    public static void registerKeyBinding(KeyBinding keyBinding) {
+    public static void registerKeyBinding(KeyMapping keyBinding) {
         ClientRegistry.registerKeyBinding(keyBinding);
     }
 }

+ 36 - 36
forge/src/main/java/me/shedaniel/architectury/registry/forge/RegistriesImpl.java

@@ -24,9 +24,9 @@ import com.google.common.collect.Table;
 import me.shedaniel.architectury.platform.forge.EventBuses;
 import me.shedaniel.architectury.registry.Registries;
 import me.shedaniel.architectury.registry.Registry;
-import net.minecraft.util.LazyValue;
-import net.minecraft.util.RegistryKey;
-import net.minecraft.util.ResourceLocation;
+import net.minecraft.resources.ResourceKey;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.util.LazyLoadedValue;
 import net.minecraftforge.event.RegistryEvent;
 import net.minecraftforge.eventbus.api.IEventBus;
 import net.minecraftforge.eventbus.api.SubscribeEvent;
@@ -48,13 +48,13 @@ public class RegistriesImpl {
         return new RegistryProviderImpl(modId);
     }
     
-    public static <T> ResourceLocation getId(T t, RegistryKey<net.minecraft.util.registry.Registry<T>> registryKey) {
+    public static <T> ResourceLocation getId(T t, ResourceKey<net.minecraft.core.Registry<T>> registryKey) {
         if (t instanceof IForgeRegistryEntry)
             return ((IForgeRegistryEntry<?>) t).getRegistryName();
         return null;
     }
     
-    public static <T> ResourceLocation getId(T t, net.minecraft.util.registry.Registry<T> registry) {
+    public static <T> ResourceLocation getId(T t, net.minecraft.core.Registry<T> registry) {
         if (t instanceof IForgeRegistryEntry)
             return ((IForgeRegistryEntry<?>) t).getRegistryName();
         return null;
@@ -72,12 +72,12 @@ public class RegistriesImpl {
         }
         
         @Override
-        public <T> Registry<T> get(RegistryKey<net.minecraft.util.registry.Registry<T>> registryKey) {
+        public <T> Registry<T> get(ResourceKey<net.minecraft.core.Registry<T>> registryKey) {
             return new ForgeBackedRegistryImpl<>(registry, (IForgeRegistry) RegistryManager.ACTIVE.getRegistry(registryKey.location()));
         }
         
         @Override
-        public <T> Registry<T> get(net.minecraft.util.registry.Registry<T> registry) {
+        public <T> Registry<T> get(net.minecraft.core.Registry<T> registry) {
             return new VanillaBackedRegistryImpl<>(registry);
         }
         
@@ -99,21 +99,21 @@ public class RegistriesImpl {
     }
     
     public static class VanillaBackedRegistryImpl<T> implements Registry<T> {
-        private net.minecraft.util.registry.Registry<T> delegate;
+        private net.minecraft.core.Registry<T> delegate;
         
-        public VanillaBackedRegistryImpl(net.minecraft.util.registry.Registry<T> delegate) {
+        public VanillaBackedRegistryImpl(net.minecraft.core.Registry<T> delegate) {
             this.delegate = delegate;
         }
         
         @Override
         public Supplier<T> delegate(ResourceLocation id) {
-            LazyValue<T> value = new LazyValue<>(() -> get(id));
+            LazyLoadedValue<T> value = new LazyLoadedValue<>(() -> get(id));
             return value::get;
         }
         
         @Override
         public Supplier<T> register(ResourceLocation id, Supplier<T> supplier) {
-            net.minecraft.util.registry.Registry.register(delegate, id, supplier.get());
+            net.minecraft.core.Registry.register(delegate, id, supplier.get());
             return delegate(id);
         }
         
@@ -122,43 +122,43 @@ public class RegistriesImpl {
         public ResourceLocation getId(T obj) {
             return delegate.getKey(obj);
         }
-    
+        
         @Override
-        public Optional<RegistryKey<T>> getKey(T t) {
+        public Optional<ResourceKey<T>> getKey(T t) {
             return delegate.getResourceKey(t);
         }
-    
+        
         @Override
         @Nullable
         public T get(ResourceLocation id) {
             return delegate.get(id);
         }
-    
+        
         @Override
         public boolean contains(ResourceLocation resourceLocation) {
             return delegate.containsKey(resourceLocation);
         }
-    
+        
         @Override
         public boolean containsValue(T t) {
             return delegate.getResourceKey(t).isPresent();
         }
-    
+        
         @Override
         public Set<ResourceLocation> getIds() {
             return delegate.keySet();
         }
-    
+        
         @Override
-        public Set<Map.Entry<RegistryKey<T>, T>> entrySet() {
+        public Set<Map.Entry<ResourceKey<T>, T>> entrySet() {
             return delegate.entrySet();
         }
-    
+        
         @Override
-        public RegistryKey<? extends net.minecraft.util.registry.Registry<T>> key() {
+        public ResourceKey<? extends net.minecraft.core.Registry<T>> key() {
             return delegate.key();
         }
-    
+        
         @Override
         public Iterator<T> iterator() {
             return delegate.iterator();
@@ -176,7 +176,7 @@ public class RegistriesImpl {
         
         @Override
         public Supplier<T> delegate(ResourceLocation id) {
-            LazyValue<T> value = new LazyValue<>(() -> get(id));
+            LazyLoadedValue<T> value = new LazyLoadedValue<>(() -> get(id));
             return value::get;
         }
         
@@ -192,43 +192,43 @@ public class RegistriesImpl {
         public ResourceLocation getId(T obj) {
             return delegate.getKey(obj);
         }
-    
+        
         @Override
-        public Optional<RegistryKey<T>> getKey(T t) {
-            return Optional.ofNullable(getId(t)).map(id -> RegistryKey.create(key(), id));
+        public Optional<ResourceKey<T>> getKey(T t) {
+            return Optional.ofNullable(getId(t)).map(id -> ResourceKey.create(key(), id));
         }
-    
+        
         @Override
         @Nullable
         public T get(ResourceLocation id) {
             return delegate.getValue(id);
         }
-    
+        
         @Override
         public boolean contains(ResourceLocation resourceLocation) {
             return delegate.containsKey(resourceLocation);
         }
-    
+        
         @Override
         public boolean containsValue(T t) {
             return delegate.containsValue(t);
         }
-    
+        
         @Override
         public Set<ResourceLocation> getIds() {
             return delegate.getKeys();
         }
-    
+        
         @Override
-        public Set<Map.Entry<RegistryKey<T>, T>> entrySet() {
+        public Set<Map.Entry<ResourceKey<T>, T>> entrySet() {
             return delegate.getEntries();
         }
-    
+        
         @Override
-        public RegistryKey<? extends net.minecraft.util.registry.Registry<T>> key() {
-            return RegistryKey.createRegistryKey(delegate.getRegistryName());
+        public ResourceKey<? extends net.minecraft.core.Registry<T>> key() {
+            return ResourceKey.createRegistryKey(delegate.getRegistryName());
         }
-    
+        
         @Override
         public Iterator<T> iterator() {
             return delegate.iterator();

+ 10 - 10
forge/src/main/java/me/shedaniel/architectury/registry/forge/ReloadListenersImpl.java

@@ -21,9 +21,9 @@ package me.shedaniel.architectury.registry.forge;
 
 import com.google.common.collect.Lists;
 import net.minecraft.client.Minecraft;
-import net.minecraft.resources.IFutureReloadListener;
-import net.minecraft.resources.IReloadableResourceManager;
-import net.minecraft.resources.ResourcePackType;
+import net.minecraft.server.packs.PackType;
+import net.minecraft.server.packs.resources.PreparableReloadListener;
+import net.minecraft.server.packs.resources.ReloadableResourceManager;
 import net.minecraftforge.api.distmarker.Dist;
 import net.minecraftforge.api.distmarker.OnlyIn;
 import net.minecraftforge.common.MinecraftForge;
@@ -32,26 +32,26 @@ import net.minecraftforge.event.AddReloadListenerEvent;
 import java.util.List;
 
 public class ReloadListenersImpl {
-    private static List<IFutureReloadListener> serverDataReloadListeners = Lists.newArrayList();
+    private static List<PreparableReloadListener> serverDataReloadListeners = Lists.newArrayList();
     
     static {
         MinecraftForge.EVENT_BUS.<AddReloadListenerEvent>addListener(event -> {
-            for (IFutureReloadListener listener : serverDataReloadListeners) {
+            for (PreparableReloadListener listener : serverDataReloadListeners) {
                 event.addListener(listener);
             }
         });
     }
     
-    public static void registerReloadListener(ResourcePackType type, IFutureReloadListener listener) {
-        if (type == ResourcePackType.SERVER_DATA) {
+    public static void registerReloadListener(PackType type, PreparableReloadListener listener) {
+        if (type == PackType.SERVER_DATA) {
             serverDataReloadListeners.add(listener);
-        } else if (type == ResourcePackType.CLIENT_RESOURCES) {
+        } else if (type == PackType.CLIENT_RESOURCES) {
             reloadClientReloadListener(listener);
         }
     }
     
     @OnlyIn(Dist.CLIENT)
-    private static void reloadClientReloadListener(IFutureReloadListener listener) {
-        ((IReloadableResourceManager) Minecraft.getInstance().getResourceManager()).registerReloadListener(listener);
+    private static void reloadClientReloadListener(PreparableReloadListener listener) {
+        ((ReloadableResourceManager) Minecraft.getInstance().getResourceManager()).registerReloadListener(listener);
     }
 }

+ 5 - 5
forge/src/main/java/me/shedaniel/architectury/registry/forge/RenderTypesImpl.java

@@ -19,21 +19,21 @@
 
 package me.shedaniel.architectury.registry.forge;
 
-import net.minecraft.block.Block;
+import net.minecraft.client.renderer.ItemBlockRenderTypes;
 import net.minecraft.client.renderer.RenderType;
-import net.minecraft.client.renderer.RenderTypeLookup;
-import net.minecraft.fluid.Fluid;
+import net.minecraft.world.level.block.Block;
+import net.minecraft.world.level.material.Fluid;
 
 public class RenderTypesImpl {
     public static void register(RenderType type, Block... blocks) {
         for (Block block : blocks) {
-            RenderTypeLookup.setRenderLayer(block, type);
+            ItemBlockRenderTypes.setRenderLayer(block, type);
         }
     }
     
     public static void register(RenderType type, Fluid... fluids) {
         for (Fluid fluid : fluids) {
-            RenderTypeLookup.setRenderLayer(fluid, type);
+            ItemBlockRenderTypes.setRenderLayer(fluid, type);
         }
     }
 }

+ 6 - 6
forge/src/main/java/me/shedaniel/architectury/registry/forge/ToolTypeImpl.java

@@ -20,23 +20,23 @@
 package me.shedaniel.architectury.registry.forge;
 
 
-import net.minecraft.item.Item;
-import net.minecraft.tags.ITag;
+import net.minecraft.tags.Tag;
+import net.minecraft.world.item.Item;
 
 public class ToolTypeImpl {
-    public static ITag<Item> pickaxeTag() {
+    public static Tag<Item> pickaxeTag() {
         return null;
     }
     
-    public static ITag<Item> axeTag() {
+    public static Tag<Item> axeTag() {
         return null;
     }
     
-    public static ITag<Item> hoeTag() {
+    public static Tag<Item> hoeTag() {
         return null;
     }
     
-    public static ITag<Item> shovelTag() {
+    public static Tag<Item> shovelTag() {
         return null;
     }
 }

+ 17 - 1
forge/src/main/resources/META-INF/accesstransformer.cfg

@@ -15,4 +15,20 @@ public net.minecraft.block.AbstractBlock$Properties field_226895_m_ #canOcclude
 public net.minecraft.block.AbstractBlock$Properties field_235813_o_ #isAir
 public net.minecraft.block.AbstractBlock$Properties field_235806_h_ #requiresCorrectToolForDrops
 public-f net.minecraft.world.Explosion field_77280_f #radius
-public net.minecraft.client.gui.screen.Screen field_230710_m_ #buttons
+public net.minecraft.client.gui.screen.Screen field_230710_m_ #buttons
+public-f net.minecraft.world.biome.Biome$Climate field_242460_b # precipitation
+public-f net.minecraft.world.biome.Biome$Climate field_242461_c # temperature
+public-f net.minecraft.world.biome.Biome$Climate field_242462_d # temperatureModifier
+public-f net.minecraft.world.biome.Biome$Climate field_242463_e # downfall
+public-f net.minecraft.world.biome.BiomeAmbience field_235205_b_ # fogColor
+public-f net.minecraft.world.biome.BiomeAmbience field_235206_c_ # waterColor
+public-f net.minecraft.world.biome.BiomeAmbience field_235207_d_ # waterFogColor
+public-f net.minecraft.world.biome.BiomeAmbience field_235208_e_ # particle
+public-f net.minecraft.world.biome.BiomeAmbience field_235209_f_ # ambientSound
+public-f net.minecraft.world.biome.BiomeAmbience field_235210_g_ # moodSound
+public-f net.minecraft.world.biome.BiomeAmbience field_235211_h_ # additionsSound
+public-f net.minecraft.world.biome.BiomeAmbience field_235212_i_ # music
+public-f net.minecraft.world.biome.BiomeAmbience field_242523_e # skyColor
+public-f net.minecraft.world.biome.BiomeAmbience field_242524_f # foliageColor
+public-f net.minecraft.world.biome.BiomeAmbience field_242525_g # grassColor
+public-f net.minecraft.world.biome.BiomeAmbience field_242526_h # grassColorModifier

+ 12 - 0
forge/src/main/resources/architectury.mixins.json

@@ -0,0 +1,12 @@
+{
+  "required": true,
+  "package": "me.shedaniel.architectury.mixin.forge",
+  "compatibilityLevel": "JAVA_8",
+  "minVersion": "0.8",
+  "client": [
+  ],
+  "mixins": ["BiomeGenerationSettingsBuilderAccessor", "BiomeSpecialEffectsAccessor", "MobSpawnSettingsBuilderAccessor"],
+  "injectors": {
+    "defaultRequire": 1
+  }
+}

+ 1 - 1
gradle.properties

@@ -5,7 +5,7 @@ minecraft_version=1.16.4
 supported_version=1.16.4
 
 archives_base_name=architectury
-mod_version=1.1
+mod_version=1.2
 maven_group=me.shedaniel
 
 fabric_loader_version=0.10.6+build.214

+ 1 - 0
settings.gradle

@@ -3,6 +3,7 @@ pluginManagement {
         jcenter()
         maven { url "https://maven.fabricmc.net/" }
         maven { url "https://dl.bintray.com/shedaniel/cloth" }
+        maven { url "https://files.minecraftforge.net/maven/" }
         gradlePluginPortal()
     }
 }