Make CLI use some classes from common and remove the obsolete ones

This commit is contained in:
Blue (Lukas Rieger) 2020-01-19 01:51:30 +01:00
parent 5dc59b454b
commit 0b8624d54e
4 changed files with 51 additions and 265 deletions

View File

@ -1,4 +1,4 @@
dependencies {
compile group: 'commons-cli', name: 'commons-cli', version: '1.4'
compile project(':BlueMapCore')
compile project(':BlueMapCommon')
}

View File

@ -45,10 +45,15 @@ import org.apache.commons.cli.Option;
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 class BlueMapCLI {
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 class BlueMapCLI {
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 class BlueMapCLI {
}
}
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.");

View File

@ -1,91 +0,0 @@
/*
* This file is part of BlueMap, licensed under the MIT License (MIT).
*
* Copyright (c) Blue (Lukas Rieger) <https://bluecolored.de>
* 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;
}
}

View File

@ -1,171 +0,0 @@
/*
* This file is part of BlueMap, licensed under the MIT License (MIT).
*
* Copyright (c) Blue (Lukas Rieger) <https://bluecolored.de>
* 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<Vector2i> tilesToRender;
private int tileCount;
private long startTime = -1;
private int renderedTiles = 0;
private Thread[] threads;
public RenderTask(MapType map, Collection<Vector2i> 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<Vector2i> 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++;
}
}
}