Spaces:
Sleeping
Sleeping
Import live AfterBlock packets in Paper plugin
Browse files- .gitignore +1 -0
- CODEX_BUILD_LOG.md +3 -0
- docs/PEBBLEHOST_DEPLOY.md +78 -0
- paper-plugin/README.md +4 -1
- paper-plugin/pom.xml +25 -0
- paper-plugin/src/main/java/com/dreamwall/DreamWallPlugin.java +150 -1
- paper-plugin/src/main/resources/plugin.yml +1 -1
.gitignore
CHANGED
|
@@ -4,3 +4,4 @@ __pycache__/
|
|
| 4 |
.venv/
|
| 5 |
dist/
|
| 6 |
build/
|
|
|
|
|
|
| 4 |
.venv/
|
| 5 |
dist/
|
| 6 |
build/
|
| 7 |
+
paper-plugin/target/
|
CODEX_BUILD_LOG.md
CHANGED
|
@@ -27,3 +27,6 @@ This file records how Codex was used to build the hackathon entry.
|
|
| 27 |
- Added per-tile Minecraft origins/bounds and documented the Paper bridge path for placing Living Canvas tiles and representing motion through particles, map updates, or block-frame updates.
|
| 28 |
- Reframed the project as DreamWall: AfterBlock Museum with `dreamwall.museum.v1`, deterministic hall placement, curation scores, artifact spirits, passport cards, seeded relic demos, museum-terminal UI, and a GitHub Actions Paper plugin build workflow.
|
| 29 |
- Expanded AfterBlock assets into a resource-pack pipeline: 1,200 generated item textures, 1,200 3D model JSONs, custom model data overrides, contact-sheet screenshots, a browser gallery, and a `/dreamwall demo` Paper command for an in-game pedestal proof.
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
- Added per-tile Minecraft origins/bounds and documented the Paper bridge path for placing Living Canvas tiles and representing motion through particles, map updates, or block-frame updates.
|
| 28 |
- Reframed the project as DreamWall: AfterBlock Museum with `dreamwall.museum.v1`, deterministic hall placement, curation scores, artifact spirits, passport cards, seeded relic demos, museum-terminal UI, and a GitHub Actions Paper plugin build workflow.
|
| 29 |
- Expanded AfterBlock assets into a resource-pack pipeline: 1,200 generated item textures, 1,200 3D model JSONs, custom model data overrides, contact-sheet screenshots, a browser gallery, and a `/dreamwall demo` Paper command for an in-game pedestal proof.
|
| 30 |
+
- Added `/dreamwall import` and `/dreamwall import here` to the Paper bridge. The plugin now calls the live Gradio `curate_artifact` endpoint, parses `dreamwall.museum.v1`, and places a packet-derived pedestal/sign/item in Minecraft.
|
| 31 |
+
- Added Gson shading plus explicit Maven Central resolution so the Paper jar compiles into a self-contained PebbleHost-friendly plugin.
|
| 32 |
+
- Verified the shaded jar locally with temporary Maven 3.9.9 and prepared an ignored deploy bundle at `dist/pebblehost/` with the plugin jar, `AfterBlockMuseum.zip`, and hashes.
|
docs/PEBBLEHOST_DEPLOY.md
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# PebbleHost Deployment Checklist
|
| 2 |
+
|
| 3 |
+
This is the shortest path to make the AfterBlock Museum demo visible in a live Minecraft server.
|
| 4 |
+
|
| 5 |
+
## Local Build Artifacts
|
| 6 |
+
|
| 7 |
+
Build the Paper plugin:
|
| 8 |
+
|
| 9 |
+
```bash
|
| 10 |
+
/tmp/apache-maven-3.9.9/bin/mvn -q -f paper-plugin/pom.xml package
|
| 11 |
+
```
|
| 12 |
+
|
| 13 |
+
Prepared local bundle:
|
| 14 |
+
|
| 15 |
+
```text
|
| 16 |
+
dist/pebblehost/dreamwall-paper-bridge-0.1.0.jar
|
| 17 |
+
dist/pebblehost/AfterBlockMuseum.zip
|
| 18 |
+
dist/pebblehost/SHA256SUMS
|
| 19 |
+
```
|
| 20 |
+
|
| 21 |
+
Current hashes from the verified local bundle:
|
| 22 |
+
|
| 23 |
+
```text
|
| 24 |
+
7ace99dec709e01c3f118bb48cde406b9711d6683d74e848707015692a78087c AfterBlockMuseum.zip
|
| 25 |
+
0bc7e6b3bb2e80b01943cea42bb3efdd7432eac6db39e394b3564dbfc584829e dreamwall-paper-bridge-0.1.0.jar
|
| 26 |
+
```
|
| 27 |
+
|
| 28 |
+
## Upload Targets
|
| 29 |
+
|
| 30 |
+
Upload with SFTP or the PebbleHost file manager:
|
| 31 |
+
|
| 32 |
+
```text
|
| 33 |
+
plugins/dreamwall-paper-bridge-0.1.0.jar
|
| 34 |
+
AfterBlockMuseum.zip
|
| 35 |
+
```
|
| 36 |
+
|
| 37 |
+
The known PebbleHost SFTP endpoint from the account screen was:
|
| 38 |
+
|
| 39 |
+
```text
|
| 40 |
+
sftp://uk144.pebblehost.net:2222
|
| 41 |
+
```
|
| 42 |
+
|
| 43 |
+
Use the PebbleHost panel username/password. Do not commit credentials.
|
| 44 |
+
|
| 45 |
+
## Server Resource Pack
|
| 46 |
+
|
| 47 |
+
In the PebbleHost panel or `server.properties`, set the server resource pack URL to a downloadable URL for:
|
| 48 |
+
|
| 49 |
+
```text
|
| 50 |
+
AfterBlockMuseum.zip
|
| 51 |
+
```
|
| 52 |
+
|
| 53 |
+
The pack contains:
|
| 54 |
+
|
| 55 |
+
```text
|
| 56 |
+
1,200 PNG item textures
|
| 57 |
+
1,200 item model JSON files
|
| 58 |
+
1,200 CustomModelData overrides on minecraft:paper
|
| 59 |
+
```
|
| 60 |
+
|
| 61 |
+
## In-Game Smoke Test
|
| 62 |
+
|
| 63 |
+
After restarting the server, run these as an op player:
|
| 64 |
+
|
| 65 |
+
```text
|
| 66 |
+
/dreamwall
|
| 67 |
+
/dreamwall fetch
|
| 68 |
+
/dreamwall demo
|
| 69 |
+
/dreamwall import here
|
| 70 |
+
```
|
| 71 |
+
|
| 72 |
+
Expected result:
|
| 73 |
+
|
| 74 |
+
- `/dreamwall fetch` reports the Hugging Face Space is reachable.
|
| 75 |
+
- `/dreamwall demo` places a small pedestal and gives a Paper item using `CustomModelData 730002`.
|
| 76 |
+
- `/dreamwall import here` calls the live `curate_artifact` endpoint, parses `dreamwall.museum.v1`, places a packet-derived pedestal/sign beside the player, and gives a Paper item using the packet's `custom_model_data`.
|
| 77 |
+
|
| 78 |
+
If the Paper item looks like ordinary paper, the plugin is working but the resource pack is not loaded.
|
paper-plugin/README.md
CHANGED
|
@@ -9,6 +9,8 @@ The hackathon Space is the official submission surface. This plugin scaffold is
|
|
| 9 |
- `/dreamwall` shows the configured Space endpoint.
|
| 10 |
- `/dreamwall fetch` calls the Space app domain and confirms the bridge can reach Hugging Face.
|
| 11 |
- `/dreamwall demo` places a safe local pedestal/sign proof and gives the player a Paper item with `CustomModelData 730002`.
|
|
|
|
|
|
|
| 12 |
- A scheduled task can be extended to poll approved museum artifacts.
|
| 13 |
- The Space now emits `dreamwall.museum.v1`, the main AfterBlock packet for the hackathon demo.
|
| 14 |
- The Space also emits `living_canvas.mc.v1` for the secondary wall/canvas mode.
|
|
@@ -28,7 +30,7 @@ The main Space endpoint is `curate_artifact`, which emits `dreamwall.museum.v1`
|
|
| 28 |
- curation scores
|
| 29 |
- resonance links
|
| 30 |
|
| 31 |
-
|
| 32 |
|
| 33 |
1. Fetch latest artifact packet.
|
| 34 |
2. Place pedestal/sign/painting marker at coordinates.
|
|
@@ -125,3 +127,4 @@ The jar will be in `target/dreamwall-paper-bridge-0.1.0.jar`.
|
|
| 125 |
5. Edit `plugins/DreamWall/config.yml` if needed.
|
| 126 |
6. Run `/dreamwall fetch` in game or console.
|
| 127 |
7. Run `/dreamwall demo` in game to place a pedestal proof and receive the AirPods demo item.
|
|
|
|
|
|
| 9 |
- `/dreamwall` shows the configured Space endpoint.
|
| 10 |
- `/dreamwall fetch` calls the Space app domain and confirms the bridge can reach Hugging Face.
|
| 11 |
- `/dreamwall demo` places a safe local pedestal/sign proof and gives the player a Paper item with `CustomModelData 730002`.
|
| 12 |
+
- `/dreamwall import` calls the live `curate_artifact` Gradio endpoint, parses the returned `dreamwall.museum.v1` packet, and places a packet-derived pedestal/sign/item at the artifact coordinates.
|
| 13 |
+
- `/dreamwall import here` uses the same live packet but places it two blocks in front of the player for fast video proof.
|
| 14 |
- A scheduled task can be extended to poll approved museum artifacts.
|
| 15 |
- The Space now emits `dreamwall.museum.v1`, the main AfterBlock packet for the hackathon demo.
|
| 16 |
- The Space also emits `living_canvas.mc.v1` for the secondary wall/canvas mode.
|
|
|
|
| 30 |
- curation scores
|
| 31 |
- resonance links
|
| 32 |
|
| 33 |
+
Implemented `/dreamwall import` V1 behavior:
|
| 34 |
|
| 35 |
1. Fetch latest artifact packet.
|
| 36 |
2. Place pedestal/sign/painting marker at coordinates.
|
|
|
|
| 127 |
5. Edit `plugins/DreamWall/config.yml` if needed.
|
| 128 |
6. Run `/dreamwall fetch` in game or console.
|
| 129 |
7. Run `/dreamwall demo` in game to place a pedestal proof and receive the AirPods demo item.
|
| 130 |
+
8. Run `/dreamwall import here` in game to place a live Hugging Face artifact packet beside you.
|
paper-plugin/pom.xml
CHANGED
|
@@ -15,6 +15,10 @@
|
|
| 15 |
</properties>
|
| 16 |
|
| 17 |
<repositories>
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
<repository>
|
| 19 |
<id>papermc</id>
|
| 20 |
<url>https://repo.papermc.io/repository/maven-public/</url>
|
|
@@ -28,6 +32,11 @@
|
|
| 28 |
<version>1.21.4-R0.1-SNAPSHOT</version>
|
| 29 |
<scope>provided</scope>
|
| 30 |
</dependency>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
</dependencies>
|
| 32 |
|
| 33 |
<build>
|
|
@@ -37,6 +46,22 @@
|
|
| 37 |
<artifactId>maven-compiler-plugin</artifactId>
|
| 38 |
<version>3.13.0</version>
|
| 39 |
</plugin>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 40 |
</plugins>
|
| 41 |
</build>
|
| 42 |
</project>
|
|
|
|
| 15 |
</properties>
|
| 16 |
|
| 17 |
<repositories>
|
| 18 |
+
<repository>
|
| 19 |
+
<id>central</id>
|
| 20 |
+
<url>https://repo.maven.apache.org/maven2/</url>
|
| 21 |
+
</repository>
|
| 22 |
<repository>
|
| 23 |
<id>papermc</id>
|
| 24 |
<url>https://repo.papermc.io/repository/maven-public/</url>
|
|
|
|
| 32 |
<version>1.21.4-R0.1-SNAPSHOT</version>
|
| 33 |
<scope>provided</scope>
|
| 34 |
</dependency>
|
| 35 |
+
<dependency>
|
| 36 |
+
<groupId>com.google.code.gson</groupId>
|
| 37 |
+
<artifactId>gson</artifactId>
|
| 38 |
+
<version>2.11.0</version>
|
| 39 |
+
</dependency>
|
| 40 |
</dependencies>
|
| 41 |
|
| 42 |
<build>
|
|
|
|
| 46 |
<artifactId>maven-compiler-plugin</artifactId>
|
| 47 |
<version>3.13.0</version>
|
| 48 |
</plugin>
|
| 49 |
+
<plugin>
|
| 50 |
+
<groupId>org.apache.maven.plugins</groupId>
|
| 51 |
+
<artifactId>maven-shade-plugin</artifactId>
|
| 52 |
+
<version>3.6.0</version>
|
| 53 |
+
<executions>
|
| 54 |
+
<execution>
|
| 55 |
+
<phase>package</phase>
|
| 56 |
+
<goals>
|
| 57 |
+
<goal>shade</goal>
|
| 58 |
+
</goals>
|
| 59 |
+
<configuration>
|
| 60 |
+
<createDependencyReducedPom>false</createDependencyReducedPom>
|
| 61 |
+
</configuration>
|
| 62 |
+
</execution>
|
| 63 |
+
</executions>
|
| 64 |
+
</plugin>
|
| 65 |
</plugins>
|
| 66 |
</build>
|
| 67 |
</project>
|
paper-plugin/src/main/java/com/dreamwall/DreamWallPlugin.java
CHANGED
|
@@ -6,8 +6,14 @@ import java.net.http.HttpClient;
|
|
| 6 |
import java.net.http.HttpRequest;
|
| 7 |
import java.net.http.HttpResponse;
|
| 8 |
import java.time.Duration;
|
|
|
|
| 9 |
import java.util.logging.Level;
|
| 10 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
import org.bukkit.Location;
|
| 12 |
import org.bukkit.Material;
|
| 13 |
import org.bukkit.Particle;
|
|
@@ -16,7 +22,6 @@ import org.bukkit.block.Block;
|
|
| 16 |
import org.bukkit.block.Sign;
|
| 17 |
import org.bukkit.command.Command;
|
| 18 |
import org.bukkit.command.CommandSender;
|
| 19 |
-
import org.bukkit.entity.ItemFrame;
|
| 20 |
import org.bukkit.entity.Player;
|
| 21 |
import org.bukkit.inventory.ItemStack;
|
| 22 |
import org.bukkit.inventory.meta.ItemMeta;
|
|
@@ -58,12 +63,18 @@ public final class DreamWallPlugin extends JavaPlugin {
|
|
| 58 |
placeDemoArtifact(sender);
|
| 59 |
return true;
|
| 60 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 61 |
|
| 62 |
sender.sendMessage("DreamWall bridge is configured for: " + spaceUrl());
|
| 63 |
sender.sendMessage("Canvas: " + getConfig().getInt("canvas-size", 12) + "x" + getConfig().getInt("canvas-size", 12)
|
| 64 |
+ " plots, plot size=" + getConfig().getInt("plot-size", 32));
|
| 65 |
sender.sendMessage("Use /dreamwall fetch to test Hugging Face reachability.");
|
| 66 |
sender.sendMessage("Use /dreamwall demo in-game to place a safe AfterBlock pedestal proof.");
|
|
|
|
| 67 |
return true;
|
| 68 |
}
|
| 69 |
|
|
@@ -94,6 +105,92 @@ public final class DreamWallPlugin extends JavaPlugin {
|
|
| 94 |
});
|
| 95 |
}
|
| 96 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 97 |
private void placeDemoArtifact(CommandSender sender) {
|
| 98 |
if (!(sender instanceof Player player)) {
|
| 99 |
sender.sendMessage("/dreamwall demo must be run by an in-game player.");
|
|
@@ -147,6 +244,58 @@ public final class DreamWallPlugin extends JavaPlugin {
|
|
| 147 |
return response.body();
|
| 148 |
}
|
| 149 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 150 |
private String spaceUrl() {
|
| 151 |
return getConfig().getString("space-url", "https://build-small-hackathon-dreamwall-mc.hf.space").replaceAll("/+$", "");
|
| 152 |
}
|
|
|
|
| 6 |
import java.net.http.HttpRequest;
|
| 7 |
import java.net.http.HttpResponse;
|
| 8 |
import java.time.Duration;
|
| 9 |
+
import java.util.Locale;
|
| 10 |
import java.util.logging.Level;
|
| 11 |
|
| 12 |
+
import com.google.gson.JsonArray;
|
| 13 |
+
import com.google.gson.JsonElement;
|
| 14 |
+
import com.google.gson.JsonObject;
|
| 15 |
+
import com.google.gson.JsonParser;
|
| 16 |
+
|
| 17 |
import org.bukkit.Location;
|
| 18 |
import org.bukkit.Material;
|
| 19 |
import org.bukkit.Particle;
|
|
|
|
| 22 |
import org.bukkit.block.Sign;
|
| 23 |
import org.bukkit.command.Command;
|
| 24 |
import org.bukkit.command.CommandSender;
|
|
|
|
| 25 |
import org.bukkit.entity.Player;
|
| 26 |
import org.bukkit.inventory.ItemStack;
|
| 27 |
import org.bukkit.inventory.meta.ItemMeta;
|
|
|
|
| 63 |
placeDemoArtifact(sender);
|
| 64 |
return true;
|
| 65 |
}
|
| 66 |
+
if (args.length > 0 && args[0].equalsIgnoreCase("import")) {
|
| 67 |
+
boolean placeHere = args.length > 1 && args[1].equalsIgnoreCase("here");
|
| 68 |
+
importArtifact(sender, placeHere);
|
| 69 |
+
return true;
|
| 70 |
+
}
|
| 71 |
|
| 72 |
sender.sendMessage("DreamWall bridge is configured for: " + spaceUrl());
|
| 73 |
sender.sendMessage("Canvas: " + getConfig().getInt("canvas-size", 12) + "x" + getConfig().getInt("canvas-size", 12)
|
| 74 |
+ " plots, plot size=" + getConfig().getInt("plot-size", 32));
|
| 75 |
sender.sendMessage("Use /dreamwall fetch to test Hugging Face reachability.");
|
| 76 |
sender.sendMessage("Use /dreamwall demo in-game to place a safe AfterBlock pedestal proof.");
|
| 77 |
+
sender.sendMessage("Use /dreamwall import or /dreamwall import here to place a live Space artifact packet.");
|
| 78 |
return true;
|
| 79 |
}
|
| 80 |
|
|
|
|
| 105 |
});
|
| 106 |
}
|
| 107 |
|
| 108 |
+
private void importArtifact(CommandSender sender, boolean placeHere) {
|
| 109 |
+
if (!(sender instanceof Player player)) {
|
| 110 |
+
sender.sendMessage("/dreamwall import must be run by an in-game player.");
|
| 111 |
+
return;
|
| 112 |
+
}
|
| 113 |
+
sender.sendMessage("Importing one live AfterBlock artifact from " + spaceUrl() + " ...");
|
| 114 |
+
getServer().getScheduler().runTaskAsynchronously(this, () -> {
|
| 115 |
+
try {
|
| 116 |
+
JsonObject packet = fetchMuseumPacket();
|
| 117 |
+
getServer().getScheduler().runTask(this, () -> placePacketArtifact(player, packet, placeHere));
|
| 118 |
+
} catch (IOException | InterruptedException e) {
|
| 119 |
+
sender.sendMessage("DreamWall import failed: " + e.getMessage());
|
| 120 |
+
Thread.currentThread().interrupt();
|
| 121 |
+
} catch (RuntimeException e) {
|
| 122 |
+
sender.sendMessage("DreamWall import parse failed: " + e.getMessage());
|
| 123 |
+
}
|
| 124 |
+
});
|
| 125 |
+
}
|
| 126 |
+
|
| 127 |
+
private JsonObject fetchMuseumPacket() throws IOException, InterruptedException {
|
| 128 |
+
String payload = "{\"data\":[\"Minecraft\",\"@afterblock\",\"object_photo\",\"a white AirPods case from a first year desk\",\"A small object that carried private worlds through public noise.\",null]}";
|
| 129 |
+
String callBody = post(spaceUrl() + "/gradio_api/call/curate_artifact", payload);
|
| 130 |
+
JsonObject call = JsonParser.parseString(callBody).getAsJsonObject();
|
| 131 |
+
String eventId = call.get("event_id").getAsString();
|
| 132 |
+
String stream = get(spaceUrl() + "/gradio_api/call/curate_artifact/" + eventId);
|
| 133 |
+
for (String line : stream.split("\\R")) {
|
| 134 |
+
if (line.startsWith("data: ")) {
|
| 135 |
+
JsonArray outputs = JsonParser.parseString(line.substring(6)).getAsJsonArray();
|
| 136 |
+
JsonObject packet = JsonParser.parseString(outputs.get(5).getAsString()).getAsJsonObject();
|
| 137 |
+
String type = text(packet, "type", "");
|
| 138 |
+
if (!"dreamwall.museum.v1".equals(type)) {
|
| 139 |
+
throw new IOException("unexpected packet type " + type);
|
| 140 |
+
}
|
| 141 |
+
return packet;
|
| 142 |
+
}
|
| 143 |
+
}
|
| 144 |
+
throw new IOException("no data event returned by Gradio");
|
| 145 |
+
}
|
| 146 |
+
|
| 147 |
+
private void placePacketArtifact(Player player, JsonObject packet, boolean placeHere) {
|
| 148 |
+
JsonObject minecraft = packet.getAsJsonObject("minecraft");
|
| 149 |
+
JsonObject artifact = packet.getAsJsonObject("artifact");
|
| 150 |
+
JsonObject coordinates = minecraft.getAsJsonObject("coordinates");
|
| 151 |
+
World world = player.getWorld();
|
| 152 |
+
Location base = placeHere
|
| 153 |
+
? player.getLocation().getBlock().getLocation().add(0, 0, 2)
|
| 154 |
+
: new Location(world, number(coordinates, "x", player.getLocation().getBlockX()),
|
| 155 |
+
number(coordinates, "y", player.getLocation().getBlockY()),
|
| 156 |
+
number(coordinates, "z", player.getLocation().getBlockZ()));
|
| 157 |
+
|
| 158 |
+
Material pedestalMaterial = materialFromPacket(minecraft);
|
| 159 |
+
base.getBlock().setType(pedestalMaterial);
|
| 160 |
+
base.clone().add(0, 1, 0).getBlock().setType(Material.AMETHYST_BLOCK);
|
| 161 |
+
|
| 162 |
+
Block signBlock = base.clone().add(0, 1, -1).getBlock();
|
| 163 |
+
signBlock.setType(Material.OAK_SIGN);
|
| 164 |
+
String title = text(minecraft, "title", text(artifact, "title", "AfterBlock Relic"));
|
| 165 |
+
String owner = text(minecraft, "owner_handle", text(artifact, "owner_handle", "@unknown"));
|
| 166 |
+
String hall = text(minecraft, "hall", text(artifact, "hall", "Museum"));
|
| 167 |
+
String plaque = text(minecraft, "plaque_text", text(artifact, "plaque_line", "Preserved in AfterBlock"));
|
| 168 |
+
if (signBlock.getState() instanceof Sign sign) {
|
| 169 |
+
sign.setLine(0, trimLine(title));
|
| 170 |
+
sign.setLine(1, trimLine(owner));
|
| 171 |
+
sign.setLine(2, trimLine(hall));
|
| 172 |
+
sign.setLine(3, trimLine(plaque));
|
| 173 |
+
sign.update();
|
| 174 |
+
}
|
| 175 |
+
|
| 176 |
+
ItemStack item = new ItemStack(Material.PAPER);
|
| 177 |
+
ItemMeta meta = item.getItemMeta();
|
| 178 |
+
if (meta != null) {
|
| 179 |
+
meta.setDisplayName(trimLine(title) + " Passport");
|
| 180 |
+
int customModelData = integer(minecraft, "custom_model_data", 730001);
|
| 181 |
+
meta.setCustomModelData(customModelData);
|
| 182 |
+
item.setItemMeta(meta);
|
| 183 |
+
}
|
| 184 |
+
player.getInventory().addItem(item);
|
| 185 |
+
world.spawnParticle(Particle.ENCHANT, base.clone().add(0.5, 1.4, 0.5), 38, 0.45, 0.65, 0.45, 0.015);
|
| 186 |
+
player.sendMessage("Imported " + title + " by " + owner + " into " + hall + ".");
|
| 187 |
+
player.sendMessage("Gave Paper item with CustomModelData " + integer(minecraft, "custom_model_data", 730001) + ".");
|
| 188 |
+
if (!placeHere) {
|
| 189 |
+
player.sendMessage("Placed at packet coordinates " + base.getBlockX() + " " + base.getBlockY() + " " + base.getBlockZ()
|
| 190 |
+
+ ". Use /dreamwall import here for a nearby proof.");
|
| 191 |
+
}
|
| 192 |
+
}
|
| 193 |
+
|
| 194 |
private void placeDemoArtifact(CommandSender sender) {
|
| 195 |
if (!(sender instanceof Player player)) {
|
| 196 |
sender.sendMessage("/dreamwall demo must be run by an in-game player.");
|
|
|
|
| 244 |
return response.body();
|
| 245 |
}
|
| 246 |
|
| 247 |
+
private String post(String url, String body) throws IOException, InterruptedException {
|
| 248 |
+
HttpRequest request = HttpRequest.newBuilder()
|
| 249 |
+
.uri(URI.create(url))
|
| 250 |
+
.timeout(Duration.ofSeconds(18))
|
| 251 |
+
.header("User-Agent", "DreamWall-Paper-Bridge/0.1")
|
| 252 |
+
.header("Content-Type", "application/json")
|
| 253 |
+
.POST(HttpRequest.BodyPublishers.ofString(body))
|
| 254 |
+
.build();
|
| 255 |
+
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
| 256 |
+
if (response.statusCode() < 200 || response.statusCode() >= 300) {
|
| 257 |
+
throw new IOException("HTTP " + response.statusCode() + " from " + url);
|
| 258 |
+
}
|
| 259 |
+
return response.body();
|
| 260 |
+
}
|
| 261 |
+
|
| 262 |
+
private Material materialFromPacket(JsonObject minecraft) {
|
| 263 |
+
JsonArray materials = minecraft.has("materials") && minecraft.get("materials").isJsonArray()
|
| 264 |
+
? minecraft.getAsJsonArray("materials")
|
| 265 |
+
: new JsonArray();
|
| 266 |
+
for (JsonElement element : materials) {
|
| 267 |
+
String name = element.getAsString().toUpperCase(Locale.ROOT).replace("MINECRAFT:", "");
|
| 268 |
+
Material material = Material.matchMaterial(name);
|
| 269 |
+
if (material != null && material.isBlock()) {
|
| 270 |
+
return material;
|
| 271 |
+
}
|
| 272 |
+
}
|
| 273 |
+
return Material.POLISHED_DEEPSLATE;
|
| 274 |
+
}
|
| 275 |
+
|
| 276 |
+
private String text(JsonObject object, String key, String fallback) {
|
| 277 |
+
if (object == null || !object.has(key) || object.get(key).isJsonNull()) {
|
| 278 |
+
return fallback;
|
| 279 |
+
}
|
| 280 |
+
return object.get(key).getAsString();
|
| 281 |
+
}
|
| 282 |
+
|
| 283 |
+
private int integer(JsonObject object, String key, int fallback) {
|
| 284 |
+
if (object == null || !object.has(key) || object.get(key).isJsonNull()) {
|
| 285 |
+
return fallback;
|
| 286 |
+
}
|
| 287 |
+
return object.get(key).getAsInt();
|
| 288 |
+
}
|
| 289 |
+
|
| 290 |
+
private int number(JsonObject object, String key, int fallback) {
|
| 291 |
+
return integer(object, key, fallback);
|
| 292 |
+
}
|
| 293 |
+
|
| 294 |
+
private String trimLine(String value) {
|
| 295 |
+
String cleaned = value == null ? "" : value.replaceAll("\\s+", " ").trim();
|
| 296 |
+
return cleaned.length() <= 15 ? cleaned : cleaned.substring(0, 15);
|
| 297 |
+
}
|
| 298 |
+
|
| 299 |
private String spaceUrl() {
|
| 300 |
return getConfig().getString("space-url", "https://build-small-hackathon-dreamwall-mc.hf.space").replaceAll("/+$", "");
|
| 301 |
}
|
paper-plugin/src/main/resources/plugin.yml
CHANGED
|
@@ -7,7 +7,7 @@ description: Bridge a Paper server to the DreamWall MC Hugging Face Space.
|
|
| 7 |
commands:
|
| 8 |
dreamwall:
|
| 9 |
description: Show or test the DreamWall Space bridge.
|
| 10 |
-
usage: /dreamwall [fetch|demo]
|
| 11 |
permission: dreamwall.use
|
| 12 |
permissions:
|
| 13 |
dreamwall.use:
|
|
|
|
| 7 |
commands:
|
| 8 |
dreamwall:
|
| 9 |
description: Show or test the DreamWall Space bridge.
|
| 10 |
+
usage: /dreamwall [fetch|demo|import]
|
| 11 |
permission: dreamwall.use
|
| 12 |
permissions:
|
| 13 |
dreamwall.use:
|