Use NPM and webpack to build web features

This commit is contained in:
Joshua Rodriguez 2020-01-13 17:22:15 -08:00
parent 7ecc86f498
commit 7ae08d1f44
9 changed files with 251 additions and 1049 deletions

5
.gitignore vendored
View File

@ -20,6 +20,9 @@ bin/*
.project
*/.project
node_modules/
package-lock.json
# exclude generated resource
BlueMapCore/src/main/resources/webroot.zip
BlueMapCore/src/main/resources/resourceExtensions.zip
BlueMapCore/src/main/resources/resourceExtensions.zip

View File

@ -1,24 +1,49 @@
plugins {
id 'com.moowork.node' version '1.3.1'
}
dependencies {
compile 'com.google.guava:guava:21.0'
compile 'com.google.code.gson:gson:2.8.0'
compile 'org.apache.commons:commons-lang3:3.5'
compile group: 'commons-io', name: 'commons-io', version: '2.6'
compile 'com.flowpowered:flow-math:1.0.3'
compile 'ninja.leaping.configurate:configurate-hocon:3.3'
compile 'ninja.leaping.configurate:configurate-gson:3.3'
compile 'ninja.leaping.configurate:configurate-yaml:3.3'
compile 'com.github.Querz:NBT:4.0'
testCompile 'junit:junit:4.12'
compile 'com.google.guava:guava:21.0'
compile 'com.google.code.gson:gson:2.8.0'
compile 'org.apache.commons:commons-lang3:3.5'
compile group: 'commons-io', name: 'commons-io', version: '2.6'
compile 'com.flowpowered:flow-math:1.0.3'
compile 'ninja.leaping.configurate:configurate-hocon:3.3'
compile 'ninja.leaping.configurate:configurate-gson:3.3'
compile 'ninja.leaping.configurate:configurate-yaml:3.3'
compile 'com.github.Querz:NBT:4.0'
testCompile 'junit:junit:4.12'
}
node {
version = '12.14.1'
download = true
}
task cleanWebroot(type: Delete) {
delete 'build/generated/webroot/'
}
// Run WebPack build to generate resources into the generated resources
task webpackWebroot(type: NpmTask) {
args = ['run', 'build']
}
task zipWebroot(type: Zip) {
from fileTree('src/main/webroot')
from fileTree('build/generated/webroot/')
archiveName 'webroot.zip'
destinationDir(file('src/main/resources/'))
outputs.upToDateWhen { false }
}
// removes tmp build directory, build project with webpack, zip contents for the shaded jar
task buildWebroot {
dependsOn 'cleanWebroot'
dependsOn 'webpackWebroot'
dependsOn 'zipWebroot'
}
task zipResourceExtensions(type: Zip) {
from fileTree('src/main/resourceExtensions')
archiveName 'resourceExtensions.zip'
@ -27,5 +52,5 @@ task zipResourceExtensions(type: Zip) {
}
//always update the zip before build
compileJava.dependsOn(zipWebroot)
compileJava.dependsOn(zipResourceExtensions)
processResources.dependsOn(buildWebroot)
processResources.dependsOn(zipResourceExtensions)

41
BlueMapCore/package.json Normal file
View File

@ -0,0 +1,41 @@
{
"name": "bluemap",
"version": "1.0.0",
"description": "BlueMap is a tool that generates 3d-maps of your Minecraft worlds and displays them in your browser.",
"private": true,
"main": "bluemap.js",
"repository": {
"type": "git",
"url": "git+https://github.com/BlueMap-Minecraft/BlueMap.git"
},
"keywords": [
"minecraft"
],
"author": "Blue",
"license": "MIT",
"bugs": {
"url": "https://github.com/BlueMap-Minecraft/BlueMap/issues"
},
"homepage": "https://github.com/BlueMap-Minecraft/BlueMap#readme",
"dependencies": {
"jquery": "^3.4.1",
"three": "^0.94.0"
},
"devDependencies": {
"css-loader": "^3.4.2",
"fibers": "^4.0.2",
"html-webpack-plugin": "^3.2.0",
"mini-css-extract-plugin": "^0.9.0",
"node-sass": "^4.13.0",
"sass": "^1.24.4",
"sass-loader": "^8.0.2",
"webpack": "^4.41.5",
"webpack-cli": "^3.3.10",
"webpack-dev-server": "^3.10.1"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack --mode production",
"start": "webpack-dev-server --watch --mode development"
}
}

View File

@ -1,22 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8>
<title>BlueMap</title>
<link rel="stylesheet" type="text/css" href="style/style.css?v=2">
<script src="js/libs/jquery.min.js"></script>
<script type="text/javascript" src="js/libs/three.min.js"></script>
<script type="text/javascript" src="js/libs/bluemap.js"></script>
</head>
<body>
<div id="map-container"></div>
<script type="text/javascript" src="js/site.js"></script>
</body>
<head>
<meta charset="utf-8">
<title>BlueMap</title>
</head>
<body>
<div id="map-container"></div>
</body>
</html>

View File

@ -22,7 +22,20 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
BlueMap = function (element, dataRoot) {
import $ from "jquery";
import * as THREE from "three";
import GEAR from "../../assets/gear.svg";
import COMPASS from "../../assets/compass.svg";
import SKYBOX_NORTH from "../../assets/skybox/north.png";
import SKYBOX_SOUTH from "../../assets/skybox/south.png";
import SKYBOX_EAST from "../../assets/skybox/east.png";
import SKYBOX_WEST from "../../assets/skybox/west.png";
import SKYBOX_UP from "../../assets/skybox/up.png";
import SKYBOX_DOWN from "../../assets/skybox/down.png";
const BlueMap = function (element, dataRoot) {
this.element = element;
this.dataRoot = dataRoot;
@ -78,10 +91,10 @@ BlueMap.prototype.initModules = function () {
BlueMap.prototype.changeMap = function (map) {
this.hiresTileManager.close();
this.lowresTileManager.close();
this.map = map;
this.controls.resetPosition();
this.lowresTileManager = new BlueMap.TileManager(
this,
this.settings[this.map]["lowres"]["viewDistance"],
@ -99,7 +112,7 @@ BlueMap.prototype.changeMap = function (map) {
this.settings[this.map]["hires"]["tileSize"],
{x: 0, z: 0}
);
this.lowresTileManager.update();
this.hiresTileManager.update();
@ -213,7 +226,7 @@ BlueMap.prototype.render = function () {
BlueMap.prototype.handleContainerResize = function () {
this.camera.aspect = this.element.clientWidth / this.element.clientHeight;
this.camera.updateProjectionMatrix();
this.skyboxCamera.aspect = this.element.clientWidth / this.element.clientHeight;
this.skyboxCamera.updateProjectionMatrix();
@ -230,22 +243,22 @@ BlueMap.prototype.loadSettings = function (callback) {
this.fileLoader.load(this.dataRoot + "settings.json", function (settings) {
scope.settings = JSON.parse(settings);
scope.maps = [];
for (map in scope.settings){
for (let map in scope.settings){
if (scope.settings.hasOwnProperty(map) && scope.settings[map].enabled){
scope.maps.push(map);
}
}
scope.maps.sort(function (map1, map2) {
var sort = scope.settings[map1].ordinal - scope.settings[map2].ordinal;
if (isNaN(sort)) return 0;
return sort;
});
scope.map = scope.maps[0];
callback.call(scope);
});
};
@ -267,7 +280,7 @@ BlueMap.prototype.initStage = function () {
this.camera = new THREE.PerspectiveCamera(75, this.element.scrollWidth / this.element.scrollHeight, 0.1, 10000);
this.camera.updateProjectionMatrix();
this.skyboxCamera = this.camera.clone();
this.skyboxCamera.updateProjectionMatrix();
@ -275,7 +288,7 @@ BlueMap.prototype.initStage = function () {
this.skyboxScene.ambient = new THREE.AmbientLight(0xffffff, 1);
this.skyboxScene.add(this.skyboxScene.ambient);
this.skyboxScene.add(this.createSkybox());
this.lowresScene = new THREE.Scene();
this.lowresScene.ambient = new THREE.AmbientLight(0xffffff, 0.6);
this.lowresScene.add(this.lowresScene.ambient);
@ -302,27 +315,27 @@ BlueMap.prototype.createSkybox = function(){
let geometry = new THREE.CubeGeometry(10, 10, 10);
let material = [
new THREE.MeshBasicMaterial({
map: new THREE.TextureLoader().load('assets/skybox/south.png'),
map: new THREE.TextureLoader().load(SKYBOX_SOUTH),
side: THREE.BackSide
}),
new THREE.MeshBasicMaterial({
map: new THREE.TextureLoader().load('assets/skybox/north.png'),
map: new THREE.TextureLoader().load(SKYBOX_NORTH),
side: THREE.BackSide
}),
new THREE.MeshBasicMaterial({
map: new THREE.TextureLoader().load('assets/skybox/up.png'),
map: new THREE.TextureLoader().load(SKYBOX_UP),
side: THREE.BackSide
}),
new THREE.MeshBasicMaterial({
map: new THREE.TextureLoader().load('assets/skybox/down.png'),
map: new THREE.TextureLoader().load(SKYBOX_DOWN),
side: THREE.BackSide
}),
new THREE.MeshBasicMaterial({
map: new THREE.TextureLoader().load('assets/skybox/east.png'),
map: new THREE.TextureLoader().load(SKYBOX_EAST),
side: THREE.BackSide
}),
new THREE.MeshBasicMaterial({
map: new THREE.TextureLoader().load('assets/skybox/west.png'),
map: new THREE.TextureLoader().load(SKYBOX_WEST),
side: THREE.BackSide
})
];
@ -441,14 +454,14 @@ BlueMap.prototype.loadLowresTile = function (tileX, tileZ, callback, onError) {
// ###### UI ######
BlueMap.prototype.alert = function (content) {
let alertBox = $('#alert-box');
let alertBox = $("#alert-box");
if (alertBox.length === 0){
alertBox = $('<div id="alert-box"></div>').appendTo(this.element);
}
let displayAlert = function(){
let alert = $('<div class="alert box" style="display: none;"><div class="alert-close-button"></div>' + content + '</div>').appendTo(alertBox);
alert.find('.alert-close-button').click(function(){
let alert = $('<div class="alert box" style="display: none;"><div class="alert-close-button"></div>' + content + "</div>").appendTo(alertBox);
alert.find(".alert-close-button").click(function(){
alert.fadeOut(200, function(){
alert.remove();
});
@ -456,10 +469,10 @@ BlueMap.prototype.alert = function (content) {
alert.fadeIn(200);
};
let oldAlerts = alertBox.find('.alert');
let oldAlerts = alertBox.find(".alert");
if (oldAlerts.length > 0){
alertBox.fadeOut(200, function () {
alertBox.html('');
alertBox.html("");
alertBox.show();
displayAlert();
})
@ -498,7 +511,7 @@ BlueMap.TileManager.prototype.setPosition = function (center) {
BlueMap.TileManager.prototype.update = function () {
if (this.closed) return;
//free a loader so if there was an error loading a tile we don't get stuck forever with the blocked loading process
//free a loader so if there was an error loading a tile we don"t get stuck forever with the blocked loading process
this.currentlyLoading--;
if (this.currentlyLoading < 0) this.currentlyLoading = 0;
@ -545,7 +558,7 @@ BlueMap.TileManager.prototype.close = function () {
BlueMap.TileManager.prototype.loadCloseTiles = function () {
if (this.closed) return;
let scope = this;
if (this.currentlyLoading < 8) {
@ -582,7 +595,7 @@ BlueMap.TileManager.prototype.loadNextTile = function () {
BlueMap.TileManager.prototype.tryLoadTile = function (x, z) {
if (this.closed) return;
let scope = this;
let tileHash = BlueMap.utils.hashTile(x, z);
@ -701,7 +714,7 @@ BlueMap.Controls = function (camera, element, heightScene) {
this.raycaster = new THREE.Raycaster();
this.rayDirection = new THREE.Vector3(0, -1, 0);
this.resetPosition();
this.mouse = new THREE.Vector2(0, 0);
@ -732,25 +745,25 @@ BlueMap.Controls = function (camera, element, heightScene) {
this.state = this.STATES.NONE;
let canvas = $(this.element).find("canvas").get(0);
window.addEventListener('contextmenu', function (e) {
window.addEventListener("contextmenu", function (e) {
e.preventDefault();
}, false);
canvas.addEventListener('mousedown', function (e) {
canvas.addEventListener("mousedown", function (e) {
scope.onMouseDown(e);
}, false);
window.addEventListener('mousemove', function (e) {
window.addEventListener("mousemove", function (e) {
scope.onMouseMove(e);
}, false);
window.addEventListener('mouseup', function (e) {
window.addEventListener("mouseup", function (e) {
scope.onMouseUp(e);
}, false);
canvas.addEventListener('wheel', function (e) {
canvas.addEventListener("wheel", function (e) {
scope.onMouseWheel(e);
}, false);
window.addEventListener('keydown', function (e) {
window.addEventListener("keydown", function (e) {
scope.onKeyDown(e);
}, false);
window.addEventListener('keyup', function (e) {
window.addEventListener("keyup", function (e) {
scope.onKeyUp(e);
}, false);
@ -777,12 +790,12 @@ BlueMap.Controls.prototype.update = function () {
this.updateMouseMoves();
let changed = false;
let zoomLerp = (this.distance - 100) / 200;
if (zoomLerp < 0) zoomLerp = 0;
if (zoomLerp > 1) zoomLerp = 1;
this.targetPosition.y = 300 * zoomLerp + this.minHeight * (1 - zoomLerp);
this.position.x += (this.targetPosition.x - this.position.x) * this.settings.move.smooth;
this.position.y += (this.targetPosition.y - this.position.y) * this.settings.move.smoothY;
this.position.z += (this.targetPosition.z - this.position.z) * this.settings.move.smooth;
@ -803,7 +816,7 @@ BlueMap.Controls.prototype.update = function () {
let last = this.camera.position.x + this.camera.position.y + this.camera.position.z;
this.orbitRot.set(this.angle, this.direction, 0);
this.cameraPosDelta.set(0, this.distance, 0).applyEuler(this.orbitRot);
this.camera.position.set(this.position.x + this.cameraPosDelta.x, this.position.y + this.cameraPosDelta.y, this.position.z + this.cameraPosDelta.z);
let move = last - (this.camera.position.x + this.camera.position.y + this.camera.position.z);
@ -812,7 +825,7 @@ BlueMap.Controls.prototype.update = function () {
if (changed) {
this.camera.lookAt(this.position);
this.camera.updateProjectionMatrix();
this.updateHeights();
}
@ -821,7 +834,7 @@ BlueMap.Controls.prototype.update = function () {
BlueMap.Controls.prototype.updateHeights = function(){
//TODO: this can be performance-improved by only intersecting the correct tile?
let rayStart = new THREE.Vector3(this.targetPosition.x, 300, this.targetPosition.z);
this.raycaster.set(rayStart, this.rayDirection);
this.raycaster.near = 1;
@ -967,33 +980,33 @@ BlueMap.Module = {
// ###### Modules.MapMenu ######
BlueMap.Module.MapMenu = function (blueMap) {
let scope = this;
this.bluemap = blueMap;
let maps = this.bluemap.settings;
$("#bluemap-mapmenu").remove();
this.element = $('<div id="bluemap-mapmenu" class="dropdown-container"><span class="selection">' + maps[this.bluemap.map].name + '</span></div>').appendTo(BlueMap.Module.getTopLeftElement(blueMap));
this.element = $('<div id="bluemap-mapmenu" class="dropdown-container"><span class="selection">' + maps[this.bluemap.map].name + "</span></div>").appendTo(BlueMap.Module.getTopLeftElement(blueMap));
let dropdown = $('<div class="dropdown"></div>').appendTo(this.element);
this.maplist = $('<ul></ul>').appendTo(dropdown);
for (mapId in maps) {
this.maplist = $("<ul></ul>").appendTo(dropdown);
for (let mapId in maps) {
if (!maps.hasOwnProperty(mapId)) continue;
if (!maps.enabled) continue;
let map = maps[mapId];
$('<li map="' + mapId + '">' + map.name + '</li>').appendTo(this.maplist);
$('<li map="" + mapId + "">' + map.name + "</li>").appendTo(this.maplist);
}
this.maplist.find('li[map=' + this.bluemap.map + ']').hide();
this.maplist.find('li[map]').click(function (e) {
let map = $(this).attr('map');
this.maplist.find("li[map=" + this.bluemap.map + "]").hide();
this.maplist.find("li[map]").click(function (e) {
let map = $(this).attr("map");
scope.bluemap.changeMap(map);
});
$(document).on('bluemap-map-change', function(){
scope.maplist.find('li').show();
scope.maplist.find('li[map=' + scope.bluemap.map + ']').hide();
$(document).on("bluemap-map-change", function(){
scope.maplist.find("li").show();
scope.maplist.find("li[map=" + scope.bluemap.map + "]").hide();
scope.element.find(".selection").html(scope.bluemap.settings[scope.bluemap.map].name);
});
@ -1006,10 +1019,10 @@ BlueMap.Module.Compass = function (blueMap) {
this.blueMap = blueMap;
$("#bluemap-compass").remove();
this.element = $('<div id="bluemap-compass" class="button"><img id="bluemap-compass-needle" src="assets/compass.svg" /></div>').appendTo(BlueMap.Module.getTopLeftElement(blueMap));
this.needle = $('#bluemap-compass-needle');
this.element = $(`<div id="bluemap-compass" class="button"><img id="bluemap-compass-needle" src="${COMPASS}" /></div>`).appendTo(BlueMap.Module.getTopLeftElement(blueMap));
this.needle = $("#bluemap-compass-needle");
$(document).on('bluemap-update-frame', function (){
$(document).on("bluemap-update-frame", function (){
scope.needle.css("transform", "rotate(" + scope.blueMap.controls.direction + "rad)");
});
@ -1034,7 +1047,7 @@ BlueMap.Module.Position = function (blueMap) {
//this.elementY = $('<div class="bluemap-position pos-y">0</div>').appendTo(parent);
this.elementZ = $('<div class="bluemap-position pos-z">0</div>').appendTo(parent);
$(document).on('bluemap-update-frame', function (){
$(document).on("bluemap-update-frame", function (){
scope.elementX.html(Math.floor(scope.blueMap.controls.targetPosition.x));
//scope.elementY.html(scope.blueMap.controls.targetPosition.y === 0 ? "-" : Math.floor(scope.blueMap.controls.targetPosition.y));
scope.elementZ.html(Math.floor(scope.blueMap.controls.targetPosition.z));
@ -1051,9 +1064,9 @@ BlueMap.Module.Settings = function (blueMap) {
$("#bluemap-settings").remove();
this.elementMenu = $('<div id="bluemap-settings-container" style="display: none"></div>').appendTo(parent);
this.elementSettings = $('<div id="bluemap-settings" class="button"><img src="assets/gear.svg" /></div>').appendTo(parent);
this.elementSettings = $(`<div id="bluemap-settings" class="button"><img src="${GEAR}" /></div>`).appendTo(parent);
this.elementSettings.click(function(){
if (scope.elementMenu.css('display') === "none"){
if (scope.elementMenu.css("display") === "none"){
scope.elementSettings.addClass("active");
} else {
scope.elementSettings.removeClass("active");
@ -1079,10 +1092,10 @@ BlueMap.Module.Settings = function (blueMap) {
let desc = $(this).html();
scope.blueMap.quality = parseFloat($(this).attr("quality"));
scope.elementQuality.find('li').show();
scope.elementQuality.find('li[quality=\'' + scope.blueMap.quality + '\']').hide();
scope.elementQuality.find("li").show();
scope.elementQuality.find("li[quality=\"" + scope.blueMap.quality + "\"]").hide();
scope.elementQuality.find('.selection > span').html(desc);
scope.elementQuality.find(".selection > span").html(desc);
scope.blueMap.handleContainerResize();
});
@ -1116,7 +1129,7 @@ BlueMap.Module.Settings = function (blueMap) {
);
let slider = scope.elementRenderDistance.find("input");
slider.on('change input', function(e){
slider.on("change input", function(e){
scope.blueMap.hiresTileManager.viewDistance = scope.pctToRenderDistance(parseFloat(slider.val()), scope.defaultHighRes);
scope.blueMap.lowresTileManager.viewDistance = scope.pctToRenderDistance(parseFloat(slider.val()), scope.defaultLowRes);
scope.elementRenderDistance.find(".selection > span").html(Math.round(scope.blueMap.hiresTileManager.viewDistance * 10) / 10);
@ -1133,7 +1146,7 @@ BlueMap.Module.Settings = function (blueMap) {
scope.init();
$(document).on('bluemap-map-change', this.init);
$(document).on("bluemap-map-change", this.init);
};
// ###### Modules.Info ######
@ -1164,7 +1177,7 @@ BlueMap.Module.Info = function (blueMap) {
BlueMap.utils = {};
BlueMap.utils.stringToImage = function (string) {
let image = document.createElementNS('http://www.w3.org/1999/xhtml', 'img');
let image = document.createElementNS("http://www.w3.org/1999/xhtml", "img");
image.src = string;
return image;
};
@ -1206,3 +1219,5 @@ BlueMap.utils.Vector2 = {};
BlueMap.utils.Vector2.ZERO = new THREE.Vector2(0, 0);
BlueMap.utils.Vector3 = {};
BlueMap.utils.Vector3.ZERO = new THREE.Vector3(0, 0);
export default BlueMap;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,3 +1,8 @@
import $ from "jquery";
import BlueMap from "./libs/bluemap.js";
import "../style/style.css"
// global variable to enable access through browser console
var blueMap;

View File

@ -0,0 +1,73 @@
const path = require('path')
const fs = require('fs')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const WEBROOT_PATH = path.resolve(__dirname, 'src/main/webroot')
const BUILD_PATH = path.resolve(__dirname, 'build/generated/webroot')
// folder with a generated world to render in the dev server
const WORLD_DATA_PATH = path.resolve(__dirname, 'build/generated/world')
module.exports = {
mode: 'production',
devtool: 'source-map',
entry: {
'bluemap': path.resolve(WEBROOT_PATH, 'js/site.js'),
},
output: {
path: BUILD_PATH,
filename: 'js/[name].js',
},
devServer: {
contentBase: WORLD_DATA_PATH,
compress: true,
port: 8080,
hot: true,
},
plugins: [
new MiniCssExtractPlugin({
filename: 'style/[name].css?[hash]',
}),
new HtmlWebpackPlugin({
template: path.resolve(WEBROOT_PATH, 'index.html'),
hash: true,
}),
],
resolve: {
extensions: ['.js', '.css', '.scss'],
},
module: {
rules: [
// Just import normal css files
{
test: /\.css$/,
include: /src/,
use: [
{ loader: MiniCssExtractPlugin.loader },
{ loader: 'css-loader' },
],
},
// Converts scss files into css to use within custom elements
{
test: /\.scss$/,
include: /src/,
use: [
{ loader: MiniCssExtractPlugin.loader },
{ loader: 'css-loader' },
{ loader: 'sass-loader' },
],
},
// Load additional files
{
test: /\.(png|svg)(\?.*$|$)/,
include: /src/,
use: [
{
loader: 'file-loader',
options: { name: 'assets/[name].[ext]?[hash]' },
},
],
},
],
},
}