Skip to content

Commit c3c30a9

Browse files
committed
Save on record stop
1 parent a3de295 commit c3c30a9

File tree

2 files changed

+64
-20
lines changed

2 files changed

+64
-20
lines changed

common/src/main/kotlin/com/lambda/module/modules/player/Replay.kt

Lines changed: 59 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10,31 +10,43 @@ import com.lambda.event.events.KeyPressEvent
1010
import com.lambda.event.events.MovementEvent
1111
import com.lambda.event.events.RotationEvent
1212
import com.lambda.event.listener.SafeListener.Companion.listener
13+
import com.lambda.gui.impl.clickgui.LambdaClickGui
1314
import com.lambda.interaction.rotation.Rotation
1415
import com.lambda.interaction.rotation.RotationContext
1516
import com.lambda.interaction.rotation.RotationMode
1617
import com.lambda.module.Module
18+
import com.lambda.module.modules.client.GuiSettings
1719
import com.lambda.module.modules.player.Replay.InputAction.Companion.toAction
1820
import com.lambda.module.tag.ModuleTag
1921
import com.lambda.util.Communication.info
2022
import com.lambda.util.Communication.logError
2123
import com.lambda.util.Communication.warn
2224
import com.lambda.util.FolderRegister
25+
import com.lambda.util.Formatting.asString
2326
import com.lambda.util.KeyCode
2427
import com.lambda.util.primitives.extension.rotation
28+
import com.lambda.util.text.buildText
29+
import com.lambda.util.text.color
30+
import com.lambda.util.text.literal
2531
import kotlinx.coroutines.Dispatchers
2632
import kotlinx.coroutines.launch
2733
import net.minecraft.client.input.Input
34+
import net.minecraft.client.sound.PositionedSoundInstance
35+
import net.minecraft.client.sound.SoundInstance
36+
import net.minecraft.sound.SoundEvents
2837
import net.minecraft.util.math.Vec3d
38+
import java.awt.Color
2939
import java.io.File
3040
import java.lang.reflect.Type
3141
import kotlin.time.Duration
3242
import kotlin.time.DurationUnit
3343
import kotlin.time.toDuration
3444

