@ -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 <t@txmn.tk> (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 < String > ,
}
#[ 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 ::Config > ,
config : Arc < Args > ,
) -> 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 < RwLock < HashMap < ( i32 , i32 , i32 ) , Sender < ( ) > > > > ,
config : Arc < config ::Config > ,
config : Arc < Args > ,
) -> 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 < RwLock < HashMap < ( i32 , i32 , i32 ) , Sender < ( ) > > > > ,
config : Arc < config ::Config > ,
config : Arc < Args > ,
) -> Result < String , Error > {
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 < RwLock < HashMap < ( i32 , i32 , i32 ) , Sender < ( ) > > > > ,
config : Arc < config ::Config > ,
config : Arc < Args > ,
) -> Result < Vec < u8 > , 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 < RwLock < HashMap < ( i32 , i32 , i32 ) , Sender < ( ) > > > > ,
config : Arc < config ::Config > ,
config : Arc < Args > ,
) -> tide ::Result {
let z : i32 = req . param ( "z" ) ? . parse ( ) ? ;