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. 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; } } 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/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/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..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 @@ -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/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
+

+

+ +""" + } +} 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 diff --git a/BlueMapCommon/webapp/src/App.vue b/BlueMapCommon/webapp/src/App.vue index 6d203776..1b5cc3f0 100644 --- a/BlueMapCommon/webapp/src/App.vue +++ b/BlueMapCommon/webapp/src/App.vue @@ -1,6 +1,6 @@