Skip to content

Commit 71f5b19

Browse files
authored
[Feature] Fixed rate tick (#100)
Tick event that always stays at 50ms no matter of game tick rate
1 parent 5ce94e9 commit 71f5b19

File tree

9 files changed

+86
-6
lines changed

9 files changed

+86
-6
lines changed

common/src/main/kotlin/com/lambda/core/TimerManager.kt

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,33 @@ package com.lambda.core
1919

2020
import com.lambda.event.EventFlow.post
2121
import com.lambda.event.events.ClientEvent
22+
import kotlin.concurrent.fixedRateTimer
2223

2324
object TimerManager : Loadable {
2425
var lastTickLength: Float = 50f
2526

2627
override fun load() = "Loaded Timer Manager"
2728

29+
private const val TICK_DELAY = 50L
30+
private var start = 0L
31+
val fixedTickDelta get() = (System.currentTimeMillis() - start).mod(TICK_DELAY).toDouble() / TICK_DELAY
32+
33+
init {
34+
fixedRateTimer(
35+
daemon = true,
36+
name = "Scheduler-Lambda-Tick",
37+
initialDelay = 0,
38+
period = TICK_DELAY
39+
) {
40+
if (start == 0L) start = System.currentTimeMillis()
41+
ClientEvent.FixedTick(this).post()
42+
}
43+
}
44+
2845
fun getLength(): Float {
2946
var length = 50f
3047

31-
ClientEvent.Timer(1.0).post {
48+
ClientEvent.TimerUpdate(1.0).post {
3249
length /= speed.toFloat()
3350
}
3451

common/src/main/kotlin/com/lambda/event/EventFlow.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import com.lambda.threading.runSafe
2525
import kotlinx.coroutines.*
2626
import kotlinx.coroutines.channels.BufferOverflow
2727
import kotlinx.coroutines.flow.*
28+
import java.util.*
2829

2930

3031
/**

common/src/main/kotlin/com/lambda/event/events/ClientEvent.kt

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@
1818
package com.lambda.event.events
1919

2020
import com.lambda.event.Event
21+
import com.lambda.event.EventFlow
2122
import com.lambda.event.callback.Cancellable
2223
import com.lambda.event.callback.ICancellable
2324
import net.minecraft.client.sound.SoundInstance
25+
import java.util.TimerTask
2426

2527
sealed class ClientEvent {
2628
/**
@@ -38,10 +40,20 @@ sealed class ClientEvent {
3840
*
3941
* @property speed The speed of the timer.
4042
*/
41-
data class Timer(var speed: Double) : Event
43+
data class TimerUpdate(var speed: Double) : Event
4244

4345
/**
4446
* Triggered before playing a sound
4547
*/
4648
data class Sound(val sound: SoundInstance) : ICancellable by Cancellable()
49+
50+
/**
51+
* Represents a fixed tick event in the application.
52+
*
53+
* A fixed tick can be used to execute a specific task consistently at regular intervals, based on the provided
54+
* timer task. This event is part of the event system and can be subscribed to for handling the specified timer task.
55+
*
56+
* @property timerTask The task that is executed during this fixed tick event.
57+
*/
58+
data class FixedTick(val timerTask: TimerTask) : Event
4759
}

common/src/main/kotlin/com/lambda/event/listener/SafeListener.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import com.lambda.event.Event
2222
import com.lambda.event.EventFlow
2323
import com.lambda.event.Muteable
2424
import com.lambda.threading.runConcurrent
25+
import com.lambda.threading.runGameScheduled
2526
import com.lambda.threading.runSafe
2627
import com.lambda.util.Pointer
2728
import com.lambda.util.selfReference
@@ -121,7 +122,7 @@ class SafeListener<T : Event>(
121122
noinline function: SafeContext.(T) -> Unit = {},
122123
): SafeListener<T> {
123124
val listener = SafeListener<T>(priority, this, alwaysListen) { event ->
124-
function(event)
125+
runGameScheduled { function(event) }
125126
}
126127

127128
EventFlow.syncListeners.subscribe(listener)

common/src/main/kotlin/com/lambda/gui/api/LambdaGui.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package com.lambda.gui.api
1919

2020
import com.lambda.Lambda.mc
2121
import com.lambda.event.Muteable
22+
import com.lambda.event.events.ClientEvent
2223
import com.lambda.event.events.RenderEvent
2324
import com.lambda.event.events.TickEvent
2425
import com.lambda.event.listener.SafeListener.Companion.listen
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright 2025 Lambda
3+
*
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
package com.lambda.module.modules.debug
19+
20+
import com.lambda.event.events.ClientEvent
21+
import com.lambda.event.listener.SafeListener.Companion.listen
22+
import com.lambda.event.listener.SafeListener.Companion.listenConcurrently
23+
import com.lambda.module.Module
24+
import com.lambda.module.tag.ModuleTag
25+
import com.lambda.util.Communication.info
26+
import com.lambda.util.KeyCode
27+
import net.minecraft.block.Blocks
28+
import net.minecraft.util.math.BlockPos
29+
import java.awt.Color
30+
31+
object TimerTest : Module(
32+
name = "TimerTest",
33+
defaultTags = setOf(ModuleTag.DEBUG)
34+
) {
35+
private var last = 0L
36+
37+
init {
38+
listen<ClientEvent.FixedTick> {
39+
val now = System.currentTimeMillis()
40+
info("${now - last} - Fixed Tick on game thread")
41+
last = now
42+
}
43+
44+
listenConcurrently<ClientEvent.FixedTick> {
45+
// info("${System.currentTimeMillis()} - Fixed Tick Concurrently (but not on mc game thread)")
46+
}
47+
}
48+
}

common/src/main/kotlin/com/lambda/module/modules/movement/Speed.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ object Speed : Module(
113113
lastDistance = player.moveDelta
114114
}
115115

116-
listen<ClientEvent.Timer> {
116+
listen<ClientEvent.TimerUpdate> {
117117
if (mode != Mode.NCP_STRAFE) return@listen
118118
if (!shouldWork() || !isInputting) return@listen
119119
it.speed = ncpTimerBoost

common/src/main/kotlin/com/lambda/module/modules/movement/TickShift.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ object TickShift : Module(
101101
}
102102
}
103103

104-
listen<ClientEvent.Timer> {
104+
listen<ClientEvent.TimerUpdate> {
105105
if (!isActive) {
106106
poolPackets()
107107
return@listen

common/src/main/kotlin/com/lambda/module/modules/movement/Timer.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ object Timer : Module(
3030
private val timer by setting("Timer", 1.0, 0.0..10.0, 0.01)
3131

3232
init {
33-
listen<ClientEvent.Timer> {
33+
listen<ClientEvent.TimerUpdate> {
3434
it.speed = timer.coerceAtLeast(0.05)
3535
}
3636
}

0 commit comments

Comments
 (0)