Client-side weather and better time handling

- Weather can now also be changed client side
  - Corresponding /cweather command
- Now optionally works in singleplayer
- /ctime command works again
- Custom time is now a slider in the config screen
This commit is contained in:
Motschen
2023-05-24 18:10:38 +02:00
parent 07e80749d6
commit 366bc058a5
9 changed files with 131 additions and 45 deletions

View File

@@ -3,15 +3,15 @@ org.gradle.jvmargs=-Xmx1G
# Fabric Properties # Fabric Properties
# check these on https://fabricmc.net/develop/ # check these on https://fabricmc.net/develop/
minecraft_version=1.19 minecraft_version=1.19.4
yarn_mappings=1.19+build.4 yarn_mappings=1.19.4+build.2
loader_version=0.14.8 loader_version=0.14.19
# Mod Properties # Mod Properties
mod_version = 1.2.0 mod_version = 1.3.0
maven_group = eu.midnightdust maven_group = eu.midnightdust
archives_base_name = timechanger archives_base_name = timechanger
# Dependencies # Dependencies
fabric_version=0.56.0+1.19 fabric_version=0.81.1+1.19.4
midnightlib_version = 0.5.2 midnightlib_version=1.3.0-fabric

View File

@@ -1,18 +1,32 @@
package eu.midnightdust.timechanger; package eu.midnightdust.timechanger;
import eu.midnightdust.timechanger.command.CTimeCommand; import eu.midnightdust.timechanger.command.CTimeCommand;
import eu.midnightdust.timechanger.command.CWeatherCommand;
import eu.midnightdust.timechanger.config.TimeChangerConfig; import eu.midnightdust.timechanger.config.TimeChangerConfig;
import net.fabricmc.api.ClientModInitializer; import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager; import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback;
import net.minecraft.client.MinecraftClient;
public class TimeChangerClient implements ClientModInitializer { public class TimeChangerClient implements ClientModInitializer {
private static MinecraftClient client = MinecraftClient.getInstance();
@Override @Override
public void onInitializeClient() { public void onInitializeClient() {
TimeChangerConfig.init("timechanger", TimeChangerConfig.class); TimeChangerConfig.init("timechanger", TimeChangerConfig.class);
if (ClientCommandManager.getActiveDispatcher() != null) ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> dispatcher.register(CTimeCommand.command()));
ClientCommandManager.getActiveDispatcher().register(ClientCommandManager.literal("ctime") ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> dispatcher.register(CWeatherCommand.command()));
.then(CTimeCommand.command()) }
); public static boolean isEnabledOnWorld() {
if (client.getCurrentServerEntry() != null) {
if (TimeChangerConfig.allowlist.isEmpty()) {
return true;
} else if (client.getCurrentServerEntry().address != null) {
if (!TimeChangerConfig.blocklist && TimeChangerConfig.allowlist.contains(client.getCurrentServerEntry().address)) {
return true;
} else return TimeChangerConfig.blocklist && !TimeChangerConfig.allowlist.contains(client.getCurrentServerEntry().address);
}
return false;
}
return TimeChangerConfig.enableInSingleplayer;
} }
} }

View File

