diff --git a/cmd/kartograph-map-generator/main.go b/cmd/kartograph-map-generator/main.go index de699b4..9d0379a 100644 --- a/cmd/kartograph-map-generator/main.go +++ b/cmd/kartograph-map-generator/main.go @@ -2,49 +2,59 @@ package main import ( "f00860/kartograph-map-editor/pkg/generator" + "f00860/kartograph-map-editor/pkg/web" "flag" "fmt" + "time" ) var ( - format string + startWebserver bool + address string + port int - size int + output string + world generator.World + seed string + size int wastelands int mountains int ruins int - - filename string ) func main() { - world := generator.New(size, wastelands, mountains, ruins) + if startWebserver { + web.Start(address, port) + return + } - switch format { + world := generator.New(size, wastelands, mountains, ruins, seed) + + switch output { case "svg": - fmt.Print(world.SVG()) + fmt.Printf("%s", world.SVG()) case "ascii": - fmt.Print(world.Plot()) + fmt.Printf("%s", world.Plot()) case "json": - fmt.Print(world.JSON()) - case "pdf": - world.PDF(filename) - case "web": - panic("Not implemented yet") + fmt.Printf("%s", world.JSON()) + default: + fmt.Printf("Output format '%v' not supported", output) } } func init() { - flag.StringVar(&format, "format", "svg", "Output format (ascii, json, svg, pdf, web)") + flag.BoolVar(&startWebserver, "web", false, "Spawn a webserver") + flag.StringVar(&address, "address", "0.0.0.0", "IP to bin the service to") + flag.IntVar(&port, "port", 80, "Port to bind the service to") - flag.IntVar(&size, "size", 11, "The size of the map") + flag.StringVar(&output, "output", "svg", "Output format (svg, ascii, json)") + flag.StringVar(&seed, "seed", time.Now().String(), "A seed string for the map generation") - flag.IntVar(&wastelands, "wastelands", 7, "Number of wastelands") - flag.IntVar(&mountains, "mountains", 5, "Number of mountains") - flag.IntVar(&ruins, "ruins", 6, "Number of ruins") - - flag.StringVar(&filename, "filename", "map.pdf", "The PDF filename") + flag.IntVar(&size, "size", 11, "The map size") + flag.IntVar(&wastelands, "wastelands", 7, "Number of wastelands to generate") + flag.IntVar(&mountains, "mountains", 5, "Number of mountains ot generate") + flag.IntVar(&ruins, "ruins", 6, "Number of ruins to generate") flag.Parse() } diff --git a/go.mod b/go.mod index 0056075..5579bf4 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module f00860/kartograph-map-editor -go 1.15 +go 1.16 require ( github.com/ajstarks/svgo v0.0.0-20200725142600-7a3c8b57fecb diff --git a/pkg/generator/pdf.go b/pkg/generator/pdf.go index 20e33bd..e65fc60 100644 --- a/pkg/generator/pdf.go +++ b/pkg/generator/pdf.go @@ -1,12 +1,7 @@ package generator -import ( - "github.com/jung-kurt/gofpdf" -) +import () -func (w World) PDF(filename string) { - pdf := gofpdf.New("P", "mm", "A4", "") - pdf.AddPage() +func (w World) PDF() { - pdf.OutputFileAndClose(filename) } diff --git a/pkg/generator/svg.go b/pkg/generator/svg.go index d05ec84..1f3df5f 100644 --- a/pkg/generator/svg.go +++ b/pkg/generator/svg.go @@ -52,7 +52,7 @@ func (w World) SVG() string { x, y := w.ToXY(pos) switch tile.Territory { case RuinsTerritory: - canvas.Text(hPadding+x*gridsize+3, vPadding+(y*gridsize)+16, "R", "stroke:lightgrey;fill:lightgrey") + canvas.Text(hPadding+x*gridsize+3, vPadding+(y*gridsize)+16, "R", "stroke:black;fill:black") case MountainTerritory: canvas.Rect(hPadding+x*gridsize, vPadding+y*gridsize, gridsize, gridsize, "fill:white; stroke:black") canvas.Circle(hPadding+x*gridsize+gridsize/2, vPadding+y*gridsize+gridsize/2, gridsize/2-8, "fill:white; stroke:black") diff --git a/pkg/generator/world.go b/pkg/generator/world.go index cca2130..de7ecca 100644 --- a/pkg/generator/world.go +++ b/pkg/generator/world.go @@ -1,12 +1,14 @@ package generator import ( + "crypto/md5" + "encoding/binary" "encoding/json" "errors" "fmt" + "io" "math" "math/rand" - "time" ) type TerritoryType int @@ -67,6 +69,7 @@ type World struct { Mountains int `json:"mountains"` World []Tile `json:"tiles"` + Seed int } func (w World) Plot() string { @@ -92,8 +95,12 @@ func (w World) ExportToPDF(filename string) error { return nil } -func New(size int, numWastelands int, numMountains int, numRuins int) World { - rand.Seed(time.Now().UnixNano()) +func New(size int, numWastelands int, numMountains int, numRuins int, seed string) World { + // Fix seed + h := md5.New() + io.WriteString(h, seed) + var intSeed uint64 = binary.BigEndian.Uint64(h.Sum(nil)) + rand.Seed(int64(intSeed)) w := World{ Size: size, diff --git a/pkg/web/service.go b/pkg/web/service.go new file mode 100644 index 0000000..2e1a75d --- /dev/null +++ b/pkg/web/service.go @@ -0,0 +1,74 @@ +package web + +import ( + "embed" + "f00860/kartograph-map-editor/pkg/generator" + "html/template" + "io" + "log" + "net/http" + "strconv" + "time" +) + +//go:embed templates +var templateFiles embed.FS + +//go:embed static +var staticFiles embed.FS + +func Start(address string, port int) { + http.Handle("/static/", http.FileServer(http.FS(staticFiles))) + http.HandleFunc("/", indexHandler) + http.HandleFunc("/map.svg", mapHandler) + + addr := address + ":" + strconv.Itoa(port) + + log.Printf("Server started on %v ...", addr) + err := http.ListenAndServe(addr, nil) + + if err != nil { + log.Fatal(err) + } +} + +func mapHandler(w http.ResponseWriter, req *http.Request) { + size, err := strconv.Atoi(req.URL.Query().Get("size")) + if err != nil { + size = 11 + } + seed := req.URL.Query().Get("seed") + if seed == "" { + seed = time.Now().String() + } + wastelands, err := strconv.Atoi(req.URL.Query().Get("wastelands")) + if err != nil { + wastelands = 7 + } + mountains, err := strconv.Atoi(req.URL.Query().Get("mountains")) + if err != nil { + mountains = 5 + } + ruins, err := strconv.Atoi(req.URL.Query().Get("ruins")) + if err != nil { + ruins = 6 + } + + world := generator.New(size, wastelands, mountains, ruins, seed) + + log.Printf("GET /map.svg?%v (%v)", req.URL.Query().Encode(), req.RemoteAddr) + w.Header().Set("Content-Type", "image/svg+xml") + w.Header().Set("Content-Length", strconv.Itoa(len(world.SVG()))) + io.WriteString(w, world.SVG()) +} + +func indexHandler(w http.ResponseWriter, req *http.Request) { + log.Printf("GET / (%v)", req.RemoteAddr) + + tpl, err := template.ParseFS(templateFiles, "templates/index.tpl.html") + if err != nil { + log.Fatal(err) + } + + tpl.Execute(w, nil) +} diff --git a/pkg/web/static/images/logo.jpg b/pkg/web/static/images/logo.jpg new file mode 100644 index 0000000..3b199ba Binary files /dev/null and b/pkg/web/static/images/logo.jpg differ diff --git a/pkg/web/static/styles.css b/pkg/web/static/styles.css new file mode 100644 index 0000000..4c73365 --- /dev/null +++ b/pkg/web/static/styles.css @@ -0,0 +1,10 @@ +p > img { + float: right; + width: 250px; +} + +.map { + margin: auto; + display: block; + width: 350px; +} diff --git a/pkg/web/templates/index.tpl.html b/pkg/web/templates/index.tpl.html new file mode 100644 index 0000000..2483e9d --- /dev/null +++ b/pkg/web/templates/index.tpl.html @@ -0,0 +1,24 @@ + + + + + + Map Generator für "Der Kartograph" + + + + + +

Map Generator für "Der Kartograph"

+

+ Wem der beigelegte Block zu eintönig wird oder schon leergespielt hat, kann sich + entweder die Mini-Erweiterung kaufen, in dem ein weiterer Block enthalten ist, + oder aber diesen Generator nutzen, um sich zufällige Maps generieren zu lassen. + Die generierten Karten entsprechen den erweiterten Regeln, können aber für etwas + mehr Spaß angepasst werden.

+ + Neue Map generieren +

+ + +