@@ -2,6 +2,7 @@ package com.lambda.module.modules.player
22
33import com.google.gson.annotations.SerializedName
44import com.lambda.config.RotationSettings
5+ import com.lambda.context.SafeContext
56import com.lambda.core.TimerManager
67import com.lambda.event.events.KeyPressEvent
78import com.lambda.event.events.MovementEvent
@@ -11,7 +12,7 @@ import com.lambda.interaction.rotation.Rotation
1112import com.lambda.interaction.rotation.RotationContext
1213import com.lambda.interaction.rotation.RotationMode
1314import com.lambda.module.Module
14- import com.lambda.module.modules.player.Replay.MoveInputAction .Companion.toAction
15+ import com.lambda.module.modules.player.Replay.InputAction .Companion.toAction
1516import com.lambda.module.tag.ModuleTag
1617import com.lambda.util.Communication.info
1718import com.lambda.util.Communication.warn
@@ -28,7 +29,7 @@ import kotlin.time.toDuration
2829// - Actually store the data in a file
2930// - Implement a way to save and load the data (Commands?)
3031// - Record other types of inputs: (Interactions, etc.)
31- // - Fix continue derivation after replaying the checkpoint for spliced runs
32+ // - Fix continue deviation after replaying the checkpoint for spliced runs
3233object Replay : Module(
3334 name = " Replay" ,
3435 description = " Record gameplay actions and replay them like a TAS." ,
@@ -37,12 +38,12 @@ object Replay : Module(
3738 private val record by setting(" Record" , KeyCode .R )
3839 private val play by setting(" Play / Pause" , KeyCode .C )
3940 private val stop by setting(" Stop" , KeyCode .X )
40- private val check by setting(" Checkpoint" , KeyCode .V , description = " Create a checkpoint in the recording." )
41- private val playCheck by setting(" Play checkpoints " , KeyCode .B , description = " Replays until the last set checkpoint." )
41+ private val check by setting(" Checkpoint" , KeyCode .V , description = " Create a checkpoint while recording." )
42+ private val playCheck by setting(" Play until checkpoint " , KeyCode .B , description = " Replays until the last set checkpoint." )
4243 private val loop by setting(" Loop" , false )
4344 private val loops by setting(" Loops" , - 1 , - 1 .. 10 , 1 , description = " Number of times to loop the replay. -1 for infinite." , unit = " repeats" ) { loop }
44- private val cancelOnDerivation by setting(" Cancel on derivation " , true )
45- private val derivationThreshold by setting(" Derivation threshold" , 0.1 , 0.1 .. 5.0 , 0.1 , description = " The threshold for the derivation to cancel the replay." ) { cancelOnDerivation }
45+ private val cancelOnDeviation by setting(" Cancel on deviation " , true )
46+ private val deviationThreshold by setting(" Deviation threshold" , 0.1 , 0.1 .. 5.0 , 0.1 , description = " The threshold for the deviation to cancel the replay." ) { cancelOnDeviation }
4647
4748 private val rotationConfig = RotationSettings (this ).apply {
4849 rotationMode = RotationMode .LOCK
@@ -59,35 +60,8 @@ object Replay : Module(
5960
6061 private var state = State .INACTIVE
6162
62- data class Recording (
63- val movement : MutableList <MoveInputAction >,
64- val rotation : MutableList <Rotation >,
65- val sprint : MutableList <Boolean >,
66- val position : MutableList <Vec3d >
67- ) {
68- val size: Int
69- get() = maxOf(movement.size, rotation.size, sprint.size, position.size)
70- val duration: Duration
71- get() = (size * TimerManager .tickLength * 1.0 ).toDuration(DurationUnit .MILLISECONDS )
72-
73- fun duplicate () = Recording (
74- movement.toMutableList(),
75- rotation.toMutableList(),
76- sprint.toMutableList(),
77- position.toMutableList()
78- )
79-
80- companion object {
81- fun new () = Recording (
82- mutableListOf (),
83- mutableListOf (),
84- mutableListOf (),
85- mutableListOf ()
86- )
87- }
88- }
89-
9063 private var checkpoint: Recording ? = null
64+
9165 private var recording: Recording ? = null
9266 private var replay: Recording ? = null
9367 private var repeats = 0
@@ -110,7 +84,7 @@ object Replay : Module(
11084 when (state) {
11185 State .RECORDING -> {
11286 recording?.let {
113- it.movement .add(event.toAction())
87+ it.input .add(event.input .toAction())
11488 it.position.add(player.pos)
11589 }
11690 }
@@ -120,16 +94,16 @@ object Replay : Module(
12094 val diff = pos.subtract(player.pos).length()
12195 if (diff < 0.001 ) return @a
12296
123- this @Replay.info( " Current derivation: ${" %.3f" .format(diff)} blocks." )
124- if (cancelOnDerivation && diff > derivationThreshold ) {
97+ this @Replay.warn( " Position deviates from the recording by ${" %.3f" .format(diff)} blocks." )
98+ if (cancelOnDeviation && diff > deviationThreshold ) {
12599 state = State .INACTIVE
126- this @Replay.info (" Replay cancelled due to exceeding derivation threshold." )
100+ this @Replay.warn (" Replay cancelled due to exceeding deviation threshold." )
127101 return @listener
128102 }
129103 }
130- it.movement .removeFirstOrNull()?.update(event) ? : run {
104+ it.input .removeFirstOrNull()?.update(event.input ) ? : run {
131105 if (loop && repeats < loops) {
132- repeats++
106+ if (repeats >= 0 ) repeats++
133107 replay = recording?.duplicate()
134108 this @Replay.info(" Replay looped. $repeats / $loops " )
135109 } else {
@@ -190,7 +164,7 @@ object Replay : Module(
190164 recording?.let {
191165 state = State .PLAYING
192166 replay = it.duplicate()
193- this @Replay.info(" Replay started and will take ${it.duration} ." )
167+ this @Replay.info(" Replay started. ETA: ${it.duration} ." )
194168 } ? : run {
195169 this @Replay.warn(" No recording to replay." )
196170 }
@@ -221,7 +195,7 @@ object Replay : Module(
221195 this @Replay.info(" Recording stopped. Recorded for ${recording?.duration} ." )
222196 }
223197 State .INACTIVE -> {
224- recording = Recording .new ()
198+ recording = Recording ()
225199 state = State .RECORDING
226200 this @Replay.info(" Recording started." )
227201 }
@@ -243,9 +217,14 @@ object Replay : Module(
243217 }
244218 }
245219
246- private fun handleCheckpoint () {
220+ private fun SafeContext. handleCheckpoint () {
247221 when (state) {
248222 State .RECORDING -> {
223+ if (player.velocity != Vec3d (0.0 , - 0.0784000015258789 , 0.0 )) {
224+ this @Replay.info(" Cannot create checkpoint while moving." )
225+ return
226+ }
227+
249228 checkpoint = recording?.duplicate()
250229 this @Replay.info(" Checkpoint created." )
251230 }
@@ -258,53 +237,29 @@ object Replay : Module(
258237 State .INACTIVE -> {
259238 state = State .PLAYING_CHECKPOINTS
260239 replay = checkpoint?.duplicate()
240+ this @Replay.info(" Replaying until last set checkpoint. ETA: ${checkpoint?.duration} " )
261241 }
262242 else -> {}
263243 }
264244 }
265245
266- data class MoveInputAction (
267- @SerializedName(" i" )
268- val input : InputAction ,
269- @SerializedName(" s" )
270- val slowDown : Boolean ,
271- @SerializedName(" f" )
272- val slowDownFactor : Float
246+ data class Recording (
247+ val input : MutableList <InputAction > = mutableListOf(),
248+ val rotation : MutableList <Rotation > = mutableListOf(),
249+ val sprint : MutableList <Boolean > = mutableListOf(),
250+ val position : MutableList <Vec3d > = mutableListOf()
273251 ) {
274- fun update (event : MovementEvent .InputUpdate ) {
275- event.input.update(input)
276- event.slowDown = slowDown
277- event.slowDownFactor = slowDownFactor
278- }
279-
280- companion object {
281- fun MovementEvent.InputUpdate.toAction () =
282- MoveInputAction (
283- InputAction (
284- input.movementSideways,
285- input.movementForward,
286- input.pressingForward,
287- input.pressingBack,
288- input.pressingLeft,
289- input.pressingRight,
290- input.jumping,
291- input.sneaking
292- ),
293- slowDown,
294- slowDownFactor
295- )
252+ val size: Int
253+ get() = minOf(input.size, rotation.size, sprint.size, position.size)
254+ val duration: Duration
255+ get() = (size * TimerManager .tickLength * 1.0 ).toDuration(DurationUnit .MILLISECONDS )
296256
297- fun Input.update (input : InputAction ) {
298- movementSideways = input.movementSideways
299- movementForward = input.movementForward
300- pressingForward = input.pressingForward
301- pressingBack = input.pressingBack
302- pressingLeft = input.pressingLeft
303- pressingRight = input.pressingRight
304- jumping = input.jumping
305- sneaking = input.sneaking
306- }
307- }
257+ fun duplicate () = Recording (
258+ input.take(size).toMutableList(),
259+ rotation.take(size).toMutableList(),
260+ sprint.take(size).toMutableList(),
261+ position.take(size).toMutableList()
262+ )
308263 }
309264
310265 data class InputAction (
@@ -324,5 +279,30 @@ object Replay : Module(
324279 val jumping : Boolean ,
325280 @SerializedName(" sn" )
326281 val sneaking : Boolean
327- )
282+ ) {
283+ fun update (input : Input ) {
284+ input.movementSideways = movementSideways
285+ input.movementForward = movementForward
286+ input.pressingForward = pressingForward
287+ input.pressingBack = pressingBack
288+ input.pressingLeft = pressingLeft
289+ input.pressingRight = pressingRight
290+ input.jumping = jumping
291+ input.sneaking = sneaking
292+ }
293+
294+ companion object {
295+ fun Input.toAction () =
296+ InputAction (
297+ movementSideways,
298+ movementForward,
299+ pressingForward,
300+ pressingBack,
301+ pressingLeft,
302+ pressingRight,
303+ jumping,
304+ sneaking
305+ )
306+ }
307+ }
328308}
0 commit comments