@@ -8,8 +8,6 @@ import at.petrak.hexcasting.api.casting.iota.Iota
88import at.petrak.hexcasting.api.casting.iota.PatternIota
99import at.petrak.hexcasting.api.casting.math.HexPattern
1010import gay.`object`.hexdebug.HexDebug
11- import gay.`object`.hexdebug.adapter.DebugAdapterState.Debugging
12- import gay.`object`.hexdebug.adapter.DebugAdapterState.NotDebugging
1311import gay.`object`.hexdebug.adapter.proxy.DebugProxyServerLauncher
1412import gay.`object`.hexdebug.config.HexDebugServerConfig
1513import gay.`object`.hexdebug.debugger.*
@@ -37,11 +35,11 @@ import java.util.concurrent.CompletableFuture
3735import java.util.concurrent.CompletionException
3836
3937class 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
0 commit comments