fix repositories

This commit is contained in:
2026-05-19 14:13:19 -04:00
parent b6e31436b2
commit 7cd09554ba
2 changed files with 154 additions and 14 deletions
@@ -13,10 +13,26 @@ import org.jetbrains.annotations.Nullable;
public interface SchedulerApi public interface SchedulerApi
{ {
/**
* Executor backed by Paper's async scheduler.
* Use it for blocking I/O and CPU work that does not touch Bukkit world,
* entity, inventory, or command state.
*/
Executor asyncExecutor(); Executor asyncExecutor();
/**
* Executes work on the global region.
* Use the global region for state owned by Folia's global region, such as
* console command dispatch, world time, weather, game rules, and plugin-level
* coordination work.
*/
void executeGlobal(Runnable task); void executeGlobal(Runnable task);
/**
* Runs work on the next global-region tick.
*
* @see #executeGlobal(Runnable)
*/
ScheduledTask runGlobal(Consumer<ScheduledTask> task); ScheduledTask runGlobal(Consumer<ScheduledTask> task);
default ScheduledTask runGlobal(Runnable task) default ScheduledTask runGlobal(Runnable task)
@@ -24,6 +40,11 @@ public interface SchedulerApi
return runGlobal(scheduledTask -> task.run()); return runGlobal(scheduledTask -> task.run());
} }
/**
* Runs work on the global region after a tick delay.
*
* @see #executeGlobal(Runnable)
*/
ScheduledTask runGlobalLater(Consumer<ScheduledTask> task, long delayTicks); ScheduledTask runGlobalLater(Consumer<ScheduledTask> task, long delayTicks);
default ScheduledTask runGlobalLater(Runnable task, long delayTicks) default ScheduledTask runGlobalLater(Runnable task, long delayTicks)
@@ -31,6 +52,11 @@ public interface SchedulerApi
return runGlobalLater(scheduledTask -> task.run(), delayTicks); return runGlobalLater(scheduledTask -> task.run(), delayTicks);
} }
/**
* Runs repeating work on the global region.
*
* @see #executeGlobal(Runnable)
*/
ScheduledTask runGlobalTimer(Consumer<ScheduledTask> task, long delayTicks, long periodTicks); ScheduledTask runGlobalTimer(Consumer<ScheduledTask> task, long delayTicks, long periodTicks);
default ScheduledTask runGlobalTimer(Runnable task, long delayTicks, long periodTicks) default ScheduledTask runGlobalTimer(Runnable task, long delayTicks, long periodTicks)
@@ -38,6 +64,10 @@ public interface SchedulerApi
return runGlobalTimer(scheduledTask -> task.run(), delayTicks, periodTicks); return runGlobalTimer(scheduledTask -> task.run(), delayTicks, periodTicks);
} }
/**
* Runs work on Paper's async scheduler.
* Do not touch Bukkit world, entity, inventory, or command state here.
*/
ScheduledTask runAsync(Consumer<ScheduledTask> task); ScheduledTask runAsync(Consumer<ScheduledTask> task);
default ScheduledTask runAsync(Runnable task) default ScheduledTask runAsync(Runnable task)
@@ -45,6 +75,11 @@ public interface SchedulerApi
return runAsync(scheduledTask -> task.run()); return runAsync(scheduledTask -> task.run());
} }
/**
* Runs async work after a wall-clock delay.
*
* @see #runAsync(Consumer)
*/
ScheduledTask runAsyncLater(Consumer<ScheduledTask> task, long delay, TimeUnit unit); ScheduledTask runAsyncLater(Consumer<ScheduledTask> task, long delay, TimeUnit unit);
default ScheduledTask runAsyncLater(Runnable task, long delay, TimeUnit unit) default ScheduledTask runAsyncLater(Runnable task, long delay, TimeUnit unit)
@@ -52,6 +87,11 @@ public interface SchedulerApi
return runAsyncLater(scheduledTask -> task.run(), delay, unit); return runAsyncLater(scheduledTask -> task.run(), delay, unit);
} }
/**
* Runs repeating async work on a wall-clock interval.
*
* @see #runAsync(Consumer)
*/
ScheduledTask runAsyncTimer(Consumer<ScheduledTask> task, long delay, long period, TimeUnit unit); ScheduledTask runAsyncTimer(Consumer<ScheduledTask> task, long delay, long period, TimeUnit unit);
default ScheduledTask runAsyncTimer(Runnable task, long delay, long period, TimeUnit unit) default ScheduledTask runAsyncTimer(Runnable task, long delay, long period, TimeUnit unit)
@@ -59,10 +99,23 @@ public interface SchedulerApi
return runAsyncTimer(scheduledTask -> task.run(), delay, period, unit); return runAsyncTimer(scheduledTask -> task.run(), delay, period, unit);
} }
/**
* Executes work on the region that owns the supplied location.
* Use this for block, chunk, and location-bound world access.
*/
void executeRegion(Location location, Runnable task); void executeRegion(Location location, Runnable task);
/**
* Executes work on the region that owns the supplied chunk.
* Use this for block, chunk, and location-bound world access.
*/
void executeRegion(World world, int chunkX, int chunkZ, Runnable task); void executeRegion(World world, int chunkX, int chunkZ, Runnable task);
/**
* Runs work on the next tick of the region that owns the supplied location.
*
* @see #executeRegion(Location, Runnable)
*/
ScheduledTask runRegion(Location location, Consumer<ScheduledTask> task); ScheduledTask runRegion(Location location, Consumer<ScheduledTask> task);
default ScheduledTask runRegion(Location location, Runnable task) default ScheduledTask runRegion(Location location, Runnable task)
@@ -70,6 +123,11 @@ public interface SchedulerApi
return runRegion(location, scheduledTask -> task.run()); return runRegion(location, scheduledTask -> task.run());
} }
/**
* Runs work on the next tick of the region that owns the supplied chunk.
*
* @see #executeRegion(World, int, int, Runnable)
*/
ScheduledTask runRegion(World world, int chunkX, int chunkZ, Consumer<ScheduledTask> task); ScheduledTask runRegion(World world, int chunkX, int chunkZ, Consumer<ScheduledTask> task);
default ScheduledTask runRegion(World world, int chunkX, int chunkZ, Runnable task) default ScheduledTask runRegion(World world, int chunkX, int chunkZ, Runnable task)
@@ -77,6 +135,11 @@ public interface SchedulerApi
return runRegion(world, chunkX, chunkZ, scheduledTask -> task.run()); return runRegion(world, chunkX, chunkZ, scheduledTask -> task.run());
} }
/**
* Runs work on a location's owning region after a tick delay.
*
* @see #executeRegion(Location, Runnable)
*/
ScheduledTask runRegionLater(Location location, Consumer<ScheduledTask> task, long delayTicks); ScheduledTask runRegionLater(Location location, Consumer<ScheduledTask> task, long delayTicks);
default ScheduledTask runRegionLater(Location location, Runnable task, long delayTicks) default ScheduledTask runRegionLater(Location location, Runnable task, long delayTicks)
@@ -84,6 +147,11 @@ public interface SchedulerApi
return runRegionLater(location, scheduledTask -> task.run(), delayTicks); return runRegionLater(location, scheduledTask -> task.run(), delayTicks);
} }
/**
* Runs work on a chunk's owning region after a tick delay.
*
* @see #executeRegion(World, int, int, Runnable)
*/
ScheduledTask runRegionLater(World world, int chunkX, int chunkZ, Consumer<ScheduledTask> task, long delayTicks); ScheduledTask runRegionLater(World world, int chunkX, int chunkZ, Consumer<ScheduledTask> task, long delayTicks);
default ScheduledTask runRegionLater(World world, int chunkX, int chunkZ, Runnable task, long delayTicks) default ScheduledTask runRegionLater(World world, int chunkX, int chunkZ, Runnable task, long delayTicks)
@@ -91,6 +159,11 @@ public interface SchedulerApi
return runRegionLater(world, chunkX, chunkZ, scheduledTask -> task.run(), delayTicks); return runRegionLater(world, chunkX, chunkZ, scheduledTask -> task.run(), delayTicks);
} }
/**
* Runs repeating work on a location's owning region.
*
* @see #executeRegion(Location, Runnable)
*/
ScheduledTask runRegionTimer(Location location, Consumer<ScheduledTask> task, long delayTicks, long periodTicks); ScheduledTask runRegionTimer(Location location, Consumer<ScheduledTask> task, long delayTicks, long periodTicks);
default ScheduledTask runRegionTimer(Location location, Runnable task, long delayTicks, long periodTicks) default ScheduledTask runRegionTimer(Location location, Runnable task, long delayTicks, long periodTicks)
@@ -98,6 +171,11 @@ public interface SchedulerApi
return runRegionTimer(location, scheduledTask -> task.run(), delayTicks, periodTicks); return runRegionTimer(location, scheduledTask -> task.run(), delayTicks, periodTicks);
} }
/**
* Runs repeating work on a chunk's owning region.
*
* @see #executeRegion(World, int, int, Runnable)
*/
ScheduledTask runRegionTimer(World world, int chunkX, int chunkZ, Consumer<ScheduledTask> task, long delayTicks, long periodTicks); ScheduledTask runRegionTimer(World world, int chunkX, int chunkZ, Consumer<ScheduledTask> task, long delayTicks, long periodTicks);
default ScheduledTask runRegionTimer(World world, int chunkX, int chunkZ, Runnable task, long delayTicks, long periodTicks) default ScheduledTask runRegionTimer(World world, int chunkX, int chunkZ, Runnable task, long delayTicks, long periodTicks)
@@ -105,6 +183,15 @@ public interface SchedulerApi
return runRegionTimer(world, chunkX, chunkZ, scheduledTask -> task.run(), delayTicks, periodTicks); return runRegionTimer(world, chunkX, chunkZ, scheduledTask -> task.run(), delayTicks, periodTicks);
} }
/**
* Executes work on the region that currently owns the entity.
* Use this for player and entity state access, inventory changes, kicks,
* teleports, passengers, potion effects, and other entity-bound work.
* Paper runs the retired callback if the entity is removed before the task
* can execute.
*
* @return true if Paper accepted the task
*/
boolean executeEntity(Entity entity, Runnable task, @Nullable Runnable retired, long delayTicks); boolean executeEntity(Entity entity, Runnable task, @Nullable Runnable retired, long delayTicks);
default boolean executeEntity(Entity entity, Runnable task, long delayTicks) default boolean executeEntity(Entity entity, Runnable task, long delayTicks)
@@ -112,6 +199,11 @@ public interface SchedulerApi
return executeEntity(entity, task, null, delayTicks); return executeEntity(entity, task, null, delayTicks);
} }
/**
* Runs work on the next tick of the entity's owning region.
*
* @see #executeEntity(Entity, Runnable, Runnable, long)
*/
@Nullable @Nullable
ScheduledTask runEntity(Entity entity, Consumer<ScheduledTask> task, @Nullable Runnable retired); ScheduledTask runEntity(Entity entity, Consumer<ScheduledTask> task, @Nullable Runnable retired);
@@ -120,6 +212,11 @@ public interface SchedulerApi
return runEntity(entity, scheduledTask -> task.run(), null); return runEntity(entity, scheduledTask -> task.run(), null);
} }
/**
* Runs work on the entity's owning region after a tick delay.
*
* @see #executeEntity(Entity, Runnable, Runnable, long)
*/
@Nullable @Nullable
ScheduledTask runEntityLater(Entity entity, Consumer<ScheduledTask> task, @Nullable Runnable retired, long delayTicks); ScheduledTask runEntityLater(Entity entity, Consumer<ScheduledTask> task, @Nullable Runnable retired, long delayTicks);
@@ -128,6 +225,11 @@ public interface SchedulerApi
return runEntityLater(entity, scheduledTask -> task.run(), null, delayTicks); return runEntityLater(entity, scheduledTask -> task.run(), null, delayTicks);
} }
/**
* Runs repeating work on the entity's owning region.
*
* @see #executeEntity(Entity, Runnable, Runnable, long)
*/
@Nullable @Nullable
ScheduledTask runEntityTimer(Entity entity, Consumer<ScheduledTask> task, @Nullable Runnable retired, long delayTicks, long periodTicks); ScheduledTask runEntityTimer(Entity entity, Consumer<ScheduledTask> task, @Nullable Runnable retired, long delayTicks, long periodTicks);
@@ -136,7 +238,13 @@ public interface SchedulerApi
return runEntityTimer(entity, scheduledTask -> task.run(), null, delayTicks, periodTicks); return runEntityTimer(entity, scheduledTask -> task.run(), null, delayTicks, periodTicks);
} }
/**
* Cancels all global-region tasks owned by Plex.
*/
void cancelGlobalTasks(); void cancelGlobalTasks();
/**
* Cancels all async tasks owned by Plex.
*/
void cancelAsyncTasks(); void cancelAsyncTasks();
} }
@@ -25,23 +25,33 @@ import org.jetbrains.annotations.NotNull;
@SuppressWarnings("UnstableApiUsage") @SuppressWarnings("UnstableApiUsage")
public class PlexLibraryManager implements PluginLoader public class PlexLibraryManager implements PluginLoader
{ {
private static final List<String> MAVEN_CENTRAL_URLS = List.of(
"https://repo1.maven.org/maven2",
"http://repo1.maven.org/maven2",
"https://repo.maven.apache.org/maven2",
"http://repo.maven.apache.org/maven2"
);
@Override @Override
public void classloader(@NotNull PluginClasspathBuilder classpathBuilder) public void classloader(@NotNull PluginClasspathBuilder classpathBuilder)
{ {
MavenLibraryResolver resolver = new MavenLibraryResolver();
PluginLibraries pluginLibraries = load(); PluginLibraries pluginLibraries = load();
var repositoryUrls = new HashSet<String>(); List<RemoteRepository> pluginRepositories = pluginLibraries.asRepositories().toList();
pluginLibraries.asRepositories().forEach(repository -> List<RemoteRepository> moduleRepositories = loadModuleRepositories().toList();
List<Dependency> moduleDependencies = loadModuleDependencies().toList();
if (!moduleDependencies.isEmpty())
{ {
repositoryUrls.add(repository.getUrl()); MavenLibraryResolver moduleResolver = new MavenLibraryResolver();
resolver.addRepository(repository); addRepositories(moduleResolver, Stream.concat(moduleRepositories.stream(), pluginRepositories.stream()));
}); moduleDependencies.forEach(moduleResolver::addDependency);
loadModuleRepositories() classpathBuilder.addLibrary(moduleResolver);
.filter(repository -> repositoryUrls.add(repository.getUrl())) }
.forEach(resolver::addRepository);
pluginLibraries.asDependencies().forEach(resolver::addDependency); MavenLibraryResolver pluginResolver = new MavenLibraryResolver();
loadModuleDependencies().forEach(resolver::addDependency); addRepositories(pluginResolver, pluginRepositories.stream());
classpathBuilder.addLibrary(resolver); pluginLibraries.asDependencies().forEach(pluginResolver::addDependency);
classpathBuilder.addLibrary(pluginResolver);
} }
public PluginLibraries load() public PluginLibraries load()
@@ -115,7 +125,7 @@ public class PlexLibraryManager implements PluginLoader
return repositories.getKeys(false).stream() return repositories.getKeys(false).stream()
.map(id -> Map.entry(id, repositories.getString(id, ""))) .map(id -> Map.entry(id, repositories.getString(id, "")))
.filter(entry -> !entry.getValue().isBlank()) .filter(entry -> !entry.getValue().isBlank())
.map(entry -> new RemoteRepository.Builder(entry.getKey(), "default", entry.getValue()).build()); .flatMap(entry -> runtimeRepository(entry.getKey(), entry.getValue()));
} }
private YamlConfiguration readModuleYml(File moduleFile) private YamlConfiguration readModuleYml(File moduleFile)
@@ -149,7 +159,29 @@ public class PlexLibraryManager implements PluginLoader
public Stream<RemoteRepository> asRepositories() public Stream<RemoteRepository> asRepositories()
{ {
return repositories.entrySet().stream().map(e -> new RemoteRepository.Builder(e.getKey(), "default", e.getValue()).build()); return repositories.entrySet().stream().flatMap(e -> runtimeRepository(e.getKey(), e.getValue()));
} }
} }
private static Stream<RemoteRepository> runtimeRepository(String id, String url)
{
String runtimeUrl = MAVEN_CENTRAL_URLS.stream().anyMatch(url::startsWith)
? MavenLibraryResolver.MAVEN_CENTRAL_DEFAULT_MIRROR
: url;
if (!runtimeUrl.startsWith("https://") && !runtimeUrl.startsWith("http://"))
{
return Stream.empty();
}
return Stream.of(new RemoteRepository.Builder(id, "default", runtimeUrl).build());
}
private static void addRepositories(MavenLibraryResolver resolver, Stream<RemoteRepository> repositories)
{
var repositoryUrls = new HashSet<String>();
repositories
.filter(repository -> repositoryUrls.add(repository.getUrl()))
.forEach(resolver::addRepository);
}
} }