2 Commits

Author SHA1 Message Date
tkrmagid
c55a9e4e05 v0.4.30: gate /videoStick behind OP (level 2) permission
Some checks failed
build / build (push) Has been cancelled
The other /video* commands already require Permissions.COMMANDS_GAMEMASTER
(level 2 — the standard OP threshold for cheats), but /videoStick was
missing the gate so any player could spawn a video stick item. Apply the
same requires() check used elsewhere so only OP players, the server
console, and command blocks can run it.
2026-05-20 10:19:43 +09:00
tkrmagid
b0c7532715 v0.4.29: delete promoted cache file on first epoch-mismatch in publishIfNotCancelled
Some checks failed
build / build (push) Has been cancelled
If wipeOnShutdown runs between download's pre-move epoch check and the
atomic Files.move, the wipe's directory scan misses the just-promoted
final file. The first epoch-mismatch branch in publishIfNotCancelled was
returning without deleting, leaking the file across sessions. Delete on
the first branch too.
2026-05-18 19:07:21 +09:00
3 changed files with 13 additions and 2 deletions

View File

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

View File

@@ -284,7 +284,13 @@ public final class VideoCache {
* caller's work was cancelled and {@code path} has been cleaned up. * caller's work was cancelled and {@code path} has been cleaned up.
*/ */
private static boolean publishIfNotCancelled(String url, Path path, long startEpoch) { private static boolean publishIfNotCancelled(String url, Path path, long startEpoch) {
if (CACHE_EPOCH.get() != startEpoch) return false; // If the wipe ran between download's pre-move epoch check and Files.move, its
// directory scan won't have seen this just-promoted file. We must delete it here,
// not just bail — otherwise the freshly-moved final file leaks across shutdown.
if (CACHE_EPOCH.get() != startEpoch) {
try { Files.deleteIfExists(path); } catch (Throwable ignored) {}
return false;
}
READY.put(url, path); READY.put(url, path);
if (CACHE_EPOCH.get() != startEpoch) { if (CACHE_EPOCH.get() != startEpoch) {
READY.remove(url, path); READY.remove(url, path);

View File

@@ -6,13 +6,18 @@ import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands; import net.minecraft.commands.Commands;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.permissions.Permissions;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
public final class VideoStickCommand { public final class VideoStickCommand {
private VideoStickCommand() {} private VideoStickCommand() {}
public static void register(CommandDispatcher<CommandSourceStack> dispatcher) { public static void register(CommandDispatcher<CommandSourceStack> dispatcher) {
// OP/console/command-block 만 사용 가능. Permissions.COMMANDS_GAMEMASTER = level 2,
// 즉 /op 받은 플레이어(level 4) 와 콘솔(level 4), command block(default level 2) 통과.
// 일반 플레이어(level 0) 는 탭 자동완성에도 안 떠야 정상.
dispatcher.register(Commands.literal("videoStick") dispatcher.register(Commands.literal("videoStick")
.requires(s -> s.permissions().hasPermission(Permissions.COMMANDS_GAMEMASTER))
.executes(ctx -> run(ctx.getSource()))); .executes(ctx -> run(ctx.getSource())));
} }