diff --git a/src/main/java/io/ib67/sfcraft/Listener.java b/src/main/java/io/ib67/sfcraft/Listener.java index 550a987..eccfacf 100644 --- a/src/main/java/io/ib67/sfcraft/Listener.java +++ b/src/main/java/io/ib67/sfcraft/Listener.java @@ -1,11 +1,14 @@ package io.ib67.sfcraft; import com.maxmind.geoip2.exception.GeoIp2Exception; +import com.mojang.datafixers.util.Either; +import io.ib67.sfcraft.event.longnight.LongNightEvent; import lombok.SneakyThrows; import net.fabricmc.fabric.api.networking.v1.PacketSender; import net.minecraft.component.DataComponentTypes; import net.minecraft.component.type.WrittenBookContentComponent; import net.minecraft.entity.damage.DamageSource; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.network.ClientConnection; @@ -15,10 +18,11 @@ import net.minecraft.server.network.ServerPlayNetworkHandler; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.RawFilteredPair; import net.minecraft.text.Text; +import net.minecraft.util.Unit; import net.minecraft.util.Uuids; +import net.minecraft.util.math.BlockPos; import java.net.InetSocketAddress; -import java.nio.file.Files; import java.time.Clock; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; @@ -133,4 +137,11 @@ public class Listener { return originalMetadata; } } + + public Either onPlayerSleep(BlockPos pos) { + if (LongNightEvent.isRunning()) { + return Either.left(PlayerEntity.SleepFailureReason.NOT_POSSIBLE_HERE); + } + return Either.right(Unit.INSTANCE); + } } diff --git a/src/main/java/io/ib67/sfcraft/SFCraft.java b/src/main/java/io/ib67/sfcraft/SFCraft.java index d50623b..5eef8e9 100644 --- a/src/main/java/io/ib67/sfcraft/SFCraft.java +++ b/src/main/java/io/ib67/sfcraft/SFCraft.java @@ -8,7 +8,7 @@ import com.mojang.brigadier.builder.RequiredArgumentBuilder; import io.ib67.sfcraft.config.SFConfig; import io.ib67.sfcraft.geoip.GeoIPService; import io.ib67.sfcraft.registry.event.RandomEventRegistry; -import io.ib67.sfcraft.registry.event.SFRandomEventRegistry; +import io.ib67.sfcraft.event.SFRandomEventRegistry; import lombok.Getter; import lombok.SneakyThrows; import net.fabricmc.api.ModInitializer; diff --git a/src/main/java/io/ib67/sfcraft/event/RandomEvent.java b/src/main/java/io/ib67/sfcraft/event/RandomEvent.java index e161da6..13bcf83 100644 --- a/src/main/java/io/ib67/sfcraft/event/RandomEvent.java +++ b/src/main/java/io/ib67/sfcraft/event/RandomEvent.java @@ -5,7 +5,7 @@ import net.minecraft.world.World; public abstract class RandomEvent { /** - * @return duration + * @return duration, -1 for no-update and {@link #end()} will not be called. */ public abstract int start(); diff --git a/src/main/java/io/ib67/sfcraft/event/SFRandomEventRegistry.java b/src/main/java/io/ib67/sfcraft/event/SFRandomEventRegistry.java new file mode 100644 index 0000000..6baeeeb --- /dev/null +++ b/src/main/java/io/ib67/sfcraft/event/SFRandomEventRegistry.java @@ -0,0 +1,13 @@ +package io.ib67.sfcraft.event; + +import io.ib67.sfcraft.event.longnight.DawnAfterLongNightEvent; +import io.ib67.sfcraft.event.longnight.LongNightEvent; +import io.ib67.sfcraft.registry.event.SimpleRandomEventRegistry; +import net.minecraft.world.World; + +public class SFRandomEventRegistry extends SimpleRandomEventRegistry { + public SFRandomEventRegistry() { + registerEvent(LongNightEvent::new, World.OVERWORLD, world -> world.getTimeOfDay() % 18000 == 0); // At midnight + registerEvent(DawnAfterLongNightEvent::new, World.OVERWORLD, world -> world.getTimeOfDay() % 22200 == 0); // At dawn + } +} diff --git a/src/main/java/io/ib67/sfcraft/event/longnight/DawnAfterLongNightEvent.java b/src/main/java/io/ib67/sfcraft/event/longnight/DawnAfterLongNightEvent.java new file mode 100644 index 0000000..9703e80 --- /dev/null +++ b/src/main/java/io/ib67/sfcraft/event/longnight/DawnAfterLongNightEvent.java @@ -0,0 +1,37 @@ +package io.ib67.sfcraft.event.longnight; + +import io.ib67.sfcraft.event.RandomEvent; +import lombok.RequiredArgsConstructor; +import net.minecraft.text.Text; +import net.minecraft.util.Colors; +import net.minecraft.world.World; + +import java.awt.*; + +@RequiredArgsConstructor +public class DawnAfterLongNightEvent extends RandomEvent { + private final World world; + + @Override + public int start() { + if (LongNightEvent.justExpirencedLongNight) { + LongNightEvent.justExpirencedLongNight = false; + world.getServer().getPlayerManager().broadcast( + Text.literal("珍惜太阳正是永夜的意义。") + .withColor(new Color(235, 91, 0).getRGB()) + .append(Text.literal("(永夜事件结束)").withColor(Colors.LIGHT_GRAY)) + , false); + } + return -1; + } + + @Override + public void onUpdate(int ticks) { + throw new UnsupportedOperationException(); + } + + @Override + public void end() { + throw new UnsupportedOperationException(); + } +} diff --git a/src/main/java/io/ib67/sfcraft/event/longnight/LongNightEvent.java b/src/main/java/io/ib67/sfcraft/event/longnight/LongNightEvent.java new file mode 100644 index 0000000..8e7db0d --- /dev/null +++ b/src/main/java/io/ib67/sfcraft/event/longnight/LongNightEvent.java @@ -0,0 +1,43 @@ +package io.ib67.sfcraft.event.longnight; + +import io.ib67.sfcraft.SFCraft; +import io.ib67.sfcraft.event.RandomEvent; +import lombok.RequiredArgsConstructor; +import net.minecraft.text.Text; +import net.minecraft.util.Colors; +import net.minecraft.world.GameRules; +import net.minecraft.world.World; + +@RequiredArgsConstructor +public class LongNightEvent extends RandomEvent { + static boolean justExpirencedLongNight; + private final World world; + private boolean doDaylightCycle; + private boolean doTraderSpawning; + + @Override + public int start() { + world.getServer().getPlayerManager().broadcast(Text.literal("月亮停滞在空中...").withColor(Colors.BLUE), false); + this.doDaylightCycle = world.getGameRules().getBoolean(GameRules.DO_DAYLIGHT_CYCLE); + this.doTraderSpawning = world.getGameRules().getBoolean(GameRules.DO_TRADER_SPAWNING); + world.getGameRules().get(GameRules.DO_DAYLIGHT_CYCLE).set(false, world.getServer()); + world.getGameRules().get(GameRules.DO_TRADER_SPAWNING).set(false, world.getServer()); + return world.random.nextBetween(8400, 2 * 8400); + } + + @Override + public void onUpdate(int ticks) { + } + + @Override + public void end() { + justExpirencedLongNight = true; + world.getGameRules().get(GameRules.DO_DAYLIGHT_CYCLE).set(doDaylightCycle, world.getServer()); + world.getGameRules().get(GameRules.DO_TRADER_SPAWNING).set(doTraderSpawning, world.getServer()); + } + + public static boolean isRunning() { + return LongNightEvent.justExpirencedLongNight || SFCraft.getInstance().getRandomEventRegistry() + .getActiveEvents().stream().anyMatch(it -> it.getEvent().getClass() == LongNightEvent.class); // faster than instanceof + } +} diff --git a/src/main/java/io/ib67/sfcraft/mixin/server/PlayerEntityMixin.java b/src/main/java/io/ib67/sfcraft/mixin/server/PlayerEntityMixin.java index e9d336f..ff1a1a7 100644 --- a/src/main/java/io/ib67/sfcraft/mixin/server/PlayerEntityMixin.java +++ b/src/main/java/io/ib67/sfcraft/mixin/server/PlayerEntityMixin.java @@ -1,13 +1,17 @@ package io.ib67.sfcraft.mixin.server; +import com.mojang.datafixers.util.Either; import io.ib67.sfcraft.SFCraft; import net.minecraft.entity.damage.DamageSource; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.Unit; +import net.minecraft.util.math.BlockPos; 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.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(ServerPlayerEntity.class) public class PlayerEntityMixin { @@ -15,4 +19,9 @@ public class PlayerEntityMixin { public void onDeath(DamageSource damageSource, CallbackInfo ci) { SFCraft.getInstance().getListener().onPlayerDeath((ServerPlayerEntity) (Object) this, damageSource); } + + @Inject(method = "trySleep", at = @At("HEAD"), cancellable = true) + public void onSleep(BlockPos pos, CallbackInfoReturnable> cir) { + if (cir.isCancellable()) cir.setReturnValue(SFCraft.getInstance().getListener().onPlayerSleep(pos)); + } } diff --git a/src/main/java/io/ib67/sfcraft/registry/event/RandomEventRegistry.java b/src/main/java/io/ib67/sfcraft/registry/event/RandomEventRegistry.java index 971b2e4..205dccc 100644 --- a/src/main/java/io/ib67/sfcraft/registry/event/RandomEventRegistry.java +++ b/src/main/java/io/ib67/sfcraft/registry/event/RandomEventRegistry.java @@ -1,6 +1,7 @@ package io.ib67.sfcraft.registry.event; import io.ib67.sfcraft.event.RandomEvent; +import net.minecraft.registry.RegistryKey; import net.minecraft.world.World; import java.util.List; @@ -9,5 +10,6 @@ import java.util.function.Predicate; public interface RandomEventRegistry { List getActiveEvents(); - void registerEvent(Function event, Predicate worldTickPredicate); + + void registerEvent(Function event, RegistryKey world, Predicate worldTickPredicate); } diff --git a/src/main/java/io/ib67/sfcraft/registry/event/SFRandomEventRegistry.java b/src/main/java/io/ib67/sfcraft/registry/event/SFRandomEventRegistry.java deleted file mode 100644 index a7858d6..0000000 --- a/src/main/java/io/ib67/sfcraft/registry/event/SFRandomEventRegistry.java +++ /dev/null @@ -1,7 +0,0 @@ -package io.ib67.sfcraft.registry.event; - -public class SFRandomEventRegistry extends SimpleRandomEventRegistry { - public SFRandomEventRegistry() { - - } -} diff --git a/src/main/java/io/ib67/sfcraft/registry/event/SimpleRandomEventRegistry.java b/src/main/java/io/ib67/sfcraft/registry/event/SimpleRandomEventRegistry.java index 7916aec..3ef24ae 100644 --- a/src/main/java/io/ib67/sfcraft/registry/event/SimpleRandomEventRegistry.java +++ b/src/main/java/io/ib67/sfcraft/registry/event/SimpleRandomEventRegistry.java @@ -4,6 +4,8 @@ import io.ib67.sfcraft.event.RandomEvent; import lombok.Getter; import lombok.RequiredArgsConstructor; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; +import net.minecraft.registry.RegistryKey; +import net.minecraft.registry.RegistryKeys; import net.minecraft.server.world.ServerWorld; import net.minecraft.world.World; @@ -22,9 +24,13 @@ public class SimpleRandomEventRegistry implements RandomEventRegistry { private void afterWorldTick(ServerWorld serverWorld) { for (RegisteredEntry entry : entries) { - if (!entry.started && entry.worldTickPredicate.test(serverWorld)) { + if (entry.world == serverWorld.getRegistryKey() + && !entry.started && entry.worldTickPredicate.test(serverWorld)) { var event = entry.event.apply(serverWorld); - activeEvents.add(new StartedEntry(event, () -> entry.started = false, event.start())); + var ticks = event.start(); + if (ticks > 0) { + activeEvents.add(new StartedEntry(event, () -> entry.started = false, ticks)); + } } } var it = activeEvents.iterator(); @@ -46,8 +52,8 @@ public class SimpleRandomEventRegistry implements RandomEventRegistry { } @Override - public void registerEvent(Function event, Predicate worldTickPredicate) { - entries.add(new RegisteredEntry(event, worldTickPredicate)); + public void registerEvent(Function event, RegistryKey world, Predicate worldTickPredicate) { + entries.add(new RegisteredEntry(world, event, worldTickPredicate)); } @RequiredArgsConstructor @@ -66,6 +72,7 @@ public class SimpleRandomEventRegistry implements RandomEventRegistry { @RequiredArgsConstructor private static final class RegisteredEntry { + private final RegistryKey world; private final Function event; private final Predicate worldTickPredicate; private boolean started;