Skip to content

Commit 748cc56

Browse files
committed
Switch to a single mixin for all base continuation frames, in preparation for dynamic mixin generation
1 parent 9be2d72 commit 748cc56

File tree

10 files changed

+130
-250
lines changed

10 files changed

+130
-250
lines changed

common/src/main/clojure/gay/object/caduceus/casting/actions/marks.clj

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,18 +34,19 @@
3434

3535
(deftype OpWriteLocalMark []
3636
Action
37-
(operate [_this _env image cont]
37+
(operate [_this env image cont]
3838
(let [stack (-> image .getStack vec)
3939
mark (last stack)]
4040
(cond
4141
(nil? mark) (throw (MishapNotEnoughArgs/new 1 0))
4242
(> (.size mark) 1) (throw (MishapInvalidIota/ofType mark 0 "continuation_mark")))
4343
(when-let [true-name (MishapOthersName/getTrueNameFromDatum mark nil)]
4444
(throw (MishapOthersName/new true-name)))
45+
(continuation/set-mark cont mark (.getWorld env))
4546
(OperationResult/new
4647
(casting/copy-image
4748
(.withUsedOp image)
4849
:stack (pop stack))
4950
[]
50-
(continuation/with-mark cont mark)
51+
cont
5152
HexEvalSounds/NORMAL_EXECUTE))))

common/src/main/clojure/gay/object/caduceus/utils/continuation.clj

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -45,36 +45,40 @@
4545
caduceus$getMark
4646
[]
4747
"Returns the continuation mark on this frame, or NullIota if none.")
48-
(^at.petrak.hexcasting.api.casting.eval.vm.ContinuationFrame
49-
caduceus$withMark
48+
(^void
49+
caduceus$setMark
5050
[^at.petrak.hexcasting.api.casting.iota.Iota mark]
51-
"Returns a copy of this frame with the given continuation mark."))
51+
"Mutably sets the continuation mark on this frame. DO NOT CALL THIS METHOD ON SINGLETONS!"))
5252

5353
; CURSED
5454
; we catch IllegalArgumentException instead of just checking instance? so other addons can add support without depending on us
5555
(defn get-frame-mark
5656
([frame] (get-frame-mark frame nil))
5757
([frame not-found]
58-
(try
58+
(if (instance? ContinuationMarkHolder frame)
5959
(.caduceus$getMark frame)
60-
(catch IllegalArgumentException _ not-found))))
60+
not-found)))
6161

6262
(defn get-mark [cont]
6363
(if-let [frame (frame cont)]
6464
(get-frame-mark frame (NullIota/new))
6565
(NullIota/new)))
6666

