add support for changing time in playgrd

This commit is contained in:
iceBear67 committed 2026-08-08 15:52:51 +08:00
1 parent 4fb219b62c
commit 21db083fed
7 files changed
+146 -4

No files matched your search

@@ -1,6 +1,7 @@
package io.ib67.sfcraft.module.room;
import com.google.inject.Inject;
import com.mojang.brigadier.arguments.IntegerArgumentType;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
@@ -29,10 +30,13 @@ import net.minecraft.commands.Commands;
import net.minecraft.commands.SharedSuggestionProvider;
import net.minecraft.commands.arguments.EntityArgument;
import net.minecraft.commands.arguments.GameModeArgument;
import net.minecraft.commands.arguments.TimeArgument;
import net.minecraft.core.Holder;
import net.minecraft.network.chat.Component;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.CommonColors;
import net.minecraft.world.clock.WorldClock;
import net.minecraft.world.level.GameType;
import net.minecraft.world.level.gamerules.GameRules;
import org.jetbrains.annotations.NotNull;
@@ -108,6 +112,20 @@ public class CreativeRoomModule extends ServerModule {
LiteralArgumentBuilder.<CommandSourceStack>literal("playgrd")
.requires(it -> it.isPlayer() && SFConsts.COMMAND_PLAYGROUND.hasPermission(it.getPlayer()))
.executes(this::gotoPlayground)
.then(Commands.literal("time")
.requires(it -> it.isPlayer() && SFConsts.COMMAND_PLAYGROUND_TIME.hasPermission(it.getPlayer()))
.then(Commands.literal("set")
.then(Commands.argument("time", TimeArgument.time())
.executes(ctx -> onSetTime(ctx, IntegerArgumentType.getInteger(ctx, "time")))))
.then(Commands.literal("add")
.then(Commands.argument("time", TimeArgument.time(Integer.MIN_VALUE))
.executes(ctx -> onAddTime(ctx, IntegerArgumentType.getInteger(ctx, "time")))))
.then(Commands.literal("query").executes(this::onQueryTime))
.then(Commands.literal("day").executes(ctx -> onSetNamedTime(ctx, 1000)))
.then(Commands.literal("noon").executes(ctx -> onSetNamedTime(ctx, 6000)))
.then(Commands.literal("night").executes(ctx -> onSetNamedTime(ctx, 13000)))
.then(Commands.literal("midnight").executes(ctx -> onSetNamedTime(ctx, 18000)))
)
);
dispatcher.register(
Commands.literal("gm")
@@ -170,13 +188,74 @@ public class CreativeRoomModule extends ServerModule {
return 0;
}
// ── /playgrd time ────────────────────────────────────────────────
// 只操作游乐场自己的 WorldClock(sfcraft:playground),绝不触碰其它钟;
// 必须身处游乐场才能使用。时间值存原始 tick(可超 24000),展示时按 24000 取余。
private int onSetTime(CommandContext<CommandSourceStack> ctx, int ticks) {
var player = requirePlaygroundPlayer(ctx);
if (player == null) return Command.SINGLE_SUCCESS;
ctx.getSource().getServer().clockManager().setTotalTicks(playgroundClock(ctx.getSource()), ticks);
player.sendSystemMessage(Component.translatable("message.sfcraft.playground.time_set", wrapTime(ticks)));
return Command.SINGLE_SUCCESS;
}
private int onAddTime(CommandContext<CommandSourceStack> ctx, int ticks) {
var player = requirePlaygroundPlayer(ctx);
if (player == null) return Command.SINGLE_SUCCESS;
ctx.getSource().getServer().clockManager().addTicks(playgroundClock(ctx.getSource()), ticks);
player.sendSystemMessage(Component.translatable("message.sfcraft.playground.time_added", wrapTime(ticks)));
return Command.SINGLE_SUCCESS;
}
private int onQueryTime(CommandContext<CommandSourceStack> ctx) {
var player = requirePlaygroundPlayer(ctx);
if (player == null) return Command.SINGLE_SUCCESS;
long ticks = ctx.getSource().getServer().clockManager().getTotalTicks(playgroundClock(ctx.getSource()));
player.sendSystemMessage(Component.translatable("message.sfcraft.playground.time_query", wrapTime(ticks)));
return Command.SINGLE_SUCCESS;
}
private int onSetNamedTime(CommandContext<CommandSourceStack> ctx, int ticks) {
var player = requirePlaygroundPlayer(ctx);
if (player == null) return Command.SINGLE_SUCCESS;
ctx.getSource().getServer().clockManager().setTotalTicks(playgroundClock(ctx.getSource()), ticks);
player.sendSystemMessage(Component.translatable("message.sfcraft.playground.time_set", wrapTime(ticks)));
return Command.SINGLE_SUCCESS;
}
/** 游乐场世界钟;必须身处游乐场(此时世界必然已加载),从维度类型解析。 */
private Holder<WorldClock> playgroundClock(CommandSourceStack source) {
var level = source.getServer().getLevel(CreativeSpaceRoom.WORLD);
if (level == null) {
throw new IllegalStateException("playground level not loaded");
}
return level.dimensionType().defaultClock()
.orElseThrow(() -> new IllegalStateException("playground dimension type has no default clock"));
}
private ServerPlayer requirePlaygroundPlayer(CommandContext<CommandSourceStack> ctx) {
var p = ctx.getSource().getPlayer();
if (p == null || !p.level().dimension().equals(CreativeSpaceRoom.WORLD)) {
if (p != null) {
p.sendSystemMessage(Component.translatable("message.sfcraft.playground.only_here"));
}
return null;
}
return p;
}
private static int wrapTime(long ticks) {
return (int) Math.floorMod(ticks, 24000L);
}
public void onPlayerJoin(ServerPlayer player) {
player.sendSystemMessage(Component.translatable("message.sfcraft.playground.welcome"));
player.sendSystemMessage(Component.translatable("message.sfcraft.playground.features_available").withColor(CommonColors.WHITE)
.append(Component.translatable("message.sfcraft.playground.features_list").withColor(Color.MAGENTA.getRGB())));
player.sendSystemMessage(Component.nullToEmpty(" "));
player.sendSystemMessage(Component.translatable("message.sfcraft.playground.upload_hint").withColor(CommonColors.GRAY)
.append(Component.literal("/upload schematic").withColor(CommonColors.BLUE).withStyle(it -> it.withUnderlined(true))));
.append(Component.literal("/upload schematic").withColor(CommonColors.SOFT_YELLOW).withStyle(it -> it.withUnderlined(true))));
player.sendSystemMessage(Component.translatable("message.sfcraft.playground.mobs_no_escape").withColor(CommonColors.GRAY));
player.sendSystemMessage(Component.translatable("message.sfcraft.playground.how_to_leave").withColor(CommonColors.GRAY));
player.setGameMode(GameType.CREATIVE);
@@ -24,6 +24,7 @@ public class SFConsts {
public static final Permission<Player> COMMAND_PLAYGROUND = ofSFCPermission("command.playground", true);
public static final Permission<Player> COMMAND_PLAYGROUND_GAMEMODE = ofSFCPermission("command.playground.gamemode", true);
public static final Permission<Player> COMMAND_PLAYGROUND_TELEPORT = ofSFCPermission("command.playground.teleport", true);
public static final Permission<Player> COMMAND_PLAYGROUND_TIME = ofSFCPermission("command.playground.time", true);
public static final Permission<Player> COMMAND_RECO = ofSFCPermission("command.reco", true);
public static Permission<Player> ofSFCPermission(String key, boolean byDefault) {
@@ -53,10 +53,13 @@
"message.sfcraft.playground.only_here": "You can only use this in playground!",
"message.sfcraft.playground.welcome": "You are now in the creative playground. Use //schem list to view available schematics.",
"message.sfcraft.playground.features_available": "The following features are now available: ",
"message.sfcraft.playground.features_list": "/player /track /summon /setblock /gm (gamemode) /pt (teleport) /polymer creative and all WorldEdit commands.",
"message.sfcraft.playground.features_list": "/player, /track, /summon, /setblock, /gm (gamemode), /pt (teleport), /playgrd time, /polymer creative and all WorldEdit commands.",
"message.sfcraft.playground.upload_hint": "How to upload schematics to the playground: ",
"message.sfcraft.playground.mobs_no_escape": "Mobs in the playground cannot escape to other dimensions.",
"message.sfcraft.playground.how_to_leave": "Use /reco or rejoin the game to leave.",
"message.sfcraft.playground.time_set": "Playground time set to %s",
"message.sfcraft.playground.time_added": "Playground time increased by %s",
"message.sfcraft.playground.time_query": "Playground time: %s",
"message.sfcraft.schem.no_permission": "You don't have permission to use the upload feature. Please contact an administrator.",
"message.sfcraft.schem.click_to_upload": "Click this URL to upload schematic files.",
"message.sfcraft.schem.saved": "Schematic %s has been saved! Use //schem list to find it",
@@ -53,10 +53,13 @@
"message.sfcraft.playground.only_here": "只能在游乐园中使用此功能!",
"message.sfcraft.playground.welcome": "你现在正在创造游乐园中,使用 //schem list 查看可用投影。",
"message.sfcraft.playground.features_available": "以下功能现在可用:",
"message.sfcraft.playground.features_list": "/player /track /summon /setblock /gm (gamemode) /pt (teleport) 及 WorldEdit 的所有命令。",
"message.sfcraft.playground.features_list": "/player, /track, /summon, /setblock, /gm (gamemode), /pt (teleport), /playgrd time, /polymer creative 及 WorldEdit 的所有命令。",
"message.sfcraft.playground.upload_hint": "如何上传投影到游乐场: ",
"message.sfcraft.playground.mobs_no_escape": "游乐园中的生物不能逃逸到其他维度。",
"message.sfcraft.playground.how_to_leave": "使用 /reco 或重新加入游戏即可离开。",
"message.sfcraft.playground.time_set": "已设置游乐园时间: %s",
"message.sfcraft.playground.time_added": "已增加游乐园时间: %s",
"message.sfcraft.playground.time_query": "游乐园当前时间: %s",
"message.sfcraft.schem.no_permission": "你没有使用上传功能的权限!请联系管理员申请",
"message.sfcraft.schem.click_to_upload": "点击此链接以上传投影文件。",
"message.sfcraft.schem.saved": "投影 %s 已保存!使用 //schem list 查找它",
@@ -1,5 +1,5 @@
{
"type": "overworld",
"type": "sfcraft:playground",
"generator": {
"type": "flat",
"settings": {
@@ -0,0 +1,55 @@
{
"ambient_light": 0.0,
"attributes": {
"minecraft:audio/ambient_sounds": {
"mood": {
"block_search_extent": 8,
"offset": 2.0,
"sound": "minecraft:ambient.cave",
"tick_delay": 6000
}
},
"minecraft:audio/background_music": {
"creative": {
"max_delay": 24000,
"min_delay": 12000,
"sound": "minecraft:music.creative"
},
"default": {
"max_delay": 24000,
"min_delay": 12000,
"sound": "minecraft:music.game"
}
},
"minecraft:gameplay/bed_rule": {
"can_set_spawn": "always",
"can_sleep": "when_dark",
"error_message": {
"translate": "block.minecraft.bed.no_sleep"
}
},
"minecraft:gameplay/nether_portal_spawns_piglin": true,
"minecraft:gameplay/respawn_anchor_works": false,
"minecraft:visual/ambient_light_color": "#0a0a0a",
"minecraft:visual/cloud_color": "#ccffffff",
"minecraft:visual/cloud_height": 192.33,
"minecraft:visual/fog_color": "#c0d8ff",
"minecraft:visual/sky_color": "#78a7ff"
},
"coordinate_scale": 1.0,
"default_clock": "sfcraft:playground",
"has_ceiling": false,
"has_ender_dragon_fight": false,
"has_skylight": true,
"height": 384,
"infiniburn": "#minecraft:infiniburn_overworld",
"logical_height": 384,
"min_y": -64,
"monster_spawn_block_light_limit": 0,
"monster_spawn_light_level": {
"type": "minecraft:uniform",
"max_inclusive": 7,
"min_inclusive": 0
},
"timelines": "#minecraft:in_overworld"
}
@@ -0,0 +1 @@
{}