aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2022-10-17 22:17:24 +0200
committermetamuffin <metamuffin@disroot.org>2022-10-17 22:17:24 +0200
commit0a6122efbbdea974d963e167db1d660c81ea16e7 (patch)
tree36bce185bc5b7e718e508dab44f3a5fb11459bfa
parentbcfc5827a949172aedbd6c7cd1881a47db42c46d (diff)
downloadtrash-map-0a6122efbbdea974d963e167db1d660c81ea16e7.tar
trash-map-0a6122efbbdea974d963e167db1d660c81ea16e7.tar.bz2
trash-map-0a6122efbbdea974d963e167db1d660c81ea16e7.tar.zst
a
-rw-r--r--.gitignore1
-rw-r--r--src/dimension.rs21
-rw-r--r--src/main.rs8
-rw-r--r--src/render/mod.rs2
-rw-r--r--src/tiling.rs27
-rw-r--r--src/viewer/mod.rs57
-rw-r--r--src/viewer/viewer.html38
-rw-r--r--src/viewer/viewer.js8
8 files changed, 135 insertions, 27 deletions
diff --git a/.gitignore b/.gitignore
index 85ef3d0..485ab96 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
/target
/assets
+/tiles
diff --git a/src/dimension.rs b/src/dimension.rs
index 6c3bea8..0f8ac3e 100644
--- a/src/dimension.rs
+++ b/src/dimension.rs
@@ -1,7 +1,7 @@
use chashmap::{CHashMap, ReadGuard, WriteGuard};
use fastanvil::{Block, Chunk, CurrentJavaChunk, Region, RegionFileLoader, RegionLoader};
use log::{debug, info};
-use std::{fs::File, path::Path};
+use std::{fs::File, path::PathBuf};
pub struct Dimension {
loader: RegionFileLoader,
@@ -10,8 +10,8 @@ pub struct Dimension {
}
impl Dimension {
- pub fn new(path: &str) -> Self {
- let loader = fastanvil::RegionFileLoader::new(Path::new(path).to_path_buf());
+ pub fn new(path: PathBuf) -> Self {
+ let loader = fastanvil::RegionFileLoader::new(path);
Self {
loader,
regions: Default::default(),
@@ -36,7 +36,7 @@ impl Dimension {
self.region(rx, rz)
}
}
-
+
pub fn chunk(
&self,
cx: isize,
@@ -46,11 +46,14 @@ impl Dimension {
self.chunks.get(&(cx, cz)).unwrap()
} else {
let mut guard = self.region(cx / 32, cz / 32);
- let reg = guard.as_mut().unwrap();
debug!("loading chunk {:?}", (cx, cz));
- let chunk: Option<CurrentJavaChunk> = reg
- .read_chunk(cx.rem_euclid(32) as usize, cz.rem_euclid(32) as usize)
- .ok()
+ let chunk: Option<CurrentJavaChunk> = guard
+ .as_mut()
+ .map(|c| {
+ c.read_chunk(cx.rem_euclid(32) as usize, cz.rem_euclid(32) as usize)
+ .ok()
+ })
+ .flatten()
.flatten()
.map(|chunk| fastnbt::from_bytes(&chunk).ok())
.flatten();
@@ -58,7 +61,7 @@ impl Dimension {
self.chunk(cx, cz)
}
}
-
+
pub fn block(&self, x: isize, y: isize, z: isize) -> Option<Block> {
self.chunk(x / 16, z / 16)
.as_ref()?
diff --git a/src/main.rs b/src/main.rs
index ce1906e..e824826 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,8 +1,10 @@
pub mod dimension;
pub mod render;
+pub mod tiling;
pub mod viewer;
use clap::{Parser, Subcommand};
+use dimension::Dimension;
use std::{net::SocketAddr, path::PathBuf};
use viewer::serve_http;
@@ -26,13 +28,15 @@ enum Action {
fn main() {
env_logger::builder()
- .filter_level(log::LevelFilter::Debug)
+ .filter_level(log::LevelFilter::Info)
.parse_env("LOG")
.init();
let args = Args::parse();
+ let dimension = Dimension::new(args.dimension);
+
match args.action {
- Action::Serve { bind } => serve_http(bind),
+ Action::Serve { bind } => serve_http(dimension, bind),
}
}
diff --git a/src/render/mod.rs b/src/render/mod.rs
index 9a5bd2d..811684f 100644
--- a/src/render/mod.rs
+++ b/src/render/mod.rs
@@ -17,7 +17,7 @@ pub mod composite;
pub mod models;
pub mod processing;
-const SEG_SIZE: isize = 128;
+const SEG_SIZE: isize = 64;
const BLOCK_NAMESPACE_LEN: usize = "minecraft:".len();
pub struct Renderer {
diff --git a/src/tiling.rs b/src/tiling.rs
new file mode 100644
index 0000000..8ab7fc3
--- /dev/null
+++ b/src/tiling.rs
@@ -0,0 +1,27 @@
+use std::{fs::File, io::Read};
+
+use log::info;
+
+use crate::render::Renderer;
+
+pub struct Tiler {
+ renderer: Renderer,
+}
+
+impl Tiler {
+ pub fn new(renderer: Renderer) -> Self {
+ Self { renderer }
+ }
+ pub fn get_tile(&self, z: isize, x: isize, y: isize) -> Vec<u8> {
+ info!("generating tile (zoom={z}, x={x}, y={z})");
+ let segment = self.renderer.render_segment(x, y);
+ segment
+ .save(format!("tiles/{},{},{}.png", z, x, y))
+ .unwrap();
+
+ let mut f = File::open(format!("tiles/{},{},{}.png", z, x, y)).unwrap();
+ let mut buf = Vec::new();
+ f.read_to_end(&mut buf).unwrap();
+ buf
+ }
+}
diff --git a/src/viewer/mod.rs b/src/viewer/mod.rs
index 6ea540b..a411c29 100644
--- a/src/viewer/mod.rs
+++ b/src/viewer/mod.rs
@@ -1,28 +1,55 @@
-use std::net::SocketAddr;
+use std::{convert::Infallible, net::SocketAddr, sync::Arc};
-use warp::Filter;
+use warp::{hyper::StatusCode, Filter, Rejection, Reply};
-pub fn serve_http(bind: SocketAddr) {
+use crate::{dimension::Dimension, render::Renderer, tiling::Tiler};
+
+pub fn serve_http(dimension: Dimension, bind: SocketAddr) {
tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.unwrap()
.block_on(async move {
+ let renderer = Renderer::new(dimension);
+ let tiler = Arc::new(Tiler::new(renderer));
+ let tiler: _ = warp::any().map(move || tiler.clone());
+
let tiles = warp::path!("tiles" / isize / isize / isize)
- .map(|z, x, y| format!("blub {:?}", (x, y, z)));
+ .and(tiler.clone())
+ .and_then(|z, x, y, tiler: Arc<Tiler>| async move {
+ Ok::<_, Infallible>(warp::reply::with_header(
+ tiler.get_tile(z, x, y),
+ "content-type",
+ "image/png",
+ ))
+ });
+
+ let viewer_html: _ = warp::path!().and(warp::fs::file("./src/viewer/viewer.html"));
+ let viewer_js: _ =
+ warp::path!("viewer.js").and(warp::fs::file("./src/viewer/viewer.js"));
- // let dim =
- // Dimension::new("/home/muffin/containers/games/home/user/server/world/region/");
- // let renderer = Renderer::new(dim);
- // for sx in 0..2 {
- // for sy in 0..2 {
- // let view = renderer.render_segment(sx, sy);
- // info!("saving png");
- // view.save(format!("/tmp/seg.{sx}.{sy}.png")).unwrap();
- // }
- // }
- let router = tiles;
+ let router: _ = tiles
+ .or(viewer_html)
+ .or(viewer_js)
+ .recover(handle_rejection);
warp::serve(router).run(bind).await;
})
}
+
+async fn handle_rejection(err: Rejection) -> Result<impl Reply, Infallible> {
+ let code;
+ let message;
+ if err.is_not_found() {
+ code = StatusCode::NOT_FOUND;
+ message = "Not found";
+ } else if let Some(_) = err.find::<warp::reject::MethodNotAllowed>() {
+ code = StatusCode::METHOD_NOT_ALLOWED;
+ message = "Method not allowed";
+ } else {
+ eprintln!("unhandled rejection: {:?}", err);
+ code = StatusCode::INTERNAL_SERVER_ERROR;
+ message = "Unhandled rejection :(";
+ }
+ Ok(warp::reply::with_status(message, code))
+}
diff --git a/src/viewer/viewer.html b/src/viewer/viewer.html
new file mode 100644
index 0000000..f78e469
--- /dev/null
+++ b/src/viewer/viewer.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="UTF-8" />
+ <meta http-equiv="X-UA-Compatible" content="IE=edge" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <link
+ rel="stylesheet"
+ href="https://unpkg.com/leaflet@1.9.2/dist/leaflet.css"
+ integrity="sha256-sA+zWATbFveLLNqWO2gtiw3HL/lh1giY/Inf1BJ0z14="
+ crossorigin=""
+ />
+ <script
+ src="https://unpkg.com/leaflet@1.9.2/dist/leaflet.js"
+ integrity="sha256-o9N1jGDZrf5tS+Ft4gbIK7mYMipq9lqpVJ91xHSyKhg="
+ crossorigin=""
+ ></script>
+ <style>
+ * {
+ padding: 0px;
+ margin: 0px;
+ }
+ #map {
+ width: 100vw;
+ height: 100vh;
+ }
+ </style>
+ <title>trash-map</title>
+ </head>
+ <body>
+ <noscript>
+ trash-map requires javascript. if really dont want to use js: point
+ your map viewer to /tiles/{z}/{x}/{y}
+ </noscript>
+ <div id="map"></div>
+ <script src="/viewer.js"></script>
+ </body>
+</html>
diff --git a/src/viewer/viewer.js b/src/viewer/viewer.js
new file mode 100644
index 0000000..bef6f74
--- /dev/null
+++ b/src/viewer/viewer.js
@@ -0,0 +1,8 @@
+
+const map = L.map('map').setView([0, 0], 13);
+
+L.tileLayer('/tiles/{z}/{x}/{y}', {
+ maxZoom: 13,
+ minZoom: 13,
+ attribution: 'trash-map'
+}).addTo(map);