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 configType; private final StorageFactory 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ểnchuột trái + kéo
thu phónglăn chuột
xoay/nghiêngchuột phải + kéo
+

+

+

Điều khiển bàn phím:

+ + + + +
di chuyểnwasd / phím mũi tên
thu phóngBàn phím số: +/- or Ins/Home
xoay/nghiêngAlt 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ểnchạm + kéo
thu phóngchạm 2 ngón + nhón
xoay/nghiêngchạ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 @@