Skip to content

Commit 9f79488

Browse files
committed
Merge branch 'master' into mc/1.12
2 parents 0425243 + a7d46b4 commit 9f79488

File tree

13 files changed

+263
-138
lines changed

13 files changed

+263
-138
lines changed

BlueMapBukkit/src/main/java/de/bluecolored/bluemap/bukkit/BukkitPlugin.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ private UUID getUUIDForWorldSync (File worldFolder) throws IOException {
104104
if (worldFolder.equals(world.getWorldFolder().getCanonicalFile())) return world.getUID();
105105
}
106106

107-
throw new IOException("There is no world with this folder loaded: " + worldFolder.getCanonicalPath());
107+
throw new IOException("There is no world with this folder loaded: " + worldFolder.getPath());
108108
}
109109

110110
@Override

BlueMapBukkit/src/main/resources/bluemap-bukkit.conf

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ renderThreadCount: -2
2424

2525
# If this is true, BlueMap might send really basic metrics reports containg only the implementation-type and the version that is being used to https://metrics.bluecolored.de/bluemap/
2626
# This allows me to track the basic usage of BlueMap and helps me stay motivated to further develop this tool! Please leave it on :)
27-
# An example report looks like this: {"implementation":"CLI","version":"%version%"}
27+
# An example report looks like this: {"implementation":"bukkit","version":"%version%"}
2828
metrics: true
2929

