44import ch .njol .skript .config .Node ;
55import ch .njol .skript .config .SectionNode ;
66import ch .njol .skript .config .SimpleNode ;
7- import ch .njol .skript .events .bukkit .PreScriptLoadEvent ;
87import ch .njol .skript .lang .*;
98import ch .njol .skript .lang .parser .ParserInstance ;
109import ch .njol .skript .log .CountingLogHandler ;
2120import ch .njol .util .StringUtils ;
2221import org .bukkit .Bukkit ;
2322import org .jetbrains .annotations .ApiStatus ;
23+ import org .jetbrains .annotations .NotNull ;
2424import org .jetbrains .annotations .Nullable ;
2525import org .jetbrains .annotations .UnknownNullability ;
2626import org .skriptlang .skript .bukkit .text .TextComponentParser ;
@@ -111,7 +111,7 @@ private static ParserInstance getParser() {
111111 * All loaded scripts.
112112 */
113113 @ SuppressWarnings ("null" )
114- private static final Set <Script > loadedScripts = Collections .synchronizedSortedSet (new TreeSet <>(new Comparator <Script >() {
114+ private static final Set <Script > loadedScripts = Collections .synchronizedSortedSet (new TreeSet <>(new Comparator <>() {
115115 @ Override
116116 public int compare (Script s1 , Script s2 ) {
117117 File f1 = s1 .getConfig ().getFile ();
@@ -157,6 +157,13 @@ private boolean isSubDir(File directory, File subDir) {
157157 public static Script getScript (File file ) {
158158 if (!file .isFile ())
159159 throw new IllegalArgumentException ("Something other than a file was provided." );
160+ try {
161+ file = file .getCanonicalFile ();
162+ } catch (IOException e ) {
163+ //noinspection ThrowableNotThrown
164+ Skript .exception (e , "An exception occurred while trying to get the canonical file of: " + file );
165+ return null ;
166+ }
160167 for (Script script : loadedScripts ) {
161168 if (file .equals (script .getConfig ().getFile ()))
162169 return script ;
@@ -284,7 +291,6 @@ public static boolean isParallel() {
284291
285292 /**
286293 * Returns the executor used for submitting tasks based on the user config.sk settings.
287- *
288294 * The thread count will be based on the value of {@link #asyncLoaderSize}.
289295 * <p>
290296 * You may also use class {@link ch.njol.skript.util.Task} and the appropriate constructor
@@ -319,7 +325,7 @@ public static void setAsyncLoaderSize(int size) throws IllegalStateException {
319325
320326 // Remove threads
321327 while (loaderThreads .size () > size ) {
322- AsyncLoaderThread thread = loaderThreads .remove ( loaderThreads . size () - 1 );
328+ AsyncLoaderThread thread = loaderThreads .removeLast ( );
323329 thread .cancelExecution ();
324330 }
325331 // Add threads
@@ -334,7 +340,7 @@ public static void setAsyncLoaderSize(int size) throws IllegalStateException {
334340 private final AtomicInteger threadId = new AtomicInteger (0 );
335341
336342 @ Override
337- public Thread newThread (Runnable runnable ) {
343+ public Thread newThread (@ NotNull Runnable runnable ) {
338344 Thread thread = new Thread (asyncLoaderThreadGroup , runnable , "Skript async loaders thread " + threadId .incrementAndGet ());
339345 thread .setDaemon (true );
340346 return thread ;
@@ -447,6 +453,26 @@ private static <T> CompletableFuture<T> makeFuture(Supplier<T> supplier, OpenClo
447453 * Script Loading Methods
448454 */
449455
456+ private static final Set <File > trackedFiles = new HashSet <>();
457+
458+ /**
459+ * Tracks that a file should be considered as loading.
460+ * @param file The file to track.
461+ * @return Whether this file was already being tracked.
462+ */
463+ private static boolean track (File file ) {
464+ return !trackedFiles .add (file );
465+ }
466+
467+ /**
468+ * Stops tracking that a script (its file) should be considered as loading.
469+ * @param script The script to stop tracking.
470+ */
471+ private static void untrack (Script script ) {
472+ // Loaded scripts are created with canonical files
473+ trackedFiles .remove (script .getConfig ().getFile ());
474+ }
475+
450476 /**
451477 * Loads the Script present at the file using {@link #loadScripts(List, OpenCloseable)},
452478 * sending info/error messages when done.
@@ -483,15 +509,14 @@ public static CompletableFuture<ScriptInfo> loadScripts(Set<File> files, OpenClo
483509 * and closed after the {@link Structure#postLoad()} stage.
484510 * @return Info on the loaded scripts.
485511 */
486- @ SuppressWarnings ("removal" )
487512 private static CompletableFuture <ScriptInfo > loadScripts (List <Config > configs , OpenCloseable openCloseable ) {
488513 if (configs .isEmpty ()) // Nothing to load
489514 return CompletableFuture .completedFuture (new ScriptInfo ());
490515
491516 eventRegistry ().events (ScriptPreInitEvent .class )
492517 .forEach (event -> event .onPreInit (configs ));
493- //noinspection deprecation - we still need to call it
494- Bukkit .getPluginManager ().callEvent (new PreScriptLoadEvent (configs ));
518+ //noinspection removal - we still need to call it
519+ Bukkit .getPluginManager ().callEvent (new ch . njol . skript . events . bukkit . PreScriptLoadEvent (configs ));
495520
496521 ScriptInfo scriptInfo = new ScriptInfo ();
497522
@@ -513,7 +538,7 @@ private static CompletableFuture<ScriptInfo> loadScripts(List<Config> configs, O
513538 }
514539
515540 return CompletableFuture .allOf (scriptInfoFutures .toArray (new CompletableFuture [0 ]))
516- .thenApply (unused -> {
541+ .thenApply (ignored -> {
517542 // TODO in the future this won't work when parallel loading is fixed
518543 // It does now though so let's avoid calling getParser() a bunch.
519544 ParserInstance parser = getParser ();
@@ -630,28 +655,18 @@ record LoadingStructure (LoadingScriptInfo loadingScriptInfo, Structure structur
630655 } finally {
631656 parser .setInactive ();
632657
658+ for (LoadingScriptInfo info : scripts ) {
659+ untrack (info .script );
660+ }
661+
633662 openCloseable .close ();
634663 }
635664 }).exceptionally (t -> {
636665 throw Skript .exception (t );
637666 });
638667 }
639668
640- private static class LoadingScriptInfo {
641-
642- public final Script script ;
643-
644- public final List <Structure > structures ;
645-
646- public final Map <Structure , Node > nodeMap ;
647-
648- public LoadingScriptInfo (Script script , List <Structure > structures , Map <Structure , Node > nodeMap ) {
649- this .script = script ;
650- this .structures = structures ;
651- this .nodeMap = nodeMap ;
652- }
653-
654- }
669+ private record LoadingScriptInfo (Script script , List <Structure > structures , Map <Structure , Node > nodeMap ) { }
655670
656671 /**
657672 * Creates a script and loads the provided config into it.
@@ -810,6 +825,8 @@ private static Config loadStructure(File file) {
810825 return null ;
811826 }
812827
828+ track (file );
829+
813830 try {
814831 String name = Skript .getInstance ().getDataFolder ().toPath ().toAbsolutePath ()
815832 .resolve (Skript .SCRIPTSFOLDER ).relativize (file .toPath ().toAbsolutePath ()).toString ();
@@ -857,6 +874,10 @@ private static Config loadStructure(InputStream source, String name) {
857874 * This data is calculated by using {@link ScriptInfo#add(ScriptInfo)}.
858875 */
859876 public static ScriptInfo unloadScripts (Set <Script > scripts ) {
877+ scripts = scripts .stream ()
878+ .filter (script -> !track (script .getConfig ().getFile ()))
879+ .collect (Collectors .toSet ());
880+
860881 // ensure unloaded scripts are not being unloaded
861882 for (Script script : scripts ) {
862883 if (!loadedScripts .contains (script ))
@@ -920,6 +941,8 @@ record UnloadingStructure (Script script, Structure structure) {}
920941 File scriptFile = script .getConfig ().getFile ();
921942 assert scriptFile != null ;
922943 disabledScripts .add (new File (scriptFile .getParentFile (), DISABLED_SCRIPT_PREFIX + scriptFile .getName ()));
944+
945+ untrack (script );
923946 }
924947
925948 return info ;
@@ -1041,6 +1064,7 @@ public static ArrayList<TriggerItem> loadItems(SectionNode node) {
10411064 items .add (item );
10421065 } else if (subNode instanceof SectionNode subSection ) {
10431066
1067+ //noinspection resource - manual management is intentional
10441068 RetainingLogHandler handler = SkriptLogger .startRetainingLog ();
10451069 find_section :
10461070 try {
@@ -1177,15 +1201,15 @@ public static Script createDummyScript(String name, @Nullable File file) {
11771201 * Any changes to loaded scripts will not be reflected in the returned set.
11781202 */
11791203 public static Set <Script > getLoadedScripts () {
1180- return Collections . unmodifiableSet ( new HashSet <>( loadedScripts ) );
1204+ return Set . copyOf ( loadedScripts );
11811205 }
11821206
11831207 /**
11841208 * @return An unmodifiable set containing a snapshot of the currently disabled scripts.
11851209 * Any changes to disabled scripts will not be reflected in the returned set.
11861210 */
11871211 public static Set <File > getDisabledScripts () {
1188- return Collections . unmodifiableSet ( new HashSet <>( disabledScripts ) );
1212+ return Set . copyOf ( disabledScripts );
11891213 }
11901214
11911215 /**
@@ -1316,7 +1340,7 @@ public static File getScriptFromName(String script, File directory) {
13161340 script = script .replace ('/' , File .separatorChar ).replace ('\\' , File .separatorChar );
13171341 } else if (!StringUtils .endsWithIgnoreCase (script , ".sk" )) {
13181342 int dot = script .lastIndexOf ('.' );
1319- if (dot > 0 && !script .substring (dot + 1 ).equals ( "" ))
1343+ if (dot > 0 && !script .substring (dot + 1 ).isEmpty ( ))
13201344 return null ;
13211345 script = script + ".sk" ;
13221346 }
0 commit comments