3545
// ToDo:
36-
// - Use a custom binary format to store the data (Protobuf / DB?)
37-
// - Record other types of inputs: (Interactions, etc.)
46+
// - Record other types of inputs: (place, break, inventory, etc.)
47+
// - Fancy logging
48+
// - Add HUD for recording / replaying info
49+
// - Maybe use a custom binary format to store the data (Protobuf / DB?)
3850
object Replay : Module(
3951
name = "Replay",
4052
description = "Record gameplay actions and replay them like a TAS.",
@@ -78,7 +90,12 @@ object Replay : Module(
7890
fun loadRecording(file: File) {
7991
recording = gsonCompact.fromJson(file.readText(), Recording::class.java)
8092

81-
info("Recording ${file.nameWithoutExtension} loaded. Duration: ${recording?.duration}.")
93+
info(buildText {
94+
literal("Recording ")
95+
color(Color.GRAY) { literal(file.nameWithoutExtension) }
96+
literal(" loaded. Duration: ")
97+
color(Color.GRAY) { literal(recording?.duration.toString()) }
98+
})
8299
}
83100

84101
init {
@@ -110,10 +127,10 @@ object Replay : Module(
110127
val diff = pos.subtract(player.pos).length()
111128
if (diff < 0.001) return@a
112129

113-
this@Replay.warn("Position deviates from the recording by ${"%.3f".format(diff)} blocks.")
130+
this@Replay.warn("Position deviates from the recording by ${"%.3f".format(diff)} blocks. Desired position: ${pos.asString(3)}")
114131
if (cancelOnDeviation && diff > deviationThreshold) {
115132
state = State.INACTIVE
116-
this@Replay.warn("Replay cancelled due to exceeding deviation threshold.")
133+
this@Replay.logError("Replay cancelled due to exceeding deviation threshold.")
117134
return@listener
118135
}
119136
}
@@ -165,12 +182,21 @@ object Replay : Module(
165182
} else {
166183
if (state != State.PLAYING_CHECKPOINTS) {
167184
state = State.INACTIVE
168-
this@Replay.info("Replay finished after ${recording?.duration}.")
185+
this@Replay.info(buildText {
186+
literal("Replay finished after ")
187+
color(Color.GRAY) { literal(it.duration.toString()) }
188+
literal(".")
189+
})
169190
return@listener
170191
}
171192

172193
state = State.RECORDING
173194
recording = checkpoint?.duplicate()
195+
mc.soundManager.play(
196+
PositionedSoundInstance.master(
197+
SoundEvents.ENTITY_EXPERIENCE_ORB_PICKUP, 1.0f
198+
)
199+
)
174200
this@Replay.info("Checkpoint replayed. Continued recording...")
175201
}
176202
}
@@ -186,7 +212,7 @@ object Replay : Module(
186212
recording?.let {
187213
state = State.PLAYING
188214
replay = it.duplicate()
189-
this@Replay.info("Replay started. ETA: ${it.duration}.")
215+
this@Replay.info("Replay started. Duration: ${it.duration}.")
190216
} ?: run {
191217
this@Replay.warn("No recording to replay.")
192218
}
@@ -210,10 +236,13 @@ object Replay : Module(
210236
}
211237
}
212238

213-
private fun handleRecord() {
239+
private fun SafeContext.handleRecord() {
214240
when (state) {
215241
State.RECORDING -> {
216242
state = State.INACTIVE
243+
recording?.let {
244+
save(it, "recording")
245+
}
217246
this@Replay.info("Recording stopped. Recorded for ${recording?.duration}.")
218247
}
219248
State.INACTIVE -> {
@@ -225,10 +254,13 @@ object Replay : Module(
225254
}
226255
}
227256

228-
private fun handleStop() {
257+
private fun SafeContext.handleStop() {
229258
when (state) {
230259
State.RECORDING, State.PAUSED_RECORDING -> {
231260
state = State.INACTIVE
261+
recording?.let {
262+
save(it, "recording")
263+
}
232264
this@Replay.info("Recording stopped. Recorded for ${recording?.duration}.")
233265
}
234266
State.PLAYING, State.PAUSED_REPLAY, State.PLAYING_CHECKPOINTS -> {
@@ -248,15 +280,8 @@ object Replay : Module(
248280
}
249281

250282
checkpoint = recording?.duplicate()
251-
lambdaScope.launch(Dispatchers.IO) {
252-
FolderRegister.replay.mkdirs()
253-
FolderRegister.replay.resolve("checkpoint-${
254-
mc.currentServerEntry?.address?.replace(":", "_")
255-
}-${
256-
world.dimensionKey?.value?.path?.replace("/", "_")
257-
}-${
258-
System.currentTimeMillis()
259-
}.json").writeText(gsonCompact.toJson(checkpoint))
283+
checkpoint?.let {
284+
save(it, "checkpoint")
260285
}
261286
this@Replay.info("Checkpoint created.")
262287
}
@@ -269,17 +294,31 @@ object Replay : Module(
269294
State.INACTIVE -> {
270295
state = State.PLAYING_CHECKPOINTS
271296
replay = checkpoint?.duplicate()
272-
this@Replay.info("Replaying until last set checkpoint. ETA: ${checkpoint?.duration}")
297+
this@Replay.info("Replaying until last set checkpoint. Duration: ${checkpoint?.duration}")
273298
}
274299
else -> {}
275300
}
276301
}
277302

303+
private fun SafeContext.save(recording: Recording, name: String) {
304+
lambdaScope.launch(Dispatchers.IO) {
305+
FolderRegister.replay.mkdirs()
306+
FolderRegister.replay.resolve("$name-${
307+
mc.currentServerEntry?.address?.replace(":", "_")
308+
}-${
309+
world.dimensionKey?.value?.path?.replace("/", "_")
310+
}-${
311+
System.currentTimeMillis()
312+
}.json").writeText(gsonCompact.toJson(recording))
313+
}
314+
}
315+
278316
data class Recording(
279317
val input: MutableList<InputAction> = mutableListOf(),
280318
val rotation: MutableList<Rotation> = mutableListOf(),
281319
val sprint: MutableList<Boolean> = mutableListOf(),
282-
val position: MutableList<Vec3d> = mutableListOf()
320+
val position: MutableList<Vec3d> = mutableListOf(),
321+
// val interaction: MutableList<Interaction> = mutableListOf()
283322
) : JsonSerializer<Recording>, JsonDeserializer<Recording> {
284323
val size: Int
285324
get() = minOf(input.size, rotation.size, sprint.size, position.size)

common/src/main/kotlin/com/lambda/util/Formatting.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ object Formatting {
1010
val Vec3d.asString: String
1111
get() = "(%.2f, %.2f, %.2f)".format(x, y, z)
1212

13+
fun Vec3d.asString(decimals: Int = 2): String {
14+
val format = "%.${decimals}f"
15+
return "(${format.format(x)}, ${format.format(y)}, ${format.format(z)})"
16+
}
17+
1318
fun getTime(formatter: DateTimeFormatter = DateTimeFormatter.RFC_1123_DATE_TIME): String {
1419
val localDateTime = LocalDateTime.now()
1520
val zoneId = ZoneId.systemDefault()

0 commit comments

Comments
 (0)