Skip to content

Commit 434afd5

Browse files
committed
Add pacing option for large region sets: limits updates per tick to avoid lag spikes
1 parent f9c8a6c commit 434afd5

File tree

2 files changed

+52
-28
lines changed

2 files changed

+52
-28
lines changed

src/main/java/org/dynmap/worldguard/DynmapWorldGuardPlugin.java

Lines changed: 50 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.dynmap.worldguard;
22

33
import java.io.IOException;
4+
import java.util.ArrayList;
45
import java.util.HashMap;
56
import java.util.HashSet;
67
import java.util.List;
@@ -44,6 +45,7 @@ public class DynmapWorldGuardPlugin extends JavaPlugin {
4445
MarkerAPI markerapi;
4546
WorldGuardPlugin wg;
4647
BooleanFlag boost_flag;
48+
int updatesPerTick = 20;
4749

4850
FileConfiguration cfg;
4951
MarkerSet set;
@@ -99,13 +101,6 @@ public static void info(String msg) {
99101
public static void severe(String msg) {
100102
log.log(Level.SEVERE, msg);
101103
}
102-
103-
private class WorldGuardUpdate implements Runnable {
104-
public void run() {
105-
if(!stop)
106-
updateRegions();
107-
}
108-
}
109104

110105
private Map<String, AreaMarker> resareas = new HashMap<String, AreaMarker>();
111106

@@ -269,17 +264,50 @@ else if(tn.equalsIgnoreCase("polygon")) {
269264
}
270265
}
271266

272-
/* Update worldguard region information */
273-
private void updateRegions() {
267+
private class UpdateJob implements Runnable {
274268
Map<String,AreaMarker> newmap = new HashMap<String,AreaMarker>(); /* Build new map */
275-
276-
/* Loop through worlds */
277-
for(World w : getServer().getWorlds()) {
278-
RegionManager rm = wg.getRegionManager(w); /* Get region manager for world */
279-
if(rm == null) continue;
280-
281-
Map<String,ProtectedRegion> regions = rm.getRegions(); /* Get all the regions */
282-
for(ProtectedRegion pr : regions.values()) {
269+
List<World> worldsToDo = null;
270+
List<ProtectedRegion> regionsToDo = null;
271+
World curworld = null;
272+
273+
public void run() {
274+
if (stop) {
275+
return;
276+
}
277+
// If worlds list isn't primed, prime it
278+
if (worldsToDo == null) {
279+
worldsToDo = new ArrayList<World>(getServer().getWorlds());
280+
}
281+
while (regionsToDo == null) { // No pending regions for world
282+
if (worldsToDo.isEmpty()) { // No more worlds?
283+
/* Now, review old map - anything left is gone */
284+
for(AreaMarker oldm : resareas.values()) {
285+
oldm.deleteMarker();
286+
}
287+
/* And replace with new map */
288+
resareas = newmap;
289+
// Set up for next update (new job)
290+
getServer().getScheduler().scheduleSyncDelayedTask(DynmapWorldGuardPlugin.this, new UpdateJob(), updperiod);
291+
return;
292+
}
293+
else {
294+
curworld = worldsToDo.remove(0);
295+
RegionManager rm = wg.getRegionManager(curworld); /* Get region manager for world */
296+
if(rm != null) {
297+
Map<String,ProtectedRegion> regions = rm.getRegions(); /* Get all the regions */
298+
if ((regions != null) && (regions.isEmpty() == false)) {
299+
regionsToDo = new ArrayList<ProtectedRegion>(regions.values());
300+
}
301+
}
302+
}
303+
}
304+
/* Now, process up to limit regions */
305+
for (int i = 0; i < updatesPerTick; i++) {
306+
if (regionsToDo.isEmpty()) {
307+
regionsToDo = null;
308+
break;
309+
}
310+
ProtectedRegion pr = regionsToDo.remove(regionsToDo.size()-1);
283311
int depth = 1;
284312
ProtectedRegion p = pr;
285313
while(p.getParent() != null) {
@@ -288,18 +316,11 @@ private void updateRegions() {
288316
}
289317
if(depth > maxdepth)
290318
continue;
291-
handleRegion(w, pr, newmap);
319+
handleRegion(curworld, pr, newmap);
292320
}
321+
// Tick next step in the job
322+
getServer().getScheduler().scheduleSyncDelayedTask(DynmapWorldGuardPlugin.this, this, 1);
293323
}
294-
/* Now, review old map - anything left is gone */
295-
for(AreaMarker oldm : resareas.values()) {
296-
oldm.deleteMarker();
297-
}
298-
/* And replace with new map */
299-
resareas = newmap;
300-
301-
getServer().getScheduler().scheduleSyncDelayedTask(this, new WorldGuardUpdate(), updperiod);
302-
303324
}
304325

305326
private class OurServerListener implements Listener {
@@ -413,6 +434,7 @@ private void activate() {
413434
use3d = cfg.getBoolean("use3dregions", false);
414435
infowindow = cfg.getString("infowindow", DEF_INFOWINDOW);
415436
maxdepth = cfg.getInt("maxdepth", 16);
437+
updatesPerTick = cfg.getInt("updates-per-tick", 20);
416438

417439
/* Get style information */
418440
defstyle = new AreaStyle(cfg, "regionstyle");
@@ -453,7 +475,7 @@ private void activate() {
453475
updperiod = (long)(per*20);
454476
stop = false;
455477

456-
getServer().getScheduler().scheduleSyncDelayedTask(this, new WorldGuardUpdate(), 40); /* First time is 2 seconds */
478+
getServer().getScheduler().scheduleSyncDelayedTask(this, new UpdateJob(), 40); /* First time is 2 seconds */
457479

458480
info("version " + this.getDescription().getVersion() + " is activated");
459481
}

src/main/resources/config.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,5 @@ ownerstyle:
5050
# Limit depth of child regions (1=just top regions, 2=top plus children of top)
5151
maxdepth: 16
5252

53+
# Limit number of regions processed per tick (avoid lag spikes on servers with lots of regions)
54+
updates-per-tick: 20

0 commit comments

Comments
 (0)