Skip to content

Commit fc9fba3

Browse files
committed
Batch PDC tag refresh and async permission-group persistence
1 parent bfeda42 commit fc9fba3

File tree

4 files changed

+140
-14
lines changed

4 files changed

+140
-14
lines changed

src/main/java/me/crafter/mc/lockettepro/BlockEnvironmentListener.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ public void onMobChangeBlock(EntityChangeBlockEvent event) {
149149

150150
@EventHandler(priority = EventPriority.MONITOR)
151151
public void onChunkLoadSyncPdc(ChunkLoadEvent event) {
152-
Utils.refreshLockedContainerPdcTagsInChunk(event.getChunk());
152+
Utils.queueRefreshLockedContainerPdcTagsInChunk(event.getChunk());
153153
}
154154

155155
}

src/main/java/me/crafter/mc/lockettepro/LockettePro.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,11 @@ public void onEnable() {
7777
plugin.getLogger().info("UUID & expiracy support requires ProtocolLib, or else signs will be ugly!");
7878
}
7979
}
80-
CompatibleScheduler.runTask(this, null, Utils::refreshLockedContainerPdcTagsInLoadedChunks);
80+
Utils.queueRefreshLockedContainerPdcTagsInLoadedChunks();
8181
}
8282

8383
public void onDisable() {
84+
Utils.stopQueuedPdcTagRefreshWorker();
8485
PermissionGroupStore.shutdown();
8586
if (Config.isUuidEnabled() && Bukkit.getPluginManager().getPlugin("ProtocolLib") != null) {
8687
DependencyProtocolLib.cleanUpProtocolLib(this);

src/main/java/me/crafter/mc/lockettepro/PermissionGroupStore.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ public final class PermissionGroupStore {
4848
private static CompatibleTask autosaveTask;
4949
private static boolean saveWorkerRunning;
5050
private static boolean saveWorkerQueued;
51+
private static volatile boolean shutdownInProgress;
5152
private static long mutationVersion;
5253
private static long persistedVersion;
5354
private static long storageVersion;
@@ -111,16 +112,21 @@ private GroupSnapshot snapshot() {
111112

112113
public static void initialize(Plugin pluginInstance) {
113114
plugin = pluginInstance;
115+
shutdownInProgress = false;
114116
storagePath = resolveStoragePath();
115117
loadFromDisk();
116118
startAutoSaveTask();
117119
}
118120

119121
public static void shutdown() {
122+
shutdownInProgress = true;
120123
if (autosaveTask != null) {
121124
autosaveTask.cancel();
122125
autosaveTask = null;
123126
}
127+
synchronized (SAVE_STATE_LOCK) {
128+
saveWorkerQueued = false;
129+
}
124130
saveNow();
125131
}
126132

@@ -238,7 +244,7 @@ private static Path resolveStoragePath() {
238244
}
239245

240246
private static void saveAsync() {
241-
if (plugin == null) return;
247+
if (plugin == null || shutdownInProgress) return;
242248
synchronized (SAVE_STATE_LOCK) {
243249
if (saveWorkerRunning) {
244250
saveWorkerQueued = true;
@@ -255,7 +261,7 @@ private static void runSaveWorker() {
255261
while (true) {
256262
saveNow();
257263
synchronized (SAVE_STATE_LOCK) {
258-
if (!saveWorkerQueued) {
264+
if (shutdownInProgress || !saveWorkerQueued) {
259265
saveWorkerRunning = false;
260266
return;
261267
}
@@ -268,7 +274,7 @@ private static void runSaveWorker() {
268274
}
269275
synchronized (SAVE_STATE_LOCK) {
270276
saveWorkerRunning = false;
271-
if (saveWorkerQueued && plugin != null) {
277+
if (!shutdownInProgress && saveWorkerQueued && plugin != null) {
272278
saveWorkerQueued = false;
273279
saveWorkerRunning = true;
274280
CompatibleScheduler.runTaskAsynchronously(plugin, PermissionGroupStore::runSaveWorker);
@@ -277,7 +283,7 @@ private static void runSaveWorker() {
277283
}
278284
}
279285

280-
public static void saveNow() {
286+
private static void saveNow() {
281287
if (plugin == null || storagePath == null) return;
282288

283289
long targetVersion;
@@ -506,6 +512,7 @@ public static Collection<String> getAllGroupNames() {
506512

507513
private static void markMutated() {
508514
mutationVersion++;
515+
saveAsync();
509516
}
510517

511518
public static boolean isGroupReference(String text) {

src/main/java/me/crafter/mc/lockettepro/Utils.java

Lines changed: 126 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ public class Utils {
4747
private static final String LOCKED_CONTAINER_PDC_KEY_DEFAULT_PATH = "locked_container";
4848
private static final Pattern HEX_COLOR_PATTERN = Pattern.compile("(?i)&\\#([0-9a-f]{6})");
4949
private static final LockedContainerPdcAccess LOCKED_CONTAINER_PDC_ACCESS = LockedContainerPdcAccess.create();
50+
private static final int PDC_TAG_REFRESH_TILE_ENTITY_BUDGET_PER_TICK = 128;
5051

5152
private static final LoadingCache<UUID, Block> selectedsign = CacheBuilder.newBuilder()
5253
.expireAfterAccess(30, TimeUnit.SECONDS)
@@ -56,6 +57,9 @@ public Block load(UUID key) {
5657
}
5758
});
5859
private static final Set<UUID> notified = new HashSet<>();
60+
private static final Deque<ChunkTagRefreshTask> queuedPdcTagRefreshTasks = new ArrayDeque<>();
61+
private static final Set<String> queuedPdcTagRefreshKeys = new HashSet<>();
62+
private static CompatibleTask queuedPdcTagRefreshWorker;
5963

6064
// Helper functions
6165
public static Block putSignOn(Block block, BlockFace blockface, String line1, String line2, Material material) {
@@ -252,22 +256,136 @@ public static void refreshLockedContainerPdcTagLater(Block block) {
252256
}
253257

254258
public static void refreshLockedContainerPdcTagsInChunk(Chunk chunk) {
259+
if (chunk == null) return;
255260
for (BlockState blockState : chunk.getTileEntities()) {
256-
if (blockState instanceof Container) {
257-
ContainerPdcLockManager.refreshLockedContainerTag(blockState.getBlock());
258-
}
259-
if (!(blockState instanceof Sign)) continue;
260-
Block signBlock = blockState.getBlock();
261-
if (!LocketteProAPI.isLockSign(signBlock)) continue;
262-
refreshLockedContainerPdcTag(LocketteProAPI.getAttachedBlock(signBlock));
261+
refreshLockedContainerPdcTagByTileState(blockState);
263262
}
264263
}
265264

266265
public static void refreshLockedContainerPdcTagsInLoadedChunks() {
266+
queueRefreshLockedContainerPdcTagsInLoadedChunks();
267+
}
268+
269+
public static void queueRefreshLockedContainerPdcTagsInChunk(Chunk chunk) {
270+
if (chunk == null) return;
271+
startQueuedPdcTagRefreshWorker();
272+
String key = toChunkQueueKey(chunk.getWorld().getUID(), chunk.getX(), chunk.getZ());
273+
if (!queuedPdcTagRefreshKeys.add(key)) return;
274+
queuedPdcTagRefreshTasks.addLast(new ChunkTagRefreshTask(chunk.getWorld().getUID(), chunk.getX(), chunk.getZ(), key));
275+
}
276+
277+
public static void queueRefreshLockedContainerPdcTagsInLoadedChunks() {
278+
startQueuedPdcTagRefreshWorker();
267279
for (World world : Bukkit.getWorlds()) {
268280
for (Chunk chunk : world.getLoadedChunks()) {
269-
refreshLockedContainerPdcTagsInChunk(chunk);
281+
queueRefreshLockedContainerPdcTagsInChunk(chunk);
282+
}
283+
}
284+
}
285+
286+
public static void stopQueuedPdcTagRefreshWorker() {
287+
if (queuedPdcTagRefreshWorker != null) {
288+
queuedPdcTagRefreshWorker.cancel();
289+
queuedPdcTagRefreshWorker = null;
290+
}
291+
queuedPdcTagRefreshTasks.clear();
292+
queuedPdcTagRefreshKeys.clear();
293+
}
294+
295+
private static void startQueuedPdcTagRefreshWorker() {
296+
if (queuedPdcTagRefreshWorker != null) return;
297+
queuedPdcTagRefreshWorker = CompatibleScheduler.runTaskTimer(
298+
LockettePro.getPlugin(),
299+
null,
300+
Utils::drainQueuedPdcTagRefreshTasks,
301+
1L,
302+
1L
303+
);
304+
}
305+
306+
private static void drainQueuedPdcTagRefreshTasks() {
307+
int budget = PDC_TAG_REFRESH_TILE_ENTITY_BUDGET_PER_TICK;
308+
while (budget > 0 && !queuedPdcTagRefreshTasks.isEmpty()) {
309+
ChunkTagRefreshTask task = queuedPdcTagRefreshTasks.peekFirst();
310+
int processed = task.process(budget);
311+
if (task.isDone()) {
312+
queuedPdcTagRefreshTasks.pollFirst();
313+
queuedPdcTagRefreshKeys.remove(task.key);
314+
}
315+
if (processed <= 0) {
316+
processed = 1;
317+
}
318+
budget -= processed;
319+
}
320+
}
321+
322+
private static void refreshLockedContainerPdcTagByTileState(BlockState blockState) {
323+
if (blockState == null) return;
324+
if (blockState instanceof Container) {
325+
ContainerPdcLockManager.refreshLockedContainerTag(blockState.getBlock());
326+
}
327+
if (!(blockState instanceof Sign)) return;
328+
Block signBlock = blockState.getBlock();
329+
if (!LocketteProAPI.isLockSign(signBlock)) return;
330+
refreshLockedContainerPdcTag(LocketteProAPI.getAttachedBlock(signBlock));
331+
}
332+
333+
private static String toChunkQueueKey(UUID worldId, int chunkX, int chunkZ) {
334+
return worldId + ":" + chunkX + ":" + chunkZ;
335+
}
336+
337+
private static final class ChunkTagRefreshTask {
338+
private final UUID worldId;
339+
private final int chunkX;
340+
private final int chunkZ;
341+
private final String key;
342+
private BlockState[] tileEntities;
343+
private int cursor;
344+
private boolean done;
345+
346+
private ChunkTagRefreshTask(UUID worldId, int chunkX, int chunkZ, String key) {
347+
this.worldId = worldId;
348+
this.chunkX = chunkX;
349+
this.chunkZ = chunkZ;
350+
this.key = key;
351+
}
352+
353+
private int process(int budget) {
354+
if (done) return 0;
355+
if (!ensureTileEntitiesLoaded()) return 0;
356+
357+
int processed = 0;
358+
while (cursor < tileEntities.length && processed < budget) {
359+
refreshLockedContainerPdcTagByTileState(tileEntities[cursor]);
360+
cursor++;
361+
processed++;
362+
}
363+
if (cursor >= tileEntities.length) {
364+
done = true;
270365
}
366+
return processed;
367+
}
368+
369+
private boolean ensureTileEntitiesLoaded() {
370+
if (tileEntities != null) {
371+
return true;
372+
}
373+
World world = Bukkit.getWorld(worldId);
374+
if (world == null || !world.isChunkLoaded(chunkX, chunkZ)) {
375+
done = true;
376+
return false;
377+
}
378+
Chunk chunk = world.getChunkAt(chunkX, chunkZ);
379+
tileEntities = chunk.getTileEntities();
380+
cursor = 0;
381+
if (tileEntities.length == 0) {
382+
done = true;
383+
}
384+
return true;
385+
}
386+
387+
private boolean isDone() {
388+
return done;
271389
}
272390
}
273391

0 commit comments

Comments
 (0)