From b33db48b63f3d676d03d613c26f4cacb9532c598 Mon Sep 17 00:00:00 2001 From: pavel444-byte Date: Mon, 5 Oct 2026 18:37:32 +0500 Subject: [PATCH] Show MineGeo console output and release plugin 0.1.2 --- artifacts-plugin-regression.json | 4 +- docs/server-plugin.md | 4 +- minecraft/build.gradle | 2 +- .../dev/minegeo/plugin/MineGeoPlugin.java | 7 ++- .../plugin/src/main/resources/plugin.yml | 3 +- .../tools/plugin/minegeo-plugin-1.21.11.jar | Bin 340716 -> 340746 bytes scripts/test-plugin.ts | 49 +++++++++++++++++- 7 files changed, 60 insertions(+), 9 deletions(-) diff --git a/artifacts-plugin-regression.json b/artifacts-plugin-regression.json index f454ed0..4625d4c 100644 --- a/artifacts-plugin-regression.json +++ b/artifacts-plugin-regression.json @@ -1,6 +1,8 @@ { "passed": true, "checks": [ + "local console help, status and errors produce visible output", + "remote console help produces visible output", "missing export guidance", "empty area failure", "real Paper export without a player", @@ -16,5 +18,5 @@ "blocks": 10112, "chunks": 16, "viewpoints": 24, - "directory": ".cache/plugin-regression-1791186051478" + "directory": ".cache/plugin-regression-1791207258927" } \ No newline at end of file diff --git a/docs/server-plugin.md b/docs/server-plugin.md index f22b612..8797f59 100644 --- a/docs/server-plugin.md +++ b/docs/server-plugin.md @@ -1,8 +1,8 @@ -# Server plugin 0.1.1 +# Server plugin 0.1.2 ## Update and connect -1. Stop the Minecraft server, replace its old MineGeo JAR with `public/tools/plugin/minegeo-plugin-1.21.11.jar`, and restart. Run `/version MineGeo` to verify 0.1.1. +1. Stop the Minecraft server, replace its old MineGeo JAR with `public/tools/plugin/minegeo-plugin-1.21.11.jar`, and restart. Run `version MineGeo` in the console to verify 0.1.2. 2. Open your MineGeo website dashboard, sign in, and generate a plugin token. 3. In the Minecraft server console, configure the website and token. Console commands do not need the leading slash: diff --git a/minecraft/build.gradle b/minecraft/build.gradle index 7891281..d8a2ca7 100644 --- a/minecraft/build.gradle +++ b/minecraft/build.gradle @@ -1 +1 @@ -allprojects { group = 'dev.minegeo'; version = '0.1.1'; repositories { mavenCentral() } } +allprojects { group = 'dev.minegeo'; version = '0.1.2'; repositories { mavenCentral() } } diff --git a/minecraft/plugin/src/main/java/dev/minegeo/plugin/MineGeoPlugin.java b/minecraft/plugin/src/main/java/dev/minegeo/plugin/MineGeoPlugin.java index c82f01a..1b66c05 100644 --- a/minecraft/plugin/src/main/java/dev/minegeo/plugin/MineGeoPlugin.java +++ b/minecraft/plugin/src/main/java/dev/minegeo/plugin/MineGeoPlugin.java @@ -37,7 +37,10 @@ public final class MineGeoPlugin extends JavaPlugin { } @Override public void onDisable(){cancelled.set(true);} @Override public boolean onCommand(CommandSender sender,Command command,String label,String[] args){ - if(!sender.hasPermission("minegeo.admin")){sender.sendMessage("MineGeo: administrator permission required.");return true;} + // Paper may dispatch hosting-panel commands through a remote console sender + // whose permissions differ from the local console. Check permissions here so + // every rejected command receives a visible explanation. + if(!(sender instanceof ConsoleCommandSender||sender instanceof RemoteConsoleCommandSender||sender instanceof Player&&sender.hasPermission("minegeo.admin"))){sender.sendMessage("MineGeo: administrator permission required.");return true;} try { if(args.length==0||args[0].equalsIgnoreCase("help")) {sender.sendMessage(new String[]{"MineGeo commands:","/minegeo website ","/minegeo server — capture server address","/minegeo link ","/minegeo area ","/minegeo export — saves a local export","/minegeo upload — uploads the latest completed export","/minegeo contribute — send up to 12 panoramas to its owner","/minegeo status | cancel | reload"});return true;} switch(args[0].toLowerCase(Locale.ROOT)) { @@ -62,7 +65,7 @@ public final class MineGeoPlugin extends JavaPlugin { }catch(Exception ex){sender.sendMessage("MineGeo: "+ex.getMessage());}return true; } private void requireIdle(){if(busy)throw new IllegalArgumentException("An operation is running. Use /minegeo status or /minegeo cancel.");} - private void report(CommandSender sender,String message){status=message;getLogger().info(message);if(sender instanceof Player&&isEnabled())Bukkit.getScheduler().runTask(this,()->sender.sendMessage("MineGeo: "+message));} + private void report(CommandSender sender,String message){status=message;getLogger().info(message);if(!(sender instanceof ConsoleCommandSender)&&isEnabled())Bukkit.getScheduler().runTask(this,()->sender.sendMessage("MineGeo: "+message));} private void fail(CommandSender sender,String phase,Exception ex){report(sender,cancelled.get()?"Cancelled. Completed exports are kept.":phase+" failed: "+ex.getMessage());if(!cancelled.get())getLogger().log(Level.WARNING,phase+" failure",ex);} private void upload(CommandSender sender,String targetMap)throws Exception { requireIdle();if(latest==null||!Files.isRegularFile(latest.resolve("manifest.json")))throw new IOException("No completed export. Run /minegeo export My World, wait for 'Export complete', then /minegeo upload. Files: "+getDataFolder().toPath().resolve("exports").toAbsolutePath()); diff --git a/minecraft/plugin/src/main/resources/plugin.yml b/minecraft/plugin/src/main/resources/plugin.yml index 92e1f54..2c2d827 100644 --- a/minecraft/plugin/src/main/resources/plugin.yml +++ b/minecraft/plugin/src/main/resources/plugin.yml @@ -1,12 +1,11 @@ name: MineGeo -version: 0.1.1 +version: 0.1.2 main: dev.minegeo.plugin.MineGeoPlugin api-version: '1.21' description: Bounded terrain export for MineGeo panorama guessing commands: minegeo: description: Link, select, export, upload, status or cancel MineGeo maps - permission: minegeo.admin permissions: minegeo.admin: default: op diff --git a/public/tools/plugin/minegeo-plugin-1.21.11.jar b/public/tools/plugin/minegeo-plugin-1.21.11.jar index b56814693d57de23c4d3f98de162829735056d9b..ddf965baf0776ce834f7dd27e8912d59a258e173 100644 GIT binary patch delta 21311 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 Rt164(YMaWV_-iZG{{fI5DdqqG delta 21280 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 diff --git a/scripts/test-plugin.ts b/scripts/test-plugin.ts index d913676..cc24d8f 100644 --- a/scripts/test-plugin.ts +++ b/scripts/test-plugin.ts @@ -1,4 +1,5 @@ import { createServer } from "node:http"; +import { connect } from "node:net"; import { spawn } from "node:child_process"; import { mkdir, copyFile, writeFile, readFile } from "node:fs/promises"; import { createHash } from "node:crypto"; @@ -17,7 +18,7 @@ await copyFile( await writeFile(`${directory}/eula.txt`, "eula=true\n"); await writeFile( `${directory}/server.properties`, - 'server-ip=127.0.0.1\nserver-port=25580\nonline-mode=true\nlevel-type=minecraft:flat\ngenerator-settings={"layers":[{"block":"minecraft:bedrock","height":1},{"block":"minecraft:dirt","height":2},{"block":"minecraft:grass_block","height":1}],"biome":"minecraft:plains"}\ngenerate-structures=false\nview-distance=2\nsimulation-distance=2\nspawn-protection=0\nmax-players=1\n', + 'server-ip=127.0.0.1\nserver-port=25580\nenable-rcon=true\nrcon.port=25581\nrcon.password=minegeo-fixture\nonline-mode=true\nlevel-type=minecraft:flat\ngenerator-settings={"layers":[{"block":"minecraft:bedrock","height":1},{"block":"minecraft:dirt","height":2},{"block":"minecraft:grass_block","height":1}],"biome":"minecraft:plains"}\ngenerate-structures=false\nview-distance=2\nsimulation-distance=2\nspawn-protection=0\nmax-players=1\n', ); let manifest: any, received = Buffer.alloc(0), @@ -164,8 +165,52 @@ const command = async (text: string, pattern: RegExp) => { child.stdin.write(text + "\n"); await pending; }; +const rconCommand = (text: string, expected: RegExp) => new Promise((resolve, reject) => { + const socket = connect(25581, "127.0.0.1"); + let buffer = Buffer.alloc(0); + let authenticated = false; + const timeout = setTimeout(() => finish(new Error(`RCON timed out waiting for ${expected}`)), 10000); + const finish = (error?: Error) => { + clearTimeout(timeout); + socket.destroy(); + if (error) reject(error); + else resolve(); + }; + const packet = (id: number, type: number, body: string) => { + const payload = Buffer.from(body); + const frame = Buffer.alloc(payload.length + 14); + frame.writeInt32LE(payload.length + 10, 0); + frame.writeInt32LE(id, 4); + frame.writeInt32LE(type, 8); + payload.copy(frame, 12); + return frame; + }; + socket.on("connect", () => socket.write(packet(1, 3, "minegeo-fixture"))); + socket.on("error", finish); + socket.on("data", (chunk) => { + buffer = Buffer.concat([buffer, chunk]); + while (buffer.length >= 4 && buffer.length >= buffer.readInt32LE(0) + 4) { + const length = buffer.readInt32LE(0); + const frame = buffer.subarray(0, length + 4); + buffer = buffer.subarray(length + 4); + const id = frame.readInt32LE(4); + const type = frame.readInt32LE(8); + if (id === -1) return finish(new Error("RCON authentication failed")); + if (id === 1 && type === 2 && !authenticated) { + authenticated = true; + socket.write(packet(2, 2, text)); + } else if (id === 2 && expected.test(frame.toString("utf8", 12, length + 2))) { + return finish(); + } + } + }); +}); try { await wait(/Done \(/, 0, 180000); + await command("minegeo help", /MineGeo commands:/); + await command("minegeo status", /MineGeo: Idle/); + await command("minegeo unknown", /Unknown command\. Use \/minegeo help/); + await rconCommand("minegeo help", /MineGeo commands:/); await command("minegeo upload", /No completed export/); await command( "minegeo area world 100000 100000 100032 100032", @@ -266,6 +311,8 @@ try { { passed: true, checks: [ + "local console help, status and errors produce visible output", + "remote console help produces visible output", "missing export guidance", "empty area failure", "real Paper export without a player",