Skip to content

Commit d178d76

Browse files
committed
Implement the evaluator
1 parent 5f2704b commit d178d76

File tree

5 files changed

+173
-24
lines changed

5 files changed

+173
-24
lines changed
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package gay.object.hexdebug.mixin;
2+
3+
import at.petrak.hexcasting.api.casting.eval.env.StaffCastEnv;
4+
import at.petrak.hexcasting.common.msgs.MsgNewSpellPatternC2S;
5+
import gay.object.hexdebug.items.ItemEvaluator;
6+
import gay.object.hexdebug.registry.HexDebugItems;
7+
import net.minecraft.server.level.ServerPlayer;
8+
import org.spongepowered.asm.mixin.Mixin;
9+
import org.spongepowered.asm.mixin.injection.At;
10+
import org.spongepowered.asm.mixin.injection.Inject;
11+
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
12+
13+
@Mixin(StaffCastEnv.class)
14+
public abstract class MixinStaffCastEnv {
15+
@Inject(
16+
method = "handleNewPatternOnServer",
17+
at = @At(
18+
value = "INVOKE",
19+
target = "Lat/petrak/hexcasting/xplat/IXplatAbstractions;getStaffcastVM(Lnet/minecraft/server/level/ServerPlayer;Lnet/minecraft/world/InteractionHand;)Lat/petrak/hexcasting/api/casting/eval/vm/CastingVM;",
20+
ordinal = 0
21+
),
22+
cancellable = true
23+
)
24+
private static void handleNewEvaluatorPatternOnServer$hexdebug(
25+
ServerPlayer sender,
26+
MsgNewSpellPatternC2S msg,
27+
CallbackInfo ci
28+
) {
29+
var item = sender.getItemInHand(msg.handUsed()).getItem();
30+
if (item == HexDebugItems.EVALUATOR.getValue()) {
31+
var success = ItemEvaluator.handleNewEvaluatorPatternOnServer(sender, msg);
32+
if (success) {
33+
ci.cancel();
34+
}
35+
}
36+
}
37+
}

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

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
package gay.`object`.hexdebug.adapter
22

3+
import at.petrak.hexcasting.api.casting.SpellList
4+
import at.petrak.hexcasting.api.casting.eval.ExecutionClientView
5+
import at.petrak.hexcasting.api.casting.iota.Iota
6+
import at.petrak.hexcasting.api.casting.iota.PatternIota
7+
import at.petrak.hexcasting.api.casting.math.HexPattern
8+
import at.petrak.hexcasting.common.msgs.MsgNewSpellPatternS2C
9+
import at.petrak.hexcasting.xplat.IXplatAbstractions
310
import gay.`object`.hexdebug.HexDebug
411
import gay.`object`.hexdebug.adapter.DebugAdapterState.*
512
import gay.`object`.hexdebug.adapter.proxy.DebugProxyServerLauncher
@@ -35,7 +42,7 @@ open class DebugAdapter(val player: ServerPlayer) : IDebugProtocolServer {
3542

3643
val canStartDebugging get() = state is ReadyToDebug
3744

38-
private val debugger get() = (state as? Debugging)?.debugger
45+
val debugger get() = (state as? Debugging)?.debugger
3946

4047
open val launcher: IHexDebugLauncher by lazy {
4148
DebugProxyServerLauncher.createLauncher(this, ::messageWrapper, ::exceptionHandler)
@@ -86,6 +93,21 @@ open class DebugAdapter(val player: ServerPlayer) : IDebugProtocolServer {
8693
})
8794
}
8895

