From 0a6122efbbdea974d963e167db1d660c81ea16e7 Mon Sep 17 00:00:00 2001 From: metamuffin Date: Mon, 17 Oct 2022 22:17:24 +0200 Subject: a --- .gitignore | 1 + src/dimension.rs | 21 ++++++++++-------- src/main.rs | 8 +++++-- src/render/mod.rs | 2 +- src/tiling.rs | 27 +++++++++++++++++++++++ src/viewer/mod.rs | 59 ++++++++++++++++++++++++++++++++++++-------------- src/viewer/viewer.html | 38 ++++++++++++++++++++++++++++++++ src/viewer/viewer.js | 8 +++++++ 8 files changed, 136 insertions(+), 28 deletions(-) create mode 100644 src/tiling.rs create mode 100644 src/viewer/viewer.html create mode 100644 src/viewer/viewer.js 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 = reg - .read_chunk(cx.rem_euclid(32) as usize, cz.rem_euclid(32) as usize) - .ok() + let chunk: Option = 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 { 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 { + 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))); - - // 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; + .and(tiler.clone()) + .and_then(|z, x, y, tiler: Arc| 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 router: _ = tiles + .or(viewer_html) + .or(viewer_js) + .recover(handle_rejection); warp::serve(router).run(bind).await; }) } + +async fn handle_rejection(err: Rejection) -> Result { + let code; + let message; + if err.is_not_found() { + code = StatusCode::NOT_FOUND; + message = "Not found"; + } else if let Some(_) = err.find::() { + 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 @@ + + + + + + + + + + trash-map + + + +
+ + + 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); -- cgit v1.2.3-70-g09d2