@@ -12,7 +12,7 @@ import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.arg
public class CTimeCommand { public class CTimeCommand {
public static LiteralArgumentBuilder<FabricClientCommandSource> command() { public static LiteralArgumentBuilder<FabricClientCommandSource> command() {
return ClientCommandManager.literal("set").then( return ClientCommandManager.literal("ctime").then(
argument("time", IntegerArgumentType.integer(-1)) argument("time", IntegerArgumentType.integer(-1))
.executes(ctx -> setTime(ctx.getSource(), IntegerArgumentType.getInteger(ctx, "time"))) .executes(ctx -> setTime(ctx.getSource(), IntegerArgumentType.getInteger(ctx, "time")))
); );
@@ -22,7 +22,7 @@ public class CTimeCommand {
TimeChangerConfig.custom_time = time; TimeChangerConfig.custom_time = time;
TimeChangerConfig.write("timechanger"); TimeChangerConfig.write("timechanger");
source.sendFeedback(Text.translatable("command.timechanger.ctime.success").append(String.valueOf(time))); source.sendFeedback(Text.translatable("command.timechanger.ctime.success").append(time >= 0 ? String.valueOf(time) : "disabled"));
return 1; return 1;
} }

View File

@@ -0,0 +1,29 @@
package eu.midnightdust.timechanger.command;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import eu.midnightdust.timechanger.config.TimeChangerConfig;
import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager;
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
import net.minecraft.text.Text;
import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal;
public class CWeatherCommand {
public static LiteralArgumentBuilder<FabricClientCommandSource> command() {
return ClientCommandManager.literal("cweather")
.then(literal("unset").executes(ctx -> setWeather(ctx.getSource(), TimeChangerConfig.Weather.UNSET)))
.then(literal("clear").executes(ctx -> setWeather(ctx.getSource(), TimeChangerConfig.Weather.CLEAR)))
.then(literal("rain").executes(ctx -> setWeather(ctx.getSource(), TimeChangerConfig.Weather.RAIN)))
.then(literal("thunder").executes(ctx -> setWeather(ctx.getSource(), TimeChangerConfig.Weather.THUNDER)));
}
private static int setWeather(FabricClientCommandSource source, TimeChangerConfig.Weather weather) {
TimeChangerConfig.custom_weather = weather;
TimeChangerConfig.write("timechanger");
source.sendFeedback(Text.translatable("command.timechanger.cweather.success").append(String.valueOf(weather)));
return 1;
}
}

View File

@@ -6,7 +6,13 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
public class TimeChangerConfig extends MidnightConfig { public class TimeChangerConfig extends MidnightConfig {
@Entry public static int custom_time = -1; @Entry(isSlider = true, min = -1, max = 24000) public static int custom_time = -1;
@Entry public static Weather custom_weather = Weather.UNSET;
@Entry public static List<String> allowlist = new ArrayList<>(); @Entry public static List<String> allowlist = new ArrayList<>();
@Entry public static boolean blocklist = false; @Entry public static boolean blocklist = false;
@Entry public static boolean enableInSingleplayer = false;
public enum Weather {
UNSET, CLEAR, RAIN, THUNDER;
}
} }

View File

@@ -1,40 +1,43 @@
package eu.midnightdust.timechanger.mixin; package eu.midnightdust.timechanger.mixin;
import eu.midnightdust.timechanger.TimeChangerClient;
import eu.midnightdust.timechanger.config.TimeChangerConfig; import eu.midnightdust.timechanger.config.TimeChangerConfig;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.world.ClientWorld; import net.minecraft.client.world.ClientWorld;
import org.spongepowered.asm.mixin.Final; import net.minecraft.registry.DynamicRegistryManager;
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.entry.RegistryEntry;
import net.minecraft.util.profiler.Profiler;
import net.minecraft.world.MutableWorldProperties;
import net.minecraft.world.World;
import net.minecraft.world.dimension.DimensionType;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At; import java.util.function.Supplier;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(ClientWorld.class) @Mixin(ClientWorld.class)
public abstract class MixinClientWorld { public abstract class MixinClientWorld extends World {
@Shadow @Final private ClientWorld.Properties clientWorldProperties; protected MixinClientWorld(MutableWorldProperties properties, RegistryKey<World> registryRef, DynamicRegistryManager registryManager, RegistryEntry<DimensionType> dimensionEntry, Supplier<Profiler> profiler, boolean isClient, boolean debugWorld, long biomeAccess, int maxChainedNeighborUpdates) {
@Shadow @Final private MinecraftClient client; super(properties, registryRef, registryManager, dimensionEntry, profiler, isClient, debugWorld, biomeAccess, maxChainedNeighborUpdates);
}
@Inject(at = @At("TAIL"), method = "setTimeOfDay", cancellable = true) @Override
@Environment(EnvType.CLIENT) public float getRainGradient(float delta) {
public void setTimeOfDay(long time, CallbackInfo ci) { if (TimeChangerClient.isEnabledOnWorld() && !TimeChangerConfig.custom_weather.equals(TimeChangerConfig.Weather.UNSET)) {
if (client.getCurrentServerEntry() != null) { if (TimeChangerConfig.custom_weather.equals(TimeChangerConfig.Weather.CLEAR)) {
if (TimeChangerConfig.custom_time >= 0 && TimeChangerConfig.allowlist.isEmpty()) { return 0f;
this.clientWorldProperties.setTimeOfDay(TimeChangerConfig.custom_time); } else return 1f;
} else if (TimeChangerConfig.custom_time >= 0 && client.getCurrentServerEntry().address != null) {
if (!TimeChangerConfig.blocklist && TimeChangerConfig.allowlist.contains(client.getCurrentServerEntry().address)) {
this.clientWorldProperties.setTimeOfDay(TimeChangerConfig.custom_time);
} else if (TimeChangerConfig.blocklist && !TimeChangerConfig.allowlist.contains(client.getCurrentServerEntry().address)) {
this.clientWorldProperties.setTimeOfDay(TimeChangerConfig.custom_time);
}
else {ci.cancel();}
}
else {ci.cancel();}
} }
else {ci.cancel();} return super.getRainGradient(delta);
}
@Override
public float getThunderGradient(float delta) {
if (TimeChangerClient.isEnabledOnWorld() && !TimeChangerConfig.custom_weather.equals(TimeChangerConfig.Weather.UNSET)) {
if (TimeChangerConfig.custom_weather.equals(TimeChangerConfig.Weather.THUNDER)) {
return 1f;
} else return 0f;
}
return super.getRainGradient(delta);
} }
} }

View File

@@ -0,0 +1,25 @@
package eu.midnightdust.timechanger.mixin;
import eu.midnightdust.timechanger.TimeChangerClient;
import eu.midnightdust.timechanger.config.TimeChangerConfig;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.world.ClientWorld;
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;
@Mixin(ClientWorld.Properties.class)
public abstract class MixinClientWorldProperties {
@Inject(at = @At("RETURN"), method = "getTimeOfDay", cancellable = true)
@Environment(EnvType.CLIENT)
public void getTimeOfDay(CallbackInfoReturnable<Long> cir) {
if (TimeChangerClient.isEnabledOnWorld() && TimeChangerConfig.custom_time >= 0) {
cir.setReturnValue((long) TimeChangerConfig.custom_time);
}
else cir.cancel();
}
}

View File

@@ -2,7 +2,15 @@
"timechanger.midnightconfig.title":"Time Changer Config", "timechanger.midnightconfig.title":"Time Changer Config",
"timechanger.midnightconfig.custom_time":"Custom Time", "timechanger.midnightconfig.custom_time":"Custom Time",
"timechanger.midnightconfig.custom_time.tooltip": "Set the Custom Time (-1 to disable)", "timechanger.midnightconfig.custom_time.tooltip": "Set the Custom Time (-1 to disable)",
"timechanger.midnightconfig.custom_weather":"Custom Weather",
"timechanger.midnightconfig.custom_weather.tooltip": "Set the Custom Time (Unset to disable)",
"timechanger.midnightconfig.enum.Weather.UNSET":"Unset",
"timechanger.midnightconfig.enum.Weather.CLEAR":"Clear",
"timechanger.midnightconfig.enum.Weather.RAIN":"Rain",
"timechanger.midnightconfig.enum.Weather.THUNDER":"Thunder",
"timechanger.midnightconfig.allowlist":"Server Allowlist", "timechanger.midnightconfig.allowlist":"Server Allowlist",
"timechanger.midnightconfig.blocklist":"Use Allowlist as Blocklist?", "timechanger.midnightconfig.blocklist":"Use Allowlist as Blocklist?",
"command.timechanger.ctime.success": "Successfully set the client time to " "timechanger.midnightconfig.enableInSingleplayer":"Enable in Singleplayer?",
"command.timechanger.ctime.success": "Successfully set the client time to ",
"command.timechanger.cweather.success": "Successfully set the client weather to "
} }

View File

@@ -1,9 +1,10 @@
{ {
"required": true, "required": true,
"package": "eu.midnightdust.timechanger.mixin", "package": "eu.midnightdust.timechanger.mixin",
"compatibilityLevel": "JAVA_8", "compatibilityLevel": "JAVA_17",
"client": [ "client": [
"MixinClientWorld" "MixinClientWorld",
"MixinClientWorldProperties"
], ],
"injectors": { "injectors": {
"defaultRequire": 1 "defaultRequire": 1