3030
# The folder where bluemap saves data-files it needs during runtime or to save e.g. the render-progress to resume it later.
@@ -74,6 +74,10 @@ maps: [
7474

7575
# The path to the save-folder of the world to render
7676
world: "world"
77+
78+
# The position on the world where the map will be centered if you open it.
79+
# This defaults to the world-spawn if you don't set it.
80+
#startPos: [500, -820]
7781

7882
# If this is false, BlueMap tries to omit all blocks that are not visible from above-ground.
7983
# More specific: Block-Faces that have a sunlight/skylight value of 0 are removed.

BlueMapCLI/src/main/java/de/bluecolored/bluemap/cli/BlueMapCLI.java

Lines changed: 108 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,14 @@
2424
*/
2525
package de.bluecolored.bluemap.cli;
2626

27+
import java.io.DataInputStream;
28+
import java.io.DataOutputStream;
2729
import java.io.File;
30+
import java.io.FileInputStream;
31+
import java.io.FileOutputStream;
2832
import java.io.IOException;
33+
import java.io.InputStream;
34+
import java.io.OutputStream;
2935
import java.net.URL;
3036
import java.util.ArrayList;
3137
import java.util.Arrays;
@@ -36,6 +42,8 @@
3642
import java.util.UUID;
3743
import java.util.concurrent.ForkJoinPool;
3844
import java.util.concurrent.TimeUnit;
45+
import java.util.zip.GZIPInputStream;
46+
import java.util.zip.GZIPOutputStream;
3947

4048
import org.apache.commons.cli.CommandLine;
4149
import org.apache.commons.cli.CommandLineParser;
@@ -136,15 +144,14 @@ public void renderMaps() throws IOException {
136144
webSettings.setAllEnabled(false);
137145
for (MapType map : maps.values()) {
138146
webSettings.setEnabled(true, map.getId());
139-
webSettings.setName(map.getName(), map.getId());
140147
webSettings.setFrom(map.getTileRenderer(), map.getId());
148+
webSettings.setFrom(map.getWorld(), map.getId());
141149
}
142150
int ordinal = 0;
143151
for (MapConfig map : config.getMapConfigs()) {
144152
if (!maps.containsKey(map.getId())) continue; //don't add not loaded maps
145153
webSettings.setOrdinal(ordinal++, map.getId());
146-
webSettings.setHiresViewDistance(map.getHiresViewDistance(), map.getId());
147-
webSettings.setLowresViewDistance(map.getLowresViewDistance(), map.getId());
154+
webSettings.setFrom(map, map.getId());
148155
}
149156
webSettings.save();
150157

@@ -153,86 +160,118 @@ public void renderMaps() throws IOException {
153160
resourcePack.saveTextureFile(textureExportFile);
154161

155162
RenderManager renderManager = new RenderManager(config.getRenderThreadCount());
156-
renderManager.start();
163+
File rmstate = new File(configFolder, "rmstate");
157164

158-
for (MapType map : maps.values()) {
159-
Logger.global.logInfo("Rendering map '" + map.getId() + "' ...");
160-
Logger.global.logInfo("Collecting tiles to render...");
161-
162-
Collection<Vector2i> chunks;
163-
if (!forceRender) {
164-
long lastRender = webSettings.getLong(map.getId(), "last-render");
165-
chunks = map.getWorld().getChunkList(lastRender);
166-
} else {
167-
chunks = map.getWorld().getChunkList();
165+
if (rmstate.exists()) {
166+
try (
167+
InputStream in = new GZIPInputStream(new FileInputStream(rmstate));
168+
DataInputStream din = new DataInputStream(in);
169+
){
170+
renderManager.readState(din, maps.values());
171+
Logger.global.logInfo("Found unfinished render, continuing ... (If you want to start a new render, delete the this file: " + rmstate.getCanonicalPath());
172+
} catch (IOException ex) {
173+
Logger.global.logError("Failed to read saved render-state! Remove the file " + rmstate.getCanonicalPath() + " to start a new render.", ex);
168174
}
169-
170-
HiresModelManager hiresModelManager = map.getTileRenderer().getHiresModelManager();
171-
Collection<Vector2i> tiles = hiresModelManager.getTilesForChunks(chunks);
172-
Logger.global.logInfo("Found " + tiles.size() + " tiles to render! (" + chunks.size() + " chunks)");
173-
if (!forceRender && chunks.size() == 0) {
174-
Logger.global.logInfo("(This is normal if nothing has changed in the world since the last render. Use -f on the command-line to force a render of all chunks)");
175-
}
176-
177-
if (tiles.isEmpty()) {
178-
continue;
175+
} else {
176+
for (MapType map : maps.values()) {
177+
Logger.global.logInfo("Creating render-task for map '" + map.getId() + "' ...");
178+
Logger.global.logInfo("Collecting tiles ...");
179+
180+
Collection<Vector2i> chunks;
181+
if (!forceRender) {
182+
long lastRender = webSettings.getLong(map.getId(), "last-render");
183+
chunks = map.getWorld().getChunkList(lastRender);
184+
} else {
185+
chunks = map.getWorld().getChunkList();
186+
}
187+
188+
HiresModelManager hiresModelManager = map.getTileRenderer().getHiresModelManager();
189+
Collection<Vector2i> tiles = hiresModelManager.getTilesForChunks(chunks);
190+
Logger.global.logInfo("Found " + tiles.size() + " tiles to render! (" + chunks.size() + " chunks)");
191+
if (!forceRender && chunks.size() == 0) {
192+
Logger.global.logInfo("(This is normal if nothing has changed in the world since the last render. Use -f on the command-line to force a render of all chunks)");
193+
}
194+
195+
if (tiles.isEmpty()) {
196+
continue;
197+
}
198+
199+
RenderTask task = new RenderTask(map.getName(), map);
200+
task.addTiles(tiles);
201+
task.optimizeQueue();
202+
203+
renderManager.addRenderTask(task);
179204
}
205+
}
206+
207+
Logger.global.logInfo("Starting render ...");
208+
renderManager.start();
180209

181-
Logger.global.logInfo("Starting Render...");
182-
long starttime = System.currentTimeMillis();
183-
184-
RenderTask task = new RenderTask("Map-Render: " + map.getName(), map);
185-
task.addTiles(tiles);
186-
task.optimizeQueue();
187-
188-
renderManager.addRenderTask(task);
210+
long startTime = System.currentTimeMillis();
211+
212+
long lastLogUpdate = startTime;
213+
long lastSave = startTime;
214+
215+
while(renderManager.getRenderTaskCount() != 0) {
216+
try {
217+
Thread.sleep(200);
218+
} catch (InterruptedException e) {}
189219

190-
long lastLogUpdate = System.currentTimeMillis();
191-
long lastSave = lastLogUpdate;
220+
221+
long now = System.currentTimeMillis();
192222

193-
while(!task.isFinished()) {
194-
try {
195-
Thread.sleep(200);
196-
} catch (InterruptedException e) {}
223+
if (lastLogUpdate < now - 10000) { // print update all 10 seconds
224+
RenderTask currentTask = renderManager.getCurrentRenderTask();
225+
lastLogUpdate = now;
226+
long time = currentTask.getActiveTime();
197227

198-
long now = System.currentTimeMillis();
228+
String durationString = DurationFormatUtils.formatDurationWords(time, true, true);
229+
int tileCount = currentTask.getRemainingTileCount() + currentTask.getRenderedTileCount();
230+
double pct = (double)currentTask.getRenderedTileCount() / (double) tileCount;
199231

200-
if (lastLogUpdate < now - 10000) { // print update all 10 seconds
201-
lastLogUpdate = now;
202-
long time = task.getActiveTime();
203-
204-
String durationString = DurationFormatUtils.formatDurationWords(time, true, true);
205-
int tileCount = task.getRemainingTileCount() + task.getRenderedTileCount();
206-
double pct = (double)task.getRenderedTileCount() / (double) tileCount;
207-
208-
long ert = (long)((time / pct) * (1d - pct));
209-
String ertDurationString = DurationFormatUtils.formatDurationWords(ert, true, true);
210-
211-
double tps = task.getRenderedTileCount() / (time / 1000.0);
212-
213-
Logger.global.logInfo("Rendered " + task.getRenderedTileCount() + " of " + tileCount + " tiles in " + durationString + " | " + GenericMath.round(tps, 3) + " tiles/s");
214-
Logger.global.logInfo(GenericMath.round(pct * 100, 3) + "% | Estimated remaining time: " + ertDurationString);
215-
}
232+
long ert = (long)((time / pct) * (1d - pct));
233+
String ertDurationString = DurationFormatUtils.formatDurationWords(ert, true, true);
216234

217-
if (lastSave < now - 5 * 60000) { // save every 5 minutes
218-
lastSave = now;
219-
map.getTileRenderer().save();
220-
}
235+
double tps = currentTask.getRenderedTileCount() / (time / 1000.0);
236+
237+
Logger.global.logInfo("Rendering map '" + currentTask.getName() + "':");
238+
Logger.global.logInfo("Rendered " + currentTask.getRenderedTileCount() + " of " + tileCount + " tiles in " + durationString + " | " + GenericMath.round(tps, 3) + " tiles/s");
239+
Logger.global.logInfo(GenericMath.round(pct * 100, 3) + "% | Estimated remaining time: " + ertDurationString);
221240
}
241+
242+
if (lastSave < now - 1 * 60000) { // save every minute
243+
RenderTask currentTask = renderManager.getCurrentRenderTask();
244+
245+
lastSave = now;
246+
currentTask.getMapType().getTileRenderer().save();
222247

223-
map.getTileRenderer().save();
224-
225-
try {
226-
webSettings.set(starttime, map.getId(), "last-render");
227-
webSettings.save();
228-
} catch (IOException e) {
229-
Logger.global.logError("Failed to update web-settings!", e);
248+
try (
249+
OutputStream os = new GZIPOutputStream(new FileOutputStream(rmstate));
250+
DataOutputStream dos = new DataOutputStream(os);
251+
){
252+
renderManager.writeState(dos);
253+
} catch (IOException ex) {
254+
Logger.global.logError("Failed to save render-state!", ex);
255+
}
230256
}
231257
}
232258

233259
renderManager.stop();
234260

235-
Logger.global.logInfo("Waiting for all threads to quit...");
261+
//render finished, so remove render state file
262+
rmstate.delete();
263+
264+
for (MapType map : maps.values()) {
265+
webSettings.set(startTime, map.getId(), "last-render");
266+
}
267+
268+
try {
269+
webSettings.save();
270+
} catch (IOException e) {
271+
Logger.global.logError("Failed to update web-settings!", e);
272+
}
273+
274+
Logger.global.logInfo("Waiting for all threads to quit ...");
236275
if (!ForkJoinPool.commonPool().awaitQuiescence(30, TimeUnit.SECONDS)) {
237276
Logger.global.logWarning("Some save-threads are taking very long to exit (>30s), they will be ignored.");
238277
}
@@ -241,14 +280,14 @@ public void renderMaps() throws IOException {
241280
}
242281

243282
public void startWebserver() throws IOException {
244-
Logger.global.logInfo("Starting webserver...");
283+
Logger.global.logInfo("Starting webserver ...");
245284

246285
BlueMapWebServer webserver = new BlueMapWebServer(configManager.getMainConfig());
247286
webserver.start();
248287
}
249288

250289
private boolean loadResources() throws IOException, ParseResourceException {
251-
Logger.global.logInfo("Loading resources...");
290+
Logger.global.logInfo("Loading resources ...");
252291

253292
MainConfig config = configManager.getMainConfig();
254293

BlueMapCLI/src/main/resources/bluemap-cli.conf

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ renderThreadCount: 0
2424

2525
# If this is true, BlueMap might send really basic metrics reports containg only the implementation-type and the version that is being used to https://metrics.bluecolored.de/bluemap/
2626
# This allows me to track the basic usage of BlueMap and helps me stay motivated to further develop this tool! Please leave it on :)
27-
# An example report looks like this: {"implementation":"CLI","version":"%version%"}
27+
# An example report looks like this: {"implementation":"cli","version":"%version%"}
2828
metrics: true
2929

3030
# The folder where bluemap saves data-files it needs during runtime
@@ -73,6 +73,10 @@ maps: [
7373

7474
# The path to the save-folder of the world to render
7575
world: "world"
76+
77+
# The position on the world where the map will be centered if you open it.
78+
# This defaults to the world-spawn if you don't set it.
79+
#startPos: [500, -820]
7680

7781
# If this is false, BlueMap tries to omit all blocks that are not visible from above-ground.
7882
# More specific: Block-Faces that have a sunlight/skylight value of 0 are removed.

BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/RenderManager.java

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,10 @@ private void renderThread() {
127127
RenderTask task = renderTasks.peek();
128128
if (task != null) {
129129
ticket = task.poll();
130-
if (task.isFinished()) renderTasks.poll();
131-
task.getMapType().getTileRenderer().save();
130+
if (task.isFinished()) {
131+
renderTasks.poll();
132+
task.getMapType().getTileRenderer().save();
133+
}
132134
}
133135
}
134136
}
@@ -155,7 +157,17 @@ public int getQueueSize() {
155157
* Returns a copy of the deque with the render tasks in order as array
156158
*/
157159
public RenderTask[] getRenderTasks(){
158-
return renderTasks.toArray(new RenderTask[renderTasks.size()]);
160+
synchronized (renderTasks) {
161+
return renderTasks.toArray(new RenderTask[renderTasks.size()]);
162+
}
163+
}
164+
165+
public int getRenderTaskCount(){
166+
return renderTasks.size();
167+
}
168+
169+
public RenderTask getCurrentRenderTask() {
170+
return renderTasks.peek();
159171
}
160172

161173
public boolean isRunning() {

0 commit comments

Comments
 (0)