diff options
Diffstat (limited to 'src/main/kotlin/features/misc')
-rw-r--r-- | src/main/kotlin/features/misc/TimerFeature.kt | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/src/main/kotlin/features/misc/TimerFeature.kt b/src/main/kotlin/features/misc/TimerFeature.kt new file mode 100644 index 0000000..7c4833d --- /dev/null +++ b/src/main/kotlin/features/misc/TimerFeature.kt @@ -0,0 +1,124 @@ +package moe.nea.firmament.features.misc + +import com.mojang.brigadier.arguments.IntegerArgumentType +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import kotlin.time.Duration +import kotlin.time.Duration.Companion.seconds +import moe.nea.firmament.Firmament +import moe.nea.firmament.annotations.Subscribe +import moe.nea.firmament.commands.DurationArgumentType +import moe.nea.firmament.commands.RestArgumentType +import moe.nea.firmament.commands.get +import moe.nea.firmament.commands.thenArgument +import moe.nea.firmament.commands.thenExecute +import moe.nea.firmament.events.CommandEvent +import moe.nea.firmament.events.TickEvent +import moe.nea.firmament.util.CommonSoundEffects +import moe.nea.firmament.util.FirmFormatters +import moe.nea.firmament.util.MC +import moe.nea.firmament.util.MinecraftDispatcher +import moe.nea.firmament.util.TimeMark +import moe.nea.firmament.util.clickCommand +import moe.nea.firmament.util.lime +import moe.nea.firmament.util.red +import moe.nea.firmament.util.tr +import moe.nea.firmament.util.yellow + +object TimerFeature { + data class Timer( + val start: TimeMark, + val duration: Duration, + val message: String, + val timerId: Int, + ) { + fun timeLeft() = (duration - start.passedTime()).coerceAtLeast(0.seconds) + fun isDone() = start.passedTime() >= duration + } + + // Theoretically for optimal performance this could be a treeset keyed to the end time + val timers = mutableListOf<Timer>() + + @Subscribe + fun tick(event: TickEvent) { + timers.removeAll { + if (it.isDone()) { + MC.sendChat(tr("firmament.timer.finished", + "The timer you set ${FirmFormatters.formatTimespan(it.duration)} ago just went off: ${it.message}") + .yellow()) + Firmament.coroutineScope.launch { + withContext(MinecraftDispatcher) { + repeat(5) { + CommonSoundEffects.playSuccess() + delay(0.2.seconds) + } + } + } + true + } else { + false + } + } + } + + fun startTimer(duration: Duration, message: String) { + val timerId = createTimerId++ + timers.add(Timer(TimeMark.now(), duration, message, timerId)) + MC.sendChat( + tr("firmament.timer.start", + "Timer started for $message in ${FirmFormatters.formatTimespan(duration)}.").lime() + .append(" ") + .append( + tr("firmament.timer.cancelbutton", + "Click here to cancel the timer." + ).clickCommand("/firm timer clear $timerId").red() + ) + ) + } + + fun clearTimer(timerId: Int) { + val timer = timers.indexOfFirst { it.timerId == timerId } + if (timer < 0) { + MC.sendChat(tr("firmament.timer.cancel.fail", + "Could not cancel that timer. Maybe it was already cancelled?").red()) + } else { + val timerData = timers[timer] + timers.removeAt(timer) + MC.sendChat(tr("firmament.timer.cancel.done", + "Cancelled timer ${timerData.message}. It would have been done in ${ + FirmFormatters.formatTimespan(timerData.timeLeft()) + }.").lime()) + } + } + + var createTimerId = 0 + + @Subscribe + fun onCommands(event: CommandEvent.SubCommand) { + event.subcommand("cleartimer") { + thenArgument("timerId", IntegerArgumentType.integer(0)) { timerId -> + thenExecute { + clearTimer(this[timerId]) + } + } + thenExecute { + timers.map { it.timerId }.forEach { + clearTimer(it) + } + } + } + event.subcommand("timer") { + thenArgument("time", DurationArgumentType) { duration -> + thenExecute { + startTimer(this[duration], "no message") + } + thenArgument("message", RestArgumentType) { message -> + thenExecute { + startTimer(this[duration], this[message]) + } + } + } + } + } +} |