From c807699c7c5ac631b2a790e9856f1b1007aab746 Mon Sep 17 00:00:00 2001
From: TechnicJelle <22576047+TechnicJelle@users.noreply.github.com>
Date: Thu, 8 Jun 2023 23:12:20 +0200
Subject: [PATCH 01/24] Add port-in-use check (#440)
* Add port-in-use check to plugin
* Add port-in-use check to CLI
---
.../bluemap/common/plugin/Plugin.java | 4 +++
.../bluecolored/bluemap/cli/BlueMapCLI.java | 26 ++++++++++++++-----
2 files changed, 24 insertions(+), 6 deletions(-)
diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/Plugin.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/Plugin.java
index 17b35e7c..442f7bc6 100644
--- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/Plugin.java
+++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/Plugin.java
@@ -55,6 +55,7 @@
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
+import java.net.BindException;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.nio.file.Path;
@@ -194,6 +195,9 @@ private void load(@Nullable ResourcePack preloadedResourcePack) throws IOExcepti
} catch (UnknownHostException ex) {
throw new ConfigurationException("BlueMap failed to resolve the ip in your webserver-config.\n" +
"Check if that is correctly configured.", ex);
+ } catch (BindException ex) {
+ throw new ConfigurationException("BlueMap failed to bind to the configured address.\n" +
+ "This usually happens when the configured port (" + webserverConfig.getPort() + ") is already in use by some other program.", ex);
} catch (IOException ex) {
throw new ConfigurationException("BlueMap failed to initialize the webserver.\n" +
"Check your webserver-config if everything is configured correctly.\n" +
diff --git a/implementations/cli/src/main/java/de/bluecolored/bluemap/cli/BlueMapCLI.java b/implementations/cli/src/main/java/de/bluecolored/bluemap/cli/BlueMapCLI.java
index 8ff7292f..55dc7909 100644
--- a/implementations/cli/src/main/java/de/bluecolored/bluemap/cli/BlueMapCLI.java
+++ b/implementations/cli/src/main/java/de/bluecolored/bluemap/cli/BlueMapCLI.java
@@ -54,7 +54,9 @@
import java.io.File;
import java.io.IOException;
+import java.net.BindException;
import java.net.InetSocketAddress;
+import java.net.UnknownHostException;
import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.TimeUnit;
@@ -204,12 +206,24 @@ public void startWebserver(BlueMapService blueMap, boolean verbose) throws IOExc
HttpRequestHandler handler = new BlueMapResponseModifier(routingRequestHandler);
if (verbose) handler = new LoggingRequestHandler(handler);
- HttpServer webServer = new HttpServer(handler);
- webServer.bind(new InetSocketAddress(
- config.resolveIp(),
- config.getPort()
- ));
- webServer.start();
+ try {
+ HttpServer webServer = new HttpServer(handler);
+ webServer.bind(new InetSocketAddress(
+ config.resolveIp(),
+ config.getPort()
+ ));
+ webServer.start();
+ } catch (UnknownHostException ex) {
+ throw new ConfigurationException("BlueMap failed to resolve the ip in your webserver-config.\n" +
+ "Check if that is correctly configured.", ex);
+ } catch (BindException ex) {
+ throw new ConfigurationException("BlueMap failed to bind to the configured address.\n" +
+ "This usually happens when the configured port (" + config.getPort() + ") is already in use by some other program.", ex);
+ } catch (IOException ex) {
+ throw new ConfigurationException("BlueMap failed to initialize the webserver.\n" +
+ "Check your webserver-config if everything is configured correctly.\n" +
+ "(Make sure you DON'T use the same port for bluemap that you also use for your minecraft server)", ex);
+ }
}
@Override
From f149b823a76e40bbb6532ee6aac467432d6899e9 Mon Sep 17 00:00:00 2001
From: MrSolarius <45536184+mrsolarius@users.noreply.github.com>
Date: Mon, 12 Jun 2023 22:55:44 +0200
Subject: [PATCH 02/24] Add support for postgres databases (#443)
* Refactor : wrap every single SQL query inside an interface
* Feat : create every SQL request for postgres
* Refactor : rename SQLQueryAbstractFactory to SQLQueryFactory
* Feat : add dialect settings to blue map !
* Feat : Create two new storageClass for different storage approche
* Feat : add read BYTEA support
* Fix : remove unuseful println
* Fix : remove edited sql.conf
* Refactor / Feat : support for mysql
* Lots of tiny tweaks
---------
Co-authored-by: Lukas Rieger (Blue)
---
.../common/config/storage/StorageType.java | 2 +-
.../core/storage/sql/MySQLStorage.java | 13 +
.../core/storage/sql/PostgreSQLStorage.java | 126 +++++++++
.../bluemap/core/storage/sql/SQLStorage.java | 187 ++++---------
.../core/storage/sql/dialect/DialectType.java | 40 +++
.../storage/sql/dialect/MySQLDialect.java | 250 ++++++++++++++++++
.../storage/sql/dialect/PostgresDialect.java | 240 +++++++++++++++++
.../storage/sql/dialect/SQLQueryDialect.java | 78 ++++++
8 files changed, 795 insertions(+), 141 deletions(-)
create mode 100644 BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/MySQLStorage.java
create mode 100644 BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/PostgreSQLStorage.java
create mode 100644 BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/DialectType.java
create mode 100644 BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/MySQLDialect.java
create mode 100644 BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/PostgresDialect.java
create mode 100644 BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/SQLQueryDialect.java
diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/storage/StorageType.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/storage/StorageType.java
index 7eb05f95..20a24e94 100644
--- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/storage/StorageType.java
+++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/storage/StorageType.java
@@ -31,7 +31,7 @@
public enum StorageType {
FILE (FileConfig.class, FileStorage::new),
- SQL (SQLConfig.class, SQLStorage::new);
+ SQL (SQLConfig.class, SQLStorage::create);
private final Class extends StorageConfig> configType;
private final StorageFactory extends StorageConfig> storageFactory;
diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/MySQLStorage.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/MySQLStorage.java
new file mode 100644
index 00000000..1f99693e
--- /dev/null
+++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/MySQLStorage.java
@@ -0,0 +1,13 @@
+package de.bluecolored.bluemap.core.storage.sql;
+
+import de.bluecolored.bluemap.core.storage.sql.dialect.MySQLDialect;
+
+import java.net.MalformedURLException;
+
+public class MySQLStorage extends SQLStorage{
+
+ public MySQLStorage(SQLStorageSettings config) throws MalformedURLException, SQLDriverException {
+ super(MySQLDialect.INSTANCE, config);
+ }
+
+}
diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/PostgreSQLStorage.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/PostgreSQLStorage.java
new file mode 100644
index 00000000..e6ef360a
--- /dev/null
+++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/PostgreSQLStorage.java
@@ -0,0 +1,126 @@
+package de.bluecolored.bluemap.core.storage.sql;
+
+import com.flowpowered.math.vector.Vector2i;
+import de.bluecolored.bluemap.core.storage.CompressedInputStream;
+import de.bluecolored.bluemap.core.storage.Compression;
+import de.bluecolored.bluemap.core.storage.sql.dialect.PostgresDialect;
+import de.bluecolored.bluemap.core.util.WrappedOutputStream;
+
+import java.io.*;
+import java.net.MalformedURLException;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Optional;
+
+public class PostgreSQLStorage extends SQLStorage {
+
+ public PostgreSQLStorage(SQLStorageSettings config) throws MalformedURLException, SQLDriverException {
+ super(PostgresDialect.INSTANCE, config);
+ }
+
+ @Override
+ public OutputStream writeMapTile(String mapId, int lod, Vector2i tile) throws IOException {
+ Compression compression = lod == 0 ? this.hiresCompression : Compression.NONE;
+ ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
+ return new WrappedOutputStream(compression.compress(byteOut), () -> {
+ int mapFK = getMapFK(mapId);
+ int tileCompressionFK = getMapTileCompressionFK(compression);
+
+ recoveringConnection(connection -> {
+ byte[] byteData = byteOut.toByteArray();
+ ByteArrayInputStream inputStream = new ByteArrayInputStream(byteData);
+
+ PreparedStatement statement = connection.prepareStatement(this.dialect.writeMapTile());
+ statement.setInt(1, mapFK);
+ statement.setInt(2, lod);
+ statement.setInt(3, tile.getX());
+ statement.setInt(4, tile.getY());
+ statement.setInt(5, tileCompressionFK);
+ statement.setBinaryStream(6, inputStream);
+
+ statement.executeUpdate();
+ }, 2);
+ });
+ }
+
+ @Override
+ public OutputStream writeMeta(String mapId, String name) {
+ ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
+ return new WrappedOutputStream(byteOut, () -> {
+ int mapFK = getMapFK(mapId);
+ recoveringConnection(connection -> {
+ byte[] byteData = byteOut.toByteArray();
+ ByteArrayInputStream inputStream = new ByteArrayInputStream(byteData);
+
+ PreparedStatement statement = connection.prepareStatement(this.dialect.writeMeta());
+ statement.setInt(1, mapFK);
+ statement.setString(2, name);
+ statement.setBinaryStream(3, inputStream);
+
+ statement.executeUpdate();
+ }, 2);
+ });
+ }
+
+ @Override
+ public Optional readMapTile(String mapId, int lod, Vector2i tile) throws IOException {
+ Compression compression = lod == 0 ? this.hiresCompression : Compression.NONE;
+
+ try {
+ byte[] data = recoveringConnection(connection -> {
+ ResultSet result = executeQuery(connection,
+ this.dialect.readMapTile(),
+ mapId,
+ lod,
+ tile.getX(),
+ tile.getY(),
+ compression.getTypeId()
+ );
+
+ if (result.next()) {
+ return result.getBytes(1);
+ } else {
+ return null;
+ }
+ }, 2);
+
+ if (data == null) {
+ return Optional.empty();
+ }
+
+ InputStream inputStream = new ByteArrayInputStream(data);
+ return Optional.of(new CompressedInputStream(inputStream, compression));
+ } catch (SQLException ex) {
+ throw new IOException(ex);
+ }
+ }
+
+ @Override
+ public Optional readMeta(String mapId, String name) throws IOException {
+ try {
+ byte[] data = recoveringConnection(connection -> {
+ ResultSet result = executeQuery(connection,
+ this.dialect.readMeta(),
+ mapId,
+ escapeMetaName(name)
+ );
+ if (result.next()) {
+ return result.getBytes(1);
+ } else {
+ return null;
+ }
+ }, 2);
+
+ if (data == null) {
+ return Optional.empty();
+ }
+
+ InputStream inputStream = new ByteArrayInputStream(data);
+ return Optional.of(inputStream);
+ } catch (SQLException ex) {
+ throw new IOException(ex);
+ }
+ }
+
+}
diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/SQLStorage.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/SQLStorage.java
index 2ec91c36..d633d73f 100644
--- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/SQLStorage.java
+++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/SQLStorage.java
@@ -30,6 +30,8 @@
import de.bluecolored.bluemap.core.BlueMap;
import de.bluecolored.bluemap.core.logger.Logger;
import de.bluecolored.bluemap.core.storage.*;
+import de.bluecolored.bluemap.core.storage.sql.dialect.DialectType;
+import de.bluecolored.bluemap.core.storage.sql.dialect.SQLQueryDialect;
import de.bluecolored.bluemap.core.util.WrappedOutputStream;
import org.apache.commons.dbcp2.*;
import org.apache.commons.pool2.ObjectPool;
@@ -48,10 +50,12 @@
import java.util.concurrent.CompletionException;
import java.util.function.Function;
-public class SQLStorage extends Storage {
+public abstract class SQLStorage extends Storage {
private final DataSource dataSource;
- private final Compression hiresCompression;
+
+ protected final SQLQueryDialect dialect;
+ protected final Compression hiresCompression;
private final LoadingCache mapFKs = Caffeine.newBuilder()
.executor(BlueMap.THREAD_POOL)
@@ -62,9 +66,9 @@ public class SQLStorage extends Storage {
private volatile boolean closed;
- public SQLStorage(SQLStorageSettings config) throws MalformedURLException, SQLDriverException {
+ public SQLStorage(SQLQueryDialect dialect, SQLStorageSettings config) throws MalformedURLException, SQLDriverException {
+ this.dialect = dialect;
this.closed = false;
-
try {
if (config.getDriverClass().isPresent()) {
if (config.getDriverJar().isPresent()) {
@@ -115,9 +119,7 @@ public OutputStream writeMapTile(String mapId, int lod, Vector2i tile) throws IO
byteOut.writeTo(blobOut);
}
- executeUpdate(connection,
- "REPLACE INTO `bluemap_map_tile` (`map`, `lod`, `x`, `z`, `compression`, `data`) " +
- "VALUES (?, ?, ?, ?, ?, ?)",
+ executeUpdate(connection,this.dialect.writeMapTile(),
mapFK,
lod,
tile.getX(),
@@ -139,17 +141,7 @@ public Optional readMapTile(String mapId, int lod, Vector
try {
byte[] data = recoveringConnection(connection -> {
ResultSet result = executeQuery(connection,
- "SELECT t.`data` " +
- "FROM `bluemap_map_tile` t " +
- " INNER JOIN `bluemap_map` m " +
- " ON t.`map` = m.`id` " +
- " INNER JOIN `bluemap_map_tile_compression` c " +
- " ON t.`compression` = c.`id` " +
- "WHERE m.`map_id` = ? " +
- "AND t.`lod` = ? " +
- "AND t.`x` = ? " +
- "AND t.`z` = ? " +
- "AND c.`compression` = ?",
+ this.dialect.readMapTile(),
mapId,
lod,
tile.getX(),
@@ -179,17 +171,7 @@ public Optional readMapTileInfo(final String mapId, int lod, final Vec
try {
TileInfo tileInfo = recoveringConnection(connection -> {
ResultSet result = executeQuery(connection,
- "SELECT t.`changed`, LENGTH(t.`data`) as 'size' " +
- "FROM `bluemap_map_tile` t " +
- " INNER JOIN `bluemap_map` m " +
- " ON t.`map` = m.`id` " +
- " INNER JOIN `bluemap_map_tile_compression` c " +
- " ON t.`compression` = c.`id` " +
- "WHERE m.`map_id` = ? " +
- "AND t.`lod` = ? " +
- "AND t.`x` = ? " +
- "AND t.`z` = ? " +
- "AND c.`compression` = ?",
+ this.dialect.readMapTileInfo(),
mapId,
lod,
tile.getX(),
@@ -238,15 +220,7 @@ public long getLastModified() {
public void deleteMapTile(String mapId, int lod, Vector2i tile) throws IOException {
try {
recoveringConnection(connection ->
- executeUpdate(connection,
- "DELETE t " +
- "FROM `bluemap_map_tile` t " +
- " INNER JOIN `bluemap_map` m " +
- " ON t.`map` = m.`id` " +
- "WHERE m.`map_id` = ? " +
- "AND t.`lod` = ? " +
- "AND t.`x` = ? " +
- "AND t.`z` = ?",
+ executeUpdate(connection,this.dialect.deleteMapTile(),
mapId,
lod,
tile.getX(),
@@ -271,8 +245,7 @@ public OutputStream writeMeta(String mapId, String name) {
}
executeUpdate(connection,
- "REPLACE INTO `bluemap_map_meta` (`map`, `key`, `value`) " +
- "VALUES (?, ?, ?)",
+ this.dialect.writeMeta(),
mapFK,
escapeMetaName(name),
dataBlob
@@ -289,12 +262,7 @@ public Optional readMeta(String mapId, String name) throws IOExcept
try {
byte[] data = recoveringConnection(connection -> {
ResultSet result = executeQuery(connection,
- "SELECT t.`value` " +
- "FROM `bluemap_map_meta` t " +
- " INNER JOIN `bluemap_map` m " +
- " ON t.`map` = m.`id` " +
- "WHERE m.`map_id` = ? " +
- "AND t.`key` = ?",
+ this.dialect.readMeta(),
mapId,
escapeMetaName(name)
);
@@ -319,12 +287,7 @@ public Optional readMetaInfo(String mapId, String name) throws IOExcep
try {
MetaInfo tileInfo = recoveringConnection(connection -> {
ResultSet result = executeQuery(connection,
- "SELECT LENGTH(t.`value`) as 'size' " +
- "FROM `bluemap_map_meta` t " +
- " INNER JOIN `bluemap_map` m " +
- " ON t.`map` = m.`id` " +
- "WHERE m.`map_id` = ? " +
- "AND t.`key` = ?",
+ this.dialect.readMetaSize(),
mapId,
escapeMetaName(name)
);
@@ -361,12 +324,7 @@ public void deleteMeta(String mapId, String name) throws IOException {
try {
recoveringConnection(connection ->
executeUpdate(connection,
- "DELETE t " +
- "FROM `bluemap_map_meta` t " +
- " INNER JOIN `bluemap_map` m " +
- " ON t.`map` = m.`id` " +
- "WHERE m.`map_id` = ? " +
- "AND t.`key` = ?",
+ this.dialect.purgeMeta(),
mapId,
escapeMetaName(name)
), 2);
@@ -381,28 +339,18 @@ public void purgeMap(String mapId, Function onProgress) t
try {
recoveringConnection(connection -> {
executeUpdate(connection,
- "DELETE t " +
- "FROM `bluemap_map_tile` t " +
- " INNER JOIN `bluemap_map` m " +
- " ON t.`map` = m.`id` " +
- "WHERE m.`map_id` = ?",
+ this.dialect.purgeMapTile(),
mapId
);
executeUpdate(connection,
- "DELETE t " +
- "FROM `bluemap_map_meta` t " +
- " INNER JOIN `bluemap_map` m " +
- " ON t.`map` = m.`id` " +
- "WHERE m.`map_id` = ?",
+ this.dialect.purgeMapMeta(),
mapId
);
executeUpdate(connection,
- "DELETE " +
- "FROM `bluemap_map` " +
- "WHERE `map_id` = ?",
+ this.dialect.purgeMap(),
mapId
);
}, 2);
@@ -420,7 +368,7 @@ public Collection collectMapIds() throws IOException {
try {
return recoveringConnection(connection -> {
ResultSet result = executeQuery(connection,
- "SELECT `map_id` FROM `bluemap_map`"
+ this.dialect.selectMapIds()
);
Collection mapIds = new ArrayList<>();
while (result.next()) {
@@ -440,15 +388,10 @@ public void initialize() throws IOException {
// initialize and get schema-version
String schemaVersionString = recoveringConnection(connection -> {
connection.createStatement().executeUpdate(
- "CREATE TABLE IF NOT EXISTS `bluemap_storage_meta` (" +
- "`key` varchar(255) NOT NULL, " +
- "`value` varchar(255) DEFAULT NULL, " +
- "PRIMARY KEY (`key`)" +
- ")");
+ this.dialect.initializeStorageMeta());
ResultSet result = executeQuery(connection,
- "SELECT `value` FROM `bluemap_storage_meta` " +
- "WHERE `key` = ?",
+ this.dialect.selectStorageMeta(),
"schema_version"
);
@@ -456,8 +399,7 @@ public void initialize() throws IOException {
return result.getString("value");
} else {
executeUpdate(connection,
- "INSERT INTO `bluemap_storage_meta` (`key`, `value`) " +
- "VALUES (?, ?)",
+ this.dialect.insertStorageMeta(),
"schema_version", "0"
);
return "0";
@@ -482,51 +424,22 @@ public void initialize() throws IOException {
recoveringConnection(connection -> {
connection.createStatement().executeUpdate(
- "CREATE TABLE `bluemap_map` (" +
- "`id` SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT," +
- "`map_id` VARCHAR(255) NOT NULL," +
- "PRIMARY KEY (`id`)," +
- "UNIQUE INDEX `map_id` (`map_id`)" +
- ");"
+ this.dialect.initializeMap()
);
connection.createStatement().executeUpdate(
- "CREATE TABLE `bluemap_map_tile_compression` (" +
- "`id` SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT," +
- "`compression` VARCHAR(255) NOT NULL," +
- "PRIMARY KEY (`id`)," +
- "UNIQUE INDEX `compression` (`compression`)" +
- ");"
+ this.dialect.initializeMapTileCompression()
);
connection.createStatement().executeUpdate(
- "CREATE TABLE `bluemap_map_meta` (" +
- "`map` SMALLINT UNSIGNED NOT NULL," +
- "`key` varchar(255) NOT NULL," +
- "`value` LONGBLOB NOT NULL," +
- "PRIMARY KEY (`map`, `key`)," +
- "CONSTRAINT `fk_bluemap_map_meta_map` FOREIGN KEY (`map`) REFERENCES `bluemap_map` (`id`) ON UPDATE RESTRICT ON DELETE RESTRICT" +
- ")");
+ this.dialect.initializeMapMeta());
connection.createStatement().executeUpdate(
- "CREATE TABLE `bluemap_map_tile` (" +
- "`map` SMALLINT UNSIGNED NOT NULL," +
- "`lod` SMALLINT UNSIGNED NOT NULL," +
- "`x` INT NOT NULL," +
- "`z` INT NOT NULL," +
- "`compression` SMALLINT UNSIGNED NOT NULL," +
- "`changed` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP," +
- "`data` LONGBLOB NOT NULL," +
- "PRIMARY KEY (`map`, `lod`, `x`, `z`)," +
- "CONSTRAINT `fk_bluemap_map_tile_map` FOREIGN KEY (`map`) REFERENCES `bluemap_map` (`id`) ON UPDATE RESTRICT ON DELETE RESTRICT," +
- "CONSTRAINT `fk_bluemap_map_tile_compression` FOREIGN KEY (`compression`) REFERENCES `bluemap_map_tile_compression` (`id`) ON UPDATE RESTRICT ON DELETE RESTRICT" +
- ");"
+ this.dialect.initializeMapTile()
);
executeUpdate(connection,
- "UPDATE `bluemap_storage_meta` " +
- "SET `value` = ? " +
- "WHERE `key` = ?",
+ this.dialect.updateStorageMeta(),
"3", "schema_version"
);
}, 2);
@@ -544,36 +457,27 @@ public void initialize() throws IOException {
// delete potential files that are already in the new format to avoid constraint-issues
executeUpdate(connection,
- "DELETE FROM `bluemap_map_meta`" +
- "WHERE `key` IN (?, ?, ?)",
+ this.dialect.deleteMapMeta(),
"settings.json", "textures.json", ".rstate"
);
// rename files
executeUpdate(connection,
- "UPDATE `bluemap_map_meta` " +
- "SET `key` = ? " +
- "WHERE `key` = ?",
+ this.dialect.updateMapMeta(),
"settings.json", "settings"
);
executeUpdate(connection,
- "UPDATE `bluemap_map_meta` " +
- "SET `key` = ? " +
- "WHERE `key` = ?",
+ this.dialect.updateMapMeta(),
"textures.json", "textures"
);
executeUpdate(connection,
- "UPDATE `bluemap_map_meta` " +
- "SET `key` = ? " +
- "WHERE `key` = ?",
+ this.dialect.updateMapMeta(),
".rstate", "render_state"
);
// update schemaVersion
executeUpdate(connection,
- "UPDATE `bluemap_storage_meta` " +
- "SET `value` = ? " +
- "WHERE `key` = ?",
+ this.dialect.updateStorageMeta(),
"3", "schema_version"
);
}, 2);
@@ -603,7 +507,7 @@ public void close() throws IOException {
}
}
- private ResultSet executeQuery(Connection connection, @Language("sql") String sql, Object... parameters) throws SQLException {
+ protected ResultSet executeQuery(Connection connection, @Language("sql") String sql, Object... parameters) throws SQLException {
// we only use this prepared statement once, but the DB-Driver caches those and reuses them
PreparedStatement statement = connection.prepareStatement(sql);
for (int i = 0; i < parameters.length; i++) {
@@ -613,7 +517,7 @@ private ResultSet executeQuery(Connection connection, @Language("sql") String sq
}
@SuppressWarnings("UnusedReturnValue")
- private int executeUpdate(Connection connection, @Language("sql") String sql, Object... parameters) throws SQLException {
+ protected int executeUpdate(Connection connection, @Language("sql") String sql, Object... parameters) throws SQLException {
// we only use this prepared statement once, but the DB-Driver caches those and reuses them
PreparedStatement statement = connection.prepareStatement(sql);
for (int i = 0; i < parameters.length; i++) {
@@ -623,12 +527,12 @@ private int executeUpdate(Connection connection, @Language("sql") String sql, Ob
}
@SuppressWarnings("SameParameterValue")
- private void recoveringConnection(ConnectionConsumer action, int tries) throws SQLException, IOException {
+ protected void recoveringConnection(ConnectionConsumer action, int tries) throws SQLException, IOException {
recoveringConnection((ConnectionFunction) action, tries);
}
@SuppressWarnings("SameParameterValue")
- private R recoveringConnection(ConnectionFunction action, int tries) throws SQLException, IOException {
+ protected R recoveringConnection(ConnectionFunction action, int tries) throws SQLException, IOException {
SQLException sqlException = null;
try {
@@ -657,7 +561,7 @@ private R recoveringConnection(ConnectionFunction action, int tries) thro
throw sqlException;
}
- private int getMapFK(String mapId) throws SQLException {
+ protected int getMapFK(String mapId) throws SQLException {
try {
return Objects.requireNonNull(mapFKs.get(mapId));
} catch (CompletionException ex) {
@@ -670,7 +574,7 @@ private int getMapFK(String mapId) throws SQLException {
}
}
- private int getMapTileCompressionFK(Compression compression) throws SQLException {
+ int getMapTileCompressionFK(Compression compression) throws SQLException {
try {
return Objects.requireNonNull(mapTileCompressionFKs.get(compression));
} catch (CompletionException ex) {
@@ -698,9 +602,7 @@ private int lookupFK(String table, String idField, String valueField, String val
return recoveringConnection(connection -> {
int key;
ResultSet result = executeQuery(connection,
- //language=SQL
- "SELECT `" + idField + "` FROM `" + table + "` " +
- "WHERE `" + valueField + "` = ?",
+ this.dialect.lookupFK(table,idField,valueField),
value
);
@@ -708,8 +610,7 @@ private int lookupFK(String table, String idField, String valueField, String val
key = result.getInt("id");
} else {
PreparedStatement statement = connection.prepareStatement(
- "INSERT INTO `" + table + "` (`" + valueField + "`) " +
- "VALUES (?)",
+ this.dialect.insertFK(table,valueField),
Statement.RETURN_GENERATED_KEYS
);
statement.setString(1, value);
@@ -774,6 +675,12 @@ private DataSource createDataSource(ConnectionFactory connectionFactory, int max
return new PoolingDataSource<>(connectionPool);
}
+ public static SQLStorage create(SQLStorageSettings settings) throws Exception {
+ String dbUrl = settings.getConnectionUrl();
+ String provider = dbUrl.strip().split(":", 3)[1];
+ return DialectType.getStorage(provider,settings);
+ }
+
@FunctionalInterface
public interface ConnectionConsumer extends ConnectionFunction {
diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/DialectType.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/DialectType.java
new file mode 100644
index 00000000..25fff0df
--- /dev/null
+++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/DialectType.java
@@ -0,0 +1,40 @@
+package de.bluecolored.bluemap.core.storage.sql.dialect;
+
+import de.bluecolored.bluemap.core.storage.sql.MySQLStorage;
+import de.bluecolored.bluemap.core.storage.sql.PostgreSQLStorage;
+import de.bluecolored.bluemap.core.storage.sql.SQLStorage;
+import de.bluecolored.bluemap.core.storage.sql.SQLStorageSettings;
+
+public enum DialectType {
+
+ MYSQL (MySQLStorage::new, "mysql"),
+ MARIADB (MySQLStorage::new, "mariadb"),
+ POSTGRESQL (PostgreSQLStorage::new,"postgresql");
+
+ private final SQLStorageFactory storageFactory;
+ private final String dialectName;
+
+ DialectType(SQLStorageFactory storageFactory, String dialectName) {
+ this.storageFactory = storageFactory;
+ this.dialectName = dialectName;
+ }
+ public String getDialectName() {
+ return dialectName;
+ }
+
+ public static SQLStorage getStorage(String dialectName, SQLStorageSettings settings) throws Exception {
+ for (DialectType dialect : values()) {
+ if (dialect.getDialectName().equals(dialectName)) {
+ return dialect.storageFactory.provide(settings);
+ }
+ }
+ return null;
+ }
+
+ @FunctionalInterface
+ public interface SQLStorageFactory {
+ SQLStorage provide(SQLStorageSettings config) throws Exception;
+
+ }
+
+}
diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/MySQLDialect.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/MySQLDialect.java
new file mode 100644
index 00000000..c7fd5d5f
--- /dev/null
+++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/MySQLDialect.java
@@ -0,0 +1,250 @@
+package de.bluecolored.bluemap.core.storage.sql.dialect;
+
+import org.intellij.lang.annotations.Language;
+
+public class MySQLDialect implements SQLQueryDialect {
+
+ public static final MySQLDialect INSTANCE = new MySQLDialect();
+
+ private MySQLDialect() {};
+
+ @Override
+ @Language("MySQL")
+ public String writeMapTile() {
+ return "REPLACE INTO `bluemap_map_tile` (`map`, `lod`, `x`, `z`, `compression`, `data`) " +
+ "VALUES (?, ?, ?, ?, ?, ?)";
+ }
+
+ @Override
+ @Language("MySQL")
+ public String readMapTile() {
+ return "SELECT t.`data` " +
+ "FROM `bluemap_map_tile` t " +
+ " INNER JOIN `bluemap_map` m " +
+ " ON t.`map` = m.`id` " +
+ " INNER JOIN `bluemap_map_tile_compression` c " +
+ " ON t.`compression` = c.`id` " +
+ "WHERE m.`map_id` = ? " +
+ "AND t.`lod` = ? " +
+ "AND t.`x` = ? " +
+ "AND t.`z` = ? " +
+ "AND c.`compression` = ?";
+ }
+
+ @Override
+ @Language("MySQL")
+ public String readMapTileInfo() {
+ return "SELECT t.`changed`, LENGTH(t.`data`) as 'size' " +
+ "FROM `bluemap_map_tile` t " +
+ " INNER JOIN `bluemap_map` m " +
+ " ON t.`map` = m.`id` " +
+ " INNER JOIN `bluemap_map_tile_compression` c " +
+ " ON t.`compression` = c.`id` " +
+ "WHERE m.`map_id` = ? " +
+ "AND t.`lod` = ? " +
+ "AND t.`x` = ? " +
+ "AND t.`z` = ? " +
+ "AND c.`compression` = ?";
+ }
+
+ @Override
+ @Language("MySQL")
+ public String deleteMapTile() {
+ return "DELETE t " +
+ "FROM `bluemap_map_tile` t " +
+ " INNER JOIN `bluemap_map` m " +
+ " ON t.`map` = m.`id` " +
+ "WHERE m.`map_id` = ? " +
+ "AND t.`lod` = ? " +
+ "AND t.`x` = ? " +
+ "AND t.`z` = ?";
+ }
+
+ @Override
+ @Language("MySQL")
+ public String writeMeta() {
+ return "REPLACE INTO `bluemap_map_meta` (`map`, `key`, `value`) " +
+ "VALUES (?, ?, ?)";
+ }
+
+ @Override
+ @Language("MySQL")
+ public String readMeta() {
+ return "SELECT t.`value` " +
+ "FROM `bluemap_map_meta` t " +
+ " INNER JOIN `bluemap_map` m " +
+ " ON t.`map` = m.`id` " +
+ "WHERE m.`map_id` = ? " +
+ "AND t.`key` = ?";
+ }
+
+ @Override
+ @Language("MySQL")
+ public String readMetaSize() {
+ return "SELECT LENGTH(t.`value`) as 'size' " +
+ "FROM `bluemap_map_meta` t " +
+ " INNER JOIN `bluemap_map` m " +
+ " ON t.`map` = m.`id` " +
+ "WHERE m.`map_id` = ? " +
+ "AND t.`key` = ?";
+ }
+
+ @Override
+ @Language("MySQL")
+ public String purgeMeta() {
+ return "DELETE t " +
+ "FROM `bluemap_map_meta` t " +
+ " INNER JOIN `bluemap_map` m " +
+ " ON t.`map` = m.`id` " +
+ "WHERE m.`map_id` = ? " +
+ "AND t.`key` = ?";
+ }
+
+ @Override
+ @Language("MySQL")
+ public String purgeMapTile() {
+ return "DELETE t " +
+ "FROM `bluemap_map_tile` t " +
+ " INNER JOIN `bluemap_map` m " +
+ " ON t.`map` = m.`id` " +
+ "WHERE m.`map_id` = ?";
+ }
+
+ @Override
+ @Language("MySQL")
+ public String purgeMapMeta() {
+ return "DELETE t " +
+ "FROM `bluemap_map_meta` t " +
+ " INNER JOIN `bluemap_map` m " +
+ " ON t.`map` = m.`id` " +
+ "WHERE m.`map_id` = ?";
+ }
+
+ @Override
+ @Language("MySQL")
+ public String purgeMap() {
+ return "DELETE " +
+ "FROM `bluemap_map` " +
+ "WHERE `map_id` = ?";
+ }
+
+ @Override
+ @Language("MySQL")
+ public String selectMapIds() {
+ return "SELECT `map_id` FROM `bluemap_map`";
+ }
+
+ @Override
+ @Language("MySQL")
+ public String initializeStorageMeta() {
+ return "CREATE TABLE IF NOT EXISTS `bluemap_storage_meta` (" +
+ "`key` varchar(255) NOT NULL, " +
+ "`value` varchar(255) DEFAULT NULL, " +
+ "PRIMARY KEY (`key`)" +
+ ")";
+ }
+
+ @Override
+ @Language("MySQL")
+ public String selectStorageMeta() {
+ return "SELECT `value` FROM `bluemap_storage_meta` " +
+ "WHERE `key` = ?";
+ }
+
+ @Override
+ @Language("MySQL")
+ public String insertStorageMeta() {
+ return "INSERT INTO `bluemap_storage_meta` (`key`, `value`) " +
+ "VALUES (?, ?)";
+ }
+
+ @Override
+ @Language("MySQL")
+ public String initializeMap() {
+ return "CREATE TABLE `bluemap_map` (" +
+ "`id` SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT," +
+ "`map_id` VARCHAR(255) NOT NULL," +
+ "PRIMARY KEY (`id`)," +
+ "UNIQUE INDEX `map_id` (`map_id`)" +
+ ");";
+ }
+
+ @Override
+ @Language("MySQL")
+ public String initializeMapTileCompression() {
+ return "CREATE TABLE `bluemap_map_tile_compression` (" +
+ "`id` SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT," +
+ "`compression` VARCHAR(255) NOT NULL," +
+ "PRIMARY KEY (`id`)," +
+ "UNIQUE INDEX `compression` (`compression`)" +
+ ");";
+ }
+
+ @Override
+ @Language("MySQL")
+ public String initializeMapMeta() {
+ return "CREATE TABLE `bluemap_map_meta` (" +
+ "`map` SMALLINT UNSIGNED NOT NULL," +
+ "`key` varchar(255) NOT NULL," +
+ "`value` LONGBLOB NOT NULL," +
+ "PRIMARY KEY (`map`, `key`)," +
+ "CONSTRAINT `fk_bluemap_map_meta_map` FOREIGN KEY (`map`) REFERENCES `bluemap_map` (`id`) ON UPDATE RESTRICT ON DELETE RESTRICT" +
+ ")";
+ }
+
+ @Override
+ @Language("MySQL")
+ public String initializeMapTile() {
+ return "CREATE TABLE `bluemap_map_tile` (" +
+ "`map` SMALLINT UNSIGNED NOT NULL," +
+ "`lod` SMALLINT UNSIGNED NOT NULL," +
+ "`x` INT NOT NULL," +
+ "`z` INT NOT NULL," +
+ "`compression` SMALLINT UNSIGNED NOT NULL," +
+ "`changed` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP," +
+ "`data` LONGBLOB NOT NULL," +
+ "PRIMARY KEY (`map`, `lod`, `x`, `z`)," +
+ "CONSTRAINT `fk_bluemap_map_tile_map` FOREIGN KEY (`map`) REFERENCES `bluemap_map` (`id`) ON UPDATE RESTRICT ON DELETE RESTRICT," +
+ "CONSTRAINT `fk_bluemap_map_tile_compression` FOREIGN KEY (`compression`) REFERENCES `bluemap_map_tile_compression` (`id`) ON UPDATE RESTRICT ON DELETE RESTRICT" +
+ ");";
+ }
+
+ @Override
+ @Language("MySQL")
+ public String updateStorageMeta() {
+ return "UPDATE `bluemap_storage_meta` " +
+ "SET `value` = ? " +
+ "WHERE `key` = ?";
+ }
+
+ @Override
+ @Language("MySQL")
+ public String deleteMapMeta() {
+ return "DELETE FROM `bluemap_map_meta`" +
+ "WHERE `key` IN (?, ?, ?)";
+ }
+
+ @Override
+ @Language("MySQL")
+ public String updateMapMeta() {
+ return "UPDATE `bluemap_map_meta` " +
+ "SET `key` = ? " +
+ "WHERE `key` = ?";
+ }
+
+ @Override
+ @Language("MySQL")
+ public String lookupFK(String table, String idField, String valueField) {
+ return "SELECT `" + idField + "` FROM `" + table + "` " +
+ "WHERE `" + valueField + "` = ?";
+ }
+
+ @Override
+ @Language("MySQL")
+ public String insertFK(String table, String valueField) {
+ return "INSERT INTO `" + table + "` (`" + valueField + "`) " +
+ "VALUES (?)";
+ }
+
+
+}
diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/PostgresDialect.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/PostgresDialect.java
new file mode 100644
index 00000000..6f5a930e
--- /dev/null
+++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/PostgresDialect.java
@@ -0,0 +1,240 @@
+package de.bluecolored.bluemap.core.storage.sql.dialect;
+
+import org.intellij.lang.annotations.Language;
+
+public class PostgresDialect implements SQLQueryDialect {
+
+ public static final PostgresDialect INSTANCE = new PostgresDialect();
+
+ private PostgresDialect() {};
+
+ @Override
+ @Language("PostgreSQL")
+ public String writeMapTile() {
+ return "INSERT INTO bluemap_map_tile (map, lod, x, z, compression, data) " +
+ "VALUES (?, ?, ?, ?, ?, ?) " +
+ "ON CONFLICT (map, lod, x, z) DO UPDATE SET compression = EXCLUDED.compression, data = EXCLUDED.data";
+ }
+
+ @Override
+ @Language("PostgreSQL")
+ public String readMapTile() {
+ return "SELECT t.data " +
+ "FROM bluemap_map_tile t " +
+ " INNER JOIN bluemap_map m " +
+ " ON t.map = m.id " +
+ " INNER JOIN bluemap_map_tile_compression c " +
+ " ON t.compression = c.id " +
+ "WHERE m.map_id = ? " +
+ "AND t.lod = ? " +
+ "AND t.x = ? " +
+ "AND t.z = ? " +
+ "AND c.compression = ?";
+ }
+
+ @Override
+ @Language("PostgreSQL")
+ public String readMapTileInfo() {
+ return "SELECT t.changed, OCTET_LENGTH(t.data) as size " +
+ "FROM bluemap_map_tile t " +
+ " INNER JOIN bluemap_map m " +
+ " ON t.map = m.id " +
+ " INNER JOIN bluemap_map_tile_compression c " +
+ " ON t.compression = c.id " +
+ "WHERE m.map_id = ? " +
+ "AND t.lod = ? " +
+ "AND t.x = ? " +
+ "AND t.z = ? " +
+ "AND c.compression = ?";
+ }
+
+ @Override
+ @Language("PostgreSQL")
+ public String deleteMapTile() {
+ return "DELETE FROM bluemap_map_tile t " +
+ "USING bluemap_map m " +
+ "WHERE t.map = m.id " +
+ "AND m.map_id = ? " +
+ "AND t.lod = ? " +
+ "AND t.x = ? " +
+ "AND t.z = ?";
+ }
+
+ @Override
+ @Language("PostgreSQL")
+ public String writeMeta() {
+ return "INSERT INTO bluemap_map_meta (map, key, value) " +
+ "VALUES (?, ?, ?) " +
+ "ON CONFLICT (map, key) DO UPDATE SET value = EXCLUDED.value";
+ }
+
+ @Override
+ @Language("PostgreSQL")
+ public String readMeta() {
+ return "SELECT t.value " +
+ "FROM bluemap_map_meta t " +
+ " INNER JOIN bluemap_map m " +
+ " ON t.map = m.id " +
+ "WHERE m.map_id = ? " +
+ "AND t.key = ?";
+ }
+
+ @Override
+ @Language("PostgreSQL")
+ public String readMetaSize() {
+ return "SELECT OCTET_LENGTH(t.value) as size " +
+ "FROM bluemap_map_meta t " +
+ " INNER JOIN bluemap_map m " +
+ " ON t.map = m.id " +
+ "WHERE m.map_id = ? " +
+ "AND t.key = ?";
+ }
+
+ @Override
+ @Language("PostgreSQL")
+ public String purgeMeta() {
+ return "DELETE FROM bluemap_map_meta t " +
+ "USING bluemap_map m " +
+ "WHERE t.map = m.id " +
+ "AND m.map_id = ? " +
+ "AND t.key = ?";
+ }
+
+ @Override
+ @Language("PostgreSQL")
+ public String purgeMapTile() {
+ return "DELETE FROM bluemap_map_tile t " +
+ "USING bluemap_map m " +
+ "WHERE t.map = m.id " +
+ "AND m.map_id = ?";
+ }
+
+ @Override
+ @Language("PostgreSQL")
+ public String purgeMapMeta() {
+ return "DELETE FROM bluemap_map_meta t " +
+ "USING bluemap_map m " +
+ "WHERE t.map = m.id " +
+ "AND m.map_id = ?";
+ }
+
+ @Override
+ @Language("PostgreSQL")
+ public String purgeMap() {
+ return "DELETE FROM bluemap_map " +
+ "WHERE map_id = ?";
+ }
+
+ @Override
+ @Language("PostgreSQL")
+ public String selectMapIds() {
+ return "SELECT map_id FROM bluemap_map";
+ }
+
+ @Override
+ @Language("PostgreSQL")
+ public String initializeStorageMeta() {
+ return "CREATE TABLE IF NOT EXISTS bluemap_storage_meta (" +
+ "key varchar(255) PRIMARY KEY, " +
+ "value varchar(255)" +
+ ")";
+ }
+
+ @Override
+ @Language("PostgreSQL")
+ public String selectStorageMeta() {
+ return "SELECT value FROM bluemap_storage_meta " +
+ "WHERE key = ?";
+ }
+
+ @Override
+ @Language("PostgreSQL")
+ public String insertStorageMeta() {
+ return "INSERT INTO bluemap_storage_meta (key, value) " +
+ "VALUES (?, ?) " +
+ "ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value";
+ }
+
+ @Override
+ @Language("PostgreSQL")
+ public String initializeMap() {
+ return "CREATE TABLE IF NOT EXISTS bluemap_map (" +
+ "id SERIAL PRIMARY KEY, " +
+ "map_id VARCHAR(255) UNIQUE NOT NULL" +
+ ")";
+ }
+
+ @Override
+ @Language("PostgreSQL")
+ public String initializeMapTileCompression() {
+ return "CREATE TABLE IF NOT EXISTS bluemap_map_tile_compression (" +
+ "id SERIAL PRIMARY KEY, " +
+ "compression VARCHAR(255) UNIQUE NOT NULL" +
+ ")";
+ }
+
+ @Override
+ @Language("PostgreSQL")
+ public String initializeMapMeta() {
+ return "CREATE TABLE IF NOT EXISTS bluemap_map_meta (" +
+ "map SMALLINT REFERENCES bluemap_map(id) ON UPDATE RESTRICT ON DELETE RESTRICT, " +
+ "key varchar(255) NOT NULL, " +
+ "value BYTEA NOT NULL, " +
+ "PRIMARY KEY (map, key)" +
+ ")";
+ }
+
+ @Override
+ @Language("PostgreSQL")
+ public String initializeMapTile() {
+ return "CREATE TABLE IF NOT EXISTS bluemap_map_tile (" +
+ "map SMALLINT REFERENCES bluemap_map(id) ON UPDATE RESTRICT ON DELETE RESTRICT, " +
+ "lod SMALLINT NOT NULL, " +
+ "x INT NOT NULL, " +
+ "z INT NOT NULL, " +
+ "compression SMALLINT REFERENCES bluemap_map_tile_compression(id) ON UPDATE RESTRICT ON DELETE RESTRICT, " +
+ "changed TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, " +
+ "data BYTEA NOT NULL, " +
+ "PRIMARY KEY (map, lod, x, z)" +
+ ")";
+ }
+
+ @Override
+ @Language("PostgreSQL")
+ public String updateStorageMeta() {
+ return "UPDATE bluemap_storage_meta " +
+ "SET value = ? " +
+ "WHERE key = ?";
+ }
+
+ @Override
+ @Language("PostgreSQL")
+ public String deleteMapMeta() {
+ return "DELETE FROM bluemap_map_meta " +
+ "WHERE key IN (?, ?, ?)";
+ }
+
+ @Override
+ @Language("PostgreSQL")
+ public String updateMapMeta() {
+ return "UPDATE bluemap_map_meta " +
+ "SET key = ? " +
+ "WHERE key = ?";
+ }
+
+ @Override
+ @Language("PostgreSQL")
+ public String lookupFK(String table, String idField, String valueField) {
+ return "SELECT " + idField + " FROM " + table +
+ " WHERE " + valueField + " = ?";
+ }
+
+ @Override
+ @Language("PostgreSQL")
+ public String insertFK(String table, String valueField) {
+ return "INSERT INTO " + table + " (" + valueField + ") " +
+ "VALUES (?)";
+ }
+
+
+}
diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/SQLQueryDialect.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/SQLQueryDialect.java
new file mode 100644
index 00000000..da0d3a50
--- /dev/null
+++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/SQLQueryDialect.java
@@ -0,0 +1,78 @@
+package de.bluecolored.bluemap.core.storage.sql.dialect;
+
+import org.intellij.lang.annotations.Language;
+
+public interface SQLQueryDialect {
+ @Language("sql")
+ String writeMapTile();
+
+ @Language("sql")
+ String readMapTile();
+
+ @Language("sql")
+ String readMapTileInfo();
+
+ @Language("sql")
+ String deleteMapTile();
+
+ @Language("sql")
+ String writeMeta();
+
+ @Language("sql")
+ String readMeta();
+
+ @Language("sql")
+ String readMetaSize();
+
+ @Language("sql")
+ String purgeMeta();
+
+ @Language("sql")
+ String purgeMapTile();
+
+ @Language("sql")
+ String purgeMapMeta();
+
+ @Language("sql")
+ String purgeMap();
+
+ @Language("sql")
+ String selectMapIds();
+
+ @Language("sql")
+ String initializeStorageMeta();
+
+ @Language("sql")
+ String selectStorageMeta();
+
+ @Language("sql")
+ String insertStorageMeta();
+
+ @Language("sql")
+ String initializeMap();
+
+ @Language("sql")
+ String initializeMapTileCompression();
+
+ @Language("sql")
+ String initializeMapMeta();
+
+ @Language("sql")
+ String initializeMapTile();
+
+ @Language("sql")
+ String updateStorageMeta(); // can be use twice in init
+
+ @Language("sql")
+ String deleteMapMeta();
+
+ @Language("sql")
+ String updateMapMeta(); // can be used twice in init
+
+ @Language("sql")
+ String lookupFK(String table, String idField, String valueField);
+
+ @Language("sql")
+ String insertFK(String table, String valueField);
+
+}
From 32f15d65552c5c4093a1ebded0acbeb24db047dc Mon Sep 17 00:00:00 2001
From: "Lukas Rieger (Blue)"
Date: Mon, 12 Jun 2023 23:07:00 +0200
Subject: [PATCH 03/24] Use fallback dialect instead of returning null
---
.../bluemap/core/storage/sql/dialect/DialectType.java | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/DialectType.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/DialectType.java
index 25fff0df..da50aa1f 100644
--- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/DialectType.java
+++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/DialectType.java
@@ -11,6 +11,8 @@ public enum DialectType {
MARIADB (MySQLStorage::new, "mariadb"),
POSTGRESQL (PostgreSQLStorage::new,"postgresql");
+ private static final DialectType FALLBACK = MYSQL;
+
private final SQLStorageFactory storageFactory;
private final String dialectName;
@@ -28,7 +30,9 @@ public static SQLStorage getStorage(String dialectName, SQLStorageSettings setti
return dialect.storageFactory.provide(settings);
}
}
- return null;
+
+ // unknown dialect, use fallback
+ return FALLBACK.storageFactory.provide(settings);
}
@FunctionalInterface
From 82f1e1321d684d118349ac1700ad786272213217 Mon Sep 17 00:00:00 2001
From: "Lukas Rieger (Blue)"
Date: Mon, 12 Jun 2023 23:09:25 +0200
Subject: [PATCH 04/24] Rename Dialect interface
---
.../de/bluecolored/bluemap/core/storage/sql/SQLStorage.java | 6 +++---
.../sql/dialect/{SQLQueryDialect.java => Dialect.java} | 2 +-
.../bluemap/core/storage/sql/dialect/MySQLDialect.java | 2 +-
.../bluemap/core/storage/sql/dialect/PostgresDialect.java | 2 +-
4 files changed, 6 insertions(+), 6 deletions(-)
rename BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/{SQLQueryDialect.java => Dialect.java} (97%)
diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/SQLStorage.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/SQLStorage.java
index d633d73f..8ea329f6 100644
--- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/SQLStorage.java
+++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/SQLStorage.java
@@ -31,7 +31,7 @@
import de.bluecolored.bluemap.core.logger.Logger;
import de.bluecolored.bluemap.core.storage.*;
import de.bluecolored.bluemap.core.storage.sql.dialect.DialectType;
-import de.bluecolored.bluemap.core.storage.sql.dialect.SQLQueryDialect;
+import de.bluecolored.bluemap.core.storage.sql.dialect.Dialect;
import de.bluecolored.bluemap.core.util.WrappedOutputStream;
import org.apache.commons.dbcp2.*;
import org.apache.commons.pool2.ObjectPool;
@@ -54,7 +54,7 @@ public abstract class SQLStorage extends Storage {
private final DataSource dataSource;
- protected final SQLQueryDialect dialect;
+ protected final Dialect dialect;
protected final Compression hiresCompression;
private final LoadingCache mapFKs = Caffeine.newBuilder()
@@ -66,7 +66,7 @@ public abstract class SQLStorage extends Storage {
private volatile boolean closed;
- public SQLStorage(SQLQueryDialect dialect, SQLStorageSettings config) throws MalformedURLException, SQLDriverException {
+ public SQLStorage(Dialect dialect, SQLStorageSettings config) throws MalformedURLException, SQLDriverException {
this.dialect = dialect;
this.closed = false;
try {
diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/SQLQueryDialect.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/Dialect.java
similarity index 97%
rename from BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/SQLQueryDialect.java
rename to BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/Dialect.java
index da0d3a50..4406e7d2 100644
--- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/SQLQueryDialect.java
+++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/Dialect.java
@@ -2,7 +2,7 @@
import org.intellij.lang.annotations.Language;
-public interface SQLQueryDialect {
+public interface Dialect {
@Language("sql")
String writeMapTile();
diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/MySQLDialect.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/MySQLDialect.java
index c7fd5d5f..1d2f49f9 100644
--- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/MySQLDialect.java
+++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/MySQLDialect.java
@@ -2,7 +2,7 @@
import org.intellij.lang.annotations.Language;
-public class MySQLDialect implements SQLQueryDialect {
+public class MySQLDialect implements Dialect {
public static final MySQLDialect INSTANCE = new MySQLDialect();
diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/PostgresDialect.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/PostgresDialect.java
index 6f5a930e..8f4b69c8 100644
--- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/PostgresDialect.java
+++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/PostgresDialect.java
@@ -2,7 +2,7 @@
import org.intellij.lang.annotations.Language;
-public class PostgresDialect implements SQLQueryDialect {
+public class PostgresDialect implements Dialect {
public static final PostgresDialect INSTANCE = new PostgresDialect();
From d120a0049611aee18997471017528cc7b099fdbf Mon Sep 17 00:00:00 2001
From: "Lukas Rieger (Blue)"
Date: Mon, 12 Jun 2023 23:14:05 +0200
Subject: [PATCH 05/24] rename _index.php to mysql.php
---
BlueMapCommon/webapp/public/{_index.php => mysql.php} | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename BlueMapCommon/webapp/public/{_index.php => mysql.php} (100%)
diff --git a/BlueMapCommon/webapp/public/_index.php b/BlueMapCommon/webapp/public/mysql.php
similarity index 100%
rename from BlueMapCommon/webapp/public/_index.php
rename to BlueMapCommon/webapp/public/mysql.php
From 969f7a78f3aa6f2e9665af0a26b804d990cfa011 Mon Sep 17 00:00:00 2001
From: "Lukas Rieger (Blue)"
Date: Wed, 14 Jun 2023 19:27:22 +0200
Subject: [PATCH 06/24] Update CONTRIBUTING.md
---
.github/CONTRIBUTING.md | 19 ++++++++++++++++---
.github/ISSUE_TEMPLATE/feature_request.md | 14 --------------
2 files changed, 16 insertions(+), 17 deletions(-)
delete mode 100644 .github/ISSUE_TEMPLATE/feature_request.md
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index 9291a4ad..fd288e2a 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -19,7 +19,7 @@ So, if something doesn't work because it is not implemented yet, its not a bug.
If you are not sure, you can briefly ask about it in our [Discord](https://discord.gg/zmkyJa3) before creating an Issue. :)
- Make sure you tested it well enough to be sure it's not an issue on your end. If something doesn't work for you but for everyone else, its probably **not** a bug!
-Also, please make sure noone else has already reported the same or a very similar bug!
+Also, please make sure no one else has already reported the same or a very similar bug!
If you have additional information for an existing bug-report, you can add a comment to the already existing Issue :)
To report your bug, please open a [new Issue](https://github.com/BlueMap-Minecraft/BlueMap/issues/new?template=bug_report.md) with the `Bug report`-template and follow these guidlines:
@@ -53,7 +53,20 @@ Make sure your Issue is easy to read and not a mess:
Create a separate Issue for each bug you find! Issues that contain more than one bug will be closed!
## Suggesting a new feature or change
-**(Todo)**
+Please use our [discord](https://discord.gg/zmkyJa3)s #suggestions channel to pitch new ideas.
+We will discuss them there and if they are considered, I'll add an issue/note to out [TODO](https://github.com/orgs/BlueMap-Minecraft/projects/2/views/1)-Board!
## Creating a Pull-Request
-**(Todo)**
+If you want to develop a new PR, please run your Idea by me first in our [discord](https://discord.gg/zmkyJa3)!
+We can discuss details there, since I have a lot of future plans in my head that are not written anywhere, and they might need to be considered
+when implementing your feature!
+*(Also, I tend to be quite picky about certain implementation styles and details ^^')*
+
+**Please keep in mind that any feature you implement will need to be maintained in the future by me.
+For this reason I will only accept PR's for features that I deem to be useful, maintainable, in-scope of the project and
+worth it's maintenance-workload!**
+
+Ofc the usual "good code quality..." stuff, i think that's common sense.
+Try to match the existing code-style.
+Don't add new libraries/dependencies without my ok.
+Hacky stuff is not allowed =)
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
deleted file mode 100644
index a872efe0..00000000
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ /dev/null
@@ -1,14 +0,0 @@
----
-name: Feature request
-about: Suggest an idea for this project
-title: ''
-labels: ''
-assignees: ''
-
----
-
-**Is your feature request related to a problem? Please describe.**
-A clear and concise description of what the problem is. Why do you want this feature
-
-**Describe the solution you'd like**
-A clear and concise description of what you want to happen.
From bac87ec5461a9062b9083bdaf5e98066ad06c3e3 Mon Sep 17 00:00:00 2001
From: stdpi
Date: Fri, 16 Jun 2023 00:12:22 +0700
Subject: [PATCH 07/24] chore: add Vietnamese translation (#448)
---
.../webapp/public/lang/settings.conf | 1 +
BlueMapCommon/webapp/public/lang/vi.conf | 171 ++++++++++++++++++
2 files changed, 172 insertions(+)
create mode 100644 BlueMapCommon/webapp/public/lang/vi.conf
diff --git a/BlueMapCommon/webapp/public/lang/settings.conf b/BlueMapCommon/webapp/public/lang/settings.conf
index 21efafc3..e3a04483 100644
--- a/BlueMapCommon/webapp/public/lang/settings.conf
+++ b/BlueMapCommon/webapp/public/lang/settings.conf
@@ -26,5 +26,6 @@
{ locale: "zh_TW", name: "中文(台灣)" }
{ locale: "zh_HK", name: "中文(香港)" }
{ locale: "ko", name: "한국어" }
+ { locale: "vi", name: "Tiếng Việt"}
]
}
diff --git a/BlueMapCommon/webapp/public/lang/vi.conf b/BlueMapCommon/webapp/public/lang/vi.conf
new file mode 100644
index 00000000..508a7a80
--- /dev/null
+++ b/BlueMapCommon/webapp/public/lang/vi.conf
@@ -0,0 +1,171 @@
+{
+ pageTitle: "BlueMap - {map}"
+ menu: {
+ title: "Menu"
+ tooltip: "Menu"
+ }
+ map: {
+ unloaded: "Không có bản đồ."
+ loading: "Đang tải bản đồ..."
+ errored: "Có lồi khi tải bản đồ!"
+ }
+ maps: {
+ title: "Bản đồ"
+ button: "Bản đồ"
+ tooltip: "Mọi bản đồ"
+ }
+ markers: {
+ title: "Đánh dấu"
+ button: "Đánh dấu"
+ tooltip: "Mọi đánh dấu"
+ marker: "đánh dấu | các đánh dấu"
+ markerSet: "cụm đánh dấu | các cụm đánh dấu"
+ searchPlaceholder: "Tìm..."
+ followPlayerTitle: "Bám theo"
+ sort {
+ title: "Sắp xếp"
+ by {
+ default: "mặc định"
+ label: "tên"
+ distance: "khoảng cách"
+ }
+ }
+ }
+ settings: {
+ title: "Cài đặt"
+ button: "Cài đặt"
+ }
+ goFullscreen: {
+ button: "Toản màn hình"
+ }
+ resetCamera: {
+ button: "Đặt lại camera"
+ tooltip: "Đặt lại camera và vị trí"
+ }
+ updateMap: {
+ button: "Cập nhật bản đồ"
+ tooltip: "Xóa bộ nhớ đệm"
+ }
+ lighting: {
+ title: "Ánh sáng"
+ dayNightSwitch: {
+ tooltip: "Ngày/Đêm"
+ }
+ sunlight: "Nhật quang"
+ ambientLight: "Phát quang"
+ }
+ resolution: {
+ title: "Độ phân giải"
+ high: "Cao (SSAA x2)"
+ normal: "Thường (Native x1)"
+ low: "Thấp (Upscaling x0.5)"
+ }
+ mapControls: {
+ title: "Điều khiển"
+ showZoomButtons: "Hiện nút thu phóng"
+ }
+ freeFlightControls: {
+ title: "Chế độ bay"
+ mouseSensitivity: "Độ nhạy chuột"
+ invertMouseY: "Đảo trục dọc"
+ }
+ renderDistance: {
+ title: "Khoảng cách kết xuất"
+ hiresLayer: "Vùng chất lượng cao"
+ lowersLayer: "Vùng chất lượng thấp"
+ loadHiresWhileMoving: "Tải vùng chất lượng cao khi di chuyển"
+ off: "Tắt"
+ }
+ theme: {
+ title: "Giao diện"
+ default: "Mặc định (hệ thống)"
+ dark: "Tối"
+ light: "Sáng"
+ contrast: "Tương phản"
+ }
+ debug: {
+ button: "Gỡ lỗi"
+ }
+ resetAllSettings: {
+ button: "Thiết đặt lại"
+ }
+ players: {
+ title: "Người chơi"
+ tooltip: "Danh sách người chơi"
+ }
+ compass: {
+ tooltip: "Hướng / chỉ bắc"
+ }
+ screenshot: {
+ title: "Chụp màn hình"
+ button: "Chụp màn hình"
+ clipboard: "Sao chép"
+ }
+ controls: {
+ title: "Chế độ"
+ perspective: {
+ button: "Xung quanh"
+ tooltip: "Góc nhìn xung quanh"
+ }
+ flatView: {
+ button: "Phẳng"
+ tooltip: "Góc nhìn từ trên xuống"
+ }
+ freeFlight: {
+ button: "Bay"
+ tooltip: "Góc nhìn chim bay"
+ }
+ }
+ language: {
+ title: "Ngôn ngữ"
+ }
+ blockTooltip: {
+ block: "Khối"
+ position: "Vị chí"
+ chunk: "Vùng"
+ region: {
+ region: "Khu vực"
+ file: "File"
+ }
+ light: {
+ light: "Ánh sáng"
+ sun: "Nhật quang"
+ block: "Phát quang"
+ }
+ }
+ info: {
+ title: "Thông tin"
+ button: "Thông tin"
+ content: """
+
+
+
Điều khiển chuột:
+
+ di chuyển | chuột trái + kéo |
+ thu phóng | lăn chuột |
+ xoay/nghiêng | chuột phải + kéo |
+
+
+
+
Điều khiển bàn phím:
+
+ di chuyển | wasd / phím mũi tên |
+ thu phóng | Bàn phím số: +/- or Ins/Home |
+ xoay/nghiêng | Alt trái + wasd / phím mũi tên hoặc Delete/End/Page Up/Page Down |
+
+
+
+
Điều khiển cảm ứng:
+
+ di chuyển | chạm + kéo |
+ thu phóng | chạm 2 ngón + nhón |
+ xoay/nghiêng | chạm 2 ngón + di chuyển / xoay |
+
+
+
+
+"""
+ }
+}
From da8a12158b622ac5388f0190fd31babfd8ee3646 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Antti=20Ellil=C3=A4?=
Date: Thu, 15 Jun 2023 21:08:36 +0300
Subject: [PATCH 08/24] Expose more JavaScript classes (#449)
With the lack of a proper JavaScript API for addons, it might be useful to just expose all the classes in the global namespace for usage and code injection.
---
BlueMapCommon/webapp/src/js/BlueMap.js | 60 ++++++++++++++++++++++----
BlueMapCommon/webapp/src/main.js | 2 +
2 files changed, 54 insertions(+), 8 deletions(-)
diff --git a/BlueMapCommon/webapp/src/js/BlueMap.js b/BlueMapCommon/webapp/src/js/BlueMap.js
index 6cb5f086..8db2cc54 100644
--- a/BlueMapCommon/webapp/src/js/BlueMap.js
+++ b/BlueMapCommon/webapp/src/js/BlueMap.js
@@ -22,41 +22,85 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-import {Object3D} from "three";
+import { Object3D } from "three";
-export * from "./MapViewer";
+export * as Three from "three";
+export * from "./controls/freeflight/FreeFlightControls";
+export * from "./controls/freeflight/keyboard/KeyHeightControls";
+// class name conflicts with map controls
+export { KeyMoveControls as FreeFlightKeyMoveControls } from "./controls/freeflight/keyboard/KeyMoveControls";
+export { MouseAngleControls as FreeFlightMouseAngleControls } from "./controls/freeflight/mouse/MouseAngleControls";
+export { MouseRotateControls as FreeFlightMouseRotateControls } from "./controls/freeflight/mouse/MouseRotateControls";
+export * from "./controls/freeflight/touch/TouchPanControls";
+
+export * from "./controls/map/MapControls";
+export * from "./controls/map/MapHeightControls";
+export * from "./controls/map/keyboard/KeyAngleControls";
+export { KeyMoveControls as MapKeyMoveControls } from "./controls/map/keyboard/KeyMoveControls";
+export * from "./controls/map/keyboard/KeyRotateControls";
+export * from "./controls/map/keyboard/KeyZoomControls";
+export { MouseAngleControls as MapMouseAngleControls } from "./controls/map/mouse/MouseAngleControls";
+export * from "./controls/map/mouse/MouseMoveControls";
+export { MouseRotateControls as MapMouseRotateControls } from "./controls/map/mouse/MouseRotateControls";
+export * from "./controls/map/mouse/MouseZoomControls";
+export * from "./controls/map/touch/TouchAngleControls";
+export * from "./controls/map/touch/TouchMoveControls";
+export * from "./controls/map/touch/TouchRotateControls";
+export * from "./controls/map/touch/TouchZoomControls";
+
+export * from "./controls/ControlsManager";
+export * from "./controls/KeyCombination";
+
+export * from "./map/LowresTileLoader";
export * from "./map/Map";
export * from "./map/Tile";
export * from "./map/TileLoader";
export * from "./map/TileManager";
export * from "./map/TileMap";
+export * from "./map/hires/HiresFragmentShader";
+export * from "./map/hires/HiresVertexShader";
+export * from "./map/lowres/LowresFragmentShader";
+export * from "./map/lowres/LowresVertexShader";
export * from "./markers/ExtrudeMarker";
export * from "./markers/HtmlMarker";
export * from "./markers/LineMarker";
export * from "./markers/Marker";
+export * from "./markers/MarkerFillFragmentShader";
+export * from "./markers/MarkerFillVertexShader";
export * from "./markers/MarkerManager";
export * from "./markers/MarkerSet";
-export * from "./markers/PlayerMarkerSet";
+export * from "./markers/NormalMarkerManager";
export * from "./markers/ObjectMarker";
export * from "./markers/PlayerMarker";
+export * from "./markers/PlayerMarkerManager";
+export * from "./markers/PlayerMarkerSet";
export * from "./markers/PoiMarker";
export * from "./markers/ShapeMarker";
-export * from "./controls/map/MapControls";
-export * from "./controls/freeflight/FreeFlightControls";
+export * from "./skybox/SkyFragmentShader";
+export * from "./skybox/SkyVertexShader";
+export * from "./skybox/SkyboxScene";
+export * from "./util/CSS2DRenderer";
export * from "./util/CombinedCamera";
+export * from "./util/LineShader";
+export * from "./util/Stats";
export * from "./util/Utils";
+export * from "./BlueMapApp";
+export * from "./MainMenu";
+export * from "./MapViewer";
+export * from "./PopupMarker";
+export * from "./Utils";
+
/**
* @param event {object}
* @return {boolean} - whether the event has been consumed (true) or not (false)
*/
-Object3D.prototype.onClick = function(event) {
-
- if (this.parent){
+Object3D.prototype.onClick = function (event) {
+ if (this.parent) {
if (!Array.isArray(event.eventStack)) event.eventStack = [];
event.eventStack.push(this);
diff --git a/BlueMapCommon/webapp/src/main.js b/BlueMapCommon/webapp/src/main.js
index 3d6c63a1..467a6c47 100644
--- a/BlueMapCommon/webapp/src/main.js
+++ b/BlueMapCommon/webapp/src/main.js
@@ -25,6 +25,7 @@
import * as Vue from 'vue';
import App from './App.vue';
+import * as BlueMap from "./js/BlueMap";
import {BlueMapApp} from "./js/BlueMapApp";
import {i18nModule, loadLanguageSettings} from "./i18n";
@@ -38,6 +39,7 @@ async function load() {
try {
const bluemap = new BlueMapApp(document.getElementById("map-container"));
window.bluemap = bluemap;
+ window.BlueMap = BlueMap;
// init vue
const vue = Vue.createApp(App, {
From 97f346534bad084eabbf51b292099311dc991814 Mon Sep 17 00:00:00 2001
From: "Lukas Rieger (Blue)"
Date: Fri, 16 Jun 2023 20:23:28 +0200
Subject: [PATCH 09/24] Fix 1.13.2 support
---
.../java/de/bluecolored/bluemap/core/mca/ChunkAnvil113.java | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/ChunkAnvil113.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/ChunkAnvil113.java
index 9f90a990..35752b08 100644
--- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/ChunkAnvil113.java
+++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/ChunkAnvil113.java
@@ -55,7 +55,9 @@ public ChunkAnvil113(MCAWorld world, CompoundTag chunkTag) {
CompoundTag levelData = chunkTag.getCompoundTag("Level");
String status = levelData.getString("Status");
- this.isGenerated = status.equals("full");
+ this.isGenerated = status.equals("full") ||
+ status.equals("fullchunk") ||
+ status.equals("postprocessed");
this.hasLight = isGenerated;
this.inhabitedTime = levelData.getLong("InhabitedTime");
From 4fc6d7f889662c9ea369389e300799e6deb30357 Mon Sep 17 00:00:00 2001
From: "Lukas Rieger (Blue)"
Date: Sat, 17 Jun 2023 11:53:39 +0200
Subject: [PATCH 10/24] Fix stuck moving when window looses focus. Fixes: #408
---
.../js/controls/freeflight/keyboard/KeyHeightControls.js | 7 +++++++
.../js/controls/freeflight/keyboard/KeyMoveControls.js | 9 +++++++++
.../src/js/controls/map/keyboard/KeyAngleControls.js | 7 +++++++
.../src/js/controls/map/keyboard/KeyMoveControls.js | 9 +++++++++
.../src/js/controls/map/keyboard/KeyRotateControls.js | 7 +++++++
.../src/js/controls/map/keyboard/KeyZoomControls.js | 7 +++++++
6 files changed, 46 insertions(+)
diff --git a/BlueMapCommon/webapp/src/js/controls/freeflight/keyboard/KeyHeightControls.js b/BlueMapCommon/webapp/src/js/controls/freeflight/keyboard/KeyHeightControls.js
index 7b4ea6c3..1013d1eb 100644
--- a/BlueMapCommon/webapp/src/js/controls/freeflight/keyboard/KeyHeightControls.js
+++ b/BlueMapCommon/webapp/src/js/controls/freeflight/keyboard/KeyHeightControls.js
@@ -66,11 +66,13 @@ export class KeyHeightControls {
window.addEventListener("keydown", this.onKeyDown);
window.addEventListener("keyup", this.onKeyUp);
+ window.addEventListener("blur", this.onStop)
}
stop() {
window.removeEventListener("keydown", this.onKeyDown);
window.removeEventListener("keyup", this.onKeyUp);
+ window.removeEventListener("blur", this.onStop)
}
/**
@@ -120,4 +122,9 @@ export class KeyHeightControls {
}
}
+ onStop = evt => {
+ this.up = false;
+ this.down = false;
+ }
+
}
\ No newline at end of file
diff --git a/BlueMapCommon/webapp/src/js/controls/freeflight/keyboard/KeyMoveControls.js b/BlueMapCommon/webapp/src/js/controls/freeflight/keyboard/KeyMoveControls.js
index 81509d9b..f64ddbf6 100644
--- a/BlueMapCommon/webapp/src/js/controls/freeflight/keyboard/KeyMoveControls.js
+++ b/BlueMapCommon/webapp/src/js/controls/freeflight/keyboard/KeyMoveControls.js
@@ -78,11 +78,13 @@ export class KeyMoveControls {
window.addEventListener("keydown", this.onKeyDown);
window.addEventListener("keyup", this.onKeyUp);
+ window.addEventListener("blur", this.onStop)
}
stop() {
window.removeEventListener("keydown", this.onKeyDown);
window.removeEventListener("keyup", this.onKeyUp);
+ window.removeEventListener("blur", this.onStop)
}
/**
@@ -152,4 +154,11 @@ export class KeyMoveControls {
}
}
+ onStop = evt => {
+ this.up = false;
+ this.down = false;
+ this.left = false;
+ this.right = false;
+ }
+
}
\ No newline at end of file
diff --git a/BlueMapCommon/webapp/src/js/controls/map/keyboard/KeyAngleControls.js b/BlueMapCommon/webapp/src/js/controls/map/keyboard/KeyAngleControls.js
index 2e2e063f..fcdb2529 100644
--- a/BlueMapCommon/webapp/src/js/controls/map/keyboard/KeyAngleControls.js
+++ b/BlueMapCommon/webapp/src/js/controls/map/keyboard/KeyAngleControls.js
@@ -67,11 +67,13 @@ export class KeyAngleControls {
window.addEventListener("keydown", this.onKeyDown);
window.addEventListener("keyup", this.onKeyUp);
+ window.addEventListener("blur", this.onStop)
}
stop() {
window.removeEventListener("keydown", this.onKeyDown);
window.removeEventListener("keyup", this.onKeyUp);
+ window.removeEventListener("blur", this.onStop)
}
/**
@@ -121,4 +123,9 @@ export class KeyAngleControls {
}
}
+ onStop = evt => {
+ this.up = false;
+ this.down = false;
+ }
+
}
\ No newline at end of file
diff --git a/BlueMapCommon/webapp/src/js/controls/map/keyboard/KeyMoveControls.js b/BlueMapCommon/webapp/src/js/controls/map/keyboard/KeyMoveControls.js
index 30aaf4a6..a91aaed0 100644
--- a/BlueMapCommon/webapp/src/js/controls/map/keyboard/KeyMoveControls.js
+++ b/BlueMapCommon/webapp/src/js/controls/map/keyboard/KeyMoveControls.js
@@ -78,11 +78,13 @@ export class KeyMoveControls {
window.addEventListener("keydown", this.onKeyDown);
window.addEventListener("keyup", this.onKeyUp);
+ window.addEventListener("blur", this.onStop)
}
stop() {
window.removeEventListener("keydown", this.onKeyDown);
window.removeEventListener("keyup", this.onKeyUp);
+ window.removeEventListener("blur", this.onStop)
}
/**
@@ -152,4 +154,11 @@ export class KeyMoveControls {
}
}
+ onStop = evt => {
+ this.up = false;
+ this.down = false;
+ this.left = false;
+ this.right = false;
+ }
+
}
\ No newline at end of file
diff --git a/BlueMapCommon/webapp/src/js/controls/map/keyboard/KeyRotateControls.js b/BlueMapCommon/webapp/src/js/controls/map/keyboard/KeyRotateControls.js
index 6ed2c4e7..1413182b 100644
--- a/BlueMapCommon/webapp/src/js/controls/map/keyboard/KeyRotateControls.js
+++ b/BlueMapCommon/webapp/src/js/controls/map/keyboard/KeyRotateControls.js
@@ -67,11 +67,13 @@ export class KeyRotateControls {
window.addEventListener("keydown", this.onKeyDown);
window.addEventListener("keyup", this.onKeyUp);
+ window.addEventListener("blur", this.onStop)
}
stop() {
window.removeEventListener("keydown", this.onKeyDown);
window.removeEventListener("keyup", this.onKeyUp);
+ window.removeEventListener("blur", this.onStop)
}
/**
@@ -121,4 +123,9 @@ export class KeyRotateControls {
}
}
+ onStop = evt => {
+ this.left = false;
+ this.right = false;
+ }
+
}
\ No newline at end of file
diff --git a/BlueMapCommon/webapp/src/js/controls/map/keyboard/KeyZoomControls.js b/BlueMapCommon/webapp/src/js/controls/map/keyboard/KeyZoomControls.js
index 0c884dfd..dd9a5b16 100644
--- a/BlueMapCommon/webapp/src/js/controls/map/keyboard/KeyZoomControls.js
+++ b/BlueMapCommon/webapp/src/js/controls/map/keyboard/KeyZoomControls.js
@@ -65,11 +65,13 @@ export class KeyZoomControls {
window.addEventListener("keydown", this.onKeyDown);
window.addEventListener("keyup", this.onKeyUp);
+ window.addEventListener("blur", this.onStop)
}
stop() {
window.removeEventListener("keydown", this.onKeyDown);
window.removeEventListener("keyup", this.onKeyUp);
+ window.removeEventListener("blur", this.onStop)
}
/**
@@ -119,4 +121,9 @@ export class KeyZoomControls {
}
}
+ onStop = evt => {
+ this.in = false;
+ this.out = false;
+ }
+
}
\ No newline at end of file
From 22f2b09fe501db95db08409dd8de518aa4dfcf31 Mon Sep 17 00:00:00 2001
From: "Lukas Rieger (Blue)"
Date: Sat, 17 Jun 2023 11:59:16 +0200
Subject: [PATCH 11/24] Fix Mobile first-person Controls not showing. Fixes:
#447
---
BlueMapCommon/webapp/src/App.vue | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/BlueMapCommon/webapp/src/App.vue b/BlueMapCommon/webapp/src/App.vue
index 6d203776..7f8aa6f7 100644
--- a/BlueMapCommon/webapp/src/App.vue
+++ b/BlueMapCommon/webapp/src/App.vue
@@ -1,6 +1,6 @@
-
+
{{ $t("map." + mapViewer.mapState) }}
From e46efc4c5348a6141e810f36f4256bc7b54f826f Mon Sep 17 00:00:00 2001
From: "Lukas Rieger (Blue)"
Date: Sat, 17 Jun 2023 12:42:34 +0200
Subject: [PATCH 12/24] Use root-map element for scroll-events. Fixes: #409
---
BlueMapCommon/webapp/src/js/BlueMapApp.js | 2 +-
BlueMapCommon/webapp/src/js/controls/map/MapControls.js | 6 ++++--
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/BlueMapCommon/webapp/src/js/BlueMapApp.js b/BlueMapCommon/webapp/src/js/BlueMapApp.js
index ff9d673a..e4a206fc 100644
--- a/BlueMapCommon/webapp/src/js/BlueMapApp.js
+++ b/BlueMapCommon/webapp/src/js/BlueMapApp.js
@@ -48,7 +48,7 @@ export class BlueMapApp {
this.mapViewer = new MapViewer(rootElement, this.events);
- this.mapControls = new MapControls(this.mapViewer.renderer.domElement);
+ this.mapControls = new MapControls(this.mapViewer.renderer.domElement, rootElement);
this.freeFlightControls = new FreeFlightControls(this.mapViewer.renderer.domElement);
/** @type {PlayerMarkerManager} */
diff --git a/BlueMapCommon/webapp/src/js/controls/map/MapControls.js b/BlueMapCommon/webapp/src/js/controls/map/MapControls.js
index 7d22150c..f835a6b5 100644
--- a/BlueMapCommon/webapp/src/js/controls/map/MapControls.js
+++ b/BlueMapCommon/webapp/src/js/controls/map/MapControls.js
@@ -50,9 +50,11 @@ export class MapControls {
/**
* @param rootElement {Element}
+ * @param scrollCaptureElement {Element}
*/
- constructor(rootElement) {
+ constructor(rootElement, scrollCaptureElement) {
this.rootElement = rootElement;
+ this.scrollCaptureElement = scrollCaptureElement;
this.data = reactive({
followingPlayer: null
@@ -68,7 +70,7 @@ export class MapControls {
this.mouseMove = new MouseMoveControls(this.rootElement, 1.5,0.3);
this.mouseRotate = new MouseRotateControls(this.rootElement, 6, 0.3);
this.mouseAngle = new MouseAngleControls(this.rootElement, 3, 0.3);
- this.mouseZoom = new MouseZoomControls(this.rootElement, 1, 0.2);
+ this.mouseZoom = new MouseZoomControls(this.scrollCaptureElement, 1, 0.2);
this.keyMove = new KeyMoveControls(this.rootElement, 0.025, 0.2);
this.keyRotate = new KeyRotateControls(this.rootElement, 0.06, 0.15);
From 55fb955ed71a8409a1eaddc79387da72e5b6b3b5 Mon Sep 17 00:00:00 2001
From: "Lukas Rieger (Blue)"
Date: Sat, 17 Jun 2023 13:33:42 +0200
Subject: [PATCH 13/24] Fix clear() method not actually clearing the markerset.
Fixes: #430
---
BlueMapCommon/webapp/src/js/BlueMapApp.js | 13 +++++--------
.../webapp/src/js/markers/MarkerManager.js | 3 ++-
BlueMapCommon/webapp/src/js/markers/MarkerSet.js | 4 ++--
.../webapp/src/js/markers/NormalMarkerManager.js | 4 ++++
.../webapp/src/js/markers/PlayerMarkerManager.js | 4 ++++
5 files changed, 17 insertions(+), 11 deletions(-)
diff --git a/BlueMapCommon/webapp/src/js/BlueMapApp.js b/BlueMapCommon/webapp/src/js/BlueMapApp.js
index e4a206fc..75b233d9 100644
--- a/BlueMapCommon/webapp/src/js/BlueMapApp.js
+++ b/BlueMapCommon/webapp/src/js/BlueMapApp.js
@@ -251,6 +251,9 @@ export class BlueMapApp {
let map = this.mapsMap.get(mapId);
if (!map) return Promise.reject(`There is no map with the id "${mapId}" loaded!`);
+ if (this.playerMarkerManager) this.playerMarkerManager.dispose();
+ if (this.markerFileManager) this.markerFileManager.dispose();
+
await this.mapViewer.switchMap(map)
if (resetCamera) this.resetCamera();
@@ -353,10 +356,8 @@ export class BlueMapApp {
}
initPlayerMarkerManager() {
- if (this.playerMarkerManager){
- this.playerMarkerManager.clear();
+ if (this.playerMarkerManager)
this.playerMarkerManager.dispose()
- }
const map = this.mapViewer.map;
if (!map) return;
@@ -369,16 +370,13 @@ export class BlueMapApp {
})
.catch(e => {
alert(this.events, e, "warning");
- this.playerMarkerManager.clear();
this.playerMarkerManager.dispose();
});
}
initMarkerFileManager() {
- if (this.markerFileManager) {
- this.markerFileManager.clear();
+ if (this.markerFileManager)
this.markerFileManager.dispose();
- }
const map = this.mapViewer.map;
if (!map) return;
@@ -390,7 +388,6 @@ export class BlueMapApp {
})
.catch(e => {
alert(this.events, e, "warning");
- this.markerFileManager.clear();
this.markerFileManager.dispose();
});
}
diff --git a/BlueMapCommon/webapp/src/js/markers/MarkerManager.js b/BlueMapCommon/webapp/src/js/markers/MarkerManager.js
index cbdd4ba5..e9dbb12b 100644
--- a/BlueMapCommon/webapp/src/js/markers/MarkerManager.js
+++ b/BlueMapCommon/webapp/src/js/markers/MarkerManager.js
@@ -83,7 +83,8 @@ export class MarkerManager {
*/
update() {
return this.loadMarkerFile()
- .then(markerFileData => this.updateFromData(markerFileData));
+ .then(markerFileData => this.updateFromData(markerFileData))
+ .catch(() => this.clear());
}
/**
diff --git a/BlueMapCommon/webapp/src/js/markers/MarkerSet.js b/BlueMapCommon/webapp/src/js/markers/MarkerSet.js
index f3aecf8b..064d9e0b 100644
--- a/BlueMapCommon/webapp/src/js/markers/MarkerSet.js
+++ b/BlueMapCommon/webapp/src/js/markers/MarkerSet.js
@@ -174,8 +174,8 @@ export class MarkerSet extends Scene {
* Removes all markers and marker-sets
*/
clear() {
- [...this.data.markerSets].forEach(markerSet => this.remove(markerSet));
- [...this.data.markers].forEach(marker => this.remove(marker));
+ [...this.markerSets.values()].forEach(markerSet => this.remove(markerSet));
+ [...this.markers.values()].forEach(marker => this.remove(marker));
}
add(...object) {
diff --git a/BlueMapCommon/webapp/src/js/markers/NormalMarkerManager.js b/BlueMapCommon/webapp/src/js/markers/NormalMarkerManager.js
index d35721ac..a9d82167 100644
--- a/BlueMapCommon/webapp/src/js/markers/NormalMarkerManager.js
+++ b/BlueMapCommon/webapp/src/js/markers/NormalMarkerManager.js
@@ -48,4 +48,8 @@ export class NormalMarkerManager extends MarkerManager {
return true;
}
+ clear() {
+ this.root.updateMarkerSetsFromData({}, [PLAYER_MARKER_SET_ID, "bm-popup-set"]);
+ }
+
}
\ No newline at end of file
diff --git a/BlueMapCommon/webapp/src/js/markers/PlayerMarkerManager.js b/BlueMapCommon/webapp/src/js/markers/PlayerMarkerManager.js
index 84dbcbd1..b114c8a4 100644
--- a/BlueMapCommon/webapp/src/js/markers/PlayerMarkerManager.js
+++ b/BlueMapCommon/webapp/src/js/markers/PlayerMarkerManager.js
@@ -78,4 +78,8 @@ export class PlayerMarkerManager extends MarkerManager {
return this.getPlayerMarkerSet().getPlayerMarker(playerUuid)
}
+ clear() {
+ this.getPlayerMarkerSet(false).clear();
+ }
+
}
\ No newline at end of file
From 7097547301fe2850039aaf84e42e9af97c4fdb8a Mon Sep 17 00:00:00 2001
From: "Lukas Rieger (Blue)"
Date: Sun, 18 Jun 2023 01:02:13 +0200
Subject: [PATCH 14/24] Add sqlite support. Closes: #322
---
.../core/storage/sql/PostgreSQLStorage.java | 46 ++--
.../bluemap/core/storage/sql/SQLStorage.java | 19 +-
.../core/storage/sql/SQLiteStorage.java | 13 +
.../core/storage/sql/dialect/Dialect.java | 2 +-
.../core/storage/sql/dialect/DialectType.java | 8 +-
.../storage/sql/dialect/MySQLDialect.java | 2 +-
.../storage/sql/dialect/PostgresDialect.java | 2 +-
.../storage/sql/dialect/SqliteDialect.java | 256 ++++++++++++++++++
8 files changed, 304 insertions(+), 44 deletions(-)
create mode 100644 BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/SQLiteStorage.java
create mode 100644 BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/SqliteDialect.java
diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/PostgreSQLStorage.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/PostgreSQLStorage.java
index e6ef360a..85825337 100644
--- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/PostgreSQLStorage.java
+++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/PostgreSQLStorage.java
@@ -3,12 +3,12 @@
import com.flowpowered.math.vector.Vector2i;
import de.bluecolored.bluemap.core.storage.CompressedInputStream;
import de.bluecolored.bluemap.core.storage.Compression;
+import de.bluecolored.bluemap.core.storage.sql.dialect.Dialect;
import de.bluecolored.bluemap.core.storage.sql.dialect.PostgresDialect;
import de.bluecolored.bluemap.core.util.WrappedOutputStream;
import java.io.*;
import java.net.MalformedURLException;
-import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Optional;
@@ -19,6 +19,10 @@ public PostgreSQLStorage(SQLStorageSettings config) throws MalformedURLException
super(PostgresDialect.INSTANCE, config);
}
+ public PostgreSQLStorage(Dialect dialect, SQLStorageSettings config) throws MalformedURLException, SQLDriverException {
+ super(dialect, config);
+ }
+
@Override
public OutputStream writeMapTile(String mapId, int lod, Vector2i tile) throws IOException {
Compression compression = lod == 0 ? this.hiresCompression : Compression.NONE;
@@ -28,18 +32,14 @@ public OutputStream writeMapTile(String mapId, int lod, Vector2i tile) throws IO
int tileCompressionFK = getMapTileCompressionFK(compression);
recoveringConnection(connection -> {
- byte[] byteData = byteOut.toByteArray();
- ByteArrayInputStream inputStream = new ByteArrayInputStream(byteData);
-
- PreparedStatement statement = connection.prepareStatement(this.dialect.writeMapTile());
- statement.setInt(1, mapFK);
- statement.setInt(2, lod);
- statement.setInt(3, tile.getX());
- statement.setInt(4, tile.getY());
- statement.setInt(5, tileCompressionFK);
- statement.setBinaryStream(6, inputStream);
-
- statement.executeUpdate();
+ executeUpdate(connection, this.dialect.writeMapTile(),
+ mapFK,
+ lod,
+ tile.getX(),
+ tile.getY(),
+ tileCompressionFK,
+ byteOut.toByteArray()
+ );
}, 2);
});
}
@@ -50,15 +50,11 @@ public OutputStream writeMeta(String mapId, String name) {
return new WrappedOutputStream(byteOut, () -> {
int mapFK = getMapFK(mapId);
recoveringConnection(connection -> {
- byte[] byteData = byteOut.toByteArray();
- ByteArrayInputStream inputStream = new ByteArrayInputStream(byteData);
-
- PreparedStatement statement = connection.prepareStatement(this.dialect.writeMeta());
- statement.setInt(1, mapFK);
- statement.setString(2, name);
- statement.setBinaryStream(3, inputStream);
-
- statement.executeUpdate();
+ executeUpdate(connection, this.dialect.writeMeta(),
+ mapFK,
+ name,
+ byteOut.toByteArray()
+ );
}, 2);
});
}
@@ -69,8 +65,7 @@ public Optional readMapTile(String mapId, int lod, Vector
try {
byte[] data = recoveringConnection(connection -> {
- ResultSet result = executeQuery(connection,
- this.dialect.readMapTile(),
+ ResultSet result = executeQuery(connection, this.dialect.readMapTile(),
mapId,
lod,
tile.getX(),
@@ -100,8 +95,7 @@ public Optional readMapTile(String mapId, int lod, Vector
public Optional readMeta(String mapId, String name) throws IOException {
try {
byte[] data = recoveringConnection(connection -> {
- ResultSet result = executeQuery(connection,
- this.dialect.readMeta(),
+ ResultSet result = executeQuery(connection, this.dialect.readMeta(),
mapId,
escapeMetaName(name)
);
diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/SQLStorage.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/SQLStorage.java
index 8ea329f6..3af604ac 100644
--- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/SQLStorage.java
+++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/SQLStorage.java
@@ -119,7 +119,7 @@ public OutputStream writeMapTile(String mapId, int lod, Vector2i tile) throws IO
byteOut.writeTo(blobOut);
}
- executeUpdate(connection,this.dialect.writeMapTile(),
+ executeUpdate(connection, this.dialect.writeMapTile(),
mapFK,
lod,
tile.getX(),
@@ -324,7 +324,7 @@ public void deleteMeta(String mapId, String name) throws IOException {
try {
recoveringConnection(connection ->
executeUpdate(connection,
- this.dialect.purgeMeta(),
+ this.dialect.deleteMeta(),
mapId,
escapeMetaName(name)
), 2);
@@ -508,22 +508,21 @@ public void close() throws IOException {
}
protected ResultSet executeQuery(Connection connection, @Language("sql") String sql, Object... parameters) throws SQLException {
- // we only use this prepared statement once, but the DB-Driver caches those and reuses them
- PreparedStatement statement = connection.prepareStatement(sql);
- for (int i = 0; i < parameters.length; i++) {
- statement.setObject(i+1, parameters[i]);
- }
- return statement.executeQuery();
+ return prepareStatement(connection, sql, parameters).executeQuery();
}
@SuppressWarnings("UnusedReturnValue")
protected int executeUpdate(Connection connection, @Language("sql") String sql, Object... parameters) throws SQLException {
+ return prepareStatement(connection, sql, parameters).executeUpdate();
+ }
+
+ private PreparedStatement prepareStatement(Connection connection, @Language("sql") String sql, Object... parameters) throws SQLException {
// we only use this prepared statement once, but the DB-Driver caches those and reuses them
PreparedStatement statement = connection.prepareStatement(sql);
for (int i = 0; i < parameters.length; i++) {
- statement.setObject(i+1, parameters[i]);
+ statement.setObject(i + 1, parameters[i]);
}
- return statement.executeUpdate();
+ return statement;
}
@SuppressWarnings("SameParameterValue")
diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/SQLiteStorage.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/SQLiteStorage.java
new file mode 100644
index 00000000..4c41217a
--- /dev/null
+++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/SQLiteStorage.java
@@ -0,0 +1,13 @@
+package de.bluecolored.bluemap.core.storage.sql;
+
+import de.bluecolored.bluemap.core.storage.sql.dialect.SqliteDialect;
+
+import java.net.MalformedURLException;
+
+public class SQLiteStorage extends PostgreSQLStorage {
+
+ public SQLiteStorage(SQLStorageSettings config) throws MalformedURLException, SQLDriverException {
+ super(SqliteDialect.INSTANCE, config);
+ }
+
+}
diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/Dialect.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/Dialect.java
index 4406e7d2..bf2b1c04 100644
--- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/Dialect.java
+++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/Dialect.java
@@ -25,7 +25,7 @@ public interface Dialect {
String readMetaSize();
@Language("sql")
- String purgeMeta();
+ String deleteMeta();
@Language("sql")
String purgeMapTile();
diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/DialectType.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/DialectType.java
index da50aa1f..d0394bdd 100644
--- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/DialectType.java
+++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/DialectType.java
@@ -1,15 +1,13 @@
package de.bluecolored.bluemap.core.storage.sql.dialect;
-import de.bluecolored.bluemap.core.storage.sql.MySQLStorage;
-import de.bluecolored.bluemap.core.storage.sql.PostgreSQLStorage;
-import de.bluecolored.bluemap.core.storage.sql.SQLStorage;
-import de.bluecolored.bluemap.core.storage.sql.SQLStorageSettings;
+import de.bluecolored.bluemap.core.storage.sql.*;
public enum DialectType {
MYSQL (MySQLStorage::new, "mysql"),
MARIADB (MySQLStorage::new, "mariadb"),
- POSTGRESQL (PostgreSQLStorage::new,"postgresql");
+ POSTGRESQL (PostgreSQLStorage::new, "postgresql"),
+ SQLITE (SQLiteStorage::new, "sqlite");
private static final DialectType FALLBACK = MYSQL;
diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/MySQLDialect.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/MySQLDialect.java
index 1d2f49f9..bed99c34 100644
--- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/MySQLDialect.java
+++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/MySQLDialect.java
@@ -91,7 +91,7 @@ public String readMetaSize() {
@Override
@Language("MySQL")
- public String purgeMeta() {
+ public String deleteMeta() {
return "DELETE t " +
"FROM `bluemap_map_meta` t " +
" INNER JOIN `bluemap_map` m " +
diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/PostgresDialect.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/PostgresDialect.java
index 8f4b69c8..0332ef8d 100644
--- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/PostgresDialect.java
+++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/PostgresDialect.java
@@ -92,7 +92,7 @@ public String readMetaSize() {
@Override
@Language("PostgreSQL")
- public String purgeMeta() {
+ public String deleteMeta() {
return "DELETE FROM bluemap_map_meta t " +
"USING bluemap_map m " +
"WHERE t.map = m.id " +
diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/SqliteDialect.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/SqliteDialect.java
new file mode 100644
index 00000000..80157aa0
--- /dev/null
+++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/dialect/SqliteDialect.java
@@ -0,0 +1,256 @@
+package de.bluecolored.bluemap.core.storage.sql.dialect;
+
+import org.intellij.lang.annotations.Language;
+
+public class SqliteDialect implements Dialect {
+
+ public static final SqliteDialect INSTANCE = new SqliteDialect();
+
+ private SqliteDialect() {}
+
+ @Override
+ @Language("sqlite")
+ public String writeMapTile() {
+ return "REPLACE INTO `bluemap_map_tile` (`map`, `lod`, `x`, `z`, `compression`, `data`) " +
+ "VALUES (?, ?, ?, ?, ?, ?)";
+ }
+
+ @Override
+ @Language("sqlite")
+ public String readMapTile() {
+ return "SELECT t.`data` " +
+ "FROM `bluemap_map_tile` t " +
+ " INNER JOIN `bluemap_map` m " +
+ " ON t.`map` = m.`id` " +
+ " INNER JOIN `bluemap_map_tile_compression` c " +
+ " ON t.`compression` = c.`id` " +
+ "WHERE m.`map_id` = ? " +
+ "AND t.`lod` = ? " +
+ "AND t.`x` = ? " +
+ "AND t.`z` = ? " +
+ "AND c.`compression` = ?";
+ }
+
+ @Override
+ @Language("sqlite")
+ public String readMapTileInfo() {
+ return "SELECT t.`changed`, LENGTH(t.`data`) as 'size' " +
+ "FROM `bluemap_map_tile` t " +
+ " INNER JOIN `bluemap_map` m " +
+ " ON t.`map` = m.`id` " +
+ " INNER JOIN `bluemap_map_tile_compression` c " +
+ " ON t.`compression` = c.`id` " +
+ "WHERE m.`map_id` = ? " +
+ "AND t.`lod` = ? " +
+ "AND t.`x` = ? " +
+ "AND t.`z` = ? " +
+ "AND c.`compression` = ?";
+ }
+
+ @Override
+ @Language("sqlite")
+ public String deleteMapTile() {
+ return "DELETE FROM `bluemap_map_tile` " +
+ "WHERE `map` IN( " +
+ " SELECT `id` " +
+ " FROM `bluemap_map` " +
+ " WHERE `map_id` = ? " +
+ " LIMIT 1 " +
+ ") " +
+ "AND `lod` = ? " +
+ "AND `x` = ? " +
+ "AND `z` = ? ";
+ }
+
+ @Override
+ @Language("sqlite")
+ public String writeMeta() {
+ return "REPLACE INTO `bluemap_map_meta` (`map`, `key`, `value`) " +
+ "VALUES (?, ?, ?)";
+ }
+
+ @Override
+ @Language("sqlite")
+ public String readMeta() {
+ return "SELECT t.`value` " +
+ "FROM `bluemap_map_meta` t " +
+ " INNER JOIN `bluemap_map` m " +
+ " ON t.`map` = m.`id` " +
+ "WHERE m.`map_id` = ? " +
+ "AND t.`key` = ?";
+ }
+
+ @Override
+ @Language("sqlite")
+ public String readMetaSize() {
+ return "SELECT LENGTH(t.`value`) as 'size' " +
+ "FROM `bluemap_map_meta` t " +
+ " INNER JOIN `bluemap_map` m " +
+ " ON t.`map` = m.`id` " +
+ "WHERE m.`map_id` = ? " +
+ "AND t.`key` = ?";
+ }
+
+ @Override
+ @Language("sqlite")
+ public String deleteMeta() {
+ return "DELETE FROM `bluemap_map_meta` " +
+ "WHERE `map` IN( " +
+ " SELECT `id` " +
+ " FROM `bluemap_map` " +
+ " WHERE `map_id` = ? " +
+ " LIMIT 1 " +
+ ") " +
+ "AND `key` = ?";
+ }
+
+ @Override
+ @Language("sqlite")
+ public String purgeMapTile() {
+ return "DELETE FROM `bluemap_map_tile` " +
+ "WHERE `map` IN( " +
+ " SELECT `id` " +
+ " FROM `bluemap_map` " +
+ " WHERE `map_id` = ? " +
+ " LIMIT 1 " +
+ ")";
+ }
+
+ @Override
+ @Language("sqlite")
+ public String purgeMapMeta() {
+ return "DELETE FROM `bluemap_map_meta` " +
+ "WHERE `map` IN( " +
+ " SELECT `id` " +
+ " FROM `bluemap_map` " +
+ " WHERE `map_id` = ? " +
+ " LIMIT 1 " +
+ ")";
+ }
+
+ @Override
+ @Language("sqlite")
+ public String purgeMap() {
+ return "DELETE " +
+ "FROM `bluemap_map` " +
+ "WHERE `map_id` = ?";
+ }
+
+ @Override
+ @Language("sqlite")
+ public String selectMapIds() {
+ return "SELECT `map_id` FROM `bluemap_map`";
+ }
+
+ @Override
+ @Language("sqlite")
+ public String initializeStorageMeta() {
+ return "CREATE TABLE IF NOT EXISTS `bluemap_storage_meta` (" +
+ "`key` varchar(255) NOT NULL, " +
+ "`value` varchar(255) DEFAULT NULL, " +
+ "PRIMARY KEY (`key`)" +
+ ")";
+ }
+
+ @Override
+ @Language("sqlite")
+ public String selectStorageMeta() {
+ return "SELECT `value` FROM `bluemap_storage_meta` " +
+ "WHERE `key` = ?";
+ }
+
+ @Override
+ @Language("sqlite")
+ public String insertStorageMeta() {
+ return "INSERT INTO `bluemap_storage_meta` (`key`, `value`) " +
+ "VALUES (?, ?)";
+ }
+
+ @Override
+ @Language("sqlite")
+ public String initializeMap() {
+ return "CREATE TABLE `bluemap_map` (" +
+ "`id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT," +
+ "`map_id` VARCHAR(255) NOT NULL," +
+ "UNIQUE (`map_id`)" +
+ ");";
+ }
+
+ @Override
+ @Language("sqlite")
+ public String initializeMapTileCompression() {
+ return "CREATE TABLE `bluemap_map_tile_compression` (" +
+ "`id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT," +
+ "`compression` VARCHAR(255) NOT NULL," +
+ "UNIQUE (`compression`)" +
+ ");";
+ }
+
+ @Override
+ @Language("sqlite")
+ public String initializeMapMeta() {
+ return "CREATE TABLE `bluemap_map_meta` (" +
+ "`map` SMALLINT UNSIGNED NOT NULL," +
+ "`key` varchar(255) NOT NULL," +
+ "`value` LONGBLOB NOT NULL," +
+ "PRIMARY KEY (`map`, `key`)," +
+ "CONSTRAINT `fk_bluemap_map_meta_map` FOREIGN KEY (`map`) REFERENCES `bluemap_map` (`id`) ON UPDATE RESTRICT ON DELETE RESTRICT" +
+ ")";
+ }
+
+ @Override
+ @Language("sqlite")
+ public String initializeMapTile() {
+ return "CREATE TABLE `bluemap_map_tile` (" +
+ "`map` SMALLINT UNSIGNED NOT NULL," +
+ "`lod` SMALLINT UNSIGNED NOT NULL," +
+ "`x` INT NOT NULL," +
+ "`z` INT NOT NULL," +
+ "`compression` SMALLINT UNSIGNED NOT NULL," +
+ "`changed` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP," +
+ "`data` LONGBLOB NOT NULL," +
+ "PRIMARY KEY (`map`, `lod`, `x`, `z`)," +
+ "CONSTRAINT `fk_bluemap_map_tile_map` FOREIGN KEY (`map`) REFERENCES `bluemap_map` (`id`) ON UPDATE RESTRICT ON DELETE RESTRICT," +
+ "CONSTRAINT `fk_bluemap_map_tile_compression` FOREIGN KEY (`compression`) REFERENCES `bluemap_map_tile_compression` (`id`) ON UPDATE RESTRICT ON DELETE RESTRICT" +
+ ");";
+ }
+
+ @Override
+ @Language("sqlite")
+ public String updateStorageMeta() {
+ return "UPDATE `bluemap_storage_meta` " +
+ "SET `value` = ? " +
+ "WHERE `key` = ?";
+ }
+
+ @Override
+ @Language("sqlite")
+ public String deleteMapMeta() {
+ return "DELETE FROM `bluemap_map_meta`" +
+ "WHERE `key` IN (?, ?, ?)";
+ }
+
+ @Override
+ @Language("sqlite")
+ public String updateMapMeta() {
+ return "UPDATE `bluemap_map_meta` " +
+ "SET `key` = ? " +
+ "WHERE `key` = ?";
+ }
+
+ @Override
+ @Language("sqlite")
+ public String lookupFK(String table, String idField, String valueField) {
+ return "SELECT `" + idField + "` FROM `" + table + "` " +
+ "WHERE `" + valueField + "` = ?";
+ }
+
+ @Override
+ @Language("sqlite")
+ public String insertFK(String table, String valueField) {
+ return "INSERT INTO `" + table + "` (`" + valueField + "`) " +
+ "VALUES (?)";
+ }
+
+
+}
From 2e572ddb114a5f7b2f070b71fa25c7b948363f0e Mon Sep 17 00:00:00 2001
From: "Lukas Rieger (Blue)"
Date: Sun, 18 Jun 2023 13:46:41 +0200
Subject: [PATCH 15/24] Fix status command formatting and add last render times
to status and maps commands
---
.../common/plugin/commands/CommandHelper.java | 31 +++++++++++-----
.../common/plugin/commands/Commands.java | 35 ++++++++++---------
.../common/rendermanager/RenderManager.java | 12 ++++++-
.../bluecolored/bluemap/core/map/BmMap.java | 2 +-
.../bluemap/core/map/MapRenderState.java | 21 +++++++++++
5 files changed, 73 insertions(+), 28 deletions(-)
diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/commands/CommandHelper.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/commands/CommandHelper.java
index 18dd3c0a..d0097112 100644
--- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/commands/CommandHelper.java
+++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/commands/CommandHelper.java
@@ -34,10 +34,18 @@
import org.apache.commons.lang3.time.DurationFormatUtils;
import java.lang.ref.WeakReference;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
import java.util.*;
public class CommandHelper {
+ private static final DateTimeFormatter TIME_FORMAT =
+ DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss")
+ .withLocale(Locale.ROOT)
+ .withZone(ZoneId.systemDefault());
+
private final Plugin plugin;
private final Map> taskRefMap;
@@ -67,7 +75,9 @@ public List createStatusMessage(){
lines.add(Text.of(TextColor.WHITE, " Render-Threads are ", status, TextColor.WHITE, "!"));
- if (!tasks.isEmpty()) {
+ if (tasks.isEmpty()) {
+ lines.add(Text.of(TextColor.GRAY, " Last time running: ", TextColor.DARK_GRAY, formatTime(renderer.getLastTimeBusy())));
+ } else {
lines.add(Text.of(TextColor.WHITE, " Queued Tasks (" + tasks.size() + "):"));
for (int i = 0; i < tasks.size(); i++) {
if (i >= 10){
@@ -76,20 +86,18 @@ public List createStatusMessage(){
}
RenderTask task = tasks.get(i);
- lines.add(Text.of(TextColor.GRAY, " [" + getRefForTask(task) + "] ", TextColor.GOLD, task.getDescription()));
+ lines.add(Text.of(TextColor.GRAY, "\u00A0\u00A0[" + getRefForTask(task) + "] ", TextColor.GOLD, task.getDescription()));
if (i == 0) {
- String detail = task.getDetail().orElse(null);
- if (detail != null) {
- lines.add(Text.of(TextColor.GRAY, " Detail: ", TextColor.WHITE, detail));
- }
+ task.getDetail().ifPresent(detail ->
+ lines.add(Text.of(TextColor.GRAY, "\u00A0\u00A0\u00A0Detail: ", TextColor.WHITE, detail)));
- lines.add(Text.of(TextColor.GRAY, " Progress: ", TextColor.WHITE,
+ lines.add(Text.of(TextColor.GRAY, "\u00A0\u00A0\u00A0Progress: ", TextColor.WHITE,
(Math.round(task.estimateProgress() * 10000) / 100.0) + "%"));
long etaMs = renderer.estimateCurrentRenderTaskTimeRemaining();
if (etaMs > 0) {
- lines.add(Text.of(TextColor.GRAY, " ETA: ", TextColor.WHITE, DurationFormatUtils.formatDuration(etaMs, "HH:mm:ss")));
+ lines.add(Text.of(TextColor.GRAY, "\u00A0\u00A0\u00A0ETA: ", TextColor.WHITE, DurationFormatUtils.formatDuration(etaMs, "HH:mm:ss")));
}
}
}
@@ -98,7 +106,7 @@ public List createStatusMessage(){
if (plugin.checkPausedByPlayerCount()) {
lines.add(Text.of(TextColor.WHITE, " Render-Threads are ",
Text.of(TextColor.GOLD, "paused")));
- lines.add(Text.of(TextColor.GRAY, TextFormat.ITALIC, " (there are " + plugin.getConfigs().getPluginConfig().getPlayerRenderLimit() + " or more players online)"));
+ lines.add(Text.of(TextColor.GRAY, TextFormat.ITALIC, "\u00A0\u00A0\u00A0(there are " + plugin.getConfigs().getPluginConfig().getPlayerRenderLimit() + " or more players online)"));
} else {
lines.add(Text.of(TextColor.WHITE, " Render-Threads are ",
Text.of(TextColor.RED, "stopped")
@@ -176,4 +184,9 @@ private String randomRef() {
return ref.subSequence(0, 4).toString();
}
+ public String formatTime(long timestamp) {
+ if (timestamp < 0) return "-";
+ return TIME_FORMAT.format(Instant.ofEpochMilli(timestamp));
+ }
+
}
diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/commands/Commands.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/commands/Commands.java
index ec66d641..fddba475 100644
--- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/commands/Commands.java
+++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/commands/Commands.java
@@ -838,27 +838,28 @@ public int worldsCommand(CommandContext context) {
}
public int mapsCommand(CommandContext context) {
- CommandSource source = commandSourceInterface.apply(context.getSource());
+ List lines = new ArrayList<>();
+ lines.add(Text.of(TextColor.BLUE, "Maps loaded by BlueMap:"));
- source.sendMessage(Text.of(TextColor.BLUE, "Maps loaded by BlueMap:"));
for (BmMap map : plugin.getMaps().values()) {
- boolean unfrozen = plugin.getPluginState().getMapState(map).isUpdateEnabled();
- if (unfrozen) {
- source.sendMessage(Text.of(
- TextColor.GRAY, " - ",
- TextColor.WHITE, map.getId(),
- TextColor.GRAY, " (" + map.getName() + ")"
- ).setHoverText(Text.of(TextColor.WHITE, "World: ", TextColor.GRAY, map.getWorld().getName())));
- } else {
- source.sendMessage(Text.of(
- TextColor.GRAY, " - ",
- TextColor.WHITE, map.getId(),
- TextColor.GRAY, " (" + map.getName() + ") - ",
- TextColor.AQUA, TextFormat.ITALIC, "frozen!"
- ).setHoverText(Text.of(TextColor.WHITE, "World: ", TextColor.GRAY, map.getWorld().getName())));
- }
+ boolean frozen = !plugin.getPluginState().getMapState(map).isUpdateEnabled();
+
+ lines.add(Text.of(TextColor.GRAY, " - ",
+ TextColor.WHITE, map.getId(),
+ TextColor.GRAY, " (" + map.getName() + ")"));
+
+ lines.add(Text.of(TextColor.GRAY, "\u00A0\u00A0\u00A0World: ",
+ TextColor.DARK_GRAY, map.getWorld().getName()));
+ lines.add(Text.of(TextColor.GRAY, "\u00A0\u00A0\u00A0Last Update: ",
+ TextColor.DARK_GRAY, helper.formatTime(map.getRenderState().getLatestRenderTime())));
+
+ if (frozen)
+ lines.add(Text.of(TextColor.AQUA, TextFormat.ITALIC, "This map is frozen!"));
}
+ CommandSource source = commandSourceInterface.apply(context.getSource());
+ source.sendMessages(lines);
+
return 1;
}
diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/RenderManager.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/RenderManager.java
index 34b4495d..222a54fa 100644
--- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/RenderManager.java
+++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/RenderManager.java
@@ -38,6 +38,8 @@ public class RenderManager {
@DebugDump private final int id;
@DebugDump private volatile boolean running;
+ @DebugDump private long lastTimeBusy;
+
private final AtomicInteger nextWorkerThreadIndex;
@DebugDump private final Collection workerThreads;
private final AtomicInteger busyCount;
@@ -55,6 +57,8 @@ public RenderManager() {
this.workerThreads = new ConcurrentLinkedDeque<>();
this.busyCount = new AtomicInteger(0);
+ this.lastTimeBusy = -1;
+
this.progressTracker = null;
this.newTask = true;
@@ -249,6 +253,10 @@ public int getWorkerThreadCount() {
return workerThreads.size();
}
+ public long getLastTimeBusy() {
+ return lastTimeBusy;
+ }
+
private void removeTasksThatAreContainedIn(RenderTask containingTask) {
synchronized (this.renderTasks) {
if (renderTasks.size() < 2) return;
@@ -290,13 +298,15 @@ private void doWork() throws Exception {
}
this.busyCount.incrementAndGet();
+ this.lastTimeBusy = System.currentTimeMillis();
}
try {
task.doWork();
} finally {
synchronized (renderTasks) {
- this.busyCount.decrementAndGet();
+ int busyCount = this.busyCount.decrementAndGet();
+ if (busyCount > 0) this.lastTimeBusy = System.currentTimeMillis();
this.renderTasks.notifyAll();
}
}
diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/BmMap.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/BmMap.java
index b4c62766..57258e7c 100644
--- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/BmMap.java
+++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/BmMap.java
@@ -219,7 +219,7 @@ public synchronized void saveMarkerState() {
public synchronized void savePlayerState() {
try (
- OutputStream out = storage.writeMeta(id, META_FILE_PLAYERS);
+ OutputStream out = storage.writeMeta(id, META_FILE_PLAYERS)
) {
out.write("{}".getBytes(StandardCharsets.UTF_8));
} catch (Exception ex) {
diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/MapRenderState.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/MapRenderState.java
index 668fc26d..5adeabdf 100644
--- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/MapRenderState.java
+++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/MapRenderState.java
@@ -37,6 +37,7 @@
public class MapRenderState {
private final Map regionRenderTimes;
+ private transient long latestRenderTime = -1;
public MapRenderState() {
regionRenderTimes = new HashMap<>();
@@ -44,6 +45,13 @@ public MapRenderState() {
public synchronized void setRenderTime(Vector2i regionPos, long renderTime) {
regionRenderTimes.put(regionPos, renderTime);
+
+ if (latestRenderTime != -1) {
+ if (renderTime > latestRenderTime)
+ latestRenderTime = renderTime;
+ else
+ latestRenderTime = -1;
+ }
}
public synchronized long getRenderTime(Vector2i regionPos) {
@@ -52,6 +60,19 @@ public synchronized long getRenderTime(Vector2i regionPos) {
else return renderTime;
}
+ public long getLatestRenderTime() {
+ if (latestRenderTime == -1) {
+ synchronized (this) {
+ latestRenderTime = regionRenderTimes.values().stream()
+ .mapToLong(Long::longValue)
+ .max()
+ .orElse(-1);
+ }
+ }
+
+ return latestRenderTime;
+ }
+
public synchronized void reset() {
regionRenderTimes.clear();
}
From 85f47350502b27ca0858fcc1df8ca312bb656cfb Mon Sep 17 00:00:00 2001
From: "Lukas Rieger (Blue)"
Date: Sun, 18 Jun 2023 13:51:07 +0200
Subject: [PATCH 16/24] Fix hours in AM/PM format instead of 24
---
.../bluemap/common/plugin/commands/CommandHelper.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/commands/CommandHelper.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/commands/CommandHelper.java
index d0097112..a3f8a3d8 100644
--- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/commands/CommandHelper.java
+++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/commands/CommandHelper.java
@@ -42,7 +42,7 @@
public class CommandHelper {
private static final DateTimeFormatter TIME_FORMAT =
- DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss")
+ DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
.withLocale(Locale.ROOT)
.withZone(ZoneId.systemDefault());
From cb638910ce239813d1e24115756cc5c8ca1d37be Mon Sep 17 00:00:00 2001
From: "Lukas Rieger (Blue)"
Date: Sun, 18 Jun 2023 17:15:44 +0200
Subject: [PATCH 17/24] Remember hide/show status of marker-sets
---
.../webapp/src/components/Menu/MarkerSet.vue | 1 +
.../webapp/src/js/markers/MarkerSet.js | 17 +++++++++++++----
2 files changed, 14 insertions(+), 4 deletions(-)
diff --git a/BlueMapCommon/webapp/src/components/Menu/MarkerSet.vue b/BlueMapCommon/webapp/src/components/Menu/MarkerSet.vue
index 82fd0435..cbe4f507 100644
--- a/BlueMapCommon/webapp/src/components/Menu/MarkerSet.vue
+++ b/BlueMapCommon/webapp/src/components/Menu/MarkerSet.vue
@@ -65,6 +65,7 @@ export default {
if (this.markerSet.toggleable) {
// eslint-disable-next-line vue/no-mutating-props
this.markerSet.visible = !this.markerSet.visible
+ this.markerSet.saveState();
}
},
more(event) {
diff --git a/BlueMapCommon/webapp/src/js/markers/MarkerSet.js b/BlueMapCommon/webapp/src/js/markers/MarkerSet.js
index 064d9e0b..b1f9c196 100644
--- a/BlueMapCommon/webapp/src/js/markers/MarkerSet.js
+++ b/BlueMapCommon/webapp/src/js/markers/MarkerSet.js
@@ -30,6 +30,7 @@ import {LineMarker} from "./LineMarker";
import {HtmlMarker} from "./HtmlMarker";
import {PoiMarker} from "./PoiMarker";
import {reactive} from "vue";
+import {getLocalStorage, setLocalStorage} from "../Utils";
export class MarkerSet extends Scene {
@@ -58,6 +59,9 @@ export class MarkerSet extends Scene {
return this.toggleable ||
this.markers.filter(marker => marker.listed).length > 0 ||
this.markerSets.filter(markerSet => markerSet.listed).length > 0
+ },
+ saveState: () => {
+ setLocalStorage("markerset-" + this.data.id + "-visible", this.visible);
}
});
@@ -65,6 +69,15 @@ export class MarkerSet extends Scene {
get() { return this.data.visible },
set(value) { this.data.visible = value }
});
+
+ if (this.data.toggleable) {
+ let storedVisible = getLocalStorage("markerset-" + this.data.id + "-visible");
+ if (storedVisible !== undefined) {
+ this.visible = !!storedVisible;
+ } else if (this.data.defaultHide) {
+ this.visible = false;
+ }
+ }
}
updateFromData(data) {
@@ -112,10 +125,6 @@ export class MarkerSet extends Scene {
if (!markerSet) {
markerSet = new MarkerSet(markerSetId);
this.add(markerSet);
-
- if (data.defaultHidden) {
- markerSet.visible = false;
- }
}
// update
From 55095f1b5e68127657ea398239decca207477afc Mon Sep 17 00:00:00 2001
From: "Lukas Rieger (Blue)"
Date: Sun, 18 Jun 2023 23:44:07 +0200
Subject: [PATCH 18/24] Add capabillity to use -follow players- in first-person
mode. Closes: #175
---
.../controls/freeflight/FreeFlightControls.js | 40 ++++++++++++++++++-
.../webapp/src/js/markers/PlayerMarker.js | 20 +++++++++-
BlueMapCommon/webapp/vite.config.js | 8 ++--
3 files changed, 60 insertions(+), 8 deletions(-)
diff --git a/BlueMapCommon/webapp/src/js/controls/freeflight/FreeFlightControls.js b/BlueMapCommon/webapp/src/js/controls/freeflight/FreeFlightControls.js
index 17f876a7..746cccf5 100644
--- a/BlueMapCommon/webapp/src/js/controls/freeflight/FreeFlightControls.js
+++ b/BlueMapCommon/webapp/src/js/controls/freeflight/FreeFlightControls.js
@@ -23,7 +23,7 @@
* THE SOFTWARE.
*/
-import {MathUtils, Vector2} from "three";
+import {MathUtils, Vector2, Vector3} from "three";
import {Manager, Pan, DIRECTION_ALL} from "hammerjs";
import {animate, EasingFunctions} from "../../util/Utils";
import {KeyMoveControls} from "./keyboard/KeyMoveControls";
@@ -32,9 +32,12 @@ import {MouseAngleControls} from "./mouse/MouseAngleControls";
import {KeyHeightControls} from "./keyboard/KeyHeightControls";
import {TouchPanControls} from "./touch/TouchPanControls";
import {reactive} from "vue";
+import {DEG2RAD} from "three/src/math/MathUtils";
export class FreeFlightControls {
+ static _beforeMoveTemp = new Vector3();
+
/**
* @param target {Element}
*/
@@ -43,7 +46,7 @@ export class FreeFlightControls {
this.manager = null;
this.data = reactive({
-
+ followingPlayer: null
});
this.hammer = new Manager(this.target);
@@ -99,12 +102,32 @@ export class FreeFlightControls {
* @param map {Map}
*/
update(delta, map) {
+ FreeFlightControls._beforeMoveTemp.copy(this.manager.position);
+ let beforeMoveRot = this.manager.rotation;
+ let beforeMoveAngle = this.manager.angle;
+
this.keyMove.update(delta, map);
this.keyHeight.update(delta, map);
this.mouseRotate.update(delta, map);
this.mouseAngle.update(delta, map);
this.touchPan.update(delta, map);
+ // if moved, stop following the marker and give back control
+ if (this.data.followingPlayer && (
+ !FreeFlightControls._beforeMoveTemp.equals(this.manager.position) ||
+ beforeMoveRot !== this.manager.rotation ||
+ beforeMoveAngle !== this.manager.angle
+ )) {
+ this.stopFollowingPlayerMarker();
+ }
+
+ // follow player marker
+ if (this.data.followingPlayer) {
+ this.manager.position.copy(this.data.followingPlayer.position);
+ this.manager.rotation = (this.data.followingPlayer.rotation.yaw - 180) * DEG2RAD;
+ this.manager.angle = -(this.data.followingPlayer.rotation.pitch - 90) * DEG2RAD;
+ }
+
this.manager.angle = MathUtils.clamp(this.manager.angle, 0, Math.PI);
this.manager.distance = 0;
this.manager.ortho = 0;
@@ -133,6 +156,19 @@ export class FreeFlightControls {
});
}
+ /**
+ * @param marker {object}
+ */
+ followPlayerMarker(marker) {
+ if (marker.isPlayerMarker) marker = marker.data;
+ this.data.followingPlayer = marker;
+ this.keyMove.deltaPosition.set(0, 0);
+ }
+
+ stopFollowingPlayerMarker() {
+ this.data.followingPlayer = null;
+ }
+
onWheel = evt => {
evt.preventDefault();
diff --git a/BlueMapCommon/webapp/src/js/markers/PlayerMarker.js b/BlueMapCommon/webapp/src/js/markers/PlayerMarker.js
index 5e29dfa8..d8d80642 100644
--- a/BlueMapCommon/webapp/src/js/markers/PlayerMarker.js
+++ b/BlueMapCommon/webapp/src/js/markers/PlayerMarker.js
@@ -41,6 +41,10 @@ export class PlayerMarker extends Marker {
this.data.playerUuid = playerUuid;
this.data.name = playerUuid;
this.data.playerHead = playerHead;
+ this.data.rotation = {
+ pitch: 0,
+ yaw: 0
+ };
this.elementObject = new CSS2DObject(htmlToElement(`
@@ -102,24 +106,34 @@ export class PlayerMarker extends Marker {
// animate position update
let pos = markerData.position || {};
+ let rot = markerData.rotation || {};
if (!this.position.x && !this.position.y && !this.position.z) {
this.position.set(
pos.x || 0,
(pos.y || 0) + 1.8,
pos.z || 0
);
+ this.data.rotation.pitch = rot.pitch || 0;
+ this.data.rotation.yaw = rot.yaw || 0;
} else {
let startPos = {
x: this.position.x,
y: this.position.y,
z: this.position.z,
+ pitch: this.data.rotation.pitch,
+ yaw: this.data.rotation.yaw,
}
let deltaPos = {
x: (pos.x || 0) - startPos.x,
y: ((pos.y || 0) + 1.8) - startPos.y,
z: (pos.z || 0) - startPos.z,
+ pitch: (rot.pitch || 0) - startPos.pitch,
+ yaw: (rot.yaw || 0) - startPos.yaw
}
- if (deltaPos.x || deltaPos.y || deltaPos.z) {
+ while (deltaPos.yaw > 180) deltaPos.yaw -= 360;
+ while (deltaPos.yaw < -180) deltaPos.yaw += 360;
+
+ if (deltaPos.x || deltaPos.y || deltaPos.z || deltaPos.pitch || deltaPos.yaw) {
animate(progress => {
let ease = EasingFunctions.easeInOutCubic(progress);
this.position.set(
@@ -127,7 +141,9 @@ export class PlayerMarker extends Marker {
startPos.y + deltaPos.y * ease || 0,
startPos.z + deltaPos.z * ease || 0
);
- }, 500);
+ this.data.rotation.pitch = startPos.pitch + deltaPos.pitch * ease || 0;
+ this.data.rotation.yaw = startPos.yaw + deltaPos.yaw * ease || 0;
+ }, 1000);
}
}
diff --git a/BlueMapCommon/webapp/vite.config.js b/BlueMapCommon/webapp/vite.config.js
index 4b4d440a..da4ecc8d 100644
--- a/BlueMapCommon/webapp/vite.config.js
+++ b/BlueMapCommon/webapp/vite.config.js
@@ -21,13 +21,13 @@ export default defineConfig({
server: {
proxy: {
'/settings.json': {
- //target: 'http://localhost:8100',
- target: 'https://bluecolored.de/bluemap',
+ target: 'http://localhost:8100',
+ //target: 'https://bluecolored.de/bluemap',
changeOrigin: true,
},
'/maps': {
- //target: 'http://localhost:8100',
- target: 'https://bluecolored.de/bluemap',
+ target: 'http://localhost:8100',
+ //target: 'https://bluecolored.de/bluemap',
changeOrigin: true,
}
}
From b3c7d897937e17a4149751ef6d0eda66e070c943 Mon Sep 17 00:00:00 2001
From: "Lukas Rieger (Blue)"
Date: Sun, 18 Jun 2023 23:52:41 +0200
Subject: [PATCH 19/24] revert accidentally committed vite config change
---
BlueMapCommon/webapp/vite.config.js | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/BlueMapCommon/webapp/vite.config.js b/BlueMapCommon/webapp/vite.config.js
index da4ecc8d..4b4d440a 100644
--- a/BlueMapCommon/webapp/vite.config.js
+++ b/BlueMapCommon/webapp/vite.config.js
@@ -21,13 +21,13 @@ export default defineConfig({
server: {
proxy: {
'/settings.json': {
- target: 'http://localhost:8100',
- //target: 'https://bluecolored.de/bluemap',
+ //target: 'http://localhost:8100',
+ target: 'https://bluecolored.de/bluemap',
changeOrigin: true,
},
'/maps': {
- target: 'http://localhost:8100',
- //target: 'https://bluecolored.de/bluemap',
+ //target: 'http://localhost:8100',
+ target: 'https://bluecolored.de/bluemap',
changeOrigin: true,
}
}
From 49f76c1b11a60e83c3da52a2d6b5a7e60c2d22b0 Mon Sep 17 00:00:00 2001
From: "Lukas Rieger (Blue)"
Date: Mon, 19 Jun 2023 11:05:56 +0200
Subject: [PATCH 20/24] Fix markers overlap over menu if more than 100 markers
are on the map
---
BlueMapCommon/webapp/src/App.vue | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/BlueMapCommon/webapp/src/App.vue b/BlueMapCommon/webapp/src/App.vue
index 7f8aa6f7..1b5cc3f0 100644
--- a/BlueMapCommon/webapp/src/App.vue
+++ b/BlueMapCommon/webapp/src/App.vue
@@ -50,7 +50,7 @@ export default {
width: 100%;
height: 100%;
- z-index: 100; // put over bluemap markers
+ z-index: 10000; // put over bluemap markers
pointer-events: none;
From 76e3c4e7581b7da02a1252467ac03f36befdfb67 Mon Sep 17 00:00:00 2001
From: "Lukas Rieger (Blue)"
Date: Mon, 19 Jun 2023 11:28:11 +0200
Subject: [PATCH 21/24] Fix markers being selectable
---
BlueMapCommon/webapp/src/scss/markers.scss | 2 ++
1 file changed, 2 insertions(+)
diff --git a/BlueMapCommon/webapp/src/scss/markers.scss b/BlueMapCommon/webapp/src/scss/markers.scss
index 820940c7..4c5c3fde 100644
--- a/BlueMapCommon/webapp/src/scss/markers.scss
+++ b/BlueMapCommon/webapp/src/scss/markers.scss
@@ -27,6 +27,8 @@
.bm-marker-html {
position: relative;
+ user-select: none;
+
.bm-marker-poi-label {
position: absolute;
top: 0;
From 2f78f75a907823d494b6b317cf711d538dbd22b3 Mon Sep 17 00:00:00 2001
From: "Lukas Rieger (Blue)"
Date: Mon, 19 Jun 2023 11:42:25 +0200
Subject: [PATCH 22/24] escape marker-set id when saving to local storage
---
BlueMapCommon/webapp/src/js/markers/MarkerSet.js | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/BlueMapCommon/webapp/src/js/markers/MarkerSet.js b/BlueMapCommon/webapp/src/js/markers/MarkerSet.js
index b1f9c196..71c9566e 100644
--- a/BlueMapCommon/webapp/src/js/markers/MarkerSet.js
+++ b/BlueMapCommon/webapp/src/js/markers/MarkerSet.js
@@ -61,7 +61,7 @@ export class MarkerSet extends Scene {
this.markerSets.filter(markerSet => markerSet.listed).length > 0
},
saveState: () => {
- setLocalStorage("markerset-" + this.data.id + "-visible", this.visible);
+ setLocalStorage(this.localStorageKey("visible"), this.visible);
}
});
@@ -71,7 +71,7 @@ export class MarkerSet extends Scene {
});
if (this.data.toggleable) {
- let storedVisible = getLocalStorage("markerset-" + this.data.id + "-visible");
+ let storedVisible = getLocalStorage(this.localStorageKey("visible"));
if (storedVisible !== undefined) {
this.visible = !!storedVisible;
} else if (this.data.defaultHide) {
@@ -229,4 +229,8 @@ export class MarkerSet extends Scene {
});
}
+ localStorageKey(key) {
+ return "bluemap-markerset-" + encodeURIComponent(this.data.id) + "-" + key;
+ }
+
}
\ No newline at end of file
From 31ae055ae59cdc3497e91651360102faf3a09d74 Mon Sep 17 00:00:00 2001
From: "Lukas Rieger (Blue)"
Date: Mon, 19 Jun 2023 11:47:53 +0200
Subject: [PATCH 23/24] Fix marker-set default-hide not working anymore
---
BlueMapCommon/webapp/src/js/markers/MarkerSet.js | 16 ++++++++++------
.../webapp/src/js/markers/PlayerMarkerSet.js | 4 ++--
2 files changed, 12 insertions(+), 8 deletions(-)
diff --git a/BlueMapCommon/webapp/src/js/markers/MarkerSet.js b/BlueMapCommon/webapp/src/js/markers/MarkerSet.js
index 71c9566e..d4719dcb 100644
--- a/BlueMapCommon/webapp/src/js/markers/MarkerSet.js
+++ b/BlueMapCommon/webapp/src/js/markers/MarkerSet.js
@@ -37,7 +37,7 @@ export class MarkerSet extends Scene {
/**
* @param id {string}
*/
- constructor(id) {
+ constructor(id, data = null) {
super();
Object.defineProperty(this, 'isMarkerSet', {value: true});
@@ -70,6 +70,10 @@ export class MarkerSet extends Scene {
set(value) { this.data.visible = value }
});
+ if (data) {
+ this.updateFromData(data);
+ }
+
if (this.data.toggleable) {
let storedVisible = getLocalStorage(this.localStorageKey("visible"));
if (storedVisible !== undefined) {
@@ -121,14 +125,14 @@ export class MarkerSet extends Scene {
updateMarkerSetFromData(markerSetId, data) {
let markerSet = this.markerSets.get(markerSetId);
- // create new if not existent
if (!markerSet) {
- markerSet = new MarkerSet(markerSetId);
+ // create new if not existent
+ markerSet = new MarkerSet(markerSetId, data);
this.add(markerSet);
+ } else {
+ // update
+ markerSet.updateFromData(data);
}
-
- // update
- markerSet.updateFromData(data);
}
updateMarkersFromData(data = {}, ignore = []) {
diff --git a/BlueMapCommon/webapp/src/js/markers/PlayerMarkerSet.js b/BlueMapCommon/webapp/src/js/markers/PlayerMarkerSet.js
index 9008e933..1883358c 100644
--- a/BlueMapCommon/webapp/src/js/markers/PlayerMarkerSet.js
+++ b/BlueMapCommon/webapp/src/js/markers/PlayerMarkerSet.js
@@ -29,8 +29,8 @@ import {PlayerMarker} from "./PlayerMarker";
export class PlayerMarkerSet extends MarkerSet {
- constructor(id, playerheadsUrl) {
- super(id);
+ constructor(id, playerheadsUrl, data = null) {
+ super(id, data);
this.data.label = "Player";
this.data.toggleable = true;
this.data.defaultHide = false;
From b4b3e72d51cf841cc52150097d58e6316aff0ea6 Mon Sep 17 00:00:00 2001
From: "Lukas Rieger (Blue)"
Date: Mon, 19 Jun 2023 15:44:57 +0200
Subject: [PATCH 24/24] Make configs generate paths with forwardslashes
whenever possible
---
.../bluemap/common/config/BlueMapConfigs.java | 29 ++++++++++++++-----
1 file changed, 21 insertions(+), 8 deletions(-)
diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/BlueMapConfigs.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/BlueMapConfigs.java
index 45a89841..ad3f640d 100644
--- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/BlueMapConfigs.java
+++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/BlueMapConfigs.java
@@ -34,10 +34,7 @@
import de.bluecolored.bluemap.core.util.Tristate;
import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.StandardOpenOption;
+import java.nio.file.*;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.HashMap;
@@ -396,12 +393,28 @@ private ConfigTemplate createEndMapTemplate(String name, Path worldFolder, int i
}
private String formatPath(Path path) {
- return Path.of("")
+ // normalize path
+ path = Path.of("")
.toAbsolutePath()
.relativize(path.toAbsolutePath())
- .normalize()
- .toString()
- .replace("\\", "\\\\");
+ .normalize();
+ String pathString = path.toString();
+
+ String formatted = pathString;
+ String separator = FileSystems.getDefault().getSeparator();
+
+ // try to replace separator with standardized forward slash
+ if (!separator.equals("/"))
+ formatted = pathString.replace(separator, "/");
+
+ // sanity check forward slash compatibility
+ if (!Path.of(formatted).equals(path))
+ formatted = pathString;
+
+ // escape all backslashes
+ formatted = formatted.replace("\\", "\\\\");
+
+ return formatted;
}
}