diff options
author | metamuffin <metamuffin@disroot.org> | 2022-10-17 22:17:24 +0200 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2022-10-17 22:17:24 +0200 |
commit | 0a6122efbbdea974d963e167db1d660c81ea16e7 (patch) | |
tree | 36bce185bc5b7e718e508dab44f3a5fb11459bfa | |
parent | bcfc5827a949172aedbd6c7cd1881a47db42c46d (diff) | |
download | trash-map-0a6122efbbdea974d963e167db1d660c81ea16e7.tar trash-map-0a6122efbbdea974d963e167db1d660c81ea16e7.tar.bz2 trash-map-0a6122efbbdea974d963e167db1d660c81ea16e7.tar.zst |
a
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | src/dimension.rs | 21 | ||||
-rw-r--r-- | src/main.rs | 8 | ||||
-rw-r--r-- | src/render/mod.rs | 2 | ||||
-rw-r--r-- | src/tiling.rs | 27 | ||||
-rw-r--r-- | src/viewer/mod.rs | 57 | ||||
-rw-r--r-- | src/viewer/viewer.html | 38 | ||||
-rw-r--r-- | src/viewer/viewer.js | 8 |
8 files changed, 135 insertions, 27 deletions
@@ -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); |