diff --git a/README.md b/README.md
index 0a8cf2e..1a5768a 100644
--- a/README.md
+++ b/README.md
@@ -8,6 +8,12 @@ The output can be used with [Leaflet](https://leafletjs.com/).
## Use
+Choose the strategy you prefer between complete periodic generation and cached on-demand generation:
+
+### Python generator
+
+Runs minetestmapper once for a given part of the map. You can run it with cron. You also need an external webserver (e.g. Apache, Nginx) to serve the generated tiles.
+
Dependencies:
* [Python3](https://www.python.org/)
@@ -17,12 +23,34 @@ Dependencies:
Edit the settings in `mtmapper.py` according to your configuration.
-```
+```bash
python3 mtmapper.py
```
Depending on the world and the settings (number of zoom levels, number of blocks), it may take a while.
+### Rust mapserver
+
+A program that runs minetestserver automatically and serves cached tiles through an included webserver. You can run it as a daemon.
+
+Dependencies:
+
+* [Rust](https://rustup.rs/) (minimal toolchain is enough) (for building only)
+* [minetestmapper](https://github.com/minetest/minetestmapper)
+* [Colors.txt](https://github.com/MilesBDyson/Colors.txt) (optional -- more complete colorset)
+
+```bash
+cd mapserver
+cargo build --release
+./target/release/mapserver --help
+# Example with arguments:
+./target/release/mapserver -w /var/games/minetest-server/.minetest/worlds/juneland-survival/ -p /home/tuxmain/minetestmapper/minetestmapper -- --drawalpha --max-y 2000 --colors /home/tuxmain/Colors.txt/colors.txt
+```
+
+### Web interface
+
+Both generation methods need a webpage(can be served by a webserver like Apache, Nginx):
+
Edit `index.html` (change the tiles URL, title, attribution and points of interest).
You can keep my server as a CDN for Leaflet, but it's preferable to host your own copy of Leaflet.
diff --git a/index.html b/index.html
index 935051d..f4b48a6 100644
--- a/index.html
+++ b/index.html
@@ -58,7 +58,7 @@ function onMapClick(e) {
map.on('click', onMapClick);
L.control.layers({
- "Juneland Survival": L.tileLayer(MAP_TILES, {attribution: "CC BY-SA Juneland Players"}).addTo(map)
+ "Juneland Survival": L.tileLayer(MAP_TILES, {attribution: 'minetest-tiler | CC BY-SA Juneland Players'}).addTo(map)
}, {
"Points d'intérêt": L.layerGroup(points).addTo(map)
}).addTo(map);
diff --git a/mapserver/Cargo.lock b/mapserver/Cargo.lock
index 604000c..7292d3f 100644
--- a/mapserver/Cargo.lock
+++ b/mapserver/Cargo.lock
@@ -447,6 +447,33 @@ dependencies = [
]
[[package]]
+name = "clap"
+version = "3.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d76c22c9b9b215eeb8d016ad3a90417bd13cb24cf8142756e6472445876cab7"
+dependencies = [
+ "bitflags",
+ "clap_derive",
+ "indexmap",
+ "lazy_static",
+ "os_str_bytes",
+ "textwrap",
+]
+
+[[package]]
+name = "clap_derive"
+version = "3.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5fd1122e63869df2cb309f449da1ad54a7c6dfeb7c7e6ccd8e0825d9eb93bb72"
+dependencies = [
+ "heck",
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
name = "color_quant"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -602,6 +629,26 @@ dependencies = [
]
[[package]]
+name = "directories"
+version = "4.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f51c5d4ddabd36886dd3e1438cb358cdcb0d7c499cb99cb4ac2e38e18b5cb210"
+dependencies = [
+ "dirs-sys",
+]
+
+[[package]]
+name = "dirs-sys"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780"
+dependencies = [
+ "libc",
+ "redox_users",
+ "winapi",
+]
+
+[[package]]
name = "discard"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -770,6 +817,18 @@ dependencies = [
]
[[package]]
+name = "hashbrown"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
+
+[[package]]
+name = "heck"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
+
+[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -876,6 +935,16 @@ dependencies = [
]
[[package]]
+name = "indexmap"
+version = "1.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223"
+dependencies = [
+ "autocfg",
+ "hashbrown",
+]
+
+[[package]]
name = "infer"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -950,7 +1019,9 @@ name = "mapserver"
version = "0.1.0"
dependencies = [
"async-std",
+ "clap",
"crossbeam-channel",
+ "directories",
"http-types",
"image",
"log",
@@ -1045,6 +1116,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]]
+name = "os_str_bytes"
+version = "6.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
name = "parking"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1160,6 +1240,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
[[package]]
+name = "proc-macro-error"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
+dependencies = [
+ "proc-macro-error-attr",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro-error-attr"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "version_check",
+]
+
+[[package]]
name = "proc-macro-hack"
version = "0.5.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1264,6 +1368,16 @@ dependencies = [
]
[[package]]
+name = "redox_users"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64"
+dependencies = [
+ "getrandom 0.2.4",
+ "redox_syscall",
+]
+
+[[package]]
name = "route-recognizer"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1539,6 +1653,12 @@ dependencies = [
]
[[package]]
+name = "textwrap"
+version = "0.14.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80"
+
+[[package]]
name = "thiserror"
version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/mapserver/Cargo.toml b/mapserver/Cargo.toml
index a67520e..ea7eb75 100644
--- a/mapserver/Cargo.toml
+++ b/mapserver/Cargo.toml
@@ -5,7 +5,9 @@ edition = "2021"
[dependencies]
async-std = { version = "1.6.5", features = ["attributes"] }
+clap = { version = "3.1.1", default-features = false, features = ["derive", "std"] }
crossbeam-channel = "0.5.2"
+directories = "4.0.0"
http-types = "2.12.0"
image = { version = "0.24.1", default-features = false, features = ["png"] }
log = "0.4.14"
diff --git a/mapserver/src/config.rs b/mapserver/src/config.rs
deleted file mode 100644
index ee8b12a..0000000
--- a/mapserver/src/config.rs
+++ /dev/null
@@ -1,44 +0,0 @@
-// TODO x,y bounds
-pub struct Config {
- /// Must start and end with `/`
- pub base_url: String,
- pub cache_age: u64,
- pub listen: String,
- pub mapper_threads: usize,
- pub minetestmapper_args: Vec,
- pub minetestmapper_path: String,
- /// Should end with `/`
- pub output_path: String,
- pub tile_size: usize,
- pub world_path: String,
- pub zoom_default: i32,
- pub zoom_max: i32,
- pub zoom_min: i32,
-}
-
-impl Default for Config {
- fn default() -> Self {
- Self {
- base_url: String::from("/"),
- cache_age: 86400,
- listen: String::from("127.0.0.1:8080"),
- mapper_threads: 4,
- minetestmapper_args: vec![
- String::from("--drawalpha"),
- String::from("--max-y"),
- String::from("2000"),
- String::from("--colors"),
- String::from("/home/tuxmain/Colors.txt/colors.txt"),
- ],
- minetestmapper_path: String::from("/home/tuxmain/minetestmapper/minetestmapper"),
- output_path: String::from("/var/www/html/minetest-map/survival/"),
- tile_size: 256,
- world_path: String::from(
- "/var/games/minetest-server/.minetest/worlds/juneland-survival/",
- ),
- zoom_default: 7,
- zoom_max: 10,
- zoom_min: 4,
- }
- }
-}
diff --git a/mapserver/src/main.rs b/mapserver/src/main.rs
index 96c86a1..4696e03 100644
--- a/mapserver/src/main.rs
+++ b/mapserver/src/main.rs
@@ -1,13 +1,70 @@
#![feature(try_blocks)]
-mod config;
+//mod config;
+use clap::Parser;
use crossbeam_channel::Sender;
-use log::{debug, error, warn};
+use log::{debug, error, info, warn};
use parking_lot::RwLock;
use std::{collections::HashMap, io::Read, sync::Arc, time::SystemTime};
use tide::Request;
+fn get_cache_dir() -> String {
+ let dir = directories::ProjectDirs::from("tk", "txmn", "minetest-tiler").map_or_else(
+ String::new,
+ |o| {
+ o.cache_dir()
+ .to_str()
+ .map_or_else(String::new, String::from)
+ },
+ );
+ if dir.ends_with('/') {
+ dir
+ } else {
+ format!("{}/", dir)
+ }
+}
+
+#[derive(Parser, Debug)]
+#[clap(
+ author = "tuxmain (GNU AGPLv3)",
+ about = "Map generator & server for MineTest"
+)]
+struct Args {
+ /// Must start and end with `/`
+ #[clap(short = 'b', long, default_value = "/")]
+ base_url: String,
+ /// Cache duration in seconds
+ #[clap(short = 'c', long, default_value_t = 86400)]
+ cache_age: u64,
+ /// Address to listen to
+ #[clap(short = 'l', long, default_value = "0.0.0.0:30800")]
+ listen: String,
+ /// Directory that will contain the map (should end with `/`)
+ #[clap(short='o', long, default_value_t=get_cache_dir())]
+ output_path: String,
+ /// World directory
+ #[clap(
+ short = 'w',
+ long,
+ default_value = "/var/games/minetest-server/.minetest/world/world/"
+ )]
+ world_path: String,
+ #[clap(short = 'z', long, default_value_t = 7)]
+ zoom_default: i32,
+ #[clap(short = 'm', long, default_value_t = 4)]
+ zoom_min: i32,
+ #[clap(short = 'M', long, default_value_t = 10)]
+ zoom_max: i32,
+ #[clap(short = 's', long, default_value_t = 256)]
+ tile_size: usize,
+ /// Path to minetestmapper executable
+ #[clap(short = 'p', long, default_value = "minetestmapper")]
+ minetestmapper_path: String,
+ #[clap(last = true)]
+ minetestmapper_args: Vec,
+}
+
#[derive(Debug)]
enum Error {
Image(image::ImageError),
@@ -17,6 +74,8 @@ enum Error {
#[async_std::main]
async fn main() -> tide::Result<()> {
+ let config = Args::parse();
+
simplelog::TermLogger::init(
simplelog::LevelFilter::Info,
simplelog::Config::default(),
@@ -25,7 +84,7 @@ async fn main() -> tide::Result<()> {
)
.unwrap();
- let config = config::Config::default();
+ info!("Output dir: {}", config.output_path);
assert!(
config.base_url.starts_with('/') && config.base_url.ends_with('/'),
"`base_url` must start and end with `/`"
@@ -50,7 +109,7 @@ fn run_minetestmapper(
y: i32,
tile_dir: &str,
tile_path: &str,
- config: Arc,
+ config: Arc,
) -> Result<(), Error> {
debug!("Generating tile ({},{},{})", z, x, y);
std::fs::create_dir_all(tile_dir).map_err(|e| {
@@ -97,7 +156,7 @@ fn generate_tile(
tile_dir: &str,
tile_path: &str,
tasks: Arc>>>,
- config: Arc,
+ config: Arc,
) -> Result<(), Error> {
let mut generate = true;
loop {
@@ -195,8 +254,13 @@ fn generate_tile(
})?;
}
std::cmp::Ordering::Greater => {
- let ntile_path =
- get_dep_tile(z - 1, lock_coord.1 / 2, lock_coord.2 / 2, tasks.clone(), config.clone())?;
+ let ntile_path = get_dep_tile(
+ z - 1,
+ lock_coord.1 / 2,
+ lock_coord.2 / 2,
+ tasks.clone(),
+ config.clone(),
+ )?;
let ntile = image::open(ntile_path).map_err(Error::Image)?;
let ntile = image::imageops::resize(
&ntile,
@@ -310,7 +374,7 @@ fn get_dep_tile(
x: i32,
y: i32,
tasks: Arc>>>,
- config: Arc,
+ config: Arc,
) -> Result {
let tile_dir = format!("{}{}/{}", config.output_path, z, x);
let tile_path = format!("{}/{}.png", tile_dir, y);
@@ -350,7 +414,7 @@ fn resp_tile(
tile_dir: &str,
tile_path: &str,
tasks: Arc>>>,
- config: Arc,
+ config: Arc,
) -> Result, Error> {
generate_tile(z, x, y, tile_dir, tile_path, tasks, config)?;
read_tile_file(tile_path)
@@ -359,7 +423,7 @@ fn resp_tile(
async fn req_tile(
req: Request<()>,
tasks: Arc>>>,
- config: Arc,
+ config: Arc,
) -> tide::Result {
let z: i32 = req.param("z")?.parse()?;