Skip to content

Commit d0e2eb5

Browse files
committed
Move breakpoints/sources into new SharedDebugState class, remove DebugAdapterState, persist sources between casts
1 parent 07d5e8a commit d0e2eb5

File tree

8 files changed

+150
-199
lines changed

8 files changed

+150
-199
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
99
### Changed
1010

1111
- Update zh_cn translations, by ChuijkYahus in [#60](https://github.com/object-Object/HexDebug/pull/60).
12+
- Source files can now be viewed after the hex that created them finishes debugging.
13+
- Removed the random prefix from source filenames.
1214

1315
### Fixed
1416

Common/src/main/kotlin/gay/object/hexdebug/adapter/DebugAdapter.kt

Lines changed: 52 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ import at.petrak.hexcasting.api.casting.iota.Iota
88
import at.petrak.hexcasting.api.casting.iota.PatternIota
99
import at.petrak.hexcasting.api.casting.math.HexPattern
1010
import gay.`object`.hexdebug.HexDebug
11-
import gay.`object`.hexdebug.adapter.DebugAdapterState.Debugging
12-
import gay.`object`.hexdebug.adapter.DebugAdapterState.NotDebugging
1311
import gay.`object`.hexdebug.adapter.proxy.DebugProxyServerLauncher
1412
import gay.`object`.hexdebug.config.HexDebugServerConfig
1513
import gay.`object`.hexdebug.debugger.*
@@ -37,11 +35,11 @@ import java.util.concurrent.CompletableFuture
3735
import java.util.concurrent.CompletionException
3836

3937
class DebugAdapter(val player: ServerPlayer) : IDebugProtocolServer {
40-
private var state: DebugAdapterState = NotDebugging()
41-
42-
private val exceptionBreakpoints = mutableSetOf<ExceptionBreakpointType>()
43-
44-
private val debuggers get() = (state as? Debugging)?.debuggers
38+
private var isConnected = false
39+
private var lastDebugger: HexDebugger? = null // for resolving sources after exit
40+
private val debuggers = mutableMapOf<Int, HexDebugger>()
41+
private val restartArgs = mutableMapOf<Int, CastArgs>()
42+
private val state = SharedDebugState()
4543

4644
val launcher: IHexDebugLauncher by lazy {
4745
DebugProxyServerLauncher.createLauncher(this, ::messageWrapper, ::exceptionHandler)
@@ -51,7 +49,7 @@ class DebugAdapter(val player: ServerPlayer) : IDebugProtocolServer {
5149

5250
fun isDebugging(threadId: Int) = debugger(threadId) != null
5351

54-
fun debugger(threadId: Int) = debuggers?.get(threadId)
52+
fun debugger(threadId: Int) = debuggers[threadId]
5553

5654
private fun packId(threadId: Int, reference: Int): Int =
5755
(threadId shl THREAD_ID_SHIFT) or (reference and REFERENCE_MASK)
@@ -76,27 +74,18 @@ class DebugAdapter(val player: ServerPlayer) : IDebugProtocolServer {
7674
iota = iota,
7775
index = index,
7876
line = state.initArgs.indexToLine(index),
79-
isConnected = state.isConnected,
77+
isConnected = isConnected,
8078
).sendToPlayer(player)
8179
}
8280

8381
fun startDebugging(threadId: Int, args: CastArgs, notifyClient: Boolean = true): Boolean {
8482
val threadLimit = if (args.env.isEnlightened) HexDebugServerConfig.config.maxDebugThreads else 1
8583
if (threadId >= threadLimit) return false
8684

87-
val debugger = when (val state = state) {
88-
is Debugging -> {
89-
state.restartArgs[threadId] = args
90-
HexDebugger(threadId, exceptionBreakpoints, state.initArgs, state.launchArgs, args).also {
91-
state.debuggers[threadId] = it
92-
}
93-
}
94-
is NotDebugging -> {
95-
val newState = Debugging(threadId, exceptionBreakpoints, state, args)
96-
this.state = newState
97-
newState.debuggers[threadId]!!
98-
}
99-
}
85+
val debugger = HexDebugger(threadId, state, args)
86+
lastDebugger = debugger
87+
debuggers[threadId] = debugger
88+
restartArgs[threadId] = args
10089

10190
remoteProxy.thread(ThreadEventArguments().also {
10291
it.reason = ThreadEventArgumentsReason.STARTED
@@ -113,9 +102,9 @@ class DebugAdapter(val player: ServerPlayer) : IDebugProtocolServer {
113102
}
114103

115104
fun disconnectClient() {
116-
if (state.isConnected) {
105+
if (isConnected) {
117106
remoteProxy.terminated(TerminatedEventArguments())
118-
state.isConnected = false
107+
isConnected = false
119108
}
120109
}
121110

@@ -161,7 +150,7 @@ class DebugAdapter(val player: ServerPlayer) : IDebugProtocolServer {
161150
it.reason = ThreadEventArgumentsReason.EXITED
162151
it.threadId = threadId
163152
})
164-
state.restartArgs[threadId]?.let { startDebugging(threadId, it) }
153+
restartArgs[threadId]?.let { startDebugging(threadId, it) }
165154
}
166155

167156
private fun messageWrapper(consumer: MessageConsumer) = MessageConsumer { message ->
@@ -193,9 +182,7 @@ class DebugAdapter(val player: ServerPlayer) : IDebugProtocolServer {
193182

194183
for ((source, reason) in result.loadedSources) {
195184
remoteProxy.loadedSource(LoadedSourceEventArguments().also {
196-
it.source = source.apply {
197-
sourceReference = packId(threadId, sourceReference)
198-
}
185+
it.source = source
199186
it.reason = reason
200187
})
201188
}
@@ -211,7 +198,7 @@ class DebugAdapter(val player: ServerPlayer) : IDebugProtocolServer {
211198

212199
private fun sendStoppedEvent(threadId: Int?, reason: StopReason) {
213200
if (threadId == null) {
214-
debuggers?.keys?.forEach { sendStoppedEvent(it, reason) }
201+
debuggers.keys.forEach { sendStoppedEvent(it, reason) }
215202
} else {
216203
remoteProxy.stopped(StoppedEventArguments().also {
217204
it.threadId = threadId
@@ -267,10 +254,8 @@ class DebugAdapter(val player: ServerPlayer) : IDebugProtocolServer {
267254
}
268255

269256
override fun attach(args: MutableMap<String, Any>): CompletableFuture<Void> {
270-
state.apply {
271-
isConnected = true
272-
launchArgs = LaunchArgs(args)
273-
}
257+
isConnected = true
258+
state.launchArgs = LaunchArgs(args)
274259
remoteProxy.initialized()
275260
player.displayClientMessage(Component.translatable("text.hexdebug.connected"), true)
276261
return futureOf()
@@ -282,25 +267,21 @@ class DebugAdapter(val player: ServerPlayer) : IDebugProtocolServer {
282267
return SetBreakpointsResponse().apply {
283268
// source prefixes generally invalidate when the server restarts
284269
// so remove all breakpoints if we haven't seen this player before
285-
val (threadId, sourceReference) = unpackId(args.source.sourceReference)
286-
val debugger = debugger(threadId)
287-
breakpoints = if (debugger != null && player.uuid in knownPlayers) {
288-
args.breakpoints
289-
.map { debugger.setBreakpoint(sourceReference, it) }
290-
.toTypedArray()
270+
breakpoints = if (player.uuid in knownPlayers) {
271+
state.setBreakpoints(args.source.sourceReference, args.breakpoints).toTypedArray()
291272
} else {
292273
invalidateBreakpoints(args.breakpoints.size)
293274
}
294275
}.toFuture()
295276
}
296277

297278
override fun setExceptionBreakpoints(args: SetExceptionBreakpointsArguments): CompletableFuture<SetExceptionBreakpointsResponse> {
298-
exceptionBreakpoints.clear()
279+
state.exceptionBreakpoints.clear()
299280
val responseBreakpoints = mutableListOf<Breakpoint>()
300281

301282
for (name in args.filters) {
302283
val verified = try {
303-
exceptionBreakpoints.add(ExceptionBreakpointType.valueOf(name))
284+
state.exceptionBreakpoints.add(ExceptionBreakpointType.valueOf(name))
304285
true
305286
} catch (_: IllegalArgumentException) {
306287
false
@@ -315,7 +296,7 @@ class DebugAdapter(val player: ServerPlayer) : IDebugProtocolServer {
315296

316297
override fun configurationDone(args: ConfigurationDoneArguments?): CompletableFuture<Void> {
317298
knownPlayers.add(player.uuid)
318-
if (state is Debugging) sendStoppedEvent(null, StopReason.STEP)
299+
if (debuggers.isNotEmpty()) sendStoppedEvent(null, StopReason.STEP)
319300
return futureOf()
320301
}
321302

@@ -374,9 +355,9 @@ class DebugAdapter(val player: ServerPlayer) : IDebugProtocolServer {
374355
}
375356

376357
override fun restart(args: RestartArguments?): CompletableFuture<Void> {
377-
state = NotDebugging(state)
358+
debuggers.clear()
378359

379-
for ((threadId, castArgs) in state.restartArgs) {
360+
for ((threadId, castArgs) in restartArgs) {
380361
startDebugging(threadId, castArgs, false)
381362
}
382363

@@ -392,23 +373,12 @@ class DebugAdapter(val player: ServerPlayer) : IDebugProtocolServer {
392373
}
393374

394375
override fun terminateThreads(args: TerminateThreadsArguments): CompletableFuture<Void> {
395-
val state = (state as? Debugging) ?: return futureOf()
396-
397376
for (threadId in args.threadIds) {
398-
// notify the client
399377
remoteProxy.thread(ThreadEventArguments().also {
400378
it.reason = ThreadEventArgumentsReason.EXITED
401379
it.threadId = threadId
402380
})
403-
404-
state.debuggers.remove(threadId)?.let { debugger ->
405-
for (source in debugger.getSources()) {
406-
remoteProxy.loadedSource(LoadedSourceEventArguments().also {
407-
it.source = source
408-
it.reason = LoadedSourceEventArgumentsReason.REMOVED
409-
})
410-
}
411-
}
381+
debuggers.remove(threadId)
412382
}
413383

414384
MsgDebuggerStateS2C(
@@ -417,9 +387,13 @@ class DebugAdapter(val player: ServerPlayer) : IDebugProtocolServer {
417387
}
418388
).sendToPlayer(player)
419389

420-
if (state.debuggers.isEmpty()) {
421-
remoteProxy.exited(ExitedEventArguments().also { it.exitCode = 0 })
422-
this.state = NotDebugging(state)
390+
if (debuggers.isEmpty()) {
391+
if (isConnected) {
392+
remoteProxy.exited(ExitedEventArguments().also { it.exitCode = 0 })
393+
} else {
394+
lastDebugger = null
395+
state.sourceAllocator.clear()
396+
}
423397
closeEvaluator(null)
424398
} else {
425399
for (threadId in args.threadIds) {
@@ -431,15 +405,19 @@ class DebugAdapter(val player: ServerPlayer) : IDebugProtocolServer {
431405
}
432406

433407
override fun terminate(args: TerminateArguments?): CompletableFuture<Void> {
434-
return debuggers?.let { debuggers ->
435-
terminateThreads(TerminateThreadsArguments().also {
436-
it.threadIds = debuggers.keys.toIntArray()
437-
})
438-
} ?: futureOf()
408+
return terminateThreads(TerminateThreadsArguments().also {
409+
it.threadIds = debuggers.keys.toIntArray()
410+
})
439411
}
440412

441413
override fun disconnect(args: DisconnectArguments?): CompletableFuture<Void> {
442-
state.isConnected = false
414+
isConnected = false
415+
state.onDisconnect()
416+
// if there's an active debug session, we need to keep the sources in case the client reconnects
417+
if (debuggers.isEmpty()) {
418+
lastDebugger = null
419+
state.sourceAllocator.clear()
420+
}
443421
return futureOf()
444422
}
445423

@@ -448,15 +426,14 @@ class DebugAdapter(val player: ServerPlayer) : IDebugProtocolServer {
448426
override fun threads(): CompletableFuture<ThreadsResponse> {
449427
return ThreadsResponse().apply {
450428
threads = debuggers
451-
?.map { (threadId, debugger) ->
429+
.map { (threadId, debugger) ->
452430
Thread().apply {
453431
id = threadId
454432
name = "Thread $threadId (${debugger.envType})"
455433
}
456434
}
457-
?.sortedBy { it.id }
458-
?.toTypedArray()
459-
?: arrayOf()
435+
.sortedBy { it.id }
436+
.toTypedArray()
460437
}.toFuture()
461438
}
462439

@@ -465,12 +442,7 @@ class DebugAdapter(val player: ServerPlayer) : IDebugProtocolServer {
465442
return ScopesResponse().apply {
466443
scopes = debugger(threadId)
467444
?.getScopes(frameId)
468-
?.onEach {
469-
it.variablesReference = packId(threadId, it.variablesReference)
470-
if (it.source != null) {
471-
it.source.sourceReference = packId(threadId, it.source.sourceReference)
472-
}
473-
}
445+
?.onEach { it.variablesReference = packId(threadId, it.variablesReference) }
474446
?.toTypedArray()
475447
?: arrayOf()
476448
}.toFuture()
@@ -491,34 +463,23 @@ class DebugAdapter(val player: ServerPlayer) : IDebugProtocolServer {
491463
return StackTraceResponse().apply {
492464
stackFrames = debugger(args.threadId)
493465
?.getStackFrames()
494-
?.onEach {
495-
it.id = packId(args.threadId, it.id)
496-
if (it.source != null) {
497-
it.source.sourceReference = packId(args.threadId, it.source.sourceReference)
498-
}
499-
}
466+
?.onEach { it.id = packId(args.threadId, it.id) }
500467
?.paginate(args.startFrame, args.levels)
501468
?: arrayOf()
502469
}.toFuture()
503470
}
504471

505472
override fun source(args: SourceArguments): CompletableFuture<SourceResponse> {
506-
val (threadId, sourceReference) = unpackId(args.source?.sourceReference ?: args.sourceReference)
473+
val debugger = (args.source?.adapterData as? Int)?.let(::debugger) ?: lastDebugger
474+
val sourceReference = args.source?.sourceReference ?: args.sourceReference
507475
return SourceResponse().apply {
508-
content = debugger(threadId)?.getSourceContents(sourceReference) ?: ""
476+
content = debugger?.getSourceContents(sourceReference) ?: ""
509477
}.toFuture()
510478
}
511479

512480
override fun loadedSources(args: LoadedSourcesArguments?): CompletableFuture<LoadedSourcesResponse> {
513481
return LoadedSourcesResponse().apply {
514-
sources = debuggers
515-
?.flatMap { (threadId, debugger) ->
516-
debugger.getSources().onEach {
517-
it.sourceReference = packId(threadId, it.sourceReference)
518-
}
519-
}
520-
?.toTypedArray()
521-
?: arrayOf()
482+
sources = state.getSources().toTypedArray()
522483
}.toFuture()
523484
}
524485

Common/src/main/kotlin/gay/object/hexdebug/adapter/DebugAdapterState.kt

Lines changed: 0 additions & 48 deletions
This file was deleted.

Common/src/main/kotlin/gay/object/hexdebug/debugger/CastArgs.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,4 @@ data class CastArgs(
99
val env: CastingEnvironment,
1010
val world: ServerLevel,
1111
val onExecute: ((Iota) -> Unit)? = null,
12-
1312
)

0 commit comments

Comments
 (0)