Skip to content

Commit

Permalink
Merge pull request #209 from MTaningco/1.20
Browse files Browse the repository at this point in the history
Implement startingSeason config and sync README.
  • Loading branch information
lucaargolo authored Oct 6, 2024
2 parents 5ea8657 + 2fdb871 commit 9d6ba7e
Show file tree
Hide file tree
Showing 5 changed files with 194 additions and 79 deletions.
71 changes: 69 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,75 @@
<a href="https://modrinth.com/mod/fabric-seasons"><img src="https://img.shields.io/badge/dynamic/json?color=00AF5C&logo=modrinth&label=modrinth&query=downloads&suffix=%20downloads&url=https://api.modrinth.com/v2/project/fabric-seasons"></a>
</p>

## Features
For a complete list of features please check the mods [official page](https://www.curseforge.com/minecraft/mc-mods/fabric-seasons)
## Description

Fabric Seasons adds four seasons to Minecraft, each lasting 28 in-game days (configurable). The current season is defined by the world time (using `/time set 0` will reset to day 1 of Spring). Each season has its own changes. Spring will match the original biome colors and biome behaviors.

The mod has 2 components:

- Server: If installed on the server, biomes will have different temperatures. This enables weather changes like snowing and block freezing in the winter. The server component also contains seasonal crops, allowing crops to grow at different speeds according to the season.
- Client: If installed on the client, biomes will have different colormaps according to the current season. This is just a visual change and it will not physically impact your world in any form.

To get the full experience, it is recommended that you install the mod on both the server and the client.

All biomes are grouped in 5 categories with the following characteristics:

- Permanently Frozen Biomes (`temp ≤ -0.51`): Permanently frozen year-round
- Usually Frozen Biomes (`temp ≤ 0.15`): Becomes ice free in the Summer
- Temperate Biomes (`temp ≤ 0.49`): Ice free in the Spring and Summer
- Usually Ice Free Biomes (`temp ≤ 0.79`): Only freezes in the Winter
- Ice Free Biomes (`temp > 0.79`): Ice free year-round, will also allow rain in the Winter

<p>
<img src="https://i.imgur.com/NdYBkgC.gif">
<img src="https://i.imgur.com/gH5seb5.gif">
<img src="https://i.imgur.com/Qs600XR.gif">
</p>

Only overworld biomes can have this seasonality, which can be configured in `config/seasons.json`

*Please note that this mod melts / applies freezing blocks and snow **within simulation distance**. This means that anything outside is unaffected by the seasons unless if you travel to these blocks. It is currently not possible to globally melt or freeze blocks outside of this distance. It is possible to mitigate this by temporarily increasing the `randomTickSpeed`. Otherwise if you want to completely avoid this limitation, set `doTemperatureChanges` in the config file to `false`.*

## Configurations

Fabric Seasons can be configured in your instance's `config` folder. The file is called `seasons.json`. To apply your own changes to the configuration, please restart your client.
| Config Variable | Description | Default
| -------- | ------- | -------
| springLength / summerLength / fallLength / winterLength | The integer for the length of a season in "game ticks" (672000 game ticks == 33600 in-game seconds == 28 in-game days) | 672000
| startingSeason | The starting season of the year. Only applicable when `isSeasonLocked` is `false` and `isSeasonTiedWithSystemTime` is `false`. Valid values are `SPRING`, `SUMMER`, `FALL`, or `WINTER`. | "SPRING"
| isSeasonLocked | Flag to lock the season | false
| lockedSeason | The season to lock if `isSeasonLocked` is true. Valid values are `SPRING`, `SUMMER`, `FALL`, or `WINTER`.| "SPRING"
| dimensionAllowList | The list of dimensions to allow seasons. This may be useful for multiplayer. A valid value would be one in the format of `"<namespace>:<world_name>"`. | ["minecraft:overworld"]
| doTemperatureChanges | Flag that modifies precipitation and freezing on biomes. **Setting to false essentially disables any biome behavior or aesthetic changes year round.** | true
| shouldSnowyBiomesMeltInSummer | Flag that determines if "Usually Freezing Biomes" should melt during Summer | true
| shouldIceNearWaterMelt | When true, ice will melt in an ice-free biome regardless of being placed by a player when it is beside a water source or flowing water. When false, default ice behavior occurs. | false
| biomeDenyList | The list of biomes that keep it's original temperature and freezing behavior year-round. A valid value would be one in the format of `"<namespace>:<biome_name>"`. | ["terralith:glacial_chasm", "minecraft:frozen_ocean", "minecraft:deep_frozen_ocean", "minecraft:ocean", "minecraft:deep_ocean", "minecraft:cold_ocean", "minecraft:deep_cold_ocean", "minecraft:lukewarm_ocean", "minecraft:deep_lukewarm_ocean", "minecraft:warm_ocean"]
| biomeForceSnowInWinterList | The list of biomes to force freezing during the winter season. A valid value would be one in the format of `"<namespace>:<biome_name>"`. | ["minecraft:plains", "minecraft:sunflower_plains", "minecraft:stony_peaks"]
| isSeasonTiedWithSystemTime | Flag that determines if the seasons should be synced to real world seasonal cycles | false
| isInNorthHemisphere | Only used if `isSeasonTiedWithSystemTime` is set to true. Determines if the player is situated in the North Hemisphere to properly calculate the seasons. | true
| isFallAndSpringReversed | By default, there are more biomes that snow over during Fall. Setting this to true will reverse it, so that more biomes snow over in the Spring compared to Fall. | false
| isSeasonMessingCrops | Flag that determines if the seasons should change the default growth rate | true
| isSeasonMessingBonemeal | Flag that determines if the seasons should change the default bonemeal behavior | false
| doCropsGrowNormallyUnderground | Flag that determines if crops underground should have default behavior. Underground is considered to be sky light level of 0. | false
| doAnimalsBreedInWinter | Flag that determines if animals should be able to breed during the winter | true
| notifyCompat | Flag that determines if a message should be sent when a mod has a compatibility addon and you do not have it installed | true
| debugCommandEnabled | Only useful in development environments | false

## Crop Growth

Crops will grow at **different speeds** depending on the current season.

<p>
<img src="https://i.imgur.com/75gqPqS.png">
</p>

Each **individual crop** will have a **pre-configured growth speed** for one of the four seasons, this is controlled by a datapack and can be changed by the user if they want.

<p>
<img src="https://i.imgur.com/dR4OYPT.png">
</p>

Please refer to online tutorials on **how to make a datapack**. Make sure that your `pack_format` is of the correct version for your particular Minecraft Version. If you are lost, there is an example datapack found in the **pinned messages** of the Discord channel.

## License
Distributed under the Mozilla Public License 2.0. See `LICENSE` for more information.
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ modrinth_version=2.8.7
github_api_version=1.314

# Mod Properties
mod_version=2.4.1-BETA+1.20
mod_version=2.4.2-BETA+1.20
maven_group=io.github.lucaargolo

# Fabric Properties
Expand Down
142 changes: 71 additions & 71 deletions src/main/java/io/github/lucaargolo/seasons/FabricSeasons.java
Original file line number Diff line number Diff line change
Expand Up @@ -152,104 +152,104 @@ public static ReplacedMeltablesState getReplacedMeltablesState(ServerWorld world
}

public static long getTimeToNextSeason(World world) {
return getTimeToNextSeason(world, false);
}

public static long getTimeToNextSeason(World world, boolean ignoreDimension) {
long springLength = CONFIG.getSpringLength();
long summerLength = CONFIG.getSummerLength();
long fallLength = CONFIG.getFallLength();
long winterLength = CONFIG.getWinterLength();
RegistryKey<World> dimension = world.getRegistryKey();
if ((ignoreDimension || CONFIG.isValidInDimension(dimension)) && !CONFIG.isSeasonLocked()) {
if (CONFIG.isValidInDimension(dimension) && !CONFIG.isSeasonLocked()) {
if(CONFIG.isSeasonTiedWithSystemTime()) {
return getTimeToNextSystemSeason() * 24000;
}
long springTime = world.getTimeOfDay() % CONFIG.getYearLength();
long summerTime = springTime - CONFIG.getSpringLength();
long fallTime = summerTime - CONFIG.getSummerLength();
long winterTime = fallTime - CONFIG.getFallLength();

long seasonTime = switch (getCurrentSeason(world)) {
case SPRING -> springTime;
case SUMMER -> summerTime;
case FALL -> fallTime;
case WINTER -> winterTime;

Season currentSeason = getCurrentSeason(world);

long[] seasonLengthArray = new long[]{springLength, summerLength, fallLength, winterLength};
Season[] seasonArray = new Season[]{Season.SPRING, Season.SUMMER, Season.FALL, Season.WINTER};

int startSeasonIndex = switch (CONFIG.getStartingSeason()) {
case SPRING -> 0;
case SUMMER -> 1;
case FALL -> 2;
case WINTER -> 3;
};
return getCurrentSeason(world).getSeasonLength() - seasonTime;

long season1LimitYTD = seasonLengthArray[startSeasonIndex];
long season2LimitYTD = season1LimitYTD + seasonLengthArray[(startSeasonIndex + 1) % 4];
long season3LimitYTD = season2LimitYTD + seasonLengthArray[(startSeasonIndex + 2) % 4];
long yearLength = season3LimitYTD + seasonLengthArray[(startSeasonIndex + 3) % 4];
long timeOfYear = world.getTimeOfDay() % yearLength;

if(currentSeason == seasonArray[startSeasonIndex]) {
return season1LimitYTD - timeOfYear;
} else if(currentSeason == seasonArray[(startSeasonIndex + 1) % 4]) {
return season2LimitYTD - timeOfYear;
} else if (currentSeason == seasonArray[(startSeasonIndex + 2) % 4]) {
return season3LimitYTD - timeOfYear;
} else if (currentSeason == seasonArray[(startSeasonIndex + 3) % 4]) {
return yearLength - timeOfYear;
}
}
return Long.MAX_VALUE;
}

public static Season getNextSeason(World world) {
return getNextSeason(world, false);
}

public static Season getNextSeason(World world, boolean ignoreDimension) {
public static Season getNextSeason(World world, Season currentSeason) {
RegistryKey<World> dimension = world.getRegistryKey();
if (ignoreDimension || CONFIG.isValidInDimension(dimension)) {
if (CONFIG.isValidInDimension(dimension)) {
if(CONFIG.isSeasonLocked()) {
return CONFIG.getLockedSeason();
}
if(CONFIG.isSeasonTiedWithSystemTime()) {
return getCurrentSystemSeason().getNext();
}

long springTime = world.getTimeOfDay() % CONFIG.getYearLength();
long summerTime = springTime - CONFIG.getSpringLength();
long fallTime = summerTime - CONFIG.getSummerLength();
long winterTime = fallTime - CONFIG.getFallLength();

long seasonTime = switch (getCurrentSeason(world)) {
case SPRING -> CONFIG.getSpringLength() - springTime;
case SUMMER -> CONFIG.getSummerLength() - summerTime;
case FALL -> CONFIG.getFallLength() - fallTime;
case WINTER -> CONFIG.getWinterLength() - winterTime;
return switch (getCurrentSeason(world)) {
case SPRING -> Season.SUMMER;
case SUMMER -> Season.FALL;
case FALL -> Season.WINTER;
case WINTER -> Season.SPRING;
};

long worldTime = world.getTimeOfDay() + seasonTime;

springTime = worldTime % CONFIG.getYearLength();
summerTime = springTime - CONFIG.getSpringLength();
fallTime = summerTime - CONFIG.getSummerLength();
winterTime = fallTime - CONFIG.getFallLength();

if(winterTime >= 0 && CONFIG.getWinterLength() > 0) {
return Season.WINTER;
}else if(fallTime >= 0 && CONFIG.getFallLength() > 0) {
return Season.FALL;
}else if(summerTime >= 0 && CONFIG.getSummerLength() > 0) {
return Season.SUMMER;
}else if(springTime >= 0 && CONFIG.getSpringLength() > 0) {
return Season.SPRING;
}
}
return Season.SPRING;
}

public static Season getCurrentSeason(World world) {
return getCurrentSeason(world, false);
}

public static Season getCurrentSeason(World world, boolean ignoreDimension) {
long springLength = CONFIG.getSpringLength();
long summerLength = CONFIG.getSummerLength();
long fallLength = CONFIG.getFallLength();
long winterLength = CONFIG.getWinterLength();
RegistryKey<World> dimension = world.getRegistryKey();
if (ignoreDimension || CONFIG.isValidInDimension(dimension)) {
if (CONFIG.isValidInDimension(dimension)) {
if(CONFIG.isSeasonLocked()) {
return CONFIG.getLockedSeason();
}
if(CONFIG.isSeasonTiedWithSystemTime()) {
}else if(CONFIG.isSeasonTiedWithSystemTime()) {
return getCurrentSystemSeason();
}

long springTime = world.getTimeOfDay() % CONFIG.getYearLength();
long summerTime = springTime - CONFIG.getSpringLength();
long fallTime = summerTime - CONFIG.getSummerLength();
long winterTime = fallTime - CONFIG.getFallLength();

if(winterTime >= 0 && CONFIG.getWinterLength() > 0) {
return Season.WINTER;
}else if(fallTime >= 0 && CONFIG.getFallLength() > 0) {
return Season.FALL;
}else if(summerTime >= 0 && CONFIG.getSummerLength() > 0) {
return Season.SUMMER;
}else if(springTime >= 0 && CONFIG.getSpringLength() > 0) {
return Season.SPRING;
}else if(CONFIG.isValidStartingSeason() && springLength >= 0 && summerLength >= 0 && fallLength >= 0 && winterLength >= 0) {
long[] seasonLengthArray = new long[]{springLength, summerLength, fallLength, winterLength};
Season[] seasonArray = new Season[]{Season.SPRING, Season.SUMMER, Season.FALL, Season.WINTER};

int startSeasonIndex = switch (CONFIG.getStartingSeason()) {
case SPRING -> 0;
case SUMMER -> 1;
case FALL -> 2;
case WINTER -> 3;
};

long season1LimitYTD = seasonLengthArray[startSeasonIndex];
long season2LimitYTD = season1LimitYTD + seasonLengthArray[(startSeasonIndex + 1) % 4];
long season3LimitYTD = season2LimitYTD + seasonLengthArray[(startSeasonIndex + 2) % 4];
long yearLength = season3LimitYTD + seasonLengthArray[(startSeasonIndex + 3) % 4];
long timeOfYear = world.getTimeOfDay() % yearLength;

if(timeOfYear < season1LimitYTD) {
return seasonArray[startSeasonIndex];
} else if(timeOfYear < season2LimitYTD) {
return seasonArray[(startSeasonIndex + 1) % 4];
} else if (timeOfYear < season3LimitYTD) {
return seasonArray[(startSeasonIndex + 2) % 4];
} else if (timeOfYear < yearLength) {
return seasonArray[(startSeasonIndex + 3) % 4];
}
}
}
return Season.SPRING;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,55 @@ public static void register(CommandDispatcher<ServerCommandSource> dispatcher) {
dispatcher.register(CommandManager.literal("season")
.then(CommandManager.literal("set").requires((source) -> source.hasPermissionLevel(2))
.then(CommandManager.literal("spring")
.executes(context -> TimeCommand.executeSet(context.getSource(), 0))
.executes(
context -> TimeCommand.executeSet(context.getSource(),
switch(FabricSeasons.CONFIG.getStartingSeason()) {
case SPRING -> 0;
case WINTER -> FabricSeasons.CONFIG.getWinterLength();
case FALL -> FabricSeasons.CONFIG.getFallLength() + FabricSeasons.CONFIG.getWinterLength();
case SUMMER -> FabricSeasons.CONFIG.getSummerLength() + FabricSeasons.CONFIG.getFallLength() + FabricSeasons.CONFIG.getWinterLength();
}
))
)
.then(CommandManager.literal("summer")
.executes(context -> TimeCommand.executeSet(context.getSource(), FabricSeasons.CONFIG.getSpringLength()))
.executes(context -> TimeCommand.executeSet(
context.getSource(),
switch(FabricSeasons.CONFIG.getStartingSeason()) {
case SUMMER -> 0;
case SPRING -> FabricSeasons.CONFIG.getSpringLength();
case WINTER -> FabricSeasons.CONFIG.getWinterLength() + FabricSeasons.CONFIG.getSpringLength();
case FALL -> FabricSeasons.CONFIG.getFallLength() + FabricSeasons.CONFIG.getWinterLength() + FabricSeasons.CONFIG.getSpringLength();
}
))
)
.then(CommandManager.literal("fall")
.executes(context -> TimeCommand.executeSet(context.getSource(), FabricSeasons.CONFIG.getSpringLength() + FabricSeasons.CONFIG.getSummerLength()))
.executes(context -> TimeCommand.executeSet(
context.getSource(),
switch(FabricSeasons.CONFIG.getStartingSeason()) {
case FALL -> 0;
case SUMMER -> FabricSeasons.CONFIG.getSummerLength();
case SPRING -> FabricSeasons.CONFIG.getSpringLength() + FabricSeasons.CONFIG.getSummerLength();
case WINTER -> FabricSeasons.CONFIG.getWinterLength() + FabricSeasons.CONFIG.getSpringLength() + FabricSeasons.CONFIG.getSummerLength();
}
))
)
.then(CommandManager.literal("winter")
.executes(context -> TimeCommand.executeSet(context.getSource(), FabricSeasons.CONFIG.getSpringLength() + FabricSeasons.CONFIG.getSummerLength() + FabricSeasons.CONFIG.getFallLength()))
.executes(context -> TimeCommand.executeSet(
context.getSource(),
switch(FabricSeasons.CONFIG.getStartingSeason()) {
case WINTER -> 0;
case FALL -> FabricSeasons.CONFIG.getFallLength();
case SUMMER -> FabricSeasons.CONFIG.getSummerLength() + FabricSeasons.CONFIG.getFallLength();
case SPRING -> FabricSeasons.CONFIG.getSpringLength() + FabricSeasons.CONFIG.getSummerLength() + FabricSeasons.CONFIG.getFallLength();
}
))
)
)
.then(CommandManager.literal("query")
.executes(context -> {
World world = context.getSource().getWorld();
Season currentSeason = FabricSeasons.getCurrentSeason(world);
Season nextSeason = FabricSeasons.getNextSeason(world);
Season nextSeason = FabricSeasons.getNextSeason(world, currentSeason);
long ticksLeft = FabricSeasons.getTimeToNextSeason(world);
context.getSource().sendFeedback(() -> Text.translatable("commands.seasons.query_1",
Text.translatable(currentSeason.getTranslationKey()).formatted(currentSeason.getFormatting())
Expand Down
Loading

0 comments on commit 9d6ba7e

Please sign in to comment.