96+
fun evaluate(pattern: HexPattern) = evaluate(PatternIota(pattern))
97+
98+
fun evaluate(iota: Iota) = evaluate(SpellList.LList(listOf(iota)))
99+
100+
fun evaluate(list: SpellList) = debugger?.let {
101+
handleDebuggerStep(it.evaluate(list))
102+
}
103+
104+
fun resetEvaluator() {
105+
debugger?.also {
106+
it.resetEvaluator()
107+
sendStoppedEvent("step")
108+
}
109+
}
110+
89111
private fun messageWrapper(consumer: MessageConsumer) = MessageConsumer { message ->
90112
HexDebug.LOGGER.debug(message)
91113
consumer.consume(message)
@@ -100,10 +122,14 @@ open class DebugAdapter(val player: ServerPlayer) : IDebugProtocolServer {
100122
?: ResponseError(ResponseErrorCode.InternalError, e.toString(), e.stackTraceToString())
101123
}
102124

103-
private fun handleDebuggerStep(result: DebugStepResult?) {
125+
private fun handleDebuggerStep(result: DebugStepResult?): ExecutionClientView? {
126+
val view = debugger?.getClientView()?.also {
127+
IXplatAbstractions.INSTANCE.sendPacketToPlayer(player, MsgNewSpellPatternS2C(it, -1))
128+
}
129+
104130
if (result == null) {
105131
terminate(null)
106-
return
132+
return view
107133
}
108134

109135
for ((source, reason) in result.loadedSources) {
@@ -114,6 +140,7 @@ open class DebugAdapter(val player: ServerPlayer) : IDebugProtocolServer {
114140
}
115141

116142
sendStoppedEvent(result.reason)
143+
return view
117144
}
118145

119146
private fun sendStoppedEvent(reason: String) {

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

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@ package gay.`object`.hexdebug.debugger
33
import at.petrak.hexcasting.api.HexAPI
44
import at.petrak.hexcasting.api.casting.PatternShapeMatch
55
import at.petrak.hexcasting.api.casting.SpellList
6-
import at.petrak.hexcasting.api.casting.eval.CastResult
7-
import at.petrak.hexcasting.api.casting.eval.ResolvedPatternType
8-
import at.petrak.hexcasting.api.casting.eval.SpecialPatterns
6+
import at.petrak.hexcasting.api.casting.eval.*
97
import at.petrak.hexcasting.api.casting.eval.sideeffects.OperatorSideEffect
108
import at.petrak.hexcasting.api.casting.eval.vm.*
119
import at.petrak.hexcasting.api.casting.eval.vm.SpellContinuation.Done
@@ -31,7 +29,7 @@ import org.eclipse.lsp4j.debug.LoadedSourceEventArgumentsReason as LoadedSourceR
3129
class HexDebugger(
3230
private val initArgs: InitializeRequestArguments,
3331
private val launchArgs: LaunchArgs,
34-
private val vm: CastingVM,
32+
val vm: CastingVM,
3533
private val world: ServerLevel,
3634
private val onExecute: ((Iota) -> Unit)? = null,
3735
iotas: List<Iota>,
@@ -42,11 +40,11 @@ class HexDebugger(
4240
castArgs: CastArgs,
4341
) : this(initArgs, launchArgs, CastingVM.empty(castArgs.env), castArgs.world, castArgs.onExecute, castArgs.iotas)
4442

45-
val debugCastEnv = vm.env as IDebugCastEnv
46-
4743
var lastEvaluatedMetadata: IotaMetadata? = null
4844
private set
4945

46+
private val debugCastEnv = vm.env as IDebugCastEnv
47+
5048
private val variablesAllocator = VariablesAllocator()
5149
private val sourceAllocator = SourceAllocator(iotas.hashCode())
5250

@@ -61,6 +59,12 @@ class HexDebugger(
6159

6260
private var callStack = listOf<NotDone>()
6361

62+
val evaluatorUIPatterns = mutableListOf<ResolvedPattern>()
63+
64+
private var evaluatorResetData: Pair<SpellContinuation, CastingImage>? = null
65+
66+
private var lastResolutionType = ResolvedPatternType.UNRESOLVED
67+
6468
// Initialize the continuation stack to a single top-level eval for all iotas.
6569
private var nextContinuation: SpellContinuation = Done
6670
set(value) {
@@ -355,6 +359,36 @@ class HexDebugger(
355359
}
356360
}
357361

362+
fun getClientView(): ExecutionClientView {
363+
val image = vm.image
364+
val (stackDescs, ravenmind) = vm.generateDescs()
365+
val isStackClear = nextContinuation is Done // only close the window if we're done evaluating
366+
return ExecutionClientView(isStackClear, lastResolutionType, stackDescs, ravenmind)
367+
}
368+
369+
/**
370+
* Use [DebugAdapter.evaluate][gay.object.hexdebug.adapter.DebugAdapter.evaluate] instead.
371+
*/
372+
internal fun evaluate(list: SpellList): DebugStepResult? {
373+
if (evaluatorResetData == null) {
374+
evaluatorResetData = Pair(nextContinuation, vm.image)
375+
}
376+
nextContinuation = nextContinuation.pushFrame(FrameEvaluate(list, false))
377+
return executeOnce()
378+
}
379+
380+
/**
381+
* Use [DebugAdapter.resetEvaluator][gay.object.hexdebug.adapter.DebugAdapter.resetEvaluator] instead.
382+
*/
383+
internal fun resetEvaluator() {
384+
evaluatorResetData?.also { (continuation, image) ->
385+
nextContinuation = continuation
386+
vm.image = image
387+
evaluatorResetData = null
388+
}
389+
evaluatorUIPatterns.clear()
390+
}
391+
358392
fun start(): DebugStepResult? {
359393
val loadedSources = mapOf(initialSource to LoadedSourceReason.NEW)
360394
return if (launchArgs.stopOnEntry) {
@@ -499,6 +533,7 @@ class HexDebugger(
499533
}
500534

501535
continuation = newContinuation
536+
lastResolutionType = castResult.resolutionType
502537

503538
try {
504539
vm.performSideEffects(info, castResult.sideEffects)
@@ -571,7 +606,6 @@ class HexDebugger(
571606
else -> stepResult
572607
}
573608

574-
@Suppress("CAST_NEVER_SUCCEEDS")
575609
private fun getStepType(
576610
castResult: CastResult,
577611
continuation: NotDone,
Lines changed: 63 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,99 @@
11
package gay.`object`.hexdebug.items
22

3+
import at.petrak.hexcasting.api.casting.ParticleSpray
34
import at.petrak.hexcasting.common.items.ItemStaff
45
import at.petrak.hexcasting.common.lib.HexSounds
5-
import at.petrak.hexcasting.common.msgs.MsgClearSpiralPatternsS2C
6+
import at.petrak.hexcasting.common.msgs.*
67
import at.petrak.hexcasting.xplat.IXplatAbstractions
8+
import gay.`object`.hexdebug.adapter.DebugAdapterManager
79
import net.minecraft.server.level.ServerPlayer
810
import net.minecraft.stats.Stats
911
import net.minecraft.world.InteractionHand
1012
import net.minecraft.world.InteractionResultHolder
1113
import net.minecraft.world.entity.player.Player
1214
import net.minecraft.world.item.ItemStack
1315
import net.minecraft.world.level.Level
16+
import net.minecraft.world.phys.Vec3
1417

1518
class ItemEvaluator(properties: Properties) : ItemStaff(properties) {
1619
override fun use(world: Level, player: Player, hand: InteractionHand): InteractionResultHolder<ItemStack> {
17-
val stack = player.getItemInHand(hand)
20+
val itemStack = player.getItemInHand(hand)
1821

1922
if (world.isClientSide) {
2023
if (player.isShiftKeyDown) {
2124
player.playSound(HexSounds.STAFF_RESET, 1f, 1f)
2225
}
23-
return InteractionResultHolder.success(stack)
26+
return InteractionResultHolder.success(itemStack)
2427
}
2528

2629
player as ServerPlayer
2730

31+
val debugAdapter = DebugAdapterManager[player]
32+
val debugger = debugAdapter?.debugger
33+
if (debugAdapter == null || debugger == null) {
34+
return InteractionResultHolder.fail(itemStack)
35+
}
36+
2837
if (player.isShiftKeyDown) {
29-
// IXplatAbstractions.INSTANCE.clearCastingData(player)
38+
debugAdapter.resetEvaluator()
3039
MsgClearSpiralPatternsS2C(player.uuid).also {
3140
IXplatAbstractions.INSTANCE.sendPacketToPlayer(player, it)
3241
IXplatAbstractions.INSTANCE.sendPacketTracking(player, it)
3342
}
3443
}
3544

36-
// val harness = IXplatAbstractions.INSTANCE.getStaffcastVM(player, hand)
37-
// val patterns = IXplatAbstractions.INSTANCE.getPatternsSavedInUi(player)
38-
// val descs = harness.generateDescs()
39-
//
40-
// IXplatAbstractions.INSTANCE.sendPacketToPlayer(
41-
// player,
42-
// MsgOpenSpellGuiS2C(hand, patterns, descs.first, descs.second, 0)
43-
// )
45+
val patterns = debugger.evaluatorUIPatterns
46+
val (stack, ravenmind) = debugger.vm.generateDescs()
47+
IXplatAbstractions.INSTANCE.sendPacketToPlayer(
48+
player, MsgOpenSpellGuiS2C(hand, patterns, stack, ravenmind, 0)
49+
)
4450

4551
player.awardStat(Stats.ITEM_USED[this])
4652

47-
return InteractionResultHolder.consume(stack)
53+
return InteractionResultHolder.consume(itemStack)
54+
}
55+
56+
companion object {
57+
/**
58+
* Copy of [StaffCastEnv.handleNewPatternOnServer][at.petrak.hexcasting.api.casting.eval.env.StaffCastEnv.handleNewPatternOnServer]
59+
* for evaluating patterns in the active debugger, if any.
60+
*
61+
* Returns `true` if the pattern was handled successfully (ie. handleNewPatternOnServer should be cancelled).
62+
*/
63+
@JvmStatic
64+
fun handleNewEvaluatorPatternOnServer(sender: ServerPlayer, msg: MsgNewSpellPatternC2S): Boolean {
65+
val debugAdapter = DebugAdapterManager[sender]
66+
val debugger = debugAdapter?.debugger
67+
if (debugAdapter == null || debugger == null) {
68+
return false
69+
}
70+
71+
val clientInfo = debugAdapter.evaluate(msg.pattern) ?: return false
72+
73+
debugger.evaluatorUIPatterns.clear()
74+
if (!clientInfo.isStackClear) {
75+
msg.resolvedPatterns.lastOrNull()?.type = clientInfo.resolutionType
76+
debugger.evaluatorUIPatterns.addAll(msg.resolvedPatterns)
77+
}
78+
79+
IXplatAbstractions.INSTANCE.sendPacketToPlayer(
80+
sender, MsgNewSpellPatternS2C(clientInfo, msg.resolvedPatterns.size - 1)
81+
)
82+
83+
val packet = if (clientInfo.isStackClear) {
84+
MsgClearSpiralPatternsS2C(sender.uuid)
85+
} else {
86+
MsgNewSpiralPatternsS2C(sender.uuid, listOf(msg.pattern()), Integer.MAX_VALUE)
87+
}
88+
IXplatAbstractions.INSTANCE.sendPacketToPlayer(sender, packet)
89+
IXplatAbstractions.INSTANCE.sendPacketTracking(sender, packet)
90+
91+
if (clientInfo.resolutionType.success) {
92+
ParticleSpray(sender.position(), Vec3(0.0, 1.5, 0.0), 0.4, Math.PI / 3, 30)
93+
.sprayParticles(sender.serverLevel(), IXplatAbstractions.INSTANCE.getPigment(sender))
94+
}
95+
96+
return true
97+
}
4898
}
4999
}

Common/src/main/resources/hexdebug-common.mixins.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
],
99
"mixins": [
1010
"MixinMsgShiftScrollC2S",
11-
"MixinOpEval"
11+
"MixinOpEval",
12+
"MixinStaffCastEnv"
1213
],
1314
"injectors": {
1415
"defaultRequire": 1

0 commit comments

Comments
 (0)