Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
6be6ce5
神秘小东西
cloudfl4re Aug 2, 2026
025b438
神秘小东西
cloudfl4re Aug 2, 2026
665e808
修正 2.0.2 版本号
cloudfl4re Aug 3, 2026
c05fe68
兼容 2.0.1 客户端视频列表协议
cloudfl4re Aug 3, 2026
083ffcf
test: 修复 Windows 换行基线检查(任务 0/7)
cloudfl4re Aug 5, 2026
8462e56
fix: 限制握手协议版本长度(任务 1/7)
cloudfl4re Aug 5, 2026
4918e02
build: 建立双版本聚合与服务端工具链(任务 2/7)
cloudfl4re Aug 5, 2026
58bd8a6
refactor: 迁移 1.21.11 至 Mojang 官方映射(任务 3/7)
cloudfl4re Aug 5, 2026
a03e14e
feat: 适配 Fabric 26.2 客户端渲染(任务 4/7)
cloudfl4re Aug 5, 2026
c051081
fix: 完善 Folia 与纹理资源生命周期(任务 5/7)
cloudfl4re Aug 5, 2026
8748213
build: 生成并验证双版本发布包(任务 6/7)
cloudfl4re Aug 5, 2026
87f167e
Merge remote-tracking branch 'mcxqk/main' into feature/minecraft-26.2
cloudfl4re Aug 5, 2026
37332be
feat(paper): expose VPLight telemetry on 26.2
cloudfl4re Aug 5, 2026
0a3f166
fix(paper): harden VPLight telemetry lifecycle
cloudfl4re Aug 5, 2026
284b078
fix: skip redundant YouTube live resolution
cloudfl4re Aug 9, 2026
fee4ff1
fix: preserve previous handshake compatibility
cloudfl4re Aug 9, 2026
f6e7da2
fix: externalize native media runtimes
cloudfl4re Aug 15, 2026
48ea1b2
Update README.md
cloudfl4re Aug 15, 2026
59b6ff6
Update build.yml
cloudfl4re Aug 16, 2026
343faf7
Update build.yml
cloudfl4re Aug 16, 2026
198b85c
Update build.yml
cloudfl4re Aug 16, 2026
255f719
Update README.md
cloudfl4re Aug 16, 2026
6d227df
Update README.md
cloudfl4re Aug 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 28 additions & 9 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,45 @@ jobs:
- name: validate gradle wrapper
uses: gradle/actions/wrapper-validation@v4
- name: setup jdk
uses: actions/setup-java@v4
uses: actions/setup-java@v5
with:
java-version: '21'
java-version: '25'
distribution: 'microsoft'
- name: make gradle wrapper executable
run: chmod +x ./gradlew
- name: build
run: ./gradlew build
- name: capture Fabric artifact
- name: capture Fabric 1.21.11 artifact
uses: actions/upload-artifact@v4
with:
name: VideoPlayer-Fabric
name: VideoPlayer-Fabric-1.21.11
path: |
build/libs/VideoPlayer-*.jar
!build/libs/*-sources.jar
!build/libs/*-dev-shadow.jar
- name: capture Paper artifact
fabric-1.21.11/build/libs/VideoPlayer-*.jar
!fabric-1.21.11/build/libs/*-sources.jar
!fabric-1.21.11/build/libs/*-dev-shadow.jar
if-no-files-found: error
- name: capture Fabric 26.2 artifact
uses: actions/upload-artifact@v4
with:
name: VideoPlayer-Paper
name: VideoPlayer-Fabric-26.2
path: |
fabric-26.2/build/libs/VideoPlayer-*-26.2.jar
!fabric-26.2/build/libs/*-plain.jar
!fabric-26.2/build/libs/*-sources.jar
if-no-files-found: error
- name: capture Paper 1.21.11 artifact
uses: actions/upload-artifact@v4
with:
name: VideoPlayer-Paper-1.21.11
path: |
paper-plugin/build/libs/VideoPlayer-Paper-*.jar
!paper-plugin/build/libs/*-plain.jar
if-no-files-found: error
- name: capture Paper 26.2 artifact
uses: actions/upload-artifact@v4
with:
name: VideoPlayer-Paper-26.2
path: |
paper-plugin-26.2/build/libs/VideoPlayer-Paper-*-26.2.jar
!paper-plugin-26.2/build/libs/*-plain.jar
if-no-files-found: error
70 changes: 70 additions & 0 deletions FOLIA_COMPATIBILITY_AUDIT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Folia compatibility audit

## Targets and limits

This audit covers the server plugin compiled for Luminol/Folia 1.21.11 and Canvas/Folia 26.2. It is a static source review backed by unit tests and compilation against Paper API 1.21.11 and Paper API 26.2. It is not a runtime test on a real Luminol, Canvas, Paper, or Folia server. Canvas-specific behavior that differs from the Paper/Folia API used for compilation remains `uncertain` until deployment testing or the matching Canvas core source confirms it.

`folia-supported: true` only allows the plugin to load. It is not treated as proof of thread safety or functional completeness.

## Pre-modification findings

| Classification | Entry point and call chain | Current context and real owner | Boundary values | Termination and cleanup | Rules |
|---|---|---|---|---|---|
| `must_fix` | Client screen draw -> `ScreenRenderer.textureIdentifier` -> `TextureManager.register` | Minecraft client/render thread; the video backend owns the raw GL texture | Raw GL integer ID crossed into a Minecraft texture wrapper | The old raw-ID cache had no release path and survived screen cleanup, disconnect, resource reload, and client stop | 2, 8 |
| `must_fix` | `VideoQuad.cleanup` / `MpvVideoBackend.cleanupTexture` / `AbstractCameraPlayer.cleanup` -> GL texture deletion | Minecraft render context, MPV shared context, or camera framebuffer owner | Raw GL integer ID | The backend deleted the GL object, but the Minecraft wrapper and cached render layer remained registered | 8 |
| `suggested_fix` | Resource reload -> texture manager reload -> next screen render | Minecraft resource apply/client context | Resource identifiers and immutable render snapshots | No explicit external-texture registry invalidation existed | 8 |
| `defer` | `VideoPlayerPaperPlugin.onEnable` -> `FoliaScheduler.initialize` -> one-time `RegionizedServer` detection | Plugin enable/global lifecycle context | Cached boolean only | Scheduler owner is cleared in `onDisable`; the detected server model remains process-stable across plugin reloads | 1, 3 |
| `defer` | Plugin message -> cloned byte array -> `DataHolder.runStateForPlayer` -> entity scheduler -> `ServerPacketHandler.handle` | Plugin messaging callback hands off to the Player entity owner | Cloned packet bytes, receive timestamp | ByteBuf is released in `finally`; state tasks are cancelled and maps cleared on disable | 1, 6, 7, 8 |
| `defer` | Player join -> entity scheduler -> fixed-rate `DataHolder.updatePlayer` | Player entity scheduler owns Player, World, and Location reads | UUID and immutable `PlayerPosition` snapshot enter the locked state tables | Quit, entity retirement, disable, and epoch mismatch cancel the task and remove references | 2, 6, 7, 8 |
| `defer` | World discovery in entity context -> immutable `WorldDescriptor` -> async read -> global locked apply | World access occurs in the owner context; file I/O occurs on the async scheduler; mutation returns through the global state executor | Dimension string and Path snapshot, then parsed configuration data | Request IDs and lifecycle epochs reject stale completion; queues are flushed or cancelled on disable | 2, 6, 8 |
| `defer` | State mutation -> lazy serialized snapshot -> `WorldSaveQueue` -> async file writer | Locked global state captures the snapshot; async tasks own file I/O | Strings, paths, generation numbers, and serialized snapshots only | Per-world slots are bounded by active dimensions, coalesced, retried, flushed with a timeout, and cancelled on disable | 2, 6, 8 |
| `defer` | Residence flag/lifecycle event -> global delayed refresh -> per-player entity refresh | Plugin lifecycle/global context enumerates players; each permission read is handed to its Player entity owner | UUID/player task target and immutable permission contexts | Listeners and task handles are cancelled and unregistered in bridge shutdown | 1, 2, 6, 7, 8 |

## Implemented resource lifecycle

The client now assigns every active raw GL texture a process-local generation. An active raw ID reuses its registration, while release followed by OpenGL ID reuse receives a new identifier such as `videoplayer:external_texture/7/2`. The registry stores integers and generation values only; it does not retain Minecraft, Player, Entity, World, Inventory, backend, or GL wrapper objects.

The following owner cleanup paths release the external registration before deleting or rebuilding their textures:

- `VideoQuad.cleanup`
- `MpvVideoBackend.cleanup` and `MpvVideoBackend.cleanupTexture`
- `AbstractCameraPlayer.cleanup`
- `AbstractCameraPlayer.updateTexture` before framebuffer resize

Disconnect, protocol reset, client stop, and client resource reload clear all remaining registrations. The 1.21.11 renderer also clears related `RenderType` entries. The 26.2 renderer clears its immutable `FrameRenderSnapshot` so a submission cannot retain the previous generation.

## Post-modification three-pass review

### 1. Functionality and scope

- Plugin name, mod ID, main classes, public commands, permissions, configuration keys, packet channel, internal version, wire revision, and unrelated playback behavior remain unchanged.
- `-26.2` is a distribution filename suffix only. It is not added to the internal version or handshake token.
- The resource change is limited to external texture registration, release, reload, and the directly owned GL/framebuffer cleanup chain.

### 2. Folia and performance

- `FoliaScheduler` is initialized once early in `onEnable`, caches Folia detection, and uses official Paper/Folia scheduler APIs after detection.
- Business code contains no direct legacy `BukkitScheduler` scheduling entry. Legacy scheduler calls exist only inside the wrapper's non-Folia path.
- Entity and region wrapper delays are clamped to at least one tick.
- No synchronous `teleport` call exists. The plugin currently has no teleport operation requiring `teleportAsync`.
- No `Bukkit.isPrimaryThread()` check is used as a Folia ownership test.
- Player, World, and Location reads occur in the Player entity owner context. Cross-context state uses UUIDs, strings, paths, byte arrays, configuration objects, or immutable position/permission snapshots.
- File and network operations run on async workers. The bounded shutdown flush occurs only during plugin disable and does not hold `DataHolder.LOCK` while waiting.
- No region callback uses `Future.get`, `CompletableFuture.join`, a blocking cross-region wait, or a synchronous database/network/file operation.

### 3. Lifecycle and resources

- Player tracking, reload handshake, world save debounce/retry, Residence retry/cache refresh, native runtime, and yt-dlp task handles have explicit cancellation paths.
- `DataHolder` clears Player UUID/name state, world state, handshake state, persistence state, and task tables on disable.
- `ClientVersionTracker` uses concurrent collections and cancels per-player timeout tasks during shutdown or session replacement.
- `DataHolder` maps and sets remain under the single `DataHolder.LOCK`; this preserves atomic mutations spanning multiple tables and avoids concurrent iteration. They are not replaced independently with concurrent collections.
- Provider concurrency is bounded by `VideoProviders.RESOLUTION_LIMIT`. World save slots are coalesced per active dimension. Client external texture registrations now have owner release and global cleanup paths.
- Plugin and Residence listeners are unregistered on disable. Native and scheduler executors are stopped, and lifecycle epochs reject stale callbacks after reload.

## Unavailable Folia events

No listener for `PlayerRespawnEvent`, `PlayerTeleportEvent`, `PlayerChangedWorldEvent`, `WorldLoadEvent`, or `WorldUnloadEvent` exists in the Paper plugin source for either target. Therefore, there is no class/listener to list as using one of these unavailable events. This result is specific to the reviewed Luminol/Folia 1.21.11 and Canvas/Folia 26.2 targets and must be rechecked after a server API upgrade.

## Runtime verification still required

Deployment verification should cover connection and handshake, screen creation and deletion, MPV/VLC playback, camera and 360 rendering, resource reload, disconnect/reconnect, plugin disable/reload, world changes discovered through player tracking, and concurrent players in separate Folia regions. Any conclusion that conflicts with the exact target server core is superseded by that core and should be recorded as a version-specific difference.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
</p>

<p align="center">
<a href="https://github.com/mcxqk/VideoPlayer/actions/workflows/build.yml"><img src="https://github.com/mcxqk/VideoPlayer/actions/workflows/build.yml/badge.svg" alt="Build"></a>
<a href="https://github.com/mcxyd/VideoPlayer/actions/workflows/build.yml"><img src="https://github.com/mcxyd/VideoPlayer/actions/workflows/build.yml/badge.svg" alt="Build"></a>
<a href="https://www.minecraft.net/"><img src="https://img.shields.io/badge/Minecraft-1.21.11-62B47A" alt="Minecraft 1.21.11"></a>
<a href="https://adoptium.net/"><img src="https://img.shields.io/badge/Java-21-ED8B00" alt="Java 21"></a>
<a href="LICENSE"><img src="https://img.shields.io/github/license/mcxqk/VideoPlayer" alt="GPL-3.0 license"></a>
Expand Down
Loading
Loading