diff options
| author | Anhgelus Morhtuuzh <william@herges.fr> | 2026-03-17 18:55:42 +0100 |
|---|---|---|
| committer | Anhgelus Morhtuuzh <william@herges.fr> | 2026-03-17 18:55:42 +0100 |
| commit | e2039260fc80c732b1b5c5cd433bb6f70dc3ba51 (patch) | |
| tree | 57c757aa67f3715808a0910c216b18b448c8c5db /src/main/java/world | |
| parent | 0473971208eac8116dd0761e595d3a0a83d8e4ee (diff) | |
refactor(): use ticks for timer
Diffstat (limited to 'src/main/java/world')
4 files changed, 211 insertions, 39 deletions
diff --git a/src/main/java/world/anhgelus/manhunt/Manhunt.java b/src/main/java/world/anhgelus/manhunt/Manhunt.java index dc14731..66b8fb4 100644 --- a/src/main/java/world/anhgelus/manhunt/Manhunt.java +++ b/src/main/java/world/anhgelus/manhunt/Manhunt.java @@ -8,7 +8,6 @@ import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
import net.fabricmc.fabric.api.entity.event.v1.ServerPlayerEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerEntityEvents;
-import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
import net.minecraft.command.EntitySelector;
import net.minecraft.command.argument.EntityArgumentType;
import net.minecraft.component.DataComponentTypes;
@@ -34,6 +33,8 @@ import net.minecraft.util.math.GlobalPos; import net.minecraft.world.GameMode;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import world.anhgelus.manhunt.timer.TickTask;
+import world.anhgelus.manhunt.timer.TimerAccess;
import java.util.*;
@@ -47,15 +48,12 @@ public class Manhunt implements ModInitializer { private final Set<UUID> speedrunners = new HashSet<>();
private final Map<UUID, UUID> trackedMap = new HashMap<>();
- private final Timer timer = new Timer();
private State state = State.OFF;
@Override
public void onInitialize() {
LOGGER.info("Initializing Manhunt");
MidnightConfig.init(MOD_ID, Config.class);
- LOGGER.info(Config.secondsBeforeRelease);
- LOGGER.info(Config.updateCompassEach);
final LiteralArgumentBuilder<ServerCommandSource> command = literal("manhunt");
@@ -100,11 +98,14 @@ public class Manhunt implements ModInitializer { final LiteralArgumentBuilder<ServerCommandSource> start = literal("start");
start.requires(CommandManager.requirePermissionLevel(CommandManager.GAMEMASTERS_CHECK));
start.executes(context -> {
+ final var source = context.getSource();
if (state == State.ON) {
- context.getSource().sendFeedback(() -> Text.literal("Cannot start a manhunt if one is already started!"), false);
+ source.sendFeedback(() -> Text.literal("Cannot start a manhunt if one is already started!"), false);
return Command.SINGLE_SUCCESS;
}
- final PlayerManager pm = context.getSource().getServer().getPlayerManager();
+ final var server = source.getServer();
+ final var timer = TimerAccess.getTimerFromOverworld(server);
+ final PlayerManager pm = server.getPlayerManager();
for (final ServerPlayerEntity player : pm.getPlayerList()) {
player.setHealth(player.getMaxHealth());
player.setExperienceLevel(0);
@@ -142,26 +143,24 @@ public class Manhunt implements ModInitializer { }
LOGGER.info("Added modifiers to {}", hunter.getDisplayName());
}
- timer.schedule(new TimerTask() {
- @Override
- public void run() {
- LOGGER.info("Removing modifier to hunters");
- for (final UUID uuid : hunters) {
- final var hunter = pm.getPlayer(uuid);
- assert hunter != null;
- var attr = hunter.getAttributeInstance(EntityAttributes.MOVEMENT_SPEED);
- if (attr != null) {
- attr.removeModifier(Identifier.of("manhunt.speed"));
- }
- attr = hunter.getAttributeInstance(EntityAttributes.GRAVITY);
- if (attr != null) {
- attr.removeModifier(Identifier.of("manhunt.gravity"));
- }
+ timer.dds_runTask(new TickTask(() -> {
+ LOGGER.info("Removing modifier to hunters");
+ for (final UUID uuid : hunters) {
+ final var hunter = pm.getPlayer(uuid);
+ assert hunter != null;
+ var attr = hunter.getAttributeInstance(EntityAttributes.MOVEMENT_SPEED);
+ if (attr != null) {
+ attr.removeModifier(Identifier.of("manhunt.speed"));
+ }
+ attr = hunter.getAttributeInstance(EntityAttributes.GRAVITY);
+ if (attr != null) {
+ attr.removeModifier(Identifier.of("manhunt.gravity"));
}
}
- }, Config.secondsBeforeRelease * 1000L);
+ pm.broadcast(Text.of("Hunters released!"), false);
+ }, Config.secondsBeforeRelease * 20L));
setTimer(pm);
- context.getSource().sendFeedback(() -> Text.literal("Game started!"), true);
+ source.sendFeedback(() -> Text.literal("Game started!"), true);
return Command.SINGLE_SUCCESS;
});
@@ -199,7 +198,7 @@ public class Manhunt implements ModInitializer { speedrunners.remove(player.getUuid());
}
state = State.OFF;
- timer.cancel();
+ TimerAccess.getTimerFromOverworld(server).dds_cancel();
});
ServerEntityEvents.ENTITY_LOAD.register((entity, world) -> {
@@ -207,25 +206,18 @@ public class Manhunt implements ModInitializer { EntityType.PIGLIN.spawn(world, entity.getBlockPos(), SpawnReason.MOB_SUMMONED);
entity.discard();
});
-
- ServerLifecycleEvents.SERVER_STOPPED.register((server) -> {
- timer.cancel();
- });
}
private void setTimer(PlayerManager pm) {
- timer.schedule(new TimerTask() {
- @Override
- public void run() {
- for (final UUID uuid : hunters) {
- final ServerPlayerEntity hunter = pm.getPlayer(uuid);
- if (hunter == null) continue;
- final ServerPlayerEntity tracked = pm.getPlayer(trackedMap.get(uuid));
- if (tracked == null) continue;
- updateCompass(hunter, tracked);
- }
+ TimerAccess.getTimerFromOverworld(pm.getServer()).dds_runTask(new TickTask(() -> {
+ for (final UUID uuid : hunters) {
+ final ServerPlayerEntity hunter = pm.getPlayer(uuid);
+ if (hunter == null) continue;
+ final ServerPlayerEntity tracked = pm.getPlayer(trackedMap.get(uuid));
+ if (tracked == null) continue;
+ updateCompass(hunter, tracked);
}
- }, Config.secondsBeforeRelease * 1000L, Config.updateCompassEach * 1000L);
+ }, Config.secondsBeforeRelease * 20L, Config.updateCompassEach * 20L));
}
private void updateCompass(ServerPlayerEntity player, ServerPlayerEntity tracked) {
diff --git a/src/main/java/world/anhgelus/manhunt/mixins/WorldTimerAccess.java b/src/main/java/world/anhgelus/manhunt/mixins/WorldTimerAccess.java new file mode 100644 index 0000000..6919b3b --- /dev/null +++ b/src/main/java/world/anhgelus/manhunt/mixins/WorldTimerAccess.java @@ -0,0 +1,44 @@ +package world.anhgelus.manhunt.mixins; + +import net.minecraft.server.world.ServerWorld; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import world.anhgelus.manhunt.timer.TimerAccess; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.BooleanSupplier; + +@Mixin(ServerWorld.class) +public class WorldTimerAccess implements TimerAccess { + @Unique + private final List<TimerAccess.TickTask> tasks = new ArrayList<>(); + + @Unique + private final List<TimerAccess.TickTask> tasksToAdd = new ArrayList<>(); + + @Inject(method = "tick", at = @At("TAIL")) + private void onTick(BooleanSupplier shouldKeepTicking, CallbackInfo ci) { + tasks.stream().filter(TickTask::isRunning).forEach(TickTask::tick); + tasks.addAll(tasksToAdd); + tasksToAdd.clear(); + } + + @Override + public void dds_runTask(TimerAccess.TickTask task) { + tasksToAdd.add(task); + } + + @Override + public void dds_cancel() { + tasks.stream().filter(TickTask::isRunning).forEach(TickTask::cancel); + } + + @Override + public List<TickTask> dds_getTasks() { + return tasks.stream().filter(TickTask::isRunning).toList(); + } +}
\ No newline at end of file diff --git a/src/main/java/world/anhgelus/manhunt/timer/TickTask.java b/src/main/java/world/anhgelus/manhunt/timer/TickTask.java new file mode 100644 index 0000000..5449166 --- /dev/null +++ b/src/main/java/world/anhgelus/manhunt/timer/TickTask.java @@ -0,0 +1,72 @@ +package world.anhgelus.manhunt.timer; + +/** + * Represents a complete task called each tick + */ +public class TickTask implements TimerAccess.TickTask { + public final long ticksDelay; + public final long ticksRepeat; + public final boolean repeating; + public final TimerAccess.Task task; + private boolean cancelled = false; + private long currentTicking; + + /** + * Create a new repeating TickTask + * + * @param task Task to run after the delay or the repeat time + * @param ticksDelay Delay before the first task's run + * @param ticksRepeat Repeat each tick (if the repeat is 0, it will repeat each tick, if it is below 0, it will not repeat) + * @throws IllegalArgumentException if ticksDelay is below 0 + */ + public TickTask(TimerAccess.Task task, long ticksDelay, long ticksRepeat) { + if (ticksDelay < 0) throw new IllegalArgumentException("Ticks delay must be non-negative"); + this.ticksDelay = ticksDelay; + this.ticksRepeat = ticksRepeat; + this.task = task; + repeating = ticksRepeat >= 0; + currentTicking = ticksDelay; + } + + /** + * Create a new delayed TickTask + * + * @param task Task to run after the delay or the repeat time + * @param ticksDelay Delay before the first task's run + * @throws IllegalArgumentException if ticksDelay or if ticksRepeat is below 0 + */ + public TickTask(TimerAccess.Task task, long ticksDelay) { + if (ticksDelay < 0) throw new IllegalArgumentException("Ticks delay must be non-negative"); + this.ticksDelay = ticksDelay; + this.ticksRepeat = -1; + this.task = task; + repeating = false; + currentTicking = ticksDelay; + } + + public void tick() { + if (--currentTicking > 0) return; + task.run(); + if (repeating) { + currentTicking = ticksRepeat; + } else { + cancel(); + } + } + + public long cancel() { + if (cancelled) throw new IllegalStateException("Task already cancelled"); + cancelled = true; + return currentTicking; + } + + public boolean isRunning() { + return !cancelled; + } + + @Override + public long getTickingBeforeRun() { + if (cancelled) return -1; + return currentTicking; + } +}
\ No newline at end of file diff --git a/src/main/java/world/anhgelus/manhunt/timer/TimerAccess.java b/src/main/java/world/anhgelus/manhunt/timer/TimerAccess.java new file mode 100644 index 0000000..f9ed08e --- /dev/null +++ b/src/main/java/world/anhgelus/manhunt/timer/TimerAccess.java @@ -0,0 +1,64 @@ +package world.anhgelus.manhunt.timer; + +import net.minecraft.server.MinecraftServer; + +import java.util.List; + +public interface TimerAccess { + /** + * Get the timer linked to the overworld + * + * @param server Current server + * @return TimerAccess linked to the overworld + */ + static TimerAccess getTimerFromOverworld(MinecraftServer server) { + final var timer = (TimerAccess) server.getOverworld(); + if (timer == null) + throw new NullPointerException("Impossible to get TimerAccess from the overworld (it is null)"); + return timer; + } + + /** + * Run a task (called each tick ticked) + * + * @param task Task to run + */ + void dds_runTask(TimerAccess.TickTask task); + + void dds_cancel(); + + /** + * @return All non-cancelled tasks + */ + List<TickTask> dds_getTasks(); + + interface TickTask { + /** + * Tick the task + */ + void tick(); + + /** + * Cancel the task + * + * @return the remaining ticks before the run of the Task + * @throws IllegalStateException if the task is already cancelled + */ + long cancel(); + + boolean isRunning(); + + /** + * @return the number of ticks before run of the task (if the task is cancelled, returns -1) + */ + long getTickingBeforeRun(); + } + + /** + * Represents a task to run after ticking + */ + @FunctionalInterface + interface Task { + void run(); + } +}
\ No newline at end of file |
