Skip to content

Commit 5022cd4

Browse files
committed
Add methods to clear interactive and non-interactive script queues
1 parent 6569750 commit 5022cd4

File tree

8 files changed

+252
-12
lines changed

8 files changed

+252
-12
lines changed

CHANGES

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
[1.8.5]
2+
- Add methods to clear interactive and non-interactive script queues
3+
14
[1.8.4]
25
- Fix regression in 1.8.3. Updated unit tests.
36

core/src/main/java/org/mini2Dx/miniscript/core/GameScriptingEngine.java

Lines changed: 97 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@
2727
import org.mini2Dx.lockprovider.jvm.JvmLocks;
2828
import org.mini2Dx.miniscript.core.exception.InsufficientCompilersException;
2929
import org.mini2Dx.miniscript.core.exception.NoSuchScriptException;
30+
import org.mini2Dx.miniscript.core.notification.ScriptCancelledNotification;
3031
import org.mini2Dx.miniscript.core.notification.ScriptNotification;
32+
import org.mini2Dx.miniscript.core.notification.ScriptSkippedNotification;
3133
import org.mini2Dx.miniscript.core.threadpool.DefaultThreadPoolProvider;
3234
import org.mini2Dx.miniscript.core.util.ReadWriteArrayQueue;
3335
import org.mini2Dx.miniscript.core.util.ReadWriteMap;
@@ -471,35 +473,110 @@ public void cancelAllQueuedGameFutures() {
471473
* Removes all currently queued {@link GameFuture}s without sending skipFuture event
472474
*/
473475
public void cancelAllQueuedScripts() {
474-
scriptInvocationQueue.clear();
476+
cancelAllQueuedScripts(true);
477+
}
478+
479+
/**
480+
* Removes all currently queued {@link GameFuture}s without sending skipFuture event
481+
* @param notifyListeners If true will notify invocation listeners of script cancellation
482+
*/
483+
public void cancelAllQueuedScripts(boolean notifyListeners) {
484+
if(!notifyListeners) {
485+
scriptInvocationQueue.clear();
486+
return;
487+
}
488+
489+
final List<ScriptInvocation> scriptInvocations = new ArrayList<>();
490+
scriptInvocationQueue.clear(scriptInvocations);
491+
notifyScriptCancelled(scriptInvocations);
475492
}
476493

477494
/**
478495
* Removes all currently queued scripts with a given script ID
479496
*/
480497
public void cancelQueuedScript(int scriptId) {
481-
scriptInvocationQueue.cancelByScriptId(scriptId);
498+
cancelQueuedScript(scriptId, true);
482499
}
483500

484501
/**
485502
* Removes a specific queued script by its task ID
486503
*/
487504
public void cancelQueuedScriptByTaskId(int taskId) {
488-
scriptInvocationQueue.cancelByTaskId(taskId);
505+
cancelQueuedScriptByTaskId(taskId, true);
506+
}
507+
508+
/**
509+
* Removes all currently queued scripts with a given script ID
510+
* @param notifyListeners If true will notify invocation listeners of script cancellation
511+
*/
512+
public void cancelQueuedScript(int scriptId, boolean notifyListeners) {
513+
final List<ScriptInvocation> scriptInvocations = new ArrayList<>();
514+
scriptInvocationQueue.cancelByScriptId(scriptId, scriptInvocations);
515+
if(!notifyListeners) {
516+
scriptInvocations.clear();
517+
return;
518+
}
519+
520+
notifyScriptCancelled(scriptInvocations);
521+
}
522+
523+
/**
524+
* Removes a specific queued script by its task ID
525+
* @param notifyListeners If true will notify invocation listeners of script cancellation
526+
*/
527+
public void cancelQueuedScriptByTaskId(int taskId, boolean notifyListeners) {
528+
final List<ScriptInvocation> scriptInvocations = new ArrayList<>();
529+
scriptInvocationQueue.cancelByTaskId(taskId, scriptInvocations);
530+
if(!notifyListeners) {
531+
scriptInvocations.clear();
532+
return;
533+
}
534+
535+
notifyScriptCancelled(scriptInvocations);
489536
}
490537

491538
/**
492539
* Clears all interactive scripts queued
493540
*/
494541
public void cancelAllQueuedInteractiveScripts() {
495-
scriptInvocationQueue.clearInteractiveScriptQueue();
542+
cancelAllQueuedInteractiveScripts(true);
496543
}
497544

498545
/**
499546
* Clears all non-interactive scripts queued
500547
*/
501548
public void cancelAllQueuedNonInteractiveScripts() {
502-
scriptInvocationQueue.clearNonInteractiveScriptQueue();
549+
cancelAllQueuedNonInteractiveScripts(true);
550+
}
551+
552+
/**
553+
* Clears all interactive scripts queued
554+
* @param notifyListeners If true will send the scriptSkipped event any listener associated with a cancelled invoke
555+
*/
556+
public void cancelAllQueuedInteractiveScripts(boolean notifyListeners) {
557+
if(!notifyListeners) {
558+
scriptInvocationQueue.clearInteractiveScriptQueue();
559+
return;
560+
}
561+
562+
final List<ScriptInvocation> scriptInvocations = new ArrayList<>();
563+
scriptInvocationQueue.clearInteractiveScriptQueue(scriptInvocations);
564+
notifyScriptCancelled(scriptInvocations);
565+
}
566+
567+
/**
568+
* Clears all non-interactive scripts queued
569+
* @param notifyListeners If true will send the scriptSkipped event any listener associated with a cancelled invoke
570+
*/
571+
public void cancelAllQueuedNonInteractiveScripts(boolean notifyListeners) {
572+
if(!notifyListeners) {
573+
scriptInvocationQueue.clearNonInteractiveScriptQueue();
574+
return;
575+
}
576+
577+
final List<ScriptInvocation> scriptInvocations = new ArrayList<>();
578+
scriptInvocationQueue.clearNonInteractiveScriptQueue(scriptInvocations);
579+
notifyScriptCancelled(scriptInvocations);
503580
}
504581

505582
/**
@@ -835,4 +912,19 @@ public void setCancelReallocatedFutures(boolean cancelReallocatedFutures) {
835912
}
836913

837914

915+
private void notifyScriptCancelled(List<ScriptInvocation> scriptInvocations) {
916+
for(ScriptInvocation invocation : scriptInvocations) {
917+
if(invocation.getInvocationListener() == null) {
918+
return;
919+
}
920+
final ScriptInvocationListener invocationListener = invocation.getInvocationListener();
921+
if(invocationListener.callOnGameThread()) {
922+
scriptNotifications
923+
.offer(new ScriptCancelledNotification(invocationListener, invocation.getScriptId()));
924+
} else {
925+
invocationListener.onScriptCancelled(invocation.getScriptId());
926+
}
927+
}
928+
scriptInvocations.clear();
929+
}
838930
}

core/src/main/java/org/mini2Dx/miniscript/core/ScriptInvocationListener.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,14 @@ public default void onScriptBegin(int scriptId) {
3838

3939
}
4040

41+
/**
42+
* Called when a script is cancelled while in the invoke queue.
43+
*
44+
* @param scriptId The script id
45+
*/
46+
public default void onScriptCancelled(int scriptId) {
47+
}
48+
4149
/**
4250
* Called when a script successfully completes
4351
*
@@ -49,7 +57,7 @@ public default void onScriptBegin(int scriptId) {
4957
public void onScriptSuccess(int scriptId, ScriptExecutionResult executionResult);
5058

5159
/**
52-
* Called when a script is skipped
60+
* Called when a script is skipped during execution
5361
*
5462
* @param scriptId
5563
* The script id
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/**
2+
* Copyright 2021 Viridian Software Ltd.
3+
*/
4+
package org.mini2Dx.miniscript.core.notification;
5+
6+
import org.mini2Dx.miniscript.core.ScriptInvocationListener;
7+
8+
public class ScriptCancelledNotification implements ScriptNotification {
9+
private final ScriptInvocationListener invocationListener;
10+
private final int scriptId;
11+
12+
public ScriptCancelledNotification(ScriptInvocationListener invocationListener, int scriptId) {
13+
this.invocationListener = invocationListener;
14+
this.scriptId = scriptId;
15+
}
16+
17+
@Override
18+
public void process() {
19+
invocationListener.onScriptCancelled(scriptId);
20+
}
21+
}

core/src/main/java/org/mini2Dx/miniscript/core/util/ScriptInvocationQueue.java

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import org.mini2Dx.miniscript.core.GameScriptingEngine;
99
import org.mini2Dx.miniscript.core.ScriptInvocation;
1010

11+
import java.util.List;
1112
import java.util.PriorityQueue;
1213
import java.util.Queue;
1314
import java.util.concurrent.atomic.AtomicBoolean;
@@ -92,12 +93,28 @@ public void clear() {
9293
super.clear();
9394
}
9495

95-
public void cancelByScriptId(int scriptId) {
96+
public void clear(List<ScriptInvocation> results) {
97+
interactiveScriptLock.lockWrite();
98+
results.addAll(interactiveScriptQueue);
99+
interactiveScriptQueue.clear();
100+
interactiveScriptLock.unlockWrite();
101+
102+
lock.lockWrite();
103+
results.addAll(internalQueue);
104+
internalQueue.clear();
105+
lock.unlockWrite();
106+
}
107+
108+
public void cancelByScriptId(int scriptId, List<ScriptInvocation> results) {
96109
interactiveScriptLock.lockWrite();
97110
interactiveScriptQueue.removeIf(new Predicate<ScriptInvocation>() {
98111
@Override
99112
public boolean test(ScriptInvocation scriptInvocation) {
100-
return scriptInvocation.getScriptId() == scriptId;
113+
if(scriptInvocation.getScriptId() == scriptId) {
114+
results.add(scriptInvocation);
115+
return true;
116+
}
117+
return false;
101118
}
102119
});
103120
interactiveScriptLock.unlockWrite();
@@ -106,18 +123,26 @@ public boolean test(ScriptInvocation scriptInvocation) {
106123
internalQueue.removeIf(new Predicate<ScriptInvocation>() {
107124
@Override
108125
public boolean test(ScriptInvocation scriptInvocation) {
109-
return scriptInvocation.getScriptId() == scriptId;
126+
if(scriptInvocation.getScriptId() == scriptId) {
127+
results.add(scriptInvocation);
128+
return true;
129+
}
130+
return false;
110131
}
111132
});
112133
lock.unlockWrite();
113134
}
114135

115-
public void cancelByTaskId(int taskId) {
136+
public void cancelByTaskId(int taskId, List<ScriptInvocation> results) {
116137
interactiveScriptLock.lockWrite();
117138
interactiveScriptQueue.removeIf(new Predicate<ScriptInvocation>() {
118139
@Override
119140
public boolean test(ScriptInvocation scriptInvocation) {
120-
return scriptInvocation.getTaskId() == taskId;
141+
if(scriptInvocation.getTaskId() == taskId) {
142+
results.add(scriptInvocation);
143+
return true;
144+
}
145+
return false;
121146
}
122147
});
123148
interactiveScriptLock.unlockWrite();
@@ -126,7 +151,11 @@ public boolean test(ScriptInvocation scriptInvocation) {
126151
internalQueue.removeIf(new Predicate<ScriptInvocation>() {
127152
@Override
128153
public boolean test(ScriptInvocation scriptInvocation) {
129-
return scriptInvocation.getTaskId() == taskId;
154+
if(scriptInvocation.getTaskId() == taskId) {
155+
results.add(scriptInvocation);
156+
return true;
157+
}
158+
return false;
130159
}
131160
});
132161
lock.unlockWrite();
@@ -144,6 +173,20 @@ public void clearNonInteractiveScriptQueue() {
144173
lock.unlockWrite();
145174
}
146175

176+
public void clearInteractiveScriptQueue(List<ScriptInvocation> results) {
177+
interactiveScriptLock.lockWrite();
178+
results.addAll(interactiveScriptQueue);
179+
interactiveScriptQueue.clear();
180+
interactiveScriptLock.unlockWrite();
181+
}
182+
183+
public void clearNonInteractiveScriptQueue(List<ScriptInvocation> results) {
184+
lock.lockWrite();
185+
results.addAll(internalQueue);
186+
internalQueue.clear();
187+
lock.unlockWrite();
188+
}
189+
147190
public void clearInteractiveScriptStatus() {
148191
interactiveScriptLock.lockWrite();
149192
interactiveScriptRunning.set(false);

core/src/test/java/org/mini2Dx/miniscript/core/AbstractGameScriptingEngineTest.java

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,77 @@ public boolean callOnGameThread() {
366366
Assert.assertEquals(Thread.currentThread().getId(), notificationThreadId.get());
367367
}
368368

369+
@Test
370+
public void testScriptCancelNotification() throws Exception {
371+
scriptingEngine.invokeCompiledScript(scriptingEngine.compileScript(getWaitForCompletionScript()), scriptBindings);
372+
scriptingEngine.invokeCompiledScript(scriptingEngine.compileScript(getWaitForCompletionScript()), scriptBindings);
373+
374+
final int expectedScriptId = scriptingEngine.compileScript(getDefaultScript());
375+
final AtomicInteger cancelledScriptId = new AtomicInteger(-1);
376+
377+
scriptingEngine.invokeCompiledScript(expectedScriptId, scriptBindings, new ScriptInvocationListener() {
378+
379+
@Override
380+
public void onScriptSuccess(int scriptId, ScriptExecutionResult executionResult) {
381+
if(scriptId != expectedScriptId) {
382+
scriptResult.set(ScriptResult.INCORRECT_SCRIPT_ID);
383+
scriptExecuted.set(true);
384+
} else if(!checkExpectedScriptResults(executionResult)) {
385+
scriptResult.set(ScriptResult.INCORRECT_VARIABLES);
386+
scriptExecuted.set(true);
387+
} else {
388+
scriptResult.set(ScriptResult.SUCCESS);
389+
scriptExecuted.set(true);
390+
}
391+
}
392+
393+
@Override
394+
public void onScriptCancelled(int scriptId) {
395+
cancelledScriptId.set(scriptId);
396+
scriptResult.set(ScriptResult.CANCELLED);
397+
scriptExecuted.set(true);
398+
}
399+
400+
@Override
401+
public void onScriptSkipped(int scriptId) {
402+
scriptResult.set(ScriptResult.SKIPPED);
403+
scriptExecuted.set(true);
404+
}
405+
406+
@Override
407+
public void onScriptException(int scriptId, Exception e) {
408+
e.printStackTrace();
409+
scriptResult.set(ScriptResult.EXCEPTION);
410+
scriptExecuted.set(true);
411+
}
412+
413+
@Override
414+
public boolean callOnGameThread() {
415+
return true;
416+
}
417+
}, 0, false);
418+
419+
long timer = 0L;
420+
while(!scriptExecuted.get()) {
421+
long startTime = System.currentTimeMillis();
422+
scriptingEngine.update(1f);
423+
try {
424+
Thread.sleep(10);
425+
} catch (Exception e) {}
426+
timer += System.currentTimeMillis() - startTime;
427+
428+
if(timer >= 1000L) {
429+
scriptingEngine.cancelQueuedScript(expectedScriptId);
430+
}
431+
}
432+
Assert.assertEquals(ScriptResult.CANCELLED, scriptResult.get());
433+
Assert.assertEquals(true, gameFuture.isUpdated());
434+
Assert.assertEquals(true, gameFuture.waitOccurred());
435+
Assert.assertEquals(false, gameFuture.isFutureSkipped());
436+
Assert.assertEquals(false, gameFuture.isScriptSkipped());
437+
Assert.assertEquals(expectedScriptId, cancelledScriptId.get());
438+
}
439+
369440
@Test
370441
public void testWaitForCompletion() throws Exception {
371442
final int expectedScriptId = scriptingEngine.compileScript(getWaitForCompletionScript());

core/src/test/java/org/mini2Dx/miniscript/core/dummy/ScriptResult.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ public enum ScriptResult {
3030
NOT_EXECUTED,
3131
INCORRECT_SCRIPT_ID,
3232
INCORRECT_VARIABLES,
33+
CANCELLED,
3334
SUCCESS,
3435
SKIPPED,
3536
EXCEPTION

ruby/src/test/resources/default.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
beginNotificationResult = false
12
stringValue = stringValue + String.new("123")
23
intValue = 101
34
booleanValue = true

0 commit comments

Comments
 (0)