@@ -55,6 +55,8 @@ public abstract class GameScriptingEngine implements Runnable {
5555
5656 public static Locks LOCK_PROVIDER = new JvmLocks ();
5757
58+ private static final int DEFAULT_MAX_CONCURRENT_SCRIPTS = 2 ;
59+
5860 private final ScriptInvocationPool scriptInvocationPool = new ScriptInvocationPool ();
5961 private final ScriptInvocationQueue scriptInvocationQueue = new ScriptInvocationQueue ();
6062 final Queue <ScriptNotification > scriptNotifications = new ReadWriteArrayQueue <ScriptNotification >();
@@ -66,6 +68,8 @@ public abstract class GameScriptingEngine implements Runnable {
6668 private final Set <Integer > completedFutures = new HashSet <Integer >();
6769 private final Set <Integer > completedScripts = new HashSet <Integer >();
6870
71+ private final List <String > tmpRunningScripts = new ArrayList <>();
72+
6973 private final ThreadPoolProvider threadPoolProvider ;
7074 private final ScriptExecutorPool <?> scriptExecutorPool ;
7175
@@ -76,15 +80,15 @@ public abstract class GameScriptingEngine implements Runnable {
7680
7781 /**
7882 * Constructs a scripting engine backed by a thread pool with the maximum
79- * amount of concurrent scripts set to the amount of processors + 1 .
83+ * amount of concurrent scripts set to 2 .
8084 * Sandboxing is enabled if the implementation supports it.
8185 */
8286 public GameScriptingEngine () {
83- this (Runtime . getRuntime (). availableProcessors () + 1 );
87+ this (DEFAULT_MAX_CONCURRENT_SCRIPTS );
8488 }
8589
8690 public GameScriptingEngine (ThreadPoolProvider threadPoolProvider ) {
87- this (Runtime . getRuntime (). availableProcessors () + 1 , threadPoolProvider );
91+ this (DEFAULT_MAX_CONCURRENT_SCRIPTS , threadPoolProvider );
8892 }
8993
9094 /**
@@ -118,7 +122,7 @@ public GameScriptingEngine(ClasspathScriptProvider classpathScriptProvider, int
118122 scriptExecutorPool = createScriptExecutorPool (classpathScriptProvider , maxConcurrentScripts , isSandboxingSupported ());
119123
120124 threadPoolProvider = new DefaultThreadPoolProvider (maxConcurrentScripts + 1 );
121- init ();
125+ init (maxConcurrentScripts );
122126 }
123127
124128 public GameScriptingEngine (ClasspathScriptProvider classpathScriptProvider , int maxConcurrentScripts , ThreadPoolProvider threadPoolProvider ) {
@@ -127,7 +131,7 @@ public GameScriptingEngine(ClasspathScriptProvider classpathScriptProvider, int
127131 scriptExecutorPool = createScriptExecutorPool (classpathScriptProvider , maxConcurrentScripts , isSandboxingSupported ());
128132
129133 this .threadPoolProvider = threadPoolProvider ;
130- init ();
134+ init (maxConcurrentScripts );
131135 }
132136
133137 /**
@@ -147,16 +151,16 @@ public GameScriptingEngine(ThreadPoolProvider threadPoolProvider, boolean sandbo
147151
148152 /**
149153 * Constructs a scripting engine backed by a thread pool with the maximum
150- * amount of concurrent scripts set to the amount of processors + 1 .
154+ * amount of concurrent scripts set to 2 .
151155 * @param classpathScriptProvider The auto-generated {@link ClasspathScriptProvider} for the game
152156 * @param sandboxed True if script sandboxing should be enabled
153157 */
154158 public GameScriptingEngine (ClasspathScriptProvider classpathScriptProvider , boolean sandboxed ) {
155- this (classpathScriptProvider ,Runtime . getRuntime (). availableProcessors () + 1 , sandboxed );
159+ this (classpathScriptProvider ,DEFAULT_MAX_CONCURRENT_SCRIPTS , sandboxed );
156160 }
157161
158162 public GameScriptingEngine (ClasspathScriptProvider classpathScriptProvider , ThreadPoolProvider threadPoolProvider , boolean sandboxed ) {
159- this (classpathScriptProvider ,Runtime . getRuntime (). availableProcessors () + 1 , threadPoolProvider , sandboxed );
163+ this (classpathScriptProvider ,DEFAULT_MAX_CONCURRENT_SCRIPTS , threadPoolProvider , sandboxed );
160164 }
161165
162166 /**
@@ -192,7 +196,7 @@ public GameScriptingEngine(ClasspathScriptProvider classpathScriptProvider,
192196 scriptExecutorPool = createScriptExecutorPool (classpathScriptProvider , maxConcurrentScripts , sandboxed );
193197
194198 threadPoolProvider = new DefaultThreadPoolProvider (maxConcurrentScripts + 1 );
195- init ();
199+ init (maxConcurrentScripts );
196200 }
197201
198202 public GameScriptingEngine (ClasspathScriptProvider classpathScriptProvider ,
@@ -202,11 +206,13 @@ public GameScriptingEngine(ClasspathScriptProvider classpathScriptProvider,
202206 scriptExecutorPool = createScriptExecutorPool (classpathScriptProvider , maxConcurrentScripts , sandboxed );
203207
204208 this .threadPoolProvider = threadPoolProvider ;
205- init ();
209+ init (maxConcurrentScripts );
206210 }
207211
208- private void init () {
209- threadPoolProvider .submit (this );
212+ private void init (int maxConcurrentScripts ) {
213+ for (int i = 0 ; i < maxConcurrentScripts ; i ++) {
214+ threadPoolProvider .submit (this );
215+ }
210216 threadPoolProvider .scheduleAtFixedRate (new Runnable () {
211217 @ Override
212218 public void run () {
@@ -240,6 +246,13 @@ public void dispose(boolean interruptScripts) {
240246 cleanupTask = null ;
241247 }
242248 threadPoolProvider .shutdown (interruptScripts );
249+
250+ if (!interruptScripts ) {
251+ return ;
252+ }
253+ cancelAllQueuedScripts ();
254+ skipAllQueuedGameFutures ();
255+ skipAllScripts ();
243256 }
244257
245258 /**
@@ -316,8 +329,8 @@ public void run() {
316329 invocationListener = scriptInvocation .getInvocationListener ();
317330 }
318331
319- ScriptExecutionTask <?> executionTask = scriptExecutorPool .execute (scriptInvocation .getScriptId (),
320- scriptInvocation .getScriptBindings (), invocationListener );
332+ ScriptExecutionTask <?> executionTask = scriptExecutorPool .execute (scriptInvocation .getTaskId (),
333+ scriptInvocation .getScriptId (), scriptInvocation . getScriptBindings (), invocationListener );
321334 Future <?> taskFuture = threadPoolProvider .submit (executionTask );
322335 executionTask .setTaskFuture (taskFuture );
323336 runningScripts .put (executionTask .getTaskId (), executionTask );
@@ -382,7 +395,7 @@ public void skipAllScripts() {
382395 }
383396
384397 /**
385- * Skips a currently running script
398+ * Skips all running instances of a script
386399 *
387400 * @param scriptId
388401 * The ID of the script to skip
@@ -400,6 +413,24 @@ public void skipScript(int scriptId) {
400413 }
401414 }
402415
416+ /**
417+ * Skips a specific running instance of a script
418+ *
419+ * @param taskId The ID of the task to skip
420+ */
421+ public void skipScriptByTaskId (int taskId ) {
422+ for (int otherTaskId : runningScripts .keySet ()) {
423+ if (taskId != otherTaskId ) {
424+ continue ;
425+ }
426+ ScriptExecutionTask <?> scriptExecutionTask = runningScripts .get (taskId );
427+ if (scriptExecutionTask == null ) {
428+ continue ;
429+ }
430+ scriptExecutionTask .skipScript ();
431+ }
432+ }
433+
403434 /**
404435 * Skips all currently running {@link GameFuture}s
405436 */
@@ -436,6 +467,61 @@ public void cancelAllQueuedGameFutures() {
436467 queuedFutures .clear ();
437468 }
438469
470+ /**
471+ * Removes all currently queued {@link GameFuture}s without sending skipFuture event
472+ */
473+ public void cancelAllQueuedScripts () {
474+ scriptInvocationQueue .clear ();
475+ }
476+
477+ /**
478+ * Removes all currently queued scripts with a given script ID
479+ */
480+ public void cancelQueuedScript (int scriptId ) {
481+ scriptInvocationQueue .cancelByScriptId (scriptId );
482+ }
483+
484+ /**
485+ * Removes a specific queued script by its task ID
486+ */
487+ public void cancelQueuedScriptByTaskId (int taskId ) {
488+ scriptInvocationQueue .cancelByTaskId (taskId );
489+ }
490+
491+ /**
492+ * Cancels a queued script or skips it if it is currently running
493+ * @param scriptId The script ID
494+ */
495+ public void skipOrCancelScript (int scriptId ) {
496+ try {
497+ skipScript (scriptId );
498+ } catch (Exception e ) {
499+ e .printStackTrace ();
500+ }
501+ try {
502+ cancelQueuedScript (scriptId );
503+ } catch (Exception e ) {
504+ e .printStackTrace ();
505+ }
506+ }
507+
508+ /**
509+ * Cancels a specific invocation of a script by its task ID, or skips it if it is currently running
510+ * @param taskId The task ID
511+ */
512+ public void skipOrCancelScriptByTaskId (int taskId ) {
513+ try {
514+ skipScriptByTaskId (taskId );
515+ } catch (Exception e ) {
516+ e .printStackTrace ();
517+ }
518+ try {
519+ cancelQueuedScriptByTaskId (taskId );
520+ } catch (Exception e ) {
521+ e .printStackTrace ();
522+ }
523+ }
524+
439525 /**
440526 * Compiles a script for execution. Note it is best to call this
441527 * sequentially before any script executions to avoid throwing a
@@ -515,9 +601,10 @@ public int compileScript(String filepath, InputStream inputStream) throws Insuff
515601 * The id of the script to run
516602 * @param scriptBindings
517603 * The variable bindings for the script
604+ * @return The unique task ID for this invocation
518605 */
519- public void invokeCompiledScript (int scriptId , ScriptBindings scriptBindings ) {
520- invokeCompiledScript (scriptId , scriptBindings , null );
606+ public int invokeCompiledScript (int scriptId , ScriptBindings scriptBindings ) {
607+ return invokeCompiledScript (scriptId , scriptBindings , null );
521608 }
522609
523610 /**
@@ -530,10 +617,11 @@ public void invokeCompiledScript(int scriptId, ScriptBindings scriptBindings) {
530617 * @param invocationListener
531618 * A {@link ScriptInvocationListener} to list for invocation
532619 * results
620+ * @return The unique task ID for this invocation
533621 */
534- public void invokeCompiledScript (int scriptId , ScriptBindings scriptBindings ,
622+ public int invokeCompiledScript (int scriptId , ScriptBindings scriptBindings ,
535623 ScriptInvocationListener invocationListener ) {
536- invokeCompiledScript (scriptId , scriptBindings , invocationListener , 0 );
624+ return invokeCompiledScript (scriptId , scriptBindings , invocationListener , 0 );
537625 }
538626
539627 /**
@@ -546,10 +634,11 @@ public void invokeCompiledScript(int scriptId, ScriptBindings scriptBindings,
546634 * @param invocationListener
547635 * A {@link ScriptInvocationListener} to list for invocation results
548636 * @param priority The script execution priority (higher value = higher priority)
637+ * @return The unique task ID for this invocation
549638 */
550- public void invokeCompiledScript (int scriptId , ScriptBindings scriptBindings ,
639+ public int invokeCompiledScript (int scriptId , ScriptBindings scriptBindings ,
551640 ScriptInvocationListener invocationListener , int priority ) {
552- invokeCompiledScript (scriptId , scriptBindings , invocationListener , priority , false );
641+ return invokeCompiledScript (scriptId , scriptBindings , invocationListener , priority , false );
553642 }
554643
555644 /**
@@ -562,10 +651,13 @@ public void invokeCompiledScript(int scriptId, ScriptBindings scriptBindings,
562651 * @param invocationListener
563652 * A {@link ScriptInvocationListener} to list for invocation results
564653 * @param priority The script execution priority (higher value = higher priority)
654+ * @return The unique task ID for this invocation
565655 */
566- public void invokeCompiledScript (int scriptId , ScriptBindings scriptBindings ,
656+ public int invokeCompiledScript (int scriptId , ScriptBindings scriptBindings ,
567657 ScriptInvocationListener invocationListener , int priority , boolean interactive ) {
568- scriptInvocationQueue .offer (scriptInvocationPool .allocate (scriptId , scriptBindings , invocationListener , priority , interactive ));
658+ final ScriptInvocation invocation = scriptInvocationPool .allocate (scriptId , scriptBindings , invocationListener , priority , interactive );
659+ scriptInvocationQueue .offer (invocation );
660+ return invocation .getTaskId ();
569661 }
570662
571663 /**
@@ -631,37 +723,77 @@ public int invokeScript(String scriptContent, ScriptBindings scriptBindings,
631723 *
632724 * Warning: If no {@link ScriptExecutor}s are available this will block
633725 * until one is available
634- *
635- * @param scriptId
636- * The script id
637- * @param scriptBindings
638- * The variable bindings for the script
726+ *
727+ * @param taskId The task id
728+ * @param scriptId The script id
729+ * @param scriptBindings The variable bindings for the script
639730 */
640- public void invokeCompiledScriptSync (int scriptId , ScriptBindings scriptBindings ) {
641- invokeCompiledScriptSync (scriptId , scriptBindings , null );
731+ public void invokeCompiledScriptSync (int taskId , int scriptId , ScriptBindings scriptBindings ) {
732+ invokeCompiledScriptSync (taskId , scriptId , scriptBindings , null );
642733 }
643734
644735 /**
645736 * Executes a compiled script synchronously on the thread calling this method.
646737 *
647738 * Warning: If no {@link ScriptExecutor}s are available this will block
648739 * until one is available
649- *
650- * @param scriptId
651- * The script id
652- * @param scriptBindings
653- * The variable bindings for the script
740+ *
741+ * @param taskId The task id
742+ * @param scriptId The script id
743+ * @param scriptBindings The variable bindings for the script
654744 * @param invocationListener
655745 * A {@link ScriptInvocationListener} to list for invocation
656746 * results
657747 */
658- public void invokeCompiledScriptSync (int scriptId , ScriptBindings scriptBindings ,
748+ public void invokeCompiledScriptSync (int taskId , int scriptId , ScriptBindings scriptBindings ,
659749 ScriptInvocationListener invocationListener ) {
660- ScriptExecutionTask <?> executionTask = scriptExecutorPool .execute (scriptId , scriptBindings , invocationListener );
750+ ScriptExecutionTask <?> executionTask = scriptExecutorPool .execute (taskId , scriptId , scriptBindings , invocationListener );
661751 runningScripts .put (executionTask .getTaskId (), executionTask );
662752 executionTask .run ();
663753 }
664754
755+ /**
756+ * Returns the list of currently running scripts.
757+ *
758+ * Note: This list reference is re-used on every invocation of this method
759+ * @return An empty list if nothing running
760+ */
761+ public List <String > getRunningScripts () {
762+ tmpRunningScripts .clear ();
763+ for (int taskId : runningScripts .keySet ()) {
764+ ScriptExecutionTask <?> scriptExecutionTask = runningScripts .get (taskId );
765+ if (scriptExecutionTask == null ) {
766+ continue ;
767+ }
768+ tmpRunningScripts .add (scriptExecutorPool .getCompiledScriptPath (scriptExecutionTask .getScriptId ()));
769+ }
770+ return tmpRunningScripts ;
771+ }
772+
773+ /**
774+ * Returns the total scripts (interactive + non-interactive) queued
775+ * @return 0 if none
776+ */
777+ public int getTotalScriptsQueued () {
778+ return scriptInvocationQueue .size ();
779+ }
780+
781+ /**
782+ * Returns the total interactive scripts queued
783+ * @return 0 if none
784+ */
785+ public int getTotalInteractiveScriptsQueued () {
786+ return scriptInvocationQueue .getInteractiveScriptsQueued ();
787+ }
788+
789+ /**
790+ * Returns the total non-interactive scripts queued
791+ * @return 0 if none
792+ */
793+ public int getTotalNonInteractiveScriptsQueued () {
794+ return scriptInvocationQueue .getNonInteractiveScriptsQueued ();
795+ }
796+
665797 void submitGameFuture (GameFuture gameFuture ) {
666798 queuedFutures .offer (gameFuture );
667799 }
0 commit comments