diff --git a/build.gradle b/build.gradle index b217cb3..259918d 100644 --- a/build.gradle +++ b/build.gradle @@ -2,8 +2,8 @@ //file:noinspection GroovyAssignabilityCheck plugins { - id 'fabric-loom' version '1.2-SNAPSHOT' - id 'maven-publish' + id "fabric-loom" version "${loom_version}" + id "maven-publish" } version = project.mod_version @@ -46,6 +46,9 @@ dependencies { // Fabric Permissions API include(modImplementation("me.lucko:fabric-permissions-api:${project.fabric_permissions_api_version}")) + + // Sodium + modImplementation("maven.modrinth:sodium:${project.sodium_version}") } processResources { diff --git a/gradle.properties b/gradle.properties index 2156a86..806507e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,7 +5,8 @@ org.gradle.jvmargs=-Xmx1G # Check these on https://modmuss50.me/fabric.html minecraft_version=1.20.1 yarn_mappings=1.20.1+build.10 -loader_version=0.14.25 +loader_version=0.15.6 +loom_version=1.6-SNAPSHOT # Mod properties mod_version=1.0-SNAPSHOT @@ -14,17 +15,10 @@ archives_base_name=simple-seasons # Runtime mods modmenu_version=7.2.1 -sodium_version=mc1.20.1-0.5.1 -reeses_sodium_options_version=mc1.20.1-1.6.4 -lithium_version=mc1.20.1-0.11.2 -lazydfu_version=0.1.3 -ferrite_core_version=6.0.0-fabric -appleskin_version=2.5.0+mc1.20 cloth_config_version=11.1.106+fabric -modernfix_version=5.6.1+mc1.20.1 -starlight_version=1.1.2+1.20 # Dependencies mixin_extras_version=0.3.6 -fabric_api_version=0.87.0+1.20.1 +fabric_api_version=0.92.2+1.20.1 fabric_permissions_api_version=0.2-SNAPSHOT +sodium_version=mc1.20.1-0.5.8 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 37aef8d..509c4a2 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/src/main/java/io/github/steveplays28/simpleseasons/client/compat/sodium/SimpleSeasonsSodiumCompat.java b/src/main/java/io/github/steveplays28/simpleseasons/client/compat/sodium/SimpleSeasonsSodiumCompat.java new file mode 100644 index 0000000..682d95c --- /dev/null +++ b/src/main/java/io/github/steveplays28/simpleseasons/client/compat/sodium/SimpleSeasonsSodiumCompat.java @@ -0,0 +1,19 @@ +package io.github.steveplays28.simpleseasons.client.compat.sodium; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.fabricmc.loader.api.FabricLoader; +import org.jetbrains.annotations.NotNull; + +@Environment(EnvType.CLIENT) +public class SimpleSeasonsSodiumCompat { + private static final @NotNull String SODIUM_MOD_ID = "sodium"; + private static final @NotNull String EMBEDDIUM_MOD_ID = "embeddium"; + private static final @NotNull String RUBIDIUM_MOD_ID = "rubidium"; + + public static boolean isSodiumLoaded() { + var fabricLoader = FabricLoader.getInstance(); + return fabricLoader.isModLoaded(SODIUM_MOD_ID) || fabricLoader.isModLoaded(EMBEDDIUM_MOD_ID) || fabricLoader.isModLoaded( + RUBIDIUM_MOD_ID); + } +} diff --git a/src/main/java/io/github/steveplays28/simpleseasons/client/resource/SimpleSeasonsResourceReloadListener.java b/src/main/java/io/github/steveplays28/simpleseasons/client/resource/SimpleSeasonsResourceReloadListener.java index 960bb92..8669944 100644 --- a/src/main/java/io/github/steveplays28/simpleseasons/client/resource/SimpleSeasonsResourceReloadListener.java +++ b/src/main/java/io/github/steveplays28/simpleseasons/client/resource/SimpleSeasonsResourceReloadListener.java @@ -3,6 +3,7 @@ import com.google.gson.JsonParser; import io.github.steveplays28.simpleseasons.SimpleSeasons; import io.github.steveplays28.simpleseasons.api.SimpleSeasonsApi; +import io.github.steveplays28.simpleseasons.client.extension.world.ClientWorldExtension; import io.github.steveplays28.simpleseasons.client.registry.SeasonColorRegistries; import io.github.steveplays28.simpleseasons.client.util.season.color.SeasonColorUtil; import io.github.steveplays28.simpleseasons.state.world.SeasonTracker; @@ -12,15 +13,16 @@ import net.fabricmc.fabric.api.client.rendering.v1.ColorProviderRegistry; import net.fabricmc.fabric.api.resource.SimpleResourceReloadListener; import net.minecraft.client.MinecraftClient; -import net.minecraft.client.color.world.BiomeColors; import net.minecraft.client.color.world.FoliageColors; import net.minecraft.registry.Registries; import net.minecraft.registry.Registry; import net.minecraft.registry.SimpleRegistry; import net.minecraft.resource.ResourceManager; import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; import net.minecraft.util.profiler.Profiler; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.io.IOException; import java.util.HashMap; @@ -136,24 +138,64 @@ private void loadSeasonColors(@NotNull ResourceManager resourceManager, @NotNull } private void registerBlockColorProvider(Identifier blockIdentifier) { - ColorProviderRegistry.BLOCK.register((blockState, world, blockPos, tintIndex) -> { - if (world == null || blockPos == null) { + ColorProviderRegistry.BLOCK.register((blockState, blockRenderView, startBlockPos, tintIndex) -> { + @NotNull var client = MinecraftClient.getInstance(); + @Nullable var clientWorld = client.world; + if (clientWorld == null || startBlockPos == null) { return FoliageColors.getDefaultColor(); } - return BiomeColors.getFoliageColor(world, blockPos); + @NotNull var blockPosColorCache = ((ClientWorldExtension) clientWorld).simple_seasons$getColorCache().blockPosColorCache; + @Nullable var cachedStartBlockSeasonColor = blockPosColorCache.get(startBlockPos); + if (cachedStartBlockSeasonColor != null) { + return cachedStartBlockSeasonColor.toInt(); + } + + var biomeBlendedBlockSeasonColor = clientWorld.calculateColor(startBlockPos, (biome, x, z) -> { + @NotNull var blockPos = new BlockPos((int) Math.round(x), startBlockPos.getY(), (int) Math.round(z)); + // Nullable due to concurrency + @Nullable var cachedBlockSeasonColor = blockPosColorCache.get(blockPos); + if (cachedBlockSeasonColor != null) { + return cachedBlockSeasonColor.toInt(); + } + + @Nullable var blockSeasonColor = SeasonColorUtil.getBlockSeasonColor( + Registries.BLOCK.getId(clientWorld.getBlockState(blockPos).getBlock()), + clientWorld.getBiome(blockPos), + SimpleSeasonsApi.getSeason(clientWorld), + SimpleSeasonsApi.getSeasonProgress(clientWorld) + ); + if (blockSeasonColor != null) { + return blockSeasonColor.toInt(); + } + + @Nullable var startBlockSeasonColor = SeasonColorUtil.getBlockSeasonColor( + Registries.BLOCK.getId(clientWorld.getBlockState(startBlockPos).getBlock()), + clientWorld.getBiome(startBlockPos), + SimpleSeasonsApi.getSeason(clientWorld), + SimpleSeasonsApi.getSeasonProgress(clientWorld) + ); + if (startBlockSeasonColor == null) { + return SeasonColorUtil.FALLBACK_SEASON_COLOR_PRECALCULATED; + } + + return startBlockSeasonColor.toInt(); + }); + + blockPosColorCache.put(startBlockPos, new Color(biomeBlendedBlockSeasonColor)); + return biomeBlendedBlockSeasonColor; }, Registries.BLOCK.get(blockIdentifier)); } private void registerItemColorProvider(Identifier itemIdentifier) { ColorProviderRegistry.ITEM.register((stack, tintIndex) -> { - var client = MinecraftClient.getInstance(); + @NotNull var client = MinecraftClient.getInstance(); if (client.world == null || client.player == null) { throw new IllegalStateException( "Error occurred while registering item color providers: client.world == null || client.player == null."); } - var itemSeasonColor = SeasonColorUtil.getItemSeasonColor(Registries.ITEM.getId(stack.getItem()), + @Nullable var itemSeasonColor = SeasonColorUtil.getItemSeasonColor(Registries.ITEM.getId(stack.getItem()), client.world.getBiome(client.player.getBlockPos()), SimpleSeasonsApi.getSeason(client.world), SimpleSeasonsApi.getSeasonProgress(client.world) ); diff --git a/src/main/java/io/github/steveplays28/simpleseasons/client/state/world/ClientSeasonTracker.java b/src/main/java/io/github/steveplays28/simpleseasons/client/state/world/ClientSeasonTracker.java index 0726c6b..96cd71e 100644 --- a/src/main/java/io/github/steveplays28/simpleseasons/client/state/world/ClientSeasonTracker.java +++ b/src/main/java/io/github/steveplays28/simpleseasons/client/state/world/ClientSeasonTracker.java @@ -4,7 +4,6 @@ import io.github.steveplays28.simpleseasons.state.world.SeasonTracker; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; -import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; import net.fabricmc.fabric.api.networking.v1.PacketSender; import net.minecraft.client.MinecraftClient; @@ -16,12 +15,9 @@ @Environment(EnvType.CLIENT) public class ClientSeasonTracker extends SeasonTracker { - private MinecraftClient client; - public ClientSeasonTracker() { super(); - ClientLifecycleEvents.CLIENT_STARTED.register(client -> this.client = client); ClientPlayNetworking.registerGlobalReceiver(SEASON_PACKET_CHANNEL, this::onSeasonStatePacketReceived); } @@ -29,6 +25,7 @@ public ClientSeasonTracker() { public void setSeasonProgress(float seasonProgress) { super.setSeasonProgress(seasonProgress); + @NotNull var client = MinecraftClient.getInstance(); if (client.world == null) { throw new IllegalStateException("Error occurred while setting the season's progress: client.world == null."); } @@ -41,8 +38,11 @@ private void onSeasonStatePacketReceived(@NotNull MinecraftClient client, @NotNu return; } - this.setSeason(buf.readInt()); - this.setSeasonProgress(buf.readFloat()); - RenderingUtil.reloadChunkColors(client.world); + final var seasonId = buf.readInt(); + final var seasonProgress = buf.readFloat(); + client.executeSync(() -> { + this.setSeason(seasonId); + this.setSeasonProgress(seasonProgress); + }); } } diff --git a/src/main/java/io/github/steveplays28/simpleseasons/client/util/rendering/RenderingUtil.java b/src/main/java/io/github/steveplays28/simpleseasons/client/util/rendering/RenderingUtil.java index f45bd89..0dfc0c4 100644 --- a/src/main/java/io/github/steveplays28/simpleseasons/client/util/rendering/RenderingUtil.java +++ b/src/main/java/io/github/steveplays28/simpleseasons/client/util/rendering/RenderingUtil.java @@ -1,18 +1,38 @@ package io.github.steveplays28.simpleseasons.client.util.rendering; +import io.github.steveplays28.simpleseasons.client.compat.sodium.SimpleSeasonsSodiumCompat; import io.github.steveplays28.simpleseasons.mixin.client.accessor.WorldRendererAccessor; +import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; +import net.minecraft.client.MinecraftClient; import net.minecraft.client.world.ClientWorld; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; @Environment(EnvType.CLIENT) public class RenderingUtil { @SuppressWarnings("ForLoopReplaceableByForEach") - public static void reloadChunkColors(@NotNull ClientWorld world) { - world.reloadColor(); + public static void reloadChunkColors(@NotNull ClientWorld clientWorld) { + clientWorld.reloadColor(); - var chunks = ((WorldRendererAccessor) world.worldRenderer).getChunks(); + if (SimpleSeasonsSodiumCompat.isSodiumLoaded()) { + @NotNull var client = MinecraftClient.getInstance(); + @Nullable var player = client.player; + if (player == null) { + return; + } + + var playerChunkPos = player.getChunkPos(); + var clampedViewDistance = MinecraftClient.getInstance().options.getClampedViewDistance(); + SodiumWorldRenderer.instance().scheduleRebuildForChunks( + playerChunkPos.x - clampedViewDistance, clientWorld.getBottomY() >> 4, playerChunkPos.z - clampedViewDistance, + playerChunkPos.x + clampedViewDistance, clientWorld.getTopY() >> 4, playerChunkPos.z + clampedViewDistance, true + ); + return; + } + + @Nullable var chunks = ((WorldRendererAccessor) clientWorld.worldRenderer).getChunks(); if (chunks == null) { return; } diff --git a/src/main/java/io/github/steveplays28/simpleseasons/mixin/client/accessor/ChunkRendererRegionAccessor.java b/src/main/java/io/github/steveplays28/simpleseasons/mixin/client/accessor/ChunkRendererRegionAccessor.java deleted file mode 100644 index 42ed0d1..0000000 --- a/src/main/java/io/github/steveplays28/simpleseasons/mixin/client/accessor/ChunkRendererRegionAccessor.java +++ /dev/null @@ -1,15 +0,0 @@ -package io.github.steveplays28.simpleseasons.mixin.client.accessor; - -import net.fabricmc.api.EnvType; -import net.fabricmc.api.Environment; -import net.minecraft.client.render.chunk.ChunkRendererRegion; -import net.minecraft.world.World; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; - -@Environment(EnvType.CLIENT) -@Mixin(ChunkRendererRegion.class) -public interface ChunkRendererRegionAccessor { - @Accessor("world") - World getWorld(); -} diff --git a/src/main/java/io/github/steveplays28/simpleseasons/mixin/client/accessor/WorldRendererAccessor.java b/src/main/java/io/github/steveplays28/simpleseasons/mixin/client/accessor/WorldRendererAccessor.java index a7a17ab..2ba6cf5 100644 --- a/src/main/java/io/github/steveplays28/simpleseasons/mixin/client/accessor/WorldRendererAccessor.java +++ b/src/main/java/io/github/steveplays28/simpleseasons/mixin/client/accessor/WorldRendererAccessor.java @@ -11,6 +11,6 @@ @Environment(EnvType.CLIENT) @Mixin(WorldRenderer.class) public interface WorldRendererAccessor { - @Accessor("chunks") + @Accessor @Nullable BuiltChunkStorage getChunks(); } diff --git a/src/main/java/io/github/steveplays28/simpleseasons/mixin/client/color/world/BiomeColorsMixin.java b/src/main/java/io/github/steveplays28/simpleseasons/mixin/client/color/world/BiomeColorsMixin.java deleted file mode 100644 index 7a7b9f7..0000000 --- a/src/main/java/io/github/steveplays28/simpleseasons/mixin/client/color/world/BiomeColorsMixin.java +++ /dev/null @@ -1,81 +0,0 @@ -package io.github.steveplays28.simpleseasons.mixin.client.color.world; - -import io.github.steveplays28.simpleseasons.api.SimpleSeasonsApi; -import io.github.steveplays28.simpleseasons.client.extension.world.ClientWorldExtension; -import io.github.steveplays28.simpleseasons.client.util.season.color.SeasonColorUtil; -import io.github.steveplays28.simpleseasons.mixin.client.accessor.ChunkRendererRegionAccessor; -import io.github.steveplays28.simpleseasons.util.Color; -import net.fabricmc.api.EnvType; -import net.fabricmc.api.Environment; -import net.minecraft.client.color.world.BiomeColors; -import net.minecraft.client.world.ClientWorld; -import net.minecraft.registry.Registries; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.BlockRenderView; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -@Environment(EnvType.CLIENT) -@Mixin(BiomeColors.class) -public abstract class BiomeColorsMixin { - /** - * A Mixin {@link Inject} into {@link BiomeColors#getGrassColor} and {@link BiomeColors#getFoliageColor}. - * - * @param world The {@link BlockRenderView} that can be used to get the {@link ClientWorld}. - * Can never be {@code null}, as {@code null} checks are done in every code path before this function is called in vanilla Minecraft. - * @param startBlockPos The position of the block where the color is being queried. - * Can never be {@code null}, as {@code null} checks are done in every code path before this function is called in vanilla Minecraft. - * @param cir The {@link CallbackInfoReturnable}. - */ - @Inject(method = {"getGrassColor", "getFoliageColor"}, at = @At(value = "RETURN"), cancellable = true) - private static void simple_seasons$modifyGrassAndFoliageColors(@NotNull BlockRenderView world, @NotNull BlockPos startBlockPos, @NotNull CallbackInfoReturnable cir) { - if (!(world instanceof ChunkRendererRegionAccessor chunkRendererRegion)) { - return; - } - - @NotNull var clientWorld = (ClientWorld) chunkRendererRegion.getWorld(); - @NotNull var blockPosColorCache = ((ClientWorldExtension) clientWorld).simple_seasons$getColorCache().blockPosColorCache; - @Nullable var cachedStartBlockSeasonColor = blockPosColorCache.get(startBlockPos); - if (cachedStartBlockSeasonColor != null) { - cir.setReturnValue(cachedStartBlockSeasonColor.toInt()); - } - - var biomeBlendedBlockSeasonColor = clientWorld.calculateColor(startBlockPos, (biome, x, z) -> { - var blockPos = new BlockPos((int) Math.round(x), startBlockPos.getY(), (int) Math.round(z)); - // Nullable due to concurrency - @Nullable var cachedBlockSeasonColor = blockPosColorCache.get(blockPos); - if (cachedBlockSeasonColor != null) { - return cachedBlockSeasonColor.toInt(); - } - - var blockSeasonColor = SeasonColorUtil.getBlockSeasonColor( - Registries.BLOCK.getId(clientWorld.getBlockState(blockPos).getBlock()), - clientWorld.getBiome(blockPos), - SimpleSeasonsApi.getSeason(clientWorld), - SimpleSeasonsApi.getSeasonProgress(clientWorld) - ); - if (blockSeasonColor != null) { - return blockSeasonColor.toInt(); - } - - var startBlockSeasonColor = SeasonColorUtil.getBlockSeasonColor( - Registries.BLOCK.getId(clientWorld.getBlockState(startBlockPos).getBlock()), - clientWorld.getBiome(startBlockPos), - SimpleSeasonsApi.getSeason(clientWorld), - SimpleSeasonsApi.getSeasonProgress(clientWorld) - ); - if (startBlockSeasonColor == null) { - return SeasonColorUtil.FALLBACK_SEASON_COLOR_PRECALCULATED; - } - - return startBlockSeasonColor.toInt(); - }); - - blockPosColorCache.put(startBlockPos, new Color(biomeBlendedBlockSeasonColor)); - cir.setReturnValue(biomeBlendedBlockSeasonColor); - } -} diff --git a/src/main/resources/simple-seasons.accesswidener b/src/main/resources/simple-seasons.accesswidener index 95903f9..26003e8 100644 --- a/src/main/resources/simple-seasons.accesswidener +++ b/src/main/resources/simple-seasons.accesswidener @@ -5,3 +5,4 @@ accessible method net/minecraft/client/render/WorldRenderer scheduleChunkRender accessible class net/minecraft/world/biome/Biome$Weather accessible field net/minecraft/world/biome/Biome weather Lnet/minecraft/world/biome/Biome$Weather; accessible class net/minecraft/client/render/WorldRenderer$ChunkInfo +accessible class net/minecraft/client/world/ClientChunkManager$ClientChunkMap diff --git a/src/main/resources/simple-seasons.mixins.json b/src/main/resources/simple-seasons.mixins.json index ea9f746..efe1e6e 100644 --- a/src/main/resources/simple-seasons.mixins.json +++ b/src/main/resources/simple-seasons.mixins.json @@ -13,9 +13,7 @@ "world.gen.feature.FreezeTopLayerFeatureMixin" ], "client": [ - "client.accessor.ChunkRendererRegionAccessor", "client.accessor.WorldRendererAccessor", - "client.color.world.BiomeColorsMixin", "client.render.WorldRendererMixin", "client.world.ClientWorldMixin" ],