v0.4.28: wipe video_player_cache on game shutdown
Some checks failed
build / build (push) Has been cancelled

Add ClientLifecycleEvents.CLIENT_STOPPING handler that deletes every
file under <gameDir>/video_player_cache/. Quieter sibling of clearAll()
- no chat notify and no concurrent-download race handling needed since
at shutdown no other code is touching the directory.

Cache repopulation on next launch is already handled: the server's
ServerPlayConnectionEvents.JOIN handler re-broadcasts a PreloadPayload
for every preload_urls and cache_entries entry on every join, so a
freshly wiped cache auto-refills from the server's named entries
without any user action.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
tkrmagid
2026-05-18 18:59:55 +09:00
parent 6abc7f9475
commit 229f499465
3 changed files with 42 additions and 1 deletions

View File

@@ -5,7 +5,7 @@ org.gradle.configuration-cache=false
# Mod
mod_id=video_player
mod_version=0.4.27
mod_version=0.4.28
maven_group=com.ejclaw.videoplayer
archives_base_name=video_player

View File

@@ -3,6 +3,7 @@ package com.ejclaw.videoplayer;
import com.ejclaw.videoplayer.block.VideoAnchorBlockEntity;
import com.ejclaw.videoplayer.client.MusicQuizClient;
import com.ejclaw.videoplayer.client.net.ClientNetworking;
import com.ejclaw.videoplayer.client.playback.VideoCache;
import com.ejclaw.videoplayer.client.playback.VideoPlayback;
import com.ejclaw.videoplayer.client.render.VideoAnchorRenderer;
import com.ejclaw.videoplayer.item.VideoStickItem;
@@ -12,6 +13,7 @@ import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientBlockEntityEvents;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
import net.fabricmc.fabric.api.client.rendering.v1.BlockEntityRendererRegistry;
@@ -82,6 +84,11 @@ public class VideoPlayerClient implements ClientModInitializer {
}
});
// Wipe video_player_cache/ on game exit so preloaded clips don't pile up across
// sessions. Cache entries are re-broadcast by the server on every JOIN, so a freshly
// started game will repopulate the cache automatically.
ClientLifecycleEvents.CLIENT_STOPPING.register(client -> VideoCache.wipeOnShutdown());
VideoPlayerMod.LOG.info("[{}] client initialized", VideoPlayerMod.MOD_ID);
}

View File

@@ -226,6 +226,40 @@ public final class VideoCache {
IN_FLIGHT.clear();
}
/**
* Wipe the cache directory at game shutdown so the user doesn't accumulate disk usage
* across sessions. Distinct from {@link #clearAll()}: at shutdown there are no concurrent
* downloads to race and no player to chat-notify, so we skip the chat ping but still bump
* the epoch (defensive — any straggler write inside the in-flight {@code .part} stream
* will detect the bump and self-clean) and drop indexes.
*/
public static void wipeOnShutdown() {
CACHE_EPOCH.incrementAndGet();
READY.clear();
IN_FLIGHT.clear();
int deleted = 0;
int failed = 0;
try {
Path dir = cacheDir();
if (dir != null && Files.isDirectory(dir)) {
try (var stream = Files.newDirectoryStream(dir)) {
for (Path p : stream) {
try {
if (Files.isRegularFile(p) && Files.deleteIfExists(p)) deleted++;
} catch (Throwable t) {
failed++;
}
}
}
}
} catch (Throwable t) {
VideoPlayerMod.LOG.warn("[{}] wipeOnShutdown failed: {}",
VideoPlayerMod.MOD_ID, t.toString());
}
VideoPlayerMod.LOG.info("[{}] wipeOnShutdown: deleted={} failed={}",
VideoPlayerMod.MOD_ID, deleted, failed);
}
/** Caller-supplied: current set of URLs that are fully cached, for diagnostics. */
public static Set<String> readyUrls() {
return new HashSet<>(READY.keySet());