66import ch .njol .skript .doc .Example ;
77import ch .njol .skript .doc .Name ;
88import ch .njol .skript .doc .Since ;
9- import ch .njol .skript .lang .Effect ;
9+ import ch .njol .skript .lang .EffectSection ;
1010import ch .njol .skript .lang .Expression ;
1111import ch .njol .skript .lang .Literal ;
12- import ch .njol .skript .lang .Section ;
1312import ch .njol .skript .lang .SkriptParser .ParseResult ;
1413import ch .njol .skript .lang .Trigger ;
1514import ch .njol .skript .lang .TriggerItem ;
4847 send "...and goodbye" to player
4948 """ )
5049@ Since ("1.4, 2.15" )
51- public class Delay extends Effect {
50+ public class Delay extends EffectSection {
5251
5352 static {
54- Skript .registerEffect (Delay .class , "(wait|halt) [for] %timespan%" );
55- Skript .registerSection (DelaySection .class , "(wait|halt) [for] %timespan%" );
53+ Skript .registerSection (Delay .class , "(wait|halt) [for] %timespan%" );
5654 }
5755
5856 @ SuppressWarnings ("NotNullFieldNotInitialized" )
5957 protected Expression <Timespan > duration ;
6058
59+ private @ Nullable Trigger trigger ;
60+
6161 @ SuppressWarnings ({"unchecked" , "null" })
6262 @ Override
63- public boolean init (Expression <?>[] exprs , int matchedPattern , Kleenean isDelayed , ParseResult parseResult ) {
64- getParser ().setHasDelayBefore (Kleenean .TRUE );
65-
63+ public boolean init (Expression <?>[] exprs , int matchedPattern , Kleenean isDelayed , ParseResult parseResult ,
64+ @ Nullable SectionNode sectionNode , @ Nullable List <TriggerItem > triggerItems ) {
6665 duration = (Expression <Timespan >) exprs [0 ];
6766 if (duration instanceof Literal ) { // If we can, do sanity check for delays
6867 Timespan timespan = ((Literal <Timespan >) duration ).getSingle ();
@@ -76,53 +75,91 @@ public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean isDelaye
7675 }
7776 }
7877
78+ if (hasSection ()) {
79+ assert sectionNode != null ;
80+ // Parse the body under the outer event context so event values still resolve inside it.
81+ // Locals are isolated at runtime via the swap dance in walk().
82+ Class <? extends Event >[] outerEvents = getParser ().getCurrentEvents ();
83+ Runnable beforeLoading = () -> getParser ().setHasDelayBefore (Kleenean .TRUE );
84+ trigger = loadCode (sectionNode , "wait" , beforeLoading , null , outerEvents );
85+ // Outer trigger is NOT delayed - code after the section runs immediately.
86+ return trigger != null ;
87+ }
88+
89+ getParser ().setHasDelayBefore (Kleenean .TRUE );
7990 return true ;
8091 }
8192
8293 @ Override
83- @ Nullable
84- protected TriggerItem walk (Event event ) {
94+ protected @ Nullable TriggerItem walk (Event event ) {
8595 debug (event , true );
8696 long start = Skript .debug () ? System .nanoTime () : 0 ;
87- TriggerItem next = getNext ();
88- if (next != null && Skript .getInstance ().isEnabled ()) { // See https://github.com/SkriptLang/Skript/issues/3702
8997
90- Timespan duration = this .duration .getSingle (event );
91- if (duration == null )
92- return null ;
98+ if (!Skript .getInstance ().isEnabled ()) // See https://github.com/SkriptLang/Skript/issues/3702
99+ return trigger != null ? super .walk (event , false ) : null ;
100+
101+ Timespan duration = this .duration .getSingle (event );
102+ if (duration == null )
103+ return trigger != null ? super .walk (event , false ) : null ;
104+
105+ long ticks = Math .max (duration .getAs (Timespan .TimePeriod .TICK ), 1 ); // Minimum delay is one tick, less than it is useless!
106+
107+ if (trigger != null ) {
108+
109+ Object snapshot = Variables .copyLocalVariables (event );
110+ Trigger body = trigger ;
111+ Bukkit .getScheduler ().scheduleSyncDelayedTask (Skript .getInstance (), () -> {
112+ Skript .debug (getIndentation () + "... running delayed section after " + (System .nanoTime () - start ) / 1_000_000_000. + "s" );
113+
93114
94- // Back up local variables
115+ Object outerLocals = Variables .removeLocals (event );
116+ if (snapshot != null )
117+ Variables .setLocalVariables (event , snapshot );
118+
119+ Object timing = null ;
120+ if (SkriptTimings .enabled ()) {
121+ Trigger parentTrigger = getTrigger ();
122+ if (parentTrigger != null )
123+ timing = SkriptTimings .start (parentTrigger .getDebugLabel ());
124+ }
125+ try {
126+ TriggerItem .walk (body , event );
127+ } finally {
128+ Variables .setLocalVariables (event , outerLocals );
129+ SkriptTimings .stop (timing ); // Stop timing if it was even started
130+ }
131+ }, ticks );
132+ return super .walk (event , false );
133+ }
134+
135+
136+ TriggerItem next = getNext ();
137+ if (next != null ) {
95138 Object localVars = Variables .removeLocals (event );
96139
97140 Bukkit .getScheduler ().scheduleSyncDelayedTask (Skript .getInstance (), () -> {
98141 addDelayedEvent (event );
99142 Skript .debug (getIndentation () + "... continuing after " + (System .nanoTime () - start ) / 1_000_000_000. + "s" );
100143
101- // Re-set local variables
102144 if (localVars != null )
103145 Variables .setLocalVariables (event , localVars );
104146
105- Object timing = null ; // Timings reference must be kept so that it can be stopped after TriggerItem execution
106- if (SkriptTimings .enabled ()) { // getTrigger call is not free, do it only if we must
107- Trigger trigger = getTrigger ();
108- if (trigger != null )
109- timing = SkriptTimings .start (trigger .getDebugLabel ());
147+ Object timing = null ;
148+ if (SkriptTimings .enabled ()) {
149+ Trigger parentTrigger = getTrigger ();
150+ if (parentTrigger != null )
151+ timing = SkriptTimings .start (parentTrigger .getDebugLabel ());
110152 }
111153
112154 TriggerItem .walk (next , event );
113155 Variables .removeLocals (event ); // Clean up local vars, we may be exiting now
114156
115- SkriptTimings .stop (timing ); // Stop timing if it was even started
116- }, Math . max ( duration . getAs ( Timespan . TimePeriod . TICK ), 1 )); // Minimum delay is one tick, less than it is useless!
157+ SkriptTimings .stop (timing );
158+ }, ticks );
117159 }
118160 return null ;
119161 }
120162
121- @ Override
122- protected void execute (Event event ) {
123- throw new UnsupportedOperationException ();
124- }
125-
126163 @ Override
127164 public String toString (@ Nullable Event event , boolean debug ) {
128165 return "wait for " + duration .toString (event , debug ) + (event == null ? "" : "..." );
@@ -140,95 +177,12 @@ public static boolean isDelayed(Event event) {
140177 return DELAYED .contains (event );
141178 }
142179
143- /**
144- * Section form of {@link Delay}. The body is deferred and executed on the same event after the
145- * delay elapses; code after the section continues immediately in the outer trigger.
146- */
147- public static class DelaySection extends Section {
148-
149- @ SuppressWarnings ("NotNullFieldNotInitialized" )
150- private Expression <Timespan > duration ;
151- private Trigger trigger ;
152-
153- @ Override
154- @ SuppressWarnings ("unchecked" )
155- public boolean init (Expression <?>[] exprs , int matchedPattern , Kleenean isDelayed ,
156- ParseResult parseResult , SectionNode sectionNode , List <TriggerItem > triggerItems ) {
157- duration = (Expression <Timespan >) exprs [0 ];
158- if (duration instanceof Literal ) { // If we can, do sanity check for delays
159- Timespan timespan = ((Literal <Timespan >) duration ).getSingle ();
160- if (timespan .isInfinite ()) {
161- Skript .error ("Delaying for an eternity is not allowed. Use the 'stop' effect instead." );
162- return false ;
163- }
164- long millis = timespan .getAs (Timespan .TimePeriod .MILLISECOND );
165- if (millis < 50 ) {
166- Skript .warning ("Delays less than one tick are not possible, defaulting to one tick." );
167- }
168- }
169-
170- // Parse the body under the outer event context so event values still resolve inside it.
171- // Locals are isolated at runtime via the swap dance in walk().
172- Class <? extends Event >[] outerEvents = getParser ().getCurrentEvents ();
173- Runnable beforeLoading = () -> getParser ().setHasDelayBefore (Kleenean .TRUE );
174- trigger = loadCode (sectionNode , "wait" , beforeLoading , null , outerEvents );
175- // Outer trigger is NOT delayed - code after the section runs immediately.
176- return trigger != null ;
177- }
178-
179- @ Override
180- protected @ Nullable TriggerItem walk (Event event ) {
181- debug (event , true );
182- long start = Skript .debug () ? System .nanoTime () : 0 ;
183-
184- if (!Skript .getInstance ().isEnabled ()) // See https://github.com/SkriptLang/Skript/issues/3702
185- return walk (event , false );
186-
187- Timespan duration = this .duration .getSingle (event );
188- if (duration == null )
189- return walk (event , false );
190-
191- long ticks = Math .max (duration .getAs (Timespan .TimePeriod .TICK ), 1 ); // Minimum delay is one tick, less than it is useless!
192-
193- Object snapshot = Variables .copyLocalVariables (event );
194- Trigger body = trigger ;
195- Bukkit .getScheduler ().scheduleSyncDelayedTask (Skript .getInstance (), () -> {
196- Skript .debug (getIndentation () + "... running delayed section after " + (System .nanoTime () - start ) / 1_000_000_000. + "s" );
197-
198- // Swap outer locals with the snapshot taken when the section was scheduled,
199- // so the body sees its own isolated copy and doesn't leak into the outer trigger.
200- Object outerLocals = Variables .removeLocals (event );
201- if (snapshot != null )
202- Variables .setLocalVariables (event , snapshot );
203-
204- Object timing = null ;
205- if (SkriptTimings .enabled ()) {
206- Trigger parentTrigger = getTrigger ();
207- if (parentTrigger != null )
208- timing = SkriptTimings .start (parentTrigger .getDebugLabel ());
209- }
210- try {
211- TriggerItem .walk (body , event );
212- } finally {
213- Variables .setLocalVariables (event , outerLocals );
214- SkriptTimings .stop (timing );
215- }
216- }, ticks );
217- return walk (event , false );
218- }
219-
220- @ Override
221- public String toString (@ Nullable Event event , boolean debug ) {
222- return "wait for " + duration .toString (event , debug ) + (event == null ? "" : "..." );
223- }
224-
225- }
226-
227180 /**
228181 * The main method for marking the execution of {@link TriggerItem}s as delayed.
229182 * @param event The event to mark as delayed.
230183 */
231184 public static void addDelayedEvent (Event event ) {
232185 DELAYED .add (event );
233186 }
187+
234188}
0 commit comments