Skip to content

Conversation

@gbpii
Copy link

@gbpii gbpii commented Dec 8, 2025

Added Folia support using FoliaLib wrapper library:

  • Replaced all Bukkit scheduler calls with FoliaLib's region-aware schedulers
  • Added folia-supported: true to plugin.yml
  • Fixed JAR build to include FoliaLib dependencies
  • Added target folder copy task for build output

Tested 15 features on Folia - all passed.

All tested features work correctly on Folia without errors.

gbpii added 4 commits December 8, 2025 07:55
This commit implements initial Folia support for HeadBlocks plugin by integrating FoliaLib (v0.5.1), a cross-platform scheduler wrapper that provides region-aware and entity-aware scheduling for Folia while maintaining full backward compatibility with Paper and Spigot.

## Overview
Folia is a Paper fork that splits the server into multiple independent regions, each with its own tick loop. This requires region-aware scheduling for all block and entity operations. FoliaLib abstracts this complexity and automatically detects the platform, using the appropriate scheduler implementation.

## Key Changes

### Build Configuration
- Added FoliaLib dependency (com.tcoded:FoliaLib:0.5.1) from tcoded-releases repository
- Added package relocation for FoliaLib to avoid dependency conflicts

### Core Plugin Class (HeadBlocks.java)
- Added FoliaLib instance initialization in onEnable() with error handling
- Plugin disables gracefully if FoliaLib initialization fails
- Updated onDisable() to use FoliaLib's cancelAllTasks()
- Refactored startInternalTaskTimer() to use FoliaLib's runTimer() for global iteration
- Implemented per-location scheduling for head processing in GlobalTask
- Added compatibility warnings for PacketEvents and HoloEasy on Folia

### Scheduler Replacements
All Bukkit scheduler calls have been replaced with FoliaLib equivalents:
- runTask() → runNextTick() for global operations
- runTaskLater() → runLater() for delayed operations
- runTaskTimer() → runTimer() for repeating operations
- runTaskAsynchronously() → runAsync() for async operations
- Block operations → runAtLocation() for region-aware execution
- Entity operations → runAtEntity() for entity-aware execution
- Teleportation → teleportAsync() for async teleportation

### Service Layer Changes

#### HeadService.java
- Replaced BukkitTask tracking with Set<UUID> for active spinning heads
- Updated addHeadToSpin() to use location-aware scheduling
- Wrapped all block modifications (setType, remove, change) in runAtLocation()
- Ensured rotateHead() is called from region-aware context

#### RewardService.java
- Replaced all runTaskLater() calls with FoliaLib's runLater()
- Updated command execution scheduling

#### GlobalTask.java
- Refactored from extending BukkitRunnable to static methods
- Core logic moved to static handleHeadLocation() method
- Removed task cancellation logic (handled by plugin disable)
- Made helper methods static for better organization

### Event Handlers

#### OnPlayerInteractEvent.java
- Wrapped all player-specific operations in runAtEntity()
- Wrapped all location-specific operations in runAtLocation()
- Fixed nested lambda variable name conflicts
- Ensured particles, fireworks, and messages are scheduled correctly

#### OnPlayerPlaceBlockEvent.java
- Fixed final variable issue for lambda usage
- Wrapped particle spawning in runAtLocation()

#### OnPlayerChatEvent.java
- Updated to use runAtEntity() for player operations

### Hologram System

#### AdvancedHologram.java
- Replaced async scheduler calls with runAtLocation()
- Updated create(), delete(), and refresh() methods

#### BasicHologram.java
- Wrapped entity spawning in runAtLocation()

### Commands

#### Tp.java
- Implemented FoliaLib's teleportAsync() for cross-platform teleportation

#### Export.java
- Replaced runTaskAsynchronously() with runAsync()
- Ensured sender.sendMessage() calls are scheduled on main thread

#### Debug.java
- Wrapped block texture application in runAtLocation()
- Ensured messages are sent on main thread

### Utilities

#### ParticlesUtils.java
- Removed redundant async scheduler wrappers
- Particle spawning now relies on caller's region-aware context

#### FireworkUtils.java
- Added location-aware scheduling support

#### BukkitFutureResult.java
- Updated executor to use FoliaLib's runNextTick()
- Maintained fallback for non-HeadBlocks plugins

#### Metrics.java
- Updated to use FoliaLib scheduler for Folia platforms
- Maintained backward compatibility with Paper/Spigot

### Hooks

#### HeadHidingPacketListener.java
- Updated all player.sendBlockChange() calls to use runAtEntity() and runAtLocation()
- Fixed nested scheduling for block state updates
- Updated onPlayerJoin(), addFoundHead(), removeFoundHead(), and showAllPreviousHeads()

## Technical Details

### Lambda Signatures
All FoliaLib scheduler methods expect Consumer<WrappedTask> instead of Runnable:
- Changed from: () -> { ... }
- Changed to: task -> { ... }

### Variable Naming
Fixed variable name conflicts in nested lambdas by using task, task2, task3, etc.

### Final Variables
Fixed lambda capture issues by ensuring variables are final or effectively final.

## Backward Compatibility
- All changes maintain full backward compatibility with Paper and Spigot
- FoliaLib automatically detects the platform and uses appropriate scheduler
- No configuration changes required
- No database migration needed

## Testing Status
⚠️ WARNING: This implementation has NOT been tested on a Folia server yet.
- Compilation successful
- All scheduler calls migrated
- Backward compatibility maintained
- Folia server testing required before production deployment

## Files Changed
19 files modified:
- build.gradle.kts
- HeadBlocks.java
- GlobalTask.java
- HeadService.java
- RewardService.java
- Reward.java
- OnPlayerInteractEvent.java
- OnPlayerPlaceBlockEvent.java
- OnPlayerChatEvent.java
- AdvancedHologram.java
- BasicHologram.java
- HeadHidingPacketListener.java
- Tp.java
- Export.java
- Debug.java
- ParticlesUtils.java
- FireworkUtils.java
- Metrics.java
- BukkitFutureResult.java
- Disabled minimization temporarily to ensure FoliaLib and NBT API are included
- Fixed copyJarToTarget task to copy from shadowJar output (with dependencies) instead of regular jar
- Added automatic copy to target/ folder on build

Fixes NoClassDefFoundError for FoliaLib on Folia server.
@AerWyn81
Copy link
Owner

AerWyn81 commented Dec 9, 2025

Hi @gbpii, thanks for the PR! Have you tested it for production purposes?
I'll watch it this weekend!

Add null and validity checks to prevent NPEs when hologram entity
is not yet created (async) or already removed.
@gbpii
Copy link
Author

gbpii commented Dec 9, 2025

Hi @gbpii, thanks for the PR! Have you tested it for production purposes? I'll watch it this weekend!

Of course, as you can see in this commit "test: Verify Folia compatibility - comprehensive feature testing" it has detailed testing lists too.

Also i added couple improvements too.

@gbpii
Copy link
Author

gbpii commented Dec 14, 2025

Also we have to test server restart / start / stop procedures, maybe there is a bug on that side. (folia)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants