CanvasMC LogoCanvasMC Docs

Plugin Compatibility

Plugin compatibility rules and information

Authors:Dueris's avatarDueris
Reading time:2 min read

General Rules

Canvas, as a fork of Folia, requires plugins to have the folia-supported flag enabled in their plugin yml to be able to load on Canvas. Canvas will never change this, we will not remove it, alter it to have exceptions for specific plugins, or anything. We aim to abide completely by Folias new rules, and we will not remove thread checks, alter safety guards, or blatantly remove systems that keep Canvas and Folia stable.

Canvas does include additional API to assist in plugin development with Canvas. Bellow is the io.canvasmc.canvas.threadedregions.ServerRegionizer, which is an interface into the ThreadedRegionizer for the world. You can access this through org.bukkit.World#getRegionizer()

Canvas also fixes numerous API that Folia breaks, which is moved to the Fixes page.

/**
 * Interface for accessing and interacting with region data managed by the ThreadedRegionizer.
 *
 * <p>This interface allows plugins or subsystems to query or iterate over {@link ThreadedWorldRegion}s</p>
 *
 * <p>Regions are guaranteed to be spatially unique, but may change size or contents over time
 * due to merging, splitting, or chunk addition/removal.</p>
 */
public interface ServerRegionizer {
    /**
     * Gets the region that owns the given chunk coordinate, using synchronized locking to ensure thread safety.
     * This method may be more expensive but guarantees the returned region is current and consistent.
     *
     * @param chunkX The X coordinate of the chunk.
     * @param chunkZ The Z coordinate of the chunk.
     * @return The {@link ThreadedWorldRegion} responsible for the chunk, or {@code null} if none exists.
     */
    ThreadedWorldRegion getRegionAtSynchronized(int chunkX, int chunkZ);

    /**
     * Gets the region that owns the given chunk coordinate without acquiring any locks.
     * This method is faster but may return a stale or inconsistent result if regions are actively mutating.
     *
     * @param chunkX The X coordinate of the chunk.
     * @param chunkZ The Z coordinate of the chunk.
     * @return The {@link ThreadedWorldRegion} responsible for the chunk, or {@code null} if none exists.
     */
    ThreadedWorldRegion getRegionAtUnsynchronized(int chunkX, int chunkZ);

    /**
     * Iterates over all regions currently managed by the regionizer in a thread-safe manner.
     * The provided consumer is called once for each region.
     *
     * @param regionConsumer A consumer to apply to each region, guaranteed to run with internal locking held.
     */
    void computeForAllRegionsSynchronized(Consumer<ThreadedWorldRegion> regionConsumer);

    /**
     * Iterates over all regions currently managed by the regionizer without acquiring any locks.
     * This method is faster but may observe inconsistent or stale data if regions are mutating concurrently.
     *
     * @param regionConsumer A consumer to apply to each region.
     */
    void computeForAllRegionsUnsynchronized(Consumer<ThreadedWorldRegion> regionConsumer);

    /**
     * Gets an immutable snapshot list of all regions currently managed by the regionizer.
     * This may include inactive or empty regions and is not guaranteed to be updated in real-time.
     *
     * @return A list of all {@link ThreadedWorldRegion}s.
     */
    List<ThreadedWorldRegion> getAllRegions();
}

Canvas also includes numerous events that can help with region threading for plugins. None of these are cancelable, as this can cause numerous issues with Folia region threading. These events include:

  • RegionActiveEvent
    • Called when a region is marked active, but directly before it is scheduled to tick.
  • RegionCreateEvent
    • Called when a region is created.
  • RegionDestroyEvent
    • Called when a region is destroyed
  • RegionInactiveEvent
    • Called when a region becomes inactive, but directly before the region is descheduled for ticking. It is guaranteed that once this event is called, the region will no longer tick

These events are always called while holding critical locks and as such should not attempt to block on anything, and should NOT retrieve or modify ANY world state.

More API coming soon! If you have a request or recommendation, please ask us on our discord or open an issue on the Git repository

Edit on GitHub

Last updated on

On this page