1
- using System ;
2
- using System . Collections ;
3
1
using System . Collections . Generic ;
4
2
using System . Reflection ;
5
3
using Celeste ;
6
4
using Mono . Cecil . Cil ;
7
5
using Monocle ;
6
+ using MonoMod . Utils ;
8
7
using TAS . Module ;
9
8
using TAS . Utils ;
10
9
11
- namespace TAS . Input . Commands ;
10
+ namespace TAS . Input . Commands ;
12
11
13
12
public static class SaveAndQuitReenterCommand {
14
- public enum SaveAndQuitReenterMode {
15
- Input ,
16
- Simulate
17
- }
18
-
19
- public class LevelReenter : Scene {
20
- public LevelReenter ( Session session ) {
21
- AreaData . Get ( session ) . RestoreASideAreaData ( ) ;
22
- }
23
-
24
- public override void Begin ( ) {
25
- base . Begin ( ) ;
26
-
27
- Entity routine = new ( ) { new Coroutine ( Routine ( ) ) } ;
28
- Add ( routine ) ;
29
- Add ( new HudRenderer ( ) ) ;
30
- }
31
-
32
- private IEnumerator Routine ( ) {
33
- UserIO . SaveHandler ( file : true , settings : true ) ;
34
- while ( UserIO . Saving ) yield return null ;
35
- while ( SaveLoadIcon . OnScreen ) yield return null ;
36
-
37
- int slot = SaveData . Instance . FileSlot ;
38
- var saveData = UserIO . Load < SaveData > ( SaveData . GetFilename ( slot ) ) ;
39
- SaveData . Start ( saveData , slot ) ;
40
-
41
- LevelEnter . Go ( SaveData . Instance . CurrentSession , fromSaveData : true ) ;
42
- }
43
- }
44
-
45
- private static bool justPressedSnQ = false ;
46
- public static SaveAndQuitReenterMode ? LocalMode ;
47
- public static SaveAndQuitReenterMode ? GlobalModeParsing ;
48
- public static SaveAndQuitReenterMode ? GlobalModeRuntime ;
49
-
50
- private static SaveAndQuitReenterMode Mode {
51
- get {
52
- if ( LibTasHelper . Exporting ) {
53
- return SaveAndQuitReenterMode . Input ;
54
- }
55
-
56
- if ( EnforceLegalCommand . EnabledWhenParsing ) {
57
- return SaveAndQuitReenterMode . Input ;
58
- }
59
-
60
- SaveAndQuitReenterMode ? globalMode = ParsingCommand ? GlobalModeParsing : GlobalModeRuntime ;
61
- return LocalMode ?? globalMode ?? SaveAndQuitReenterMode . Simulate ;
62
- }
63
- }
13
+ private static bool justPressedSnQ ;
64
14
65
15
private static int ActiveFileSlot {
66
16
get {
67
17
if ( LibTasHelper . Exporting ) {
68
18
return 0 ;
69
19
}
70
-
20
+
71
21
if ( Engine . Scene is Overworld { Current : OuiFileSelect select } ) {
72
22
return select . SlotIndex ;
73
23
}
@@ -77,137 +27,94 @@ private static int ActiveFileSlot {
77
27
}
78
28
79
29
private static bool preventClear = false ;
30
+
80
31
// Contains which slot was used for each command, to ensure that inputs before the current frame stay the same
81
32
public static Dictionary < int , int > InsertedSlots = new ( ) ;
82
-
33
+
83
34
[ Load ]
84
35
private static void Load ( ) {
85
36
typeof ( Level )
86
37
. GetNestedType ( "<>c__DisplayClass149_0" , BindingFlags . NonPublic )
87
38
. GetMethod ( "<Pause>b__8" , BindingFlags . NonPublic | BindingFlags . Instance )
88
39
. IlHook ( ( cursor , _ ) => cursor . Emit ( OpCodes . Ldc_I4_1 )
89
40
. Emit ( OpCodes . Stsfld , typeof ( SaveAndQuitReenterCommand ) . GetFieldInfo ( nameof ( justPressedSnQ ) ) ) ) ;
90
-
41
+
91
42
typeof ( Level ) . GetMethod ( "Update" ) . IlHook ( ( cursor , _ ) => cursor . Emit ( OpCodes . Ldc_I4_0 )
92
- . Emit ( OpCodes . Stsfld , typeof ( SaveAndQuitReenterCommand ) . GetFieldInfo ( nameof ( justPressedSnQ ) ) ) ) ;
43
+ . Emit ( OpCodes . Stsfld , typeof ( SaveAndQuitReenterCommand ) . GetFieldInfo ( nameof ( justPressedSnQ ) ) ) ) ;
93
44
}
94
45
95
46
[ ClearInputs ]
96
47
private static void Clear ( ) {
97
- if ( preventClear ) return ;
98
48
InsertedSlots . Clear ( ) ;
99
49
}
100
50
101
- [ ClearInputs ]
102
- [ ParseFileEnd ]
103
- private static void ParseFileEnd ( ) {
104
- GlobalModeParsing = null ;
105
- }
106
-
107
51
[ DisableRun ]
108
52
private static void DisableRun ( ) {
109
- LocalMode = null ;
110
- GlobalModeRuntime = null ;
111
53
justPressedSnQ = false ;
112
54
}
113
-
55
+
114
56
[ TasCommand ( "SaveAndQuitReenter" , ExecuteTiming = ExecuteTiming . Parse | ExecuteTiming . Runtime ) ]
115
57
private static void SaveAndQuitReenter ( string [ ] args , int studioLine , string filePath , int fileLine ) {
116
- LocalMode = null ;
58
+ InputController controller = Manager . Controller ;
117
59
118
- if ( args . IsNotEmpty ( ) ) {
119
- if ( Enum . TryParse ( args [ 0 ] , true , out SaveAndQuitReenterMode value ) ) {
120
- LocalMode = value ;
121
- } else if ( ParsingCommand ) {
122
- AbortTas ( "SaveAndQuitReenter command failed. \n Mode must be Input or Simulate" ) ;
123
- return ;
60
+ if ( ParsingCommand ) {
61
+ int slot = ActiveFileSlot ;
62
+ if ( InsertedSlots . TryGetValue ( studioLine , out int prevSlot ) ) {
63
+ slot = prevSlot ;
64
+ } else {
65
+ InsertedSlots [ studioLine ] = slot ;
124
66
}
125
- }
126
67
127
- if ( ParsingCommand ) {
128
- if ( Mode == SaveAndQuitReenterMode . Simulate ) {
129
- // Wait for the Save & Quit wipe
130
- Manager . Controller . AddFrames ( "32" , studioLine ) ;
68
+ bool isSafe = SafeCommand . DisallowUnsafeInputParsing ;
69
+
70
+ LibTasHelper . AddInputFrame ( "58" ) ;
71
+ controller . AddFrames ( "31" , studioLine ) ;
72
+ Command . TryParse ( controller , filePath , fileLine , "Unsafe" , controller . CurrentParsingFrame , studioLine , out _ ) ;
73
+ controller . AddFrames ( "14" , studioLine ) ;
74
+ if ( slot == - 1 ) {
75
+ // Load debug slot
76
+ controller . AddFrames ( "1,D" , studioLine ) ;
77
+ controller . AddFrames ( "1,O" , studioLine ) ;
78
+ controller . AddFrames ( "33" , studioLine ) ;
131
79
} else {
132
- if ( SafeCommand . DisallowUnsafeInputParsing ) {
133
- AbortTas ( "\" SaveAndQuitReenter, Input\" requires unsafe inputs" ) ;
134
- return ;
135
- }
136
-
137
- int slot = ActiveFileSlot ;
138
- if ( InsertedSlots . TryGetValue ( studioLine , out int prevSlot ) ) {
139
- slot = prevSlot ;
80
+ // Get to the save files screen
81
+ controller . AddFrames ( "1,O" , studioLine ) ;
82
+ controller . AddFrames ( "56" , studioLine ) ;
83
+ // Alternate 1,D and 1,F,180 to select the slot
84
+ for ( int i = 0 ; i < slot ; i ++ ) {
85
+ controller . AddFrames ( i % 2 == 0 ? "1,D" : "1,F,180" , studioLine ) ;
140
86
}
141
87
142
- LibTasHelper . AddInputFrame ( "58" ) ;
143
- Manager . Controller . AddFrames ( "31" , studioLine ) ;
144
- Manager . Controller . AddFrames ( "14" , studioLine ) ;
145
-
146
- if ( slot == - 1 ) {
147
- // Load debug slot
148
- Manager . Controller . AddFrames ( "1,D" , studioLine ) ;
149
- Manager . Controller . AddFrames ( "1,O" , studioLine ) ;
150
- Manager . Controller . AddFrames ( "33" , studioLine ) ;
151
- } else {
152
- // Get to the save files screen
153
- Manager . Controller . AddFrames ( "1,O" , studioLine ) ;
154
- Manager . Controller . AddFrames ( "56" , studioLine ) ;
155
- // Alternate 1,D and 1,F,180 to select the slot
156
- for ( int i = 0 ; i < slot ; i ++ ) {
157
- Manager . Controller . AddFrames ( i % 2 == 0 ? "1,D" : "1,F,180" , studioLine ) ;
158
- }
159
- // Load the selected save file
160
- Manager . Controller . AddFrames ( "1,O" , studioLine ) ;
161
- Manager . Controller . AddFrames ( "14" , studioLine ) ;
162
- Manager . Controller . AddFrames ( "1,O" , studioLine ) ;
163
- Manager . Controller . AddFrames ( "1" , studioLine ) ;
164
- LibTasHelper . AddInputFrame ( "32" ) ;
165
- }
88
+ // Load the selected save file
89
+ controller . AddFrames ( "1,O" , studioLine ) ;
90
+ controller . AddFrames ( "14" , studioLine ) ;
91
+ controller . AddFrames ( "1,O" , studioLine ) ;
92
+ controller . AddFrames ( "1" , studioLine ) ;
93
+ LibTasHelper . AddInputFrame ( "32" ) ;
94
+ }
166
95
167
- InsertedSlots [ studioLine ] = slot ;
96
+ Command . TryParse ( controller , filePath , fileLine , isSafe ? "Safe" : "Unsafe" , controller . CurrentParsingFrame , studioLine , out _ ) ;
97
+ } else {
98
+ if ( ! justPressedSnQ ) {
99
+ AbortTas ( "SaveAndQuitReenter must be exactly after pressing the \" Save & Quit\" button" ) ;
100
+ return ;
168
101
}
169
-
170
- return ;
171
- }
172
102
173
- if ( ! justPressedSnQ ) {
174
- AbortTas ( "SaveAndQuitReenter must be exactly after pressing the \" Save & Quit\" button" ) ;
175
- return ;
176
- }
177
-
178
- if ( Engine . Scene is not Level level ) {
179
- AbortTas ( "SaveAndQuitReenter can't be used outside levels" ) ;
180
- return ;
181
- }
103
+ if ( Engine . Scene is not Level level ) {
104
+ AbortTas ( "SaveAndQuitReenter can't be used outside levels" ) ;
105
+ return ;
106
+ }
182
107
183
- if ( Mode == SaveAndQuitReenterMode . Simulate ) {
184
- // Replace the Save & Quit wipe with our work action
185
- level . Wipe . OnComplete = delegate {
186
- Engine . Scene = new LevelReenter ( level . Session ) ;
187
- } ;
188
- } else {
189
108
// Re-insert inputs of the save file slot changed
190
109
if ( InsertedSlots . TryGetValue ( studioLine , out int slot ) && slot != ActiveFileSlot ) {
191
110
InsertedSlots [ studioLine ] = ActiveFileSlot ;
192
- // Avoid clearing our InsertedSlots info
193
- preventClear = true ;
194
- Manager . Controller . NeedsReload = true ;
195
- Manager . Controller . RefreshInputs ( enableRun : false ) ;
196
- preventClear = false ;
197
- }
198
- }
199
- }
200
-
201
- [ TasCommand ( "SaveAndQuitReenterMode" , ExecuteTiming = ExecuteTiming . Parse | ExecuteTiming . Runtime ) ]
202
- private static void StunPauseCommandMode ( string [ ] args ) {
203
- if ( args . IsNotEmpty ( ) && Enum . TryParse ( args [ 0 ] , true , out SaveAndQuitReenterMode value ) ) {
204
- if ( ParsingCommand ) {
205
- GlobalModeParsing = value ;
206
- } else {
207
- GlobalModeRuntime = value ;
111
+ // Avoid clearing our InsertedSlots info when RefreshInputs()
112
+ Dictionary < int , int > backup = new ( InsertedSlots ) ;
113
+ controller . NeedsReload = true ;
114
+ controller . RefreshInputs ( enableRun : false ) ;
115
+ InsertedSlots . Clear ( ) ;
116
+ InsertedSlots . AddRange ( backup ) ;
208
117
}
209
- } else if ( ParsingCommand ) {
210
- AbortTas ( "SaveAndQuitReenterMode command failed.\n Mode must be Input or Simulate" ) ;
211
118
}
212
119
}
213
120
}
0 commit comments