67-
(defn with-frame-mark [frame iota]
68-
(try
69-
(.caduceus$withMark frame iota)
70-
(catch IllegalArgumentException _ frame)))
71-
72-
(defn with-mark [cont mark]
73-
(if-let [frame (frame cont)]
74-
(.pushFrame
75-
(.getNext cont)
76-
(with-frame-mark frame mark))
77-
cont))
67+
(defn set-frame-mark [frame iota world]
68+
(let [frame-type (.getType frame)]
69+
(when (and
70+
(instance? ContinuationMarkHolder frame)
71+
; CURSED: pass the frame through serialization to detect singletons
72+
(-> frame
73+
.serializeToNBT
74+
(#(.deserializeFromNBT frame-type % world))
75+
(identical? frame)
76+
not))
77+
(.caduceus$setMark frame iota))))
78+
79+
(defn set-mark [cont mark world]
80+
(when-let [frame (frame cont)]
81+
(set-frame-mark frame mark world)))
7882

7983
(defn- frame-tag-type-id [tag]
8084
(-> tag
@@ -85,12 +89,11 @@
8589
(def MARK-TAG "caduceus:mark")
8690

8791
(defn- get-frame-tag-mark [tag]
88-
(let [data-tag (.getCompound tag HexContinuationTypes/KEY_DATA)]
89-
(if (.contains data-tag MARK-TAG net.minecraft.nbt.Tag/TAG_COMPOUND)
90-
(let [mark-tag (.getCompound data-tag MARK-TAG)
91-
mark-type (.getString mark-tag HexIotaTypes/KEY_TYPE)]
92-
(when-not (= mark-type "hexcasting:null")
93-
mark-tag)))))
92+
(if (.contains tag MARK-TAG net.minecraft.nbt.Tag/TAG_COMPOUND)
93+
(let [mark-tag (.getCompound tag MARK-TAG)
94+
mark-type (.getString mark-tag HexIotaTypes/KEY_TYPE)]
95+
(when-not (= mark-type "hexcasting:null")
96+
mark-tag))))
9497

9598
(defn- mod-name [id]
9699
(if-let [mod (-> id Platform/getOptionalMod (.orElse nil))]
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package gay.object.caduceus.mixin;
2+
3+
import at.petrak.hexcasting.api.casting.eval.vm.*;
4+
import at.petrak.hexcasting.api.casting.iota.Iota;
5+
import at.petrak.hexcasting.api.casting.iota.NullIota;
6+
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
7+
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
8+
import gay.object.caduceus.utils.continuation.ContinuationMarkHolder;
9+
import org.jetbrains.annotations.Nullable;
10+
import org.spongepowered.asm.mixin.Mixin;
11+
import org.spongepowered.asm.mixin.Unique;
12+
import org.spongepowered.asm.mixin.injection.At;
13+
import org.spongepowered.asm.mixin.injection.Inject;
14+
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
15+
16+
// FrameFinishEval is a singleton, so caduceus$setMark SHOULD never be called on it
17+
// technically we don't even need this mixin for it, but it's here for testing
18+
@Mixin(value = {FrameEvaluate.class, FrameForEach.class, FrameFinishEval.class}, remap = false)
19+
public abstract class MixinAllContinuationFrames implements ContinuationFrame, ContinuationMarkHolder {
20+
@Unique
21+
@Nullable
22+
private Iota caduceus$mark;
23+
24+
@Unique
25+
@Override
26+
public Iota caduceus$getMark() {
27+
if (caduceus$mark == null) {
28+
return new NullIota();
29+
}
30+
return caduceus$mark;
31+
}
32+
33+
@Unique
34+
@Override
35+
public void caduceus$setMark(Iota newMark) {
36+
caduceus$mark = newMark;
37+
}
38+
39+
@WrapOperation(
40+
method = "evaluate",
41+
at = @At(value = "INVOKE", target = "Lat/petrak/hexcasting/api/casting/eval/vm/SpellContinuation;pushFrame(Lat/petrak/hexcasting/api/casting/eval/vm/ContinuationFrame;)Lat/petrak/hexcasting/api/casting/eval/vm/SpellContinuation;"),
42+
require = 0
43+
)
44+
private SpellContinuation caduceus$addMarkToPushedFrame(SpellContinuation instance, ContinuationFrame frame, Operation<SpellContinuation> original) {
45+
// if we're pushing a frame which is the same class as (or a subclass of) this one, copy the mark over
46+
// this handles cases like FrameEvaluate creating a new frame with list.cdr
47+
if (getClass().isInstance(frame) && frame instanceof ContinuationMarkHolder holder) {
48+
holder.caduceus$setMark(caduceus$mark);
49+
}
50+
return original.call(instance, frame);
51+
}
52+
53+
@Inject(method = "copy", at = @At("RETURN"), require = 0)
54+
private void caduceus$addMarkToCopy(CallbackInfoReturnable<ContinuationFrame> cir) {
55+
if (cir.getReturnValue() instanceof ContinuationMarkHolder holder) {
56+
holder.caduceus$setMark(caduceus$mark);
57+
}
58+
}
59+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package gay.object.caduceus.mixin;
2+
3+
import at.petrak.hexcasting.api.casting.iota.IotaType;
4+
import gay.object.caduceus.utils.continuation.ContinuationMarkHolder;
5+
import gay.object.caduceus.utils.continuation.ContinuationUtils;
6+
import at.petrak.hexcasting.api.casting.eval.vm.ContinuationFrame;
7+
import com.llamalad7.mixinextras.injector.ModifyReturnValue;
8+
import net.minecraft.nbt.CompoundTag;
9+
import net.minecraft.nbt.Tag;
10+
import net.minecraft.server.level.ServerLevel;
11+
import org.spongepowered.asm.mixin.Mixin;
12+
import org.spongepowered.asm.mixin.injection.At;
13+
14+
@Mixin(ContinuationFrame.Companion.class)
15+
public class MixinContinuationFrameCompanion {
16+
@ModifyReturnValue(method = "fromNBT", at = @At("RETURN"))
17+
private ContinuationFrame caduceus$deserializeMark(ContinuationFrame frame, CompoundTag tag, ServerLevel world) {
18+
if (
19+
frame instanceof ContinuationMarkHolder holder
20+
&& tag.contains(ContinuationUtils.getMarkTagKey(), Tag.TAG_COMPOUND)
21+
// CURSED: pass the frame through serialization to detect singletons
22+
&& frame.getType().deserializeFromNBT(frame.serializeToNBT(), world) != frame
23+
) {
24+
var markTag = tag.getCompound(ContinuationUtils.getMarkTagKey());
25+
var mark = IotaType.deserialize(markTag, world);
26+
holder.caduceus$setMark(mark);
27+
}
28+
return frame;
29+
}
30+
31+
@ModifyReturnValue(method = "toNBT", at = @At("RETURN"))
32+
private CompoundTag caduceus$serializeMark(CompoundTag tag, ContinuationFrame frame) {
33+
if (frame instanceof ContinuationMarkHolder holder) {
34+
var markTag = IotaType.serialize(holder.caduceus$getMark());
35+
tag.put(ContinuationUtils.getMarkTagKey(), markTag);
36+
}
37+
return tag;
38+
}
39+
}

common/src/main/java/gay/object/caduceus/mixin/frames/MixinFrameEvaluate.java

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

common/src/main/java/gay/object/caduceus/mixin/frames/MixinFrameEvaluateType.java

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

common/src/main/java/gay/object/caduceus/mixin/frames/MixinFrameForEach.java

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

0 commit comments

Comments
 (0)