From 0b8624d54e69f75fdeba9538796a66bb182577a7 Mon Sep 17 00:00:00 2001 From: "Blue (Lukas Rieger)" Date: Sun, 19 Jan 2020 01:51:30 +0100 Subject: [PATCH] Make CLI use some classes from common and remove the obsolete ones --- BlueMapCLI/build.gradle | 2 +- .../bluecolored/bluemap/cli/BlueMapCLI.java | 52 +++++- .../de/bluecolored/bluemap/cli/MapType.java | 91 ---------- .../bluecolored/bluemap/cli/RenderTask.java | 171 ------------------ 4 files changed, 51 insertions(+), 265 deletions(-) delete mode 100644 BlueMapCLI/src/main/java/de/bluecolored/bluemap/cli/MapType.java delete mode 100644 BlueMapCLI/src/main/java/de/bluecolored/bluemap/cli/RenderTask.java diff --git a/BlueMapCLI/build.gradle b/BlueMapCLI/build.gradle index b17d6fa5..0820d22c 100644 --- a/BlueMapCLI/build.gradle +++ b/BlueMapCLI/build.gradle @@ -1,4 +1,4 @@ dependencies { compile group: 'commons-cli', name: 'commons-cli', version: '1.4' - compile project(':BlueMapCore') + compile project(':BlueMapCommon') } diff --git a/BlueMapCLI/src/main/java/de/bluecolored/bluemap/cli/BlueMapCLI.java b/BlueMapCLI/src/main/java/de/bluecolored/bluemap/cli/BlueMapCLI.java index d6bca0e8..881d4a21 100644 --- a/BlueMapCLI/src/main/java/de/bluecolored/bluemap/cli/BlueMapCLI.java +++ b/BlueMapCLI/src/main/java/de/bluecolored/bluemap/cli/BlueMapCLI.java @@ -45,10 +45,15 @@ import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.time.DurationFormatUtils; +import com.flowpowered.math.GenericMath; import com.flowpowered.math.vector.Vector2i; import com.google.common.base.Preconditions; +import de.bluecolored.bluemap.common.MapType; +import de.bluecolored.bluemap.common.RenderManager; +import de.bluecolored.bluemap.common.RenderTask; import de.bluecolored.bluemap.core.config.ConfigManager; import de.bluecolored.bluemap.core.config.MainConfig; import de.bluecolored.bluemap.core.config.MainConfig.MapConfig; @@ -147,6 +152,9 @@ public void renderMaps() throws IOException { File textureExportFile = config.getWebDataPath().resolve("textures.json").toFile(); resourcePack.saveTextureFile(textureExportFile); + RenderManager renderManager = new RenderManager(config.getRenderThreadCount()); + renderManager.start(); + for (MapType map : maps.values()) { Logger.global.logInfo("Rendering map '" + map.getId() + "' ..."); Logger.global.logInfo("Collecting tiles to render..."); @@ -173,8 +181,46 @@ public void renderMaps() throws IOException { Logger.global.logInfo("Starting Render..."); long starttime = System.currentTimeMillis(); - RenderTask task = new RenderTask(map, tiles, config.getRenderThreadCount()); - task.render(); + RenderTask task = new RenderTask("Map-Render: " + map.getName(), map); + task.addTiles(tiles); + task.optimizeQueue(); + + renderManager.addRenderTask(task); + + long lastLogUpdate = System.currentTimeMillis(); + long lastSave = lastLogUpdate; + + while(!task.isFinished()) { + try { + Thread.sleep(200); + } catch (InterruptedException e) {} + + long now = System.currentTimeMillis(); + + if (lastLogUpdate < now - 10000) { // print update all 10 seconds + lastLogUpdate = now; + long time = task.getActiveTime(); + + String durationString = DurationFormatUtils.formatDurationWords(time, true, true); + int tileCount = task.getRemainingTileCount() + task.getRenderedTileCount(); + double pct = (double)task.getRenderedTileCount() / (double) tileCount; + + long ert = (long)((time / pct) * (1d - pct)); + String ertDurationString = DurationFormatUtils.formatDurationWords(ert, true, true); + + double tps = task.getRenderedTileCount() / (time / 1000.0); + + Logger.global.logInfo("Rendered " + task.getRenderedTileCount() + " of " + tileCount + " tiles in " + durationString + " | " + GenericMath.round(tps, 3) + " tiles/s"); + Logger.global.logInfo(GenericMath.round(pct * 100, 3) + "% | Estimated remaining time: " + ertDurationString); + } + + if (lastSave < now - 5 * 60000) { // save every 5 minutes + lastSave = now; + map.getTileRenderer().save(); + } + } + + map.getTileRenderer().save(); try { webSettings.set(starttime, map.getId(), "last-render"); @@ -184,6 +230,8 @@ public void renderMaps() throws IOException { } } + renderManager.stop(); + Logger.global.logInfo("Waiting for all threads to quit..."); if (!ForkJoinPool.commonPool().awaitQuiescence(30, TimeUnit.SECONDS)) { Logger.global.logWarning("Some save-threads are taking very long to exit (>30s), they will be ignored."); diff --git a/BlueMapCLI/src/main/java/de/bluecolored/bluemap/cli/MapType.java b/BlueMapCLI/src/main/java/de/bluecolored/bluemap/cli/MapType.java deleted file mode 100644 index 501a79d3..00000000 --- a/BlueMapCLI/src/main/java/de/bluecolored/bluemap/cli/MapType.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * This file is part of BlueMap, licensed under the MIT License (MIT). - * - * Copyright (c) Blue (Lukas Rieger) - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package de.bluecolored.bluemap.cli; - -import java.io.IOException; - -import com.flowpowered.math.vector.Vector2i; -import com.google.common.base.Preconditions; - -import de.bluecolored.bluemap.core.render.TileRenderer; -import de.bluecolored.bluemap.core.render.WorldTile; -import de.bluecolored.bluemap.core.world.World; - -public class MapType { - - private final String id; - private String name; - private World world; - private TileRenderer tileRenderer; - - public MapType(String id, String name, World world, TileRenderer tileRenderer) { - Preconditions.checkNotNull(id); - Preconditions.checkNotNull(name); - Preconditions.checkNotNull(world); - Preconditions.checkNotNull(tileRenderer); - - this.id = id; - this.name = name; - this.world = world; - this.tileRenderer = tileRenderer; - } - - public String getId() { - return id; - } - - public String getName() { - return name; - } - - public World getWorld() { - return world; - } - - public TileRenderer getTileRenderer() { - return tileRenderer; - } - - public void renderTile(Vector2i tile) throws IOException { - getTileRenderer().render(new WorldTile(getWorld(), tile)); - } - - @Override - public int hashCode() { - return id.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (obj != null && obj instanceof MapType) { - MapType that = (MapType) obj; - - return this.id.equals(that.id); - } - - return false; - } - -} diff --git a/BlueMapCLI/src/main/java/de/bluecolored/bluemap/cli/RenderTask.java b/BlueMapCLI/src/main/java/de/bluecolored/bluemap/cli/RenderTask.java deleted file mode 100644 index 5ae8ec89..00000000 --- a/BlueMapCLI/src/main/java/de/bluecolored/bluemap/cli/RenderTask.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * This file is part of BlueMap, licensed under the MIT License (MIT). - * - * Copyright (c) Blue (Lukas Rieger) - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package de.bluecolored.bluemap.cli; - -import java.io.IOException; -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Deque; - -import org.apache.commons.lang3.time.DurationFormatUtils; - -import com.flowpowered.math.GenericMath; -import com.flowpowered.math.vector.Vector2d; -import com.flowpowered.math.vector.Vector2i; - -import de.bluecolored.bluemap.core.logger.Logger; -import de.bluecolored.bluemap.core.render.TileRenderer; -import de.bluecolored.bluemap.core.render.WorldTile; -import de.bluecolored.bluemap.core.world.World; - -public class RenderTask { - - private World world; - private TileRenderer tileRenderer; - private Deque tilesToRender; - - private int tileCount; - private long startTime = -1; - private int renderedTiles = 0; - - private Thread[] threads; - - public RenderTask(MapType map, Collection tilesToRender, int threadCount) { - this.world = map.getWorld(); - this.tileRenderer = map.getTileRenderer(); - - //Sort the chunks to opimize the chunk-cache usage of MCAWorld and generate the world in a nicer order, so you can see the first results early in the web-map during render - Vector2d sortGridSize = new Vector2d(20, 20).div(tileRenderer.getHiresModelManager().getTileSize().toDouble().div(16)).ceil().max(1, 1); //Find a good grid size to match the MCAWorlds chunk-cache size of 500 - ArrayList sortedTiles = new ArrayList<>(tilesToRender); - sortedTiles.sort((v1, v2) -> { - Vector2i v1SortGridPos = v1.toDouble().div(sortGridSize).floor().toInt(); - Vector2i v2SortGridPos = v2.toDouble().div(sortGridSize).floor().toInt(); - - if (v1SortGridPos != v2SortGridPos){ - int v1Dist = v1SortGridPos.distanceSquared(Vector2i.ZERO); - int v2Dist = v2SortGridPos.distanceSquared(Vector2i.ZERO); - - if (v1Dist < v2Dist) return -1; - if (v1Dist > v2Dist) return 1; - - if (v1SortGridPos.getY() < v2SortGridPos.getY()) return -1; - if (v1SortGridPos.getY() > v2SortGridPos.getY()) return 1; - if (v1SortGridPos.getX() < v2SortGridPos.getX()) return -1; - if (v1SortGridPos.getX() > v2SortGridPos.getX()) return 1; - } - - if (v1.getY() < v2.getY()) return -1; - if (v1.getY() > v2.getY()) return 1; - if (v1.getX() < v2.getX()) return -1; - if (v1.getX() > v2.getX()) return 1; - - return 0; - }); - - this.tilesToRender = new ArrayDeque<>(sortedTiles); - - this.tileCount = this.tilesToRender.size(); - this.threads = new Thread[threadCount]; - - - } - - public void render() { - this.startTime = System.currentTimeMillis(); - - for (int i = 0; i < threads.length; i++) { - if (threads[i] != null) threads[i].interrupt(); - - threads[i] = new Thread(this::renderThread); - threads[i].start(); - } - - long lastLogUpdate = startTime; - long lastSave = startTime; - - while (!Thread.interrupted()) { - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - break; - } - - boolean stillRendering = false; - for (Thread t : threads) { - if (t.isAlive()) { - stillRendering = true; - break; - } - } - if (!stillRendering) break; - - long now = System.currentTimeMillis(); - if (lastLogUpdate < now - 10000) { // print update all 10 seconds - lastLogUpdate = now; - - long time = now - startTime; - String durationString = DurationFormatUtils.formatDurationWords(time, true, true); - double pct = (double)renderedTiles / (double)tileCount; - - long ert = (long)((time / pct) * (1d - pct)); - String ertDurationString = DurationFormatUtils.formatDurationWords(ert, true, true); - - double tps = renderedTiles / (time / 1000.0); - - Logger.global.logInfo("Rendered " + renderedTiles + " of " + tileCount + " tiles in " + durationString + " | " + GenericMath.round(tps, 3) + " tiles/s"); - Logger.global.logInfo(GenericMath.round(pct * 100, 3) + "% | Estimated remaining time: " + ertDurationString); - } - - if (lastSave < now - 5 * 60000) { // save every 5 minutes - lastSave = now; - tileRenderer.save(); - } - } - - tileRenderer.save(); - } - - private void renderThread() { - Vector2i tilePos; - - while (!Thread.interrupted()) { - synchronized (tilesToRender) { - if (tilesToRender.isEmpty()) break; - tilePos = tilesToRender.poll(); - } - - WorldTile tile = new WorldTile(world, tilePos); - try { - tileRenderer.render(tile); - } catch (IOException e) { - Logger.global.logError("Failed to render tile " + tilePos, e); - } - - renderedTiles++; - } - } - -}