Skip to content

Commit

Permalink
feat: Add linear interpolation for season colors
Browse files Browse the repository at this point in the history
Season progress is now accurately represented in the world by linearly interpolating season colors to the next season.
  • Loading branch information
Steveplays28 committed May 28, 2024
1 parent a00d8b9 commit 1fde9b7
Show file tree
Hide file tree
Showing 16 changed files with 210 additions and 137 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import io.github.steveplays28.simpleseasons.command.season.SetSeasonCommand;
import io.github.steveplays28.simpleseasons.server.state.ServerSeasonTracker;
import io.github.steveplays28.simpleseasons.state.SeasonTracker;
import io.github.steveplays28.simpleseasons.state.SeasonState;
import io.github.steveplays28.simpleseasons.util.Color;
import io.github.steveplays28.simpleseasons.state.SeasonTracker;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
Expand All @@ -17,7 +16,6 @@
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.Map;

public class SimpleSeasons implements ModInitializer {
public static final String MOD_ID = "simple-seasons";
Expand All @@ -28,26 +26,6 @@ public class SimpleSeasons implements ModInitializer {
public static final Identifier SEASON_PACKET_CHANNEL = new Identifier(MOD_NAMESPACE);
// Mod IDs
public static final String MINECRAFT_MOD_ID = "minecraft";
// Per-season color additions
public static final Color SPRING_COLOR_ADDITION = new Color(255 / 3, 255 / 3, 0);
public static final Color SUMMER_COLOR_ADDITION = new Color(0, 0, 0);
public static final Color FALL_COLOR_ADDITION = new Color(255 / 3, 0, 0);
public static final Color WINTER_COLOR_ADDITION = new Color(255 / 2, 255 / 2, 255 / 2);
// Dry biomes
public static final Color HOT_DRY_BIOMES_COLOR_ADDITION = new Color(120, 0, 0);
public static final Color WET_DRY_BIOMES_COLOR_ADDITION = new Color(50, 50, 0);
// Seasons color map
public static final Map<Integer, Color> SEASONS_COLOR_ADDITIONS_MAP = Map.of(
SeasonTracker.Seasons.SPRING.ordinal(),
SPRING_COLOR_ADDITION, SeasonTracker.Seasons.SUMMER.ordinal(), SUMMER_COLOR_ADDITION, SeasonTracker.Seasons.FALL.ordinal(),
FALL_COLOR_ADDITION, SeasonTracker.Seasons.WINTER.ordinal(), WINTER_COLOR_ADDITION
);
// Dry biomes
public static final Map<Integer, Color> SEASONS_DRY_BIOMES_COLOR_ADDITIONS_MAP = Map.of(SeasonTracker.Seasons.SPRING.ordinal(),
HOT_DRY_BIOMES_COLOR_ADDITION, SeasonTracker.Seasons.SUMMER.ordinal(), HOT_DRY_BIOMES_COLOR_ADDITION,
SeasonTracker.Seasons.FALL.ordinal(), WET_DRY_BIOMES_COLOR_ADDITION, SeasonTracker.Seasons.WINTER.ordinal(),
WET_DRY_BIOMES_COLOR_ADDITION
);
public static final long TIME_PER_DAY = 50;
public static final long TIME_PER_SEASON_CHANGE = TIME_PER_DAY * 30 * 3;

Expand All @@ -70,17 +48,22 @@ public void onInitialize() {
});
}

// TODO: Move into SimpleSeasonsAPI
// TODO: Move into SimpleSeasonsApi
public static SeasonTracker.Seasons getSeason() {
var simpleSeasonsState = SeasonState.getServerState(server);
return SeasonTracker.Seasons.of(simpleSeasonsState.season);
}

// TODO: Move into SimpleSeasonsAPI
// TODO: Move into SimpleSeasonsApi
public static void setSeason(int seasonId) {
SEASON_TRACKER.setSeason(seasonId);
}

// TODO: Move into SimpleSeasonsApi
public static float getSeasonProgress() {
return SEASON_TRACKER.getSeasonProgress();
}

