SparklyPaper

repository·ver/26.2·Indexed 41 days ago

https://github.com/sparklypower/sparklypaper

A high-performance Minecraft server software fork of Paper optimized for Survival servers with high player counts. It features Parallel World Ticking to distribute ticking loads across multiple threads, custom events like CraftItemRecipeEvent and PlayerPreMoveEvent, and specialized performance patches for high-concurrency environments.

Tokens
4.5K
Snippets
12
Records
29
Agent score
53%

What's inside SparklyPaper

  1. Overview of SparklyPaper

    ver/26.2
    SparklyPaper is a high-performance fork of Paper designed to make large Minecraft servers snappier. It is specifically optimized for Survival servers with high player counts. The fork includes handmade patches and cherry-picked optimizations to improve performance in high-concurrency environments.
  2. Thread safety requirements for BlockEntity access

    ver/26.2

    When accessing NMS (net.minecraft.server) level methods setBlockEntity and getBlockEntity, you must be aware of the threading model to avoid server freezes.

    • getBlockEntity: Generally thread-safe, EXCEPT when accessed from a separate ServerLevelTickThread. Accessing it from a different world's tick thread will trigger a main-thread chunk load, causing the server to freeze.
    • setBlockEntity: Requires strict thread checks.

    To ensure safety, the implementation uses ensureTickThreadOrAsyncThread for getBlockEntity and ensureTickThread for setBlockEntity. Developers should ensure that any custom logic interacting with block entities does not attempt to cross ServerLevelTickThread boundaries for different worlds.

  3. Understand SparklyPaper support and plugin compatibility

    ver/26.2

    SparklyPaper is a fork specifically made for SparklyPower. Users should be aware of the following:

    • No Official Support: Support is not provided for issues occurring in your server while using SparklyPaper.
    • Plugin Compatibility: SparklyPaper may break certain plugins. The maintainers only prioritize fixing plugin compatibility issues if those plugins are used within the SparklyPower ecosystem.
    • Custom Patching: If you only require specific patches included in SparklyPaper, it is recommended to create your own fork (using paperweight-examples as a base) and cherry-pick the desired patches. This gives you full control over which optimizations are active in your server.
  4. Understand Parallel World Ticking

    ver/26.2

    Parallel World Ticking is an experimental feature in SparklyPaper that moves world ticking into separate threads, allowing multiple worlds to be ticked in parallel.

    Key Characteristics:

    • Synchronization: Every tick waits until all worlds finish ticking before proceeding. Your server's TPS is primarily determined by the MSPT (Milliseconds Per Tick) of your heaviest world.
    • Thread Safety: Thread checks are strictly enforced. Only the ServerLevelTickThread bound to a specific world, or the main TickThread, can modify that world's data.
    • Use Case: This is highly effective for spreading players across multiple worlds (e.g., multiple Survival worlds) to distribute the ticking load.
    • Limitations: Unlike Folia (which uses asynchronous region ticking), Parallel World Ticking does not provide the same level of granular performance scaling and requires players to be in different worlds to see TPS improvements.
  5. Important usage warnings for SparklyPaper

    ver/26.2

    SparklyPaper is tailor-made for the SparklyPower Survival server and is not intended to be a general-purpose stable public fork (unlike Purpur or Pufferfish).

    Key considerations before using SparklyPaper:

    • No Support: Builds are provided for use, but the maintainers do not provide support for external servers. If your server encounters issues or crashes, the maintainers will not assist.
    • Pull Request Policy: Pull requests are generally only accepted if they fix an issue specifically affecting the SparklyPower server.
    • Recommendation: If you need specific optimizations but require a stable public fork, it is recommended to create your own Paper fork and manually port the SparklyPaper patches you require.
  6. Download SparklyPaper builds

    ver/26.2

    SparklyPaper builds are provided via GitHub Actions. To download a build:

    1. Navigate to the SparklyPaper GitHub Actions workflow.
    2. Select a recent workflow run.
    3. Scroll down to the Artifacts section.
    4. Download the desired artifact.

    Important Version Notes (v1.21.4+)

    • Parallel World Ticking: Since version 1.21.4, builds without the Parallel World Ticking feature are no longer provided. To get a version without this feature, you must build manually and remove the parallel world ticking patches and associated classes from sparklypaper-server/src/main/.
    • Reobf (Spigot Mappings) JARs: Since version 1.21.4, Reobf JARs are no longer provided because Paper has deprecated them. To obtain a build with reobf mappings, you must build it yourself and enable Paperweight's debug mode.
    https://github.com/SparklyPower/SparklyPaper/actions/workflows/build.yml
  7. Avoid server lockups when opening inventories after teleportation

    ver/26.2

    In a parallel world environment, teleporting a player and immediately opening a BlockEntity inventory (e.g., a chest) can cause the server to lock up. This happens because the inventory opening process may attempt to load chunks from the old world while the player is being ticked in the new world, leading to a deadlock.

    To prevent this, the system implements two safeguards:

    1. openMenu ignores requests until the player hasTickedAtLeastOnceInNewWorld.
    2. BaseContainerBlockEntity#canUnlock rejects containers attempted to be opened after a world switch.

    Workaround: If you are developing a plugin that teleports a player and then immediately opens an inventory, you must wait at least 1 tick before attempting to open the inventory to ensure the player has successfully transitioned to the new world.

    // Avoid doing this immediately after teleportation:
    @EventHandler
    fun onInteract(e: PlayerInteractEvent) {
        e.player.teleport(Location(Bukkit.getWorld("..."), 0.0, 0.0, 0.0))
        // DO NOT open an inventory here immediately!
    }
    
    // Instead, wait at least 1 tick before opening the inventory.
  8. Handle Plugin Incompatibilities with Parallel World Ticking

    ver/26.2

    Because world data can only be modified by the thread bound to that specific world, plugins that attempt to modify other worlds from a different thread will fail.

    Common Failure Scenario: Teleporting players or entities to another world during events called on a ServerLevelTickThread will cause issues.

    Workaround: To avoid thread-safety errors, schedule these API calls (like teleportation) to be run after all worlds have finished ticking (e.g., by scheduling a task on the main thread).

  9. Profile Parallel World Ticking using Spark

    ver/26.2

    By default, Spark profiles the Server thread, which does not capture the activity of individual world tick threads. To profile the parallel worlds, you must configure Spark to dump all threads.

    1. In your Spark config.json, add the following setting: "backgroundProfilerThreadDumper": "all"
    2. When reviewing the profiler results, look for threads named: serverlevel-tick-worker [WorldNameHere]

    Note: Parallel execution is limited by a semaphore based on the parallel-world-ticking.threads value.

    {
      "backgroundProfilerThreadDumper": "all"
    }
  10. Allow item version downgrades using system properties

    ver/26.2

    If you are running a server on a downgraded Minecraft version, the server may throw errors when attempting to deserialize an ItemStack serialized on a newer version. You can bypass the item version check by setting the following system property:

    -Dsparklypaper.ignoreItemDataVersion=true

    -Dsparklypaper.ignoreItemDataVersion=true
  11. Implement performance optimizations for custom map plugins

    ver/26.2
    If you are developing a custom "image on map" plugin, you can achieve performance benefits similar to vanilla Paper by setting mapView.isLocked = true. This prevents hefty updates when a custom renderer is present. Note that while the map is locked, vanilla map data will not be updated.