Add click menu and debug option to web-app and fix two render-saving bugs that caused corrupted files sometimes

This commit is contained in:
Blue (Lukas Rieger) 2020-03-13 18:11:31 +01:00
parent dde30e932d
commit 2ed2fa3e35
20 changed files with 287 additions and 34 deletions

View File

@ -40,8 +40,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.TimeUnit;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
@ -122,8 +120,7 @@ public class BlueMapCLI {
config.getWebDataPath().resolve(mapConfig.getId()).resolve("hires"),
resourcePack,
mapConfig,
new Vector2i(mapConfig.getHiresTileSize(), mapConfig.getHiresTileSize()),
ForkJoinPool.commonPool()
new Vector2i(mapConfig.getHiresTileSize(), mapConfig.getHiresTileSize())
);
LowresModelManager lowresModelManager = new LowresModelManager(
@ -224,6 +221,8 @@ public class BlueMapCLI {
if (lastLogUpdate < now - 10000) { // print update all 10 seconds
RenderTask currentTask = renderManager.getCurrentRenderTask();
if (currentTask == null) continue;
lastLogUpdate = now;
long time = currentTask.getActiveTime();
@ -243,6 +242,7 @@ public class BlueMapCLI {
if (lastSave < now - 1 * 60000) { // save every minute
RenderTask currentTask = renderManager.getCurrentRenderTask();
if (currentTask == null) continue;
lastSave = now;
currentTask.getMapType().getTileRenderer().save();
@ -272,11 +272,6 @@ public class BlueMapCLI {
} catch (IOException e) {
Logger.global.logError("Failed to update web-settings!", e);
}
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.");
}
Logger.global.logInfo("Render finished!");
}

View File

@ -41,7 +41,6 @@ public class RenderManager {
for (int i = 0; i < renderThreads.length; i++) {
renderThreads[i] = new Thread(this::renderThread);
renderThreads[i].setDaemon(true);
renderThreads[i].setPriority(Thread.MIN_PRIORITY);
renderThreads[i].start();
}

View File

@ -14,7 +14,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.TimeUnit;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
@ -184,8 +183,7 @@ public class Plugin {
config.getWebDataPath().resolve(id).resolve("hires"),
resourcePack,
mapConfig,
new Vector2i(mapConfig.getHiresTileSize(), mapConfig.getHiresTileSize()),
ForkJoinPool.commonPool()
new Vector2i(mapConfig.getHiresTileSize(), mapConfig.getHiresTileSize())
);
LowresModelManager lowresModelManager = new LowresModelManager(

View File

@ -35,7 +35,6 @@ import java.nio.file.Path;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.zip.GZIPOutputStream;
import com.flowpowered.math.vector.Vector2i;
@ -57,22 +56,19 @@ public class HiresModelManager {
private Vector2i tileSize;
private Vector2i gridOrigin;
private ExecutorService savingExecutor;
private boolean useGzip;
public HiresModelManager(Path fileRoot, ResourcePack resourcePack, RenderSettings renderSettings, Vector2i tileSize, ExecutorService savingExecutor) {
this(fileRoot, new HiresModelRenderer(resourcePack, renderSettings), tileSize, new Vector2i(2, 2), savingExecutor, renderSettings.useGzipCompression());
public HiresModelManager(Path fileRoot, ResourcePack resourcePack, RenderSettings renderSettings, Vector2i tileSize) {
this(fileRoot, new HiresModelRenderer(resourcePack, renderSettings), tileSize, new Vector2i(2, 2), renderSettings.useGzipCompression());
}
public HiresModelManager(Path fileRoot, HiresModelRenderer renderer, Vector2i tileSize, Vector2i gridOrigin, ExecutorService savingExecutor, boolean useGzip) {
public HiresModelManager(Path fileRoot, HiresModelRenderer renderer, Vector2i tileSize, Vector2i gridOrigin, boolean useGzip) {
this.fileRoot = fileRoot;
this.renderer = renderer;
this.tileSize = tileSize;
this.gridOrigin = gridOrigin;
this.savingExecutor = savingExecutor;
this.useGzip = useGzip;
}
@ -87,7 +83,7 @@ public class HiresModelManager {
private void save(final HiresModel model) {
final String modelJson = model.toBufferGeometry().toJson();
savingExecutor.submit(() -> save(model, modelJson));
save(model, modelJson);
}
private void save(HiresModel model, String modelJson){

View File

@ -126,6 +126,7 @@ public class LowresModel {
PrintWriter pw = new PrintWriter(osw);
){
pw.print(json);
pw.flush();
}
}

View File

@ -195,7 +195,16 @@ public class LowresModelManager {
model = new CachedModel(world, tile, BufferGeometry.fromJson(json));
} catch (IllegalArgumentException | IOException ex){
Logger.global.logError("Failed to load lowres model: " + modelFile, ex);
modelFile.delete();
/*
File brokenFile = modelFile.toPath().getParent().resolve(modelFile.getName() + ".broken").toFile();
if (brokenFile.exists()) brokenFile.delete();
if (!modelFile.renameTo(brokenFile)) {
modelFile.delete();
}
*/
}
}

View File

@ -77,6 +77,7 @@ export default class BlueMap {
this.skyColor = {
value: new Vector3(0, 0, 0)
};
this.debugInfo = false;
this.ui = new UI(this);
@ -139,6 +140,7 @@ export default class BlueMap {
this.loadLowresTile,
this.lowresScene,
this.settings.maps[this.map]['lowres']['tileSize'],
this.settings.maps[this.map]['lowres']['translate'],
startPos
);
@ -148,6 +150,7 @@ export default class BlueMap {
this.loadHiresTile,
this.hiresScene,
this.settings.maps[this.map]['hires']['tileSize'],
this.settings.maps[this.map]['hires']['translate'],
startPos
);
@ -349,6 +352,7 @@ export default class BlueMap {
this.quality = this.loadUserSetting("renderQuality", this.quality);
this.hiresViewDistance = this.loadUserSetting("hiresViewDistance", this.hiresViewDistance);
this.lowresViewDistance = this.loadUserSetting("lowresViewDistance", this.lowresViewDistance);
this.debugInfo = this.loadUserSetting("debugInfo", this.debugInfo);
}
saveUserSettings(){
@ -361,6 +365,7 @@ export default class BlueMap {
this.saveUserSetting("renderQuality", this.quality);
this.saveUserSetting("hiresViewDistance", this.hiresViewDistance);
this.saveUserSetting("lowresViewDistance", this.lowresViewDistance);
this.saveUserSetting("debugInfo", this.debugInfo);
}
loadUserSetting(key, defaultValue){

View File

@ -100,6 +100,7 @@ export default class Controls {
this.keyStates = {};
this.state = Controls.STATES.NONE;
this.mouseMoved = false;
let canvas = $(this.element).find('canvas').get(0);
@ -116,6 +117,7 @@ export default class Controls {
// touch events
this.hammer = new Hammer.Manager(canvas);
let touchTap = new Hammer.Tap({ event: 'tap', pointers: 1, taps: 1, threshold: 2 });
let touchMove = new Hammer.Pan({ event: 'move', direction: Hammer.DIRECTION_ALL, threshold: 0 });
let touchTilt = new Hammer.Pan({ event: 'tilt', direction: Hammer.DIRECTION_VERTICAL, pointers: 2, threshold: 0 });
let touchRotate = new Hammer.Rotate({ event: 'rotate', pointers: 2, threshold: 10 });
@ -125,6 +127,7 @@ export default class Controls {
touchTilt.recognizeWith(touchZoom);
touchRotate.recognizeWith(touchZoom);
this.hammer.add( touchTap );
this.hammer.add( touchMove );
this.hammer.add( touchTilt );
this.hammer.add( touchRotate );
@ -144,6 +147,7 @@ export default class Controls {
this.hammer.on('rotatecancel', this.onTouchRotateUp);
this.hammer.on('zoomstart', this.onTouchZoomDown);
this.hammer.on('zoommove', this.onTouchZoomMove);
this.hammer.on('tap', this.onInfoClick);
this.camera.position.set(0, 1000, 0);
this.camera.lookAt(this.position);
@ -429,4 +433,11 @@ export default class Controls {
onKeyUp = event => {
this.keyStates[event.keyCode] = false;
};
onInfoClick = event => {
$(document).trigger({
type: 'bluemap-info-click',
pos: event.center
});
}
}

View File

@ -30,9 +30,10 @@ import Tile from './Tile.js';
import { hashTile } from './utils.js';
export default class TileManager {
constructor(blueMap, viewDistance, tileLoader, scene, tileSize, position) {
constructor(blueMap, viewDistance, tileLoader, scene, tileSize, tileOffset, position) {
this.blueMap = blueMap;
this.tileSize = new Vector2(tileSize.x, tileSize.z);
this.tileOffset = new Vector2(tileOffset.x, tileOffset.z);
this.setViewDistance(viewDistance);
this.tileLoader = tileLoader;
this.scene = scene;
@ -54,7 +55,7 @@ export default class TileManager {
}
setPosition(center) {
this.tile.set(center.x, center.z).divide(this.tileSize).floor();
this.tile.set(center.x, center.z).sub(this.tileOffset).divide(this.tileSize).floor();
if (!this.tile.equals(this.lastTile) && !this.closed) {
this.update();

View File

@ -0,0 +1,138 @@
import $ from 'jquery';
import {
Raycaster,
Vector2
} from 'three';
import {pathFromCoords} from "../utils";
export default class HudInfo {
constructor(blueMap, container){
this.blueMap = blueMap;
this.container = container;
this.rayPosition = new Vector2();
this.raycaster = new Raycaster();
this.element = $(`
<div class="hud-info" style="display: none">
<div class="content"></div>
</div>
`).appendTo(this.container);
$(document).on('bluemap-info-click', this.onShowInfo);
$(window).on('mousedown wheel', this.onHideInfo);
}
onShowInfo = event => {
this.rayPosition.x = ( event.pos.x / this.blueMap.element.offsetWidth ) * 2 - 1;
this.rayPosition.y = - ( event.pos.y / this.blueMap.element.offsetHeight ) * 2 + 1;
this.raycaster.setFromCamera(this.rayPosition, this.blueMap.camera);
let hiresData = true;
let intersects = this.raycaster.intersectObjects( this.blueMap.hiresScene.children );
if (intersects.length === 0){
hiresData = false;
intersects = this.raycaster.intersectObjects( this.blueMap.lowresScene.children );
}
if (intersects.length > 0) {
this.element.hide();
let content = this.element.find(".content");
content.html("");
if (this.blueMap.debugInfo){
console.debug("Tapped position data: ", intersects[0]);
}
//clicked position
let point = intersects[0].point;
let normal = intersects[0].face.normal;
let block = {
x: Math.floor(point.x - normal.x * 0.001),
y: Math.floor(point.y - normal.y * 0.001),
z: Math.floor(point.z - normal.z * 0.001),
};
if (hiresData) {
$(`
<div class="label">block:</div>
<div class="coords block">
<div class="coord"><span class="label">x</span><span class="value">${block.x}</span></div>
<div class="coord"><span class="label">y</span><span class="value">${block.y}</span></div>
<div class="coord"><span class="label">z</span><span class="value">${block.z}</span></div>
</div>
`).appendTo(content);
} else {
$(`
<div class="label">position:</div>
<div class="coords block">
<div class="coord"><span class="label">x</span><span class="value">${block.x}</span></div>
<div class="coord"><span class="label">z</span><span class="value">${block.z}</span></div>
</div>
`).appendTo(content);
}
//find light-data
if (hiresData) {
let vecIndex = intersects[0].face.a;
let attributes = intersects[0].object.geometry.attributes;
let sunlight = attributes.sunlight.array[vecIndex * attributes.sunlight.itemSize];
let blocklight = attributes.blocklight.array[vecIndex * attributes.blocklight.itemSize];
$(`
<div class="label" data-show="light">light:</div>
<div class="coords block">
<div class="coord"><span class="label">sun</span><span class="value">${sunlight}</span></div>
<div class="coord"><span class="label">block</span><span class="value">${blocklight}</span></div>
</div>
`).appendTo(content);
}
if (this.blueMap.debugInfo) {
//hires tile path
let hiresTileSize = this.blueMap.settings.maps[this.blueMap.map]['hires']['tileSize'];
hiresTileSize.y = hiresTileSize.z;
let hiresTileOffset = this.blueMap.settings.maps[this.blueMap.map]['hires']['translate'];
hiresTileOffset.y = hiresTileOffset.z;
let hiresTile = new Vector2(block.x, block.z).sub(hiresTileOffset).divide(hiresTileSize).floor();
let hrpath = this.blueMap.dataRoot + this.blueMap.map + '/hires/';
hrpath += pathFromCoords(hiresTile.x, hiresTile.y);
hrpath += '.json';
//lowres tile path
let lowresTileSize = this.blueMap.settings.maps[this.blueMap.map]['lowres']['tileSize'];
lowresTileSize.y = lowresTileSize.z;
let lowresTileOffset = this.blueMap.settings.maps[this.blueMap.map]['lowres']['translate'];
lowresTileOffset.y = lowresTileOffset.z;
let lowresTile = new Vector2(block.x, block.z).sub(lowresTileOffset).divide(lowresTileSize).floor();
let lrpath = this.blueMap.dataRoot + this.blueMap.map + '/lowres/';
lrpath += pathFromCoords(lowresTile.x, lowresTile.y);
lrpath += '.json';
$(`
<div class="files">
<span class="value">${hrpath}</span><br>
<span class="value">${lrpath}</span>
</div>
`).appendTo(content);
}
//display the element
this.element.css('left', `${event.pos.x}px`);
this.element.css('top', `${event.pos.y}px`);
if (event.pos.y < this.blueMap.element.offsetHeight / 3){
this.element.addClass("below");
} else {
this.element.removeClass("below");
}
this.element.fadeIn(200);
}
};
onHideInfo = event => {
if (!this.element.is(':animated')) {
this.element.fadeOut(200);
}
};
};

View File

@ -46,7 +46,7 @@ vec3 lerp(vec3 v1, vec3 v2, float amount){
}
bool mobSpawnColor() {
if (vBlocklight < 7.1){
if (vBlocklight < 7.1 && vNormal.y > 0.8){
float cross1 = vUv.x - vUv.y;
float cross2 = vUv.x - (1.0 - vUv.y);
return cross1 < 0.05 && cross1 > -0.05 || cross2 < 0.05 && cross2 > -0.05;

View File

@ -24,7 +24,7 @@
*/
import $ from 'jquery';
import Button from '../ui/Button.js';
import Button from './Button.js';
import COMPASS from '../../../assets/compass.svg';

View File

@ -24,7 +24,7 @@
*/
import $ from 'jquery';
import Dropdown from "../ui/Dropdown";
import Dropdown from "./Dropdown";
export default class MapSelection extends Dropdown {
constructor(bluemap) {

View File

@ -24,7 +24,7 @@
*/
import $ from 'jquery';
import ToggleButton from '../ui/ToggleButton.js';
import ToggleButton from './ToggleButton.js';
import BURGER from '../../../assets/burger.svg';

View File

@ -24,7 +24,7 @@
*/
import $ from 'jquery';
import Element from "../ui/Element";
import Element from "./Element";
export default class Position extends Element {
constructor(blueMap, axis) {

View File

@ -29,15 +29,16 @@ import Menu from './Menu.js';
import Dropdown from "./Dropdown";
import Separator from "./Separator";
import Label from "./Label";
import MenuButton from '../modules/MenuButton.js';
import Compass from "../modules/Compass";
import Position from "../modules/Position";
import MenuButton from './MenuButton.js';
import Compass from "./Compass";
import Position from "./Position";
import Button from "./Button";
import Slider from "./Slider";
import ToggleButton from "./ToggleButton";
import MapSelection from "../modules/MapSeletion";
import MapSelection from "./MapSeletion";
import NIGHT from '../../../assets/night.svg';
import HudInfo from "../modules/HudInfo";
export default class UI {
@ -52,6 +53,9 @@ export default class UI {
this.toolbar = new Toolbar();
this.toolbar.element.appendTo(this.hud);
//modules
this.hudInfo = new HudInfo(this.blueMap, this.element);
}
load() {
@ -87,6 +91,9 @@ export default class UI {
this.blueMap.lowresTileManager.setViewDistance(this.blueMap.lowresViewDistance);
this.blueMap.lowresTileManager.update();
});
let debugInfo = new ToggleButton("debug-info", this.blueMap.debugInfo, button => {
this.blueMap.debugInfo = button.isSelected();
});
//toolbar
this.toolbar.addElement(menuButton);
@ -109,6 +116,8 @@ export default class UI {
this.menu.addElement(hiresSlider);
this.menu.addElement(new Label('lowres render-distance (blocks):'));
this.menu.addElement(lowresSlider);
this.menu.addElement(new Separator());
this.menu.addElement(debugInfo);
this.menu.update();
}

View File

@ -51,7 +51,7 @@ export const splitNumberToPath = num => {
path += '-';
}
let s = num.toString();
let s = parseInt(num).toString();
for (let i = 0; i < s.length; i++) {
path += s.charAt(i) + '/';

View File

@ -0,0 +1,89 @@
.bluemap-container .ui .hud-info {
position: absolute;
transform: translate(-50%, calc(-100% - 1rem));
background-color: $normal_bg;
filter: drop-shadow(1px 1px 3px #0008);
pointer-events: none;
white-space: nowrap;
&.below {
transform: translate(-50%, 1rem);
}
.content {
position: relative;
> .label {
min-height: 0;
font-size: 0.8rem;
padding: 0.5rem 0.5rem 0 1rem;
line-height: 0.8rem;
color: $label_fg;
border-top: solid 1px $line_color;
&:first-child {
border-top: none;
}
}
> * {
padding: 0.5rem;
}
.coords {
display: flex;
justify-content: center;
> .coord {
margin: 0 0.2rem;
padding: 0 0.2rem;
border-radius: 0.2rem;
//background-color: #ccc;
> .label {
color: $label_fg;
margin-right: 0.2rem;
&::after {
content: ':';
}
}
}
}
> .files {
border-top: solid 1px $line_color;
font-size: 0.8rem;
line-height: 0.8rem;
color: $label_fg;
}
&::after {
content: '';
position: absolute;
bottom: -1rem;
left: calc(50% - 0.5rem);
width: 0;
height: 0;
z-index: 0;
border: solid 0.5rem;
border-color: $normal_bg transparent transparent transparent;
}
}
&.below .content::after {
top: -1rem;
border: solid 0.5rem;
border-color: transparent transparent $normal_bg transparent;
}
}

View File

@ -100,4 +100,6 @@ html, body {
@import "ui/separator";
@import "ui/dropdown";
@import "ui/label";
@import "modules/position";
@import "ui/position";
@import "modules/hudInfo";