@Contract(pure = true)
public static boolean isDryBiome(float temperature, float downfall) {
return temperature > 1.5f && downfall < 0.35f;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,32 @@

@SuppressWarnings("unused")
public class SimpleSeasonsApi {
/**
* Gets the {@link SeasonTracker.Seasons} of the specified {@link World}.
*
* @param world The {@link World} to get the {@link SeasonTracker.Seasons} from.
* @return The {@link SeasonTracker.Seasons} of the specified {@link World}.
*/
public static SeasonTracker.Seasons getSeason(@NotNull World world) {
if (world.isClient()) {
return SimpleSeasonsClient.seasonTracker.getSeason();
} else {
return SimpleSeasons.getSeason();
}
}

/**
* Gets the progress of the {@link SeasonTracker.Seasons} of the specified {@link World}.
* A value between 0-1.
*
* @param world The {@link World} to get the progress of the {@link SeasonTracker.Seasons} from.
* @return The progress of the {@link SeasonTracker.Seasons} of the specified {@link World}.
*/
public static float getSeasonProgress(@NotNull World world) {
if (world.isClient()) {
return SimpleSeasonsClient.seasonTracker.getSeasonProgress();
} else {
return SimpleSeasons.getSeasonProgress();
}
}
}
Original file line number Diff line number Diff line change
@@ -1,29 +1,36 @@
package io.github.steveplays28.simpleseasons.client;

import io.github.steveplays28.simpleseasons.api.SimpleSeasonsApi;
import io.github.steveplays28.simpleseasons.client.api.BlockColorProviderRegistry;
import io.github.steveplays28.simpleseasons.client.model.SeasonClampedModelPredicateProvider;
import io.github.steveplays28.simpleseasons.client.state.ClientSeasonTracker;
import io.github.steveplays28.simpleseasons.client.util.season.color.SeasonColorUtil;
import io.github.steveplays28.simpleseasons.state.SeasonTracker;
import net.fabricmc.api.ClientModInitializer;
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.rendering.v1.ColorProviderRegistry;
import net.minecraft.block.Blocks;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.item.ModelPredicateProviderRegistry;
import net.minecraft.item.Items;
import net.minecraft.util.Identifier;

import java.util.List;

import static io.github.steveplays28.simpleseasons.SimpleSeasons.MOD_ID;
import static io.github.steveplays28.simpleseasons.SimpleSeasons.SEASONS_COLOR_ADDITIONS_MAP;

@Environment(EnvType.CLIENT)
public class SimpleSeasonsClient implements ClientModInitializer {
public static final SeasonTracker seasonTracker = new ClientSeasonTracker();

private MinecraftClient client;

@Override
public void onInitializeClient() {
ClientLifecycleEvents.CLIENT_STARTED.register(client -> this.client = client);

// Register vanilla block color providers using the API
registerVanillaColorProviders();

Expand All @@ -40,6 +47,12 @@ private void registerVanillaColorProviders() {
));

// TODO: Fix bamboo item color
ColorProviderRegistry.ITEM.register((stack, tintIndex) -> SEASONS_COLOR_ADDITIONS_MAP.get(seasonTracker.getSeason().getId()).toInt(), Items.BAMBOO);
ColorProviderRegistry.ITEM.register((stack, tintIndex) -> {
if (client.world == null) {
throw new IllegalStateException("Error occurred while registering item color providers: client.world == null.");
}

return SeasonColorUtil.getSeasonColorAddition(SimpleSeasonsApi.getSeason(client.world), SimpleSeasonsApi.getSeasonProgress(client.world)).toInt();
}, Items.BAMBOO);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import io.github.steveplays28.simpleseasons.state.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;
Expand All @@ -15,17 +16,32 @@

@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);
}

@Override
public void setSeasonProgress(float seasonProgress) {
super.setSeasonProgress(seasonProgress);

if (client.world == null) {
throw new IllegalStateException("Error occurred while setting the season's progress: client.world == null.");
}

RenderingUtil.reloadChunkColors(client.world);
}

private void onSeasonStatePacketReceived(@NotNull MinecraftClient client, @NotNull ClientPlayNetworkHandler clientPlayNetworkHandler, @NotNull PacketByteBuf buf, @NotNull PacketSender responseSender) {
if (client.world == null) {
return;
}

this.setSeason(buf.readInt());
this.setSeasonProgress(buf.readFloat());
RenderingUtil.reloadChunkColors(client.world);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,23 @@
import io.github.steveplays28.simpleseasons.mixin.client.accessor.WorldRendererAccessor;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.render.chunk.ChunkBuilder;
import net.minecraft.client.world.ClientWorld;
import org.jetbrains.annotations.NotNull;

@Environment(EnvType.CLIENT)
public class RenderingUtil {
@SuppressWarnings("ForLoopReplaceableByForEach")
public static void reloadChunkColors(@NotNull ClientWorld world) {
world.reloadColor();

for (ChunkBuilder.BuiltChunk builtChunk : ((WorldRendererAccessor) world.worldRenderer).getChunks().chunks) {
builtChunk.scheduleRebuild(true);
var chunks = ((WorldRendererAccessor) world.worldRenderer).getChunks();
if (chunks == null) {
return;
}

@NotNull var builtChunks = chunks.chunks;
for (int i = 0; i < builtChunks.length; i++) {
builtChunks[i].scheduleRebuild(true);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package io.github.steveplays28.simpleseasons.client.util.season.color;

import io.github.steveplays28.simpleseasons.state.SeasonTracker;
import io.github.steveplays28.simpleseasons.util.Color;
import org.jetbrains.annotations.NotNull;

import java.util.Map;

public class SeasonColorUtil {
// Per-season color additions
public static final Color SPRING_COLOR_ADDITION = new Color(255 / 3, 255 / 3, 0);
public static final Color SUMMER_COLOR_ADDITION = new Color(0, 0, 0);
public static final Color FALL_COLOR_ADDITION = new Color(255 / 3, 0, 0);
public static final Color WINTER_COLOR_ADDITION = new Color(255 / 2, 255 / 2, 255 / 2);
// Dry biomes
public static final Color HOT_DRY_BIOMES_COLOR_ADDITION = new Color(120, 0, 0);
public static final Color WET_DRY_BIOMES_COLOR_ADDITION = new Color(50, 50, 0);
// Seasons color map
public static final Map<Integer, Color> SEASONS_COLOR_ADDITIONS_MAP = Map.of(
SeasonTracker.Seasons.SPRING.ordinal(),
SPRING_COLOR_ADDITION, SeasonTracker.Seasons.SUMMER.ordinal(), SUMMER_COLOR_ADDITION, SeasonTracker.Seasons.FALL.ordinal(),
FALL_COLOR_ADDITION, SeasonTracker.Seasons.WINTER.ordinal(), WINTER_COLOR_ADDITION
);
// Dry biomes
public static final Map<Integer, Color> SEASONS_DRY_BIOMES_COLOR_ADDITIONS_MAP = Map.of(SeasonTracker.Seasons.SPRING.ordinal(),
HOT_DRY_BIOMES_COLOR_ADDITION, SeasonTracker.Seasons.SUMMER.ordinal(), HOT_DRY_BIOMES_COLOR_ADDITION,
SeasonTracker.Seasons.FALL.ordinal(), WET_DRY_BIOMES_COLOR_ADDITION, SeasonTracker.Seasons.WINTER.ordinal(),
WET_DRY_BIOMES_COLOR_ADDITION
);

public static Color getSeasonColorAddition(SeasonTracker.@NotNull Seasons season, float seasonProgress) {
return SEASONS_COLOR_ADDITIONS_MAP.get(season.getId()).lerp(SEASONS_COLOR_ADDITIONS_MAP.get(season.getNext().getId()), seasonProgress);
}

public static Color getSeasonColorAddition(SeasonTracker.@NotNull Seasons season, float seasonProgress, boolean isDryBiome) {
if (isDryBiome) {
return SEASONS_DRY_BIOMES_COLOR_ADDITIONS_MAP.get(season.getId()).lerp(SEASONS_COLOR_ADDITIONS_MAP.get(season.getNext().getId()), seasonProgress);
}

return getSeasonColorAddition(season, seasonProgress);
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package io.github.steveplays28.simpleseasons.mixin.client;

import io.github.steveplays28.simpleseasons.SimpleSeasons;
import io.github.steveplays28.simpleseasons.client.SimpleSeasonsClient;
import io.github.steveplays28.simpleseasons.api.SimpleSeasonsApi;
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;
Expand All @@ -15,9 +16,6 @@
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

import static io.github.steveplays28.simpleseasons.SimpleSeasons.SEASONS_COLOR_ADDITIONS_MAP;
import static io.github.steveplays28.simpleseasons.SimpleSeasons.SEASONS_DRY_BIOMES_COLOR_ADDITIONS_MAP;

@Environment(EnvType.CLIENT)
@Mixin(BiomeColors.class)
public class BiomeColorsMixin {
Expand All @@ -32,13 +30,14 @@ private static void getGrassColorInject(BlockRenderView world, BlockPos pos, Cal
var biomeWeather = biome.weather;

if (SimpleSeasons.isDryBiome(biomeWeather.temperature(), biomeWeather.downfall())) {
grassColor = grassColor.add(SEASONS_DRY_BIOMES_COLOR_ADDITIONS_MAP.get(SimpleSeasonsClient.seasonTracker.getSeason().getId()));
grassColor = grassColor.add(SeasonColorUtil.getSeasonColorAddition(SimpleSeasonsApi.getSeason(clientWorld), SimpleSeasonsApi.getSeasonProgress(clientWorld), true));
cir.setReturnValue(grassColor.toInt());
return;
}

grassColor = grassColor.add(SeasonColorUtil.getSeasonColorAddition(SimpleSeasonsApi.getSeason(clientWorld), SimpleSeasonsApi.getSeasonProgress(clientWorld)));
}

grassColor = grassColor.add(SEASONS_COLOR_ADDITIONS_MAP.get(SimpleSeasonsClient.seasonTracker.getSeason().getId()));
cir.setReturnValue(grassColor.toInt());
}
}

This file was deleted.

Loading

0 comments on commit 1fde9b7

Please sign in to comment.