map
This commit is contained in:
parent
001f398137
commit
9f38f9b17d
|
@ -5,4 +5,5 @@ legendsbrowser
|
||||||
*.png
|
*.png
|
||||||
/*.json
|
/*.json
|
||||||
.DS_Store
|
.DS_Store
|
||||||
bin
|
bin
|
||||||
|
/inputs/*
|
|
@ -5,6 +5,36 @@
|
||||||
"df_world|historical_events|historical_event+KnowledgeDiscovered|knowledge": true
|
"df_world|historical_events|historical_event+KnowledgeDiscovered|knowledge": true
|
||||||
},
|
},
|
||||||
"AdditionalFields": {
|
"AdditionalFields": {
|
||||||
|
"DfWorld": [
|
||||||
|
{
|
||||||
|
"Name": "FilePath",
|
||||||
|
"Type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "PlusFilePath",
|
||||||
|
"Type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "MapReady",
|
||||||
|
"Type": "bool"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "MapData",
|
||||||
|
"Type": "[]byte"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "Width",
|
||||||
|
"Type": "int"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "Height",
|
||||||
|
"Type": "int"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "EndYear",
|
||||||
|
"Type": "int"
|
||||||
|
}
|
||||||
|
],
|
||||||
"Structure": [
|
"Structure": [
|
||||||
{
|
{
|
||||||
"Name": "SiteId",
|
"Name": "SiteId",
|
||||||
|
|
|
@ -10,6 +10,7 @@ require (
|
||||||
github.com/pkg/profile v1.6.0
|
github.com/pkg/profile v1.6.0
|
||||||
github.com/shirou/gopsutil v3.21.11+incompatible
|
github.com/shirou/gopsutil v3.21.11+incompatible
|
||||||
golang.org/x/exp v0.0.0-20220428152302-39d4317da171
|
golang.org/x/exp v0.0.0-20220428152302-39d4317da171
|
||||||
|
golang.org/x/image v0.0.0-20220413100746-70e8d0d3baa9
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
|
|
@ -29,9 +29,13 @@ github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPR
|
||||||
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||||
golang.org/x/exp v0.0.0-20220428152302-39d4317da171 h1:TfdoLivD44QwvssI9Sv1xwa5DcL5XQr4au4sZ2F2NV4=
|
golang.org/x/exp v0.0.0-20220428152302-39d4317da171 h1:TfdoLivD44QwvssI9Sv1xwa5DcL5XQr4au4sZ2F2NV4=
|
||||||
golang.org/x/exp v0.0.0-20220428152302-39d4317da171/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
|
golang.org/x/exp v0.0.0-20220428152302-39d4317da171/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
|
||||||
|
golang.org/x/image v0.0.0-20220413100746-70e8d0d3baa9 h1:LRtI4W37N+KFebI/qV0OFiLUv4GLOWeEW5hn/KEJvxE=
|
||||||
|
golang.org/x/image v0.0.0-20220413100746-70e8d0d3baa9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
|
||||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 h1:xHms4gcpe1YE7A3yIllJXP16CMAGuqwO2lX1mTyyRRc=
|
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 h1:xHms4gcpe1YE7A3yIllJXP16CMAGuqwO2lX1mTyyRRc=
|
||||||
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
|
|
@ -3,10 +3,9 @@ package main
|
||||||
import (
|
import (
|
||||||
"embed"
|
"embed"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
_ "net/http/pprof"
|
_ "net/http/pprof"
|
||||||
"os"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
"github.com/pkg/profile"
|
"github.com/pkg/profile"
|
||||||
|
@ -26,6 +25,8 @@ func main() {
|
||||||
|
|
||||||
templates.DebugTemplates = *d
|
templates.DebugTemplates = *d
|
||||||
|
|
||||||
|
var world *model.DfWorld
|
||||||
|
|
||||||
if len(*f) > 0 {
|
if len(*f) > 0 {
|
||||||
if *p {
|
if *p {
|
||||||
defer profile.Start(profile.ProfilePath(".")).Stop()
|
defer profile.Start(profile.ProfilePath(".")).Stop()
|
||||||
|
@ -36,14 +37,15 @@ func main() {
|
||||||
|
|
||||||
w, err := model.Parse(*f, nil)
|
w, err := model.Parse(*f, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
log.Fatal(err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
runtime.GC()
|
runtime.GC()
|
||||||
server.StartServer(w, static)
|
world = w
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
err := server.StartServer(world, static)
|
||||||
server.StartServer(nil, static)
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -23,6 +24,21 @@ var LinkMusicalForm = func(w *DfWorld, id int) template.HTML { return template.H
|
||||||
var LinkPoeticForm = func(w *DfWorld, id int) template.HTML { return template.HTML((&Context{World: w}).poeticForm(id)) }
|
var LinkPoeticForm = func(w *DfWorld, id int) template.HTML { return template.HTML((&Context{World: w}).poeticForm(id)) }
|
||||||
var LinkWrittenContent = func(w *DfWorld, id int) template.HTML { return template.HTML((&Context{World: w}).writtenContent(id)) }
|
var LinkWrittenContent = func(w *DfWorld, id int) template.HTML { return template.HTML((&Context{World: w}).writtenContent(id)) }
|
||||||
|
|
||||||
|
var AddMapSite = func(w *DfWorld, id int) template.HTML {
|
||||||
|
if site, ok := w.Sites[id]; ok {
|
||||||
|
coords := strings.Split(site.Rectangle, ":")
|
||||||
|
c1 := strings.Split(coords[0], ",")
|
||||||
|
x1, _ := strconv.ParseFloat(c1[0], 32)
|
||||||
|
y1, _ := strconv.ParseFloat(c1[1], 32)
|
||||||
|
c2 := strings.Split(coords[1], ",")
|
||||||
|
x2, _ := strconv.ParseFloat(c2[0], 32)
|
||||||
|
y2, _ := strconv.ParseFloat(c2[1], 32)
|
||||||
|
return template.HTML(fmt.Sprintf(`<script>addSite("%s", %f, %f, %f, %f, "#FF0", "")</script>`, site.Name(), x1/16.0, y1/16.0-1, x2/16.0, y2/16.0-1))
|
||||||
|
} else {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func andList(list []string) string {
|
func andList(list []string) string {
|
||||||
if len(list) > 1 {
|
if len(list) > 1 {
|
||||||
return strings.Join(list[:len(list)-1], ", ") + " and " + list[len(list)-1]
|
return strings.Join(list[:len(list)-1], ", ") + " and " + list[len(list)-1]
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"image"
|
||||||
|
"image/png"
|
||||||
|
_ "image/png"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
_ "golang.org/x/image/bmp"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (w *DfWorld) LoadMap() {
|
||||||
|
w.LoadDimensions()
|
||||||
|
|
||||||
|
path := ""
|
||||||
|
files, err := filepath.Glob(strings.ReplaceAll(w.FilePath, "-legends.xml", "-world_map.*"))
|
||||||
|
if err == nil && len(files) > 0 {
|
||||||
|
path = files[len(files)-1]
|
||||||
|
}
|
||||||
|
files, err = filepath.Glob(strings.ReplaceAll(w.FilePath, "-legends.xml", "-detailed.*"))
|
||||||
|
if err == nil && len(files) > 0 {
|
||||||
|
path = files[len(files)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
if path == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
mapImage, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Found Map", path)
|
||||||
|
img, format, err := image.Decode(mapImage)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Println("loaded img", format)
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
err = png.Encode(buf, img)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.MapData = buf.Bytes()
|
||||||
|
w.MapReady = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *DfWorld) LoadDimensions() {
|
||||||
|
files, err := filepath.Glob(filepath.Join(filepath.Dir(w.FilePath), "*-world_gen_param.txt"))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
path := ""
|
||||||
|
for _, f := range files {
|
||||||
|
prefix := filepath.Base(f)[:len(filepath.Base(f))-len("world_gen_param.txt")]
|
||||||
|
if strings.HasPrefix(filepath.Base(w.FilePath), prefix) {
|
||||||
|
path = f
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if path == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Found Worldgen", path)
|
||||||
|
|
||||||
|
content, err := ioutil.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
text := string(content)
|
||||||
|
fmt.Println(text)
|
||||||
|
|
||||||
|
r := regexp.MustCompile(`\[DIM:(\d+):(\d+)\]`)
|
||||||
|
result := r.FindAllStringSubmatch(text, 1)
|
||||||
|
if result == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.Width, _ = strconv.Atoi(result[0][2])
|
||||||
|
w.Height, _ = strconv.Atoi(result[0][1])
|
||||||
|
}
|
|
@ -1561,6 +1561,13 @@ type DfWorld struct {
|
||||||
UndergroundRegions map[int]*UndergroundRegion `json:"undergroundRegions" legend:"both"` // underground_regions
|
UndergroundRegions map[int]*UndergroundRegion `json:"undergroundRegions" legend:"both"` // underground_regions
|
||||||
WorldConstructions map[int]*WorldConstruction `json:"worldConstructions" legend:"both"` // world_constructions
|
WorldConstructions map[int]*WorldConstruction `json:"worldConstructions" legend:"both"` // world_constructions
|
||||||
WrittenContents map[int]*WrittenContent `json:"writtenContents" legend:"both"` // written_contents
|
WrittenContents map[int]*WrittenContent `json:"writtenContents" legend:"both"` // written_contents
|
||||||
|
EndYear int `json:"endYear" legend:"add"` // EndYear
|
||||||
|
FilePath string `json:"filePath" legend:"add"` // FilePath
|
||||||
|
Height int `json:"height" legend:"add"` // Height
|
||||||
|
MapData []byte `json:"mapData" legend:"add"` // MapData
|
||||||
|
MapReady bool `json:"mapReady" legend:"add"` // MapReady
|
||||||
|
PlusFilePath string `json:"plusFilePath" legend:"add"` // PlusFilePath
|
||||||
|
Width int `json:"width" legend:"add"` // Width
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDfWorld() *DfWorld {
|
func NewDfWorld() *DfWorld {
|
||||||
|
@ -1582,6 +1589,9 @@ func NewDfWorld() *DfWorld {
|
||||||
UndergroundRegions: make(map[int]*UndergroundRegion),
|
UndergroundRegions: make(map[int]*UndergroundRegion),
|
||||||
WorldConstructions: make(map[int]*WorldConstruction),
|
WorldConstructions: make(map[int]*WorldConstruction),
|
||||||
WrittenContents: make(map[int]*WrittenContent),
|
WrittenContents: make(map[int]*WrittenContent),
|
||||||
|
EndYear: -1,
|
||||||
|
Height: -1,
|
||||||
|
Width: -1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (x *DfWorld) Name() string { return x.Name_ }
|
func (x *DfWorld) Name() string { return x.Name_ }
|
||||||
|
|
|
@ -2,10 +2,8 @@ package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"encoding/json"
|
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -98,6 +96,7 @@ BaseLoop:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
world.FilePath = file
|
||||||
|
|
||||||
bar.Finish()
|
bar.Finish()
|
||||||
|
|
||||||
|
@ -133,15 +132,18 @@ BaseLoop:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
world.PlusFilePath = file
|
||||||
|
|
||||||
bar.Finish()
|
bar.Finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
same, err := json.MarshalIndent(exportSameFields(), "", " ")
|
// same, err := json.MarshalIndent(exportSameFields(), "", " ")
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return world, err
|
// return world, err
|
||||||
}
|
// }
|
||||||
ioutil.WriteFile("same.json", same, 0644)
|
// ioutil.WriteFile("same.json", same, 0644)
|
||||||
|
|
||||||
|
world.LoadMap()
|
||||||
|
|
||||||
world.process()
|
world.process()
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
LastPath string
|
||||||
|
LastFile string
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadConfig() (*Config, error) {
|
||||||
|
path, err := configPath()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := ioutil.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("OPEN", err)
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
fmt.Println("EX", err)
|
||||||
|
home, err := os.UserHomeDir()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Config{LastPath: home}, nil
|
||||||
|
} else {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c := &Config{}
|
||||||
|
json.Unmarshal(data, c)
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) Save() error {
|
||||||
|
path, err := configPath()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
file, err := json.MarshalIndent(c, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return ioutil.WriteFile(path, file, 0644)
|
||||||
|
}
|
||||||
|
|
||||||
|
func configPath() (string, error) {
|
||||||
|
path, err := os.UserHomeDir()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
path = filepath.Join(path, ".legendsbrowser")
|
||||||
|
os.MkdirAll(path, os.ModePerm)
|
||||||
|
|
||||||
|
return filepath.Join(path, "config.json"), nil
|
||||||
|
}
|
|
@ -63,7 +63,7 @@ func (h loadHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
Current: path,
|
Current: path,
|
||||||
}
|
}
|
||||||
if p.Current == "" {
|
if p.Current == "" {
|
||||||
p.Current = "."
|
p.Current = h.server.context.config.LastPath
|
||||||
}
|
}
|
||||||
var err error
|
var err error
|
||||||
p.Current, err = filepath.Abs(p.Current)
|
p.Current, err = filepath.Abs(p.Current)
|
||||||
|
@ -74,6 +74,9 @@ func (h loadHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
if f, err := os.Stat(p.Current); err == nil {
|
if f, err := os.Stat(p.Current); err == nil {
|
||||||
if f.IsDir() {
|
if f.IsDir() {
|
||||||
|
h.server.context.config.LastPath = p.Current
|
||||||
|
h.server.context.config.Save()
|
||||||
|
|
||||||
p.List, err = ioutil.ReadDir(p.Current)
|
p.List, err = ioutil.ReadDir(p.Current)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
httpError(w, err)
|
httpError(w, err)
|
||||||
|
|
|
@ -3,9 +3,7 @@ package server
|
||||||
import (
|
import (
|
||||||
"embed"
|
"embed"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/fs"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
@ -16,6 +14,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type DfServerContext struct {
|
type DfServerContext struct {
|
||||||
|
config *Config
|
||||||
world *model.DfWorld
|
world *model.DfWorld
|
||||||
isLoading bool
|
isLoading bool
|
||||||
progress *model.LoadProgress
|
progress *model.LoadProgress
|
||||||
|
@ -28,10 +27,16 @@ type DfServer struct {
|
||||||
context *DfServerContext
|
context *DfServerContext
|
||||||
}
|
}
|
||||||
|
|
||||||
func StartServer(world *model.DfWorld, static embed.FS) {
|
func StartServer(world *model.DfWorld, static embed.FS) error {
|
||||||
|
config, err := LoadConfig()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
srv := &DfServer{
|
srv := &DfServer{
|
||||||
router: mux.NewRouter().StrictSlash(true),
|
router: mux.NewRouter().StrictSlash(true),
|
||||||
context: &DfServerContext{
|
context: &DfServerContext{
|
||||||
|
config: config,
|
||||||
world: world,
|
world: world,
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
progress: &model.LoadProgress{},
|
progress: &model.LoadProgress{},
|
||||||
|
@ -99,6 +104,12 @@ func StartServer(world *model.DfWorld, static embed.FS) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
srv.router.HandleFunc("/map", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Set("Content-Type", "image/png")
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
w.Write(srv.loader.server.context.world.MapData)
|
||||||
|
})
|
||||||
|
|
||||||
srv.router.PathPrefix("/search").Handler(searchHandler{server: srv})
|
srv.router.PathPrefix("/search").Handler(searchHandler{server: srv})
|
||||||
|
|
||||||
srv.router.PathPrefix("/load").Handler(srv.loader)
|
srv.router.PathPrefix("/load").Handler(srv.loader)
|
||||||
|
@ -110,6 +121,7 @@ func StartServer(world *model.DfWorld, static embed.FS) {
|
||||||
|
|
||||||
fmt.Println("Serving at :8080")
|
fmt.Println("Serving at :8080")
|
||||||
http.ListenAndServe(":8080", srv.router)
|
http.ListenAndServe(":8080", srv.router)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *DfServer) findStructure(p Parms) any {
|
func (srv *DfServer) findStructure(p Parms) any {
|
||||||
|
@ -127,53 +139,6 @@ func (srv *DfServer) findStructure(p Parms) any {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type spaHandler struct {
|
|
||||||
server *DfServer
|
|
||||||
staticFS embed.FS
|
|
||||||
staticPath string
|
|
||||||
indexPath string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h spaHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
||||||
// get the absolute path to prevent directory traversal
|
|
||||||
path := r.URL.Path
|
|
||||||
// if err != nil {
|
|
||||||
// // if we failed to get the absolute path respond with a 400 bad request and stop
|
|
||||||
// http.Error(w, err.Error(), http.StatusBadRequest)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// prepend the path with the path to the static directory
|
|
||||||
path = h.staticPath + path
|
|
||||||
|
|
||||||
_, err := h.staticFS.Open(path)
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
// file does not exist, serve index.html
|
|
||||||
fmt.Println(path)
|
|
||||||
index, err := h.staticFS.ReadFile(h.staticPath + "/" + h.indexPath)
|
|
||||||
if err != nil {
|
|
||||||
h.server.notFound(w)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
|
||||||
w.WriteHeader(http.StatusAccepted)
|
|
||||||
w.Write(index)
|
|
||||||
return
|
|
||||||
} else if err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the subdirectory of the static dir
|
|
||||||
statics, err := fs.Sub(h.staticFS, h.staticPath)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// otherwise, use http.FileServer to serve the static dir
|
|
||||||
http.FileServer(http.FS(statics)).ServeHTTP(w, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (srv *DfServer) notFound(w http.ResponseWriter) {
|
func (srv *DfServer) notFound(w http.ResponseWriter) {
|
||||||
err := srv.templates.Render(w, "notFound.html", nil)
|
err := srv.templates.Render(w, "notFound.html", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"embed"
|
||||||
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
type spaHandler struct {
|
||||||
|
server *DfServer
|
||||||
|
staticFS embed.FS
|
||||||
|
staticPath string
|
||||||
|
indexPath string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h spaHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// get the absolute path to prevent directory traversal
|
||||||
|
path := r.URL.Path
|
||||||
|
// if err != nil {
|
||||||
|
// // if we failed to get the absolute path respond with a 400 bad request and stop
|
||||||
|
// http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// prepend the path with the path to the static directory
|
||||||
|
path = h.staticPath + path
|
||||||
|
|
||||||
|
_, err := h.staticFS.Open(path)
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
// file does not exist, serve index.html
|
||||||
|
fmt.Println(path)
|
||||||
|
index, err := h.staticFS.ReadFile(h.staticPath + "/" + h.indexPath)
|
||||||
|
if err != nil {
|
||||||
|
h.server.notFound(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||||
|
w.WriteHeader(http.StatusAccepted)
|
||||||
|
w.Write(index)
|
||||||
|
return
|
||||||
|
} else if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the subdirectory of the static dir
|
||||||
|
statics, err := fs.Sub(h.staticFS, h.staticPath)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise, use http.FileServer to serve the static dir
|
||||||
|
http.FileServer(http.FS(statics)).ServeHTTP(w, r)
|
||||||
|
}
|
|
@ -21,13 +21,19 @@ func (srv *DfServer) LoadTemplates() {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
"title": util.Title,
|
"title": util.Title,
|
||||||
"kebab": func(s string) string { return strcase.ToKebab(s) },
|
"kebab": func(s string) string { return strcase.ToKebab(s) },
|
||||||
|
"world": func() *model.DfWorld { return srv.context.world },
|
||||||
|
"initMap": func() template.HTML {
|
||||||
|
return template.HTML(fmt.Sprintf(`<script>var worldWidth = %d, worldHeight = %d;</script><script src="/js/map.js"></script>`,
|
||||||
|
srv.context.world.Width, srv.context.world.Height))
|
||||||
|
},
|
||||||
"hf": func(id int) template.HTML { return model.LinkHf(srv.context.world, id) },
|
"hf": func(id int) template.HTML { return model.LinkHf(srv.context.world, id) },
|
||||||
"getHf": func(id int) *model.HistoricalFigure { return srv.context.world.HistoricalFigures[id] },
|
"getHf": func(id int) *model.HistoricalFigure { return srv.context.world.HistoricalFigures[id] },
|
||||||
"entity": func(id int) template.HTML { return model.LinkEntity(srv.context.world, id) },
|
"entity": func(id int) template.HTML { return model.LinkEntity(srv.context.world, id) },
|
||||||
"getEntity": func(id int) *model.Entity { return srv.context.world.Entities[id] },
|
"getEntity": func(id int) *model.Entity { return srv.context.world.Entities[id] },
|
||||||
"site": func(id int) template.HTML { return model.LinkSite(srv.context.world, id) },
|
"site": func(id int) template.HTML { return model.LinkSite(srv.context.world, id) },
|
||||||
|
"addSite": func(id int) template.HTML { return model.AddMapSite(srv.context.world, id) },
|
||||||
"getSite": func(id int) *model.Site { return srv.context.world.Sites[id] },
|
"getSite": func(id int) *model.Site { return srv.context.world.Sites[id] },
|
||||||
"structure": func(siteId, id int) template.HTML { return model.LinkStructure(srv.context.world, siteId, id) },
|
"structure": func(siteId, id int) template.HTML { return model.LinkStructure(srv.context.world, siteId, id) },
|
||||||
"region": func(id int) template.HTML { return model.LinkRegion(srv.context.world, id) },
|
"region": func(id int) template.HTML { return model.LinkRegion(srv.context.world, id) },
|
||||||
|
|
|
@ -0,0 +1,198 @@
|
||||||
|
var sitesLayer = L.layerGroup();
|
||||||
|
var constructionsLayer = L.layerGroup();
|
||||||
|
var landmassesLayer = L.layerGroup();
|
||||||
|
var regionsLayer = L.layerGroup();
|
||||||
|
var mountainsLayer = L.layerGroup();
|
||||||
|
var evilnessLayer = L.layerGroup();
|
||||||
|
|
||||||
|
var map = L.map('map', {
|
||||||
|
maxZoom: 6,
|
||||||
|
minZoom: 0,
|
||||||
|
crs: L.CRS.Simple,
|
||||||
|
layers: [sitesLayer, constructionsLayer, mountainsLayer, evilnessLayer]
|
||||||
|
});
|
||||||
|
|
||||||
|
map.getBoundsZoom = function (bounds, inside, padding) { // (LatLngBounds[, Boolean, Point]) -> Number
|
||||||
|
bounds = L.latLngBounds(bounds);
|
||||||
|
|
||||||
|
var zoom = this.getMinZoom() - (inside ? 1 : 0),
|
||||||
|
maxZoom = this.getMaxZoom(),
|
||||||
|
size = this.getSize(),
|
||||||
|
|
||||||
|
nw = bounds.getNorthWest(),
|
||||||
|
se = bounds.getSouthEast(),
|
||||||
|
|
||||||
|
zoomNotFound = true,
|
||||||
|
boundsSize;
|
||||||
|
|
||||||
|
padding = L.point(padding || [0, 0]);
|
||||||
|
|
||||||
|
var incement = 0.02;
|
||||||
|
do {
|
||||||
|
zoom += incement;
|
||||||
|
boundsSize = this.project(se, zoom).subtract(this.project(nw, zoom)).add(padding).floor();
|
||||||
|
zoomNotFound = !inside ? size.contains(boundsSize) : boundsSize.x < size.x || boundsSize.y < size.y;
|
||||||
|
|
||||||
|
} while (zoomNotFound && zoom <= maxZoom);
|
||||||
|
|
||||||
|
if (zoomNotFound && inside) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return inside ? zoom : zoom - incement;
|
||||||
|
}
|
||||||
|
|
||||||
|
var bounds = new L.LatLngBounds([0, 0], [worldWidth,
|
||||||
|
worldHeight]);
|
||||||
|
map.setMaxBounds(bounds);
|
||||||
|
map.fitBounds(bounds);
|
||||||
|
|
||||||
|
map.options.minZoom = map.getZoom();
|
||||||
|
|
||||||
|
var imageUrl = '/map'
|
||||||
|
var imageBounds = [[0, 0],
|
||||||
|
[worldWidth, worldHeight]];
|
||||||
|
|
||||||
|
var overlayMaps = {
|
||||||
|
"Sites": sitesLayer,
|
||||||
|
"World Constructions": constructionsLayer,
|
||||||
|
"Mountain Peaks": mountainsLayer,
|
||||||
|
"Landmasses": landmassesLayer,
|
||||||
|
"Regions": regionsLayer,
|
||||||
|
"Evilness": evilnessLayer,
|
||||||
|
};
|
||||||
|
|
||||||
|
L.control.layers(null, overlayMaps).addTo(map);
|
||||||
|
|
||||||
|
var imageLayer = L.imageOverlay(imageUrl, imageBounds, { opacity: 0.5 });
|
||||||
|
imageLayer.addTo(map);
|
||||||
|
|
||||||
|
// var opacitySlider = new L.Control.opacitySlider();
|
||||||
|
// map.addControl(opacitySlider);
|
||||||
|
// opacitySlider.setOpacityLayer(imageLayer);
|
||||||
|
|
||||||
|
|
||||||
|
var minx = 1000, miny = 1000, maxx = 0, maxy = 0;
|
||||||
|
|
||||||
|
function zoomTo(y, x, zoom) {
|
||||||
|
x = worldWidth - x - 1;
|
||||||
|
map.setView([x, y], zoom);
|
||||||
|
}
|
||||||
|
|
||||||
|
function zoom() {
|
||||||
|
var sw = L.latLng(minx, miny), ne = L.latLng(maxx + 1, maxy + 1);
|
||||||
|
var bounds = new L.LatLngBounds(sw, ne);
|
||||||
|
console.log(sw, ne, bounds);
|
||||||
|
map.fitBounds(bounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var siteOffset = 0.1;
|
||||||
|
var structureOffset = 0.35;
|
||||||
|
var battleOffset = 0.2;
|
||||||
|
var mountainOffset = -0.2;
|
||||||
|
|
||||||
|
function coordO(y, x, yo, xo) {
|
||||||
|
var c = coord(y, x);
|
||||||
|
return [c[0] + yo, c[1] + xo]
|
||||||
|
}
|
||||||
|
|
||||||
|
function square(y, x, o) {
|
||||||
|
return [coordO(y, x, o, o), coordO(y, x, 1 - o, o), coordO(y, x, 1 - o, 1 - o), coordO(y, x, o, 1 - o)];
|
||||||
|
}
|
||||||
|
|
||||||
|
function attachTooltip(layer, tip) {
|
||||||
|
layer.bindTooltip(tip, { direction: 'top' }).bindPopup(tip);
|
||||||
|
}
|
||||||
|
|
||||||
|
function addSite(name, y1, x1, y2, x2, color, glyph) {
|
||||||
|
/* resize tiny sites like lairs */
|
||||||
|
var MIN_SIZE = .3;
|
||||||
|
if (y2 - y1 < MIN_SIZE) {
|
||||||
|
y1 = (y1 + y2) / 2 - MIN_SIZE / 2;
|
||||||
|
y2 = y1 + MIN_SIZE;
|
||||||
|
}
|
||||||
|
if (x2 - x1 < MIN_SIZE) {
|
||||||
|
x1 = (x1 + x2) / 2 - MIN_SIZE / 2;
|
||||||
|
x2 = x1 + MIN_SIZE;
|
||||||
|
}
|
||||||
|
/* TODO: use glyph of the site instead of a polygon? */
|
||||||
|
var polygon = L.polygon(
|
||||||
|
[coord(y1, x1), coord(y2, x1), coord(y2, x2), coord(y1, x2)], {
|
||||||
|
color: color,
|
||||||
|
opacity: 1, fillOpacity: 0.7,
|
||||||
|
weight: 3
|
||||||
|
}).addTo(sitesLayer);
|
||||||
|
|
||||||
|
attachTooltip(polygon, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
function addWc(name, y, x, color) {
|
||||||
|
var polygon = L.polygon(square(y, x, structureOffset), {
|
||||||
|
color: color,
|
||||||
|
opacity: 1, fillOpacity: 0.7,
|
||||||
|
weight: 3
|
||||||
|
}).addTo(constructionsLayer);
|
||||||
|
|
||||||
|
attachTooltip(polygon, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
function addRegion(name, y1, x1, y2, x2, color) {
|
||||||
|
x1--; y2++;
|
||||||
|
var polygon = L.polygon(
|
||||||
|
[coord(y1, x1), coord(y2, x1), coord(y2, x2), coord(y1, x2)], {
|
||||||
|
color: color,
|
||||||
|
opacity: 0.5, fillOpacity: 0.3,
|
||||||
|
weight: 1
|
||||||
|
}).addTo(landmassesLayer);
|
||||||
|
|
||||||
|
attachTooltip(polygon, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
function addMountain(name, y, x, color) {
|
||||||
|
x = worldWidth - x - 1;
|
||||||
|
var polygon = L.polygon(
|
||||||
|
[[x + mountainOffset / 2, y + mountainOffset], [x + mountainOffset / 2, y + 1 - mountainOffset], [x + 1 - mountainOffset, y + 0.5]], {
|
||||||
|
color: color,
|
||||||
|
opacity: 1, fillOpacity: 0.7,
|
||||||
|
weight: 3
|
||||||
|
}).addTo(mountainsLayer);
|
||||||
|
|
||||||
|
attachTooltip(polygon, name);
|
||||||
|
|
||||||
|
minx = Math.min(x, minx);
|
||||||
|
miny = Math.min(y, miny);
|
||||||
|
maxx = Math.max(x, maxx);
|
||||||
|
maxy = Math.max(y, maxy);
|
||||||
|
}
|
||||||
|
|
||||||
|
function coord(y, x) {
|
||||||
|
x = worldWidth - x - 1;
|
||||||
|
|
||||||
|
minx = Math.min(x, minx);
|
||||||
|
miny = Math.min(y, miny);
|
||||||
|
maxx = Math.max(x, maxx);
|
||||||
|
maxy = Math.max(y, maxy);
|
||||||
|
|
||||||
|
return [x, y];
|
||||||
|
}
|
||||||
|
|
||||||
|
function addBattle(name, y, x) {
|
||||||
|
x = worldWidth - x - 1;
|
||||||
|
var polygon = L.polygon(
|
||||||
|
[[x + 0.5, y + battleOffset],
|
||||||
|
[x + battleOffset, y + 0.5],
|
||||||
|
[x + 0.5, y + 1 - battleOffset],
|
||||||
|
[x + 1 - battleOffset, y + 0.5]], {
|
||||||
|
color: '#f00',
|
||||||
|
opacity: 1, fillOpacity: 0.7,
|
||||||
|
weight: 3
|
||||||
|
}).addTo(map);
|
||||||
|
|
||||||
|
attachTooltip(polygon, name);
|
||||||
|
|
||||||
|
minx = Math.min(x, minx);
|
||||||
|
miny = Math.min(y, miny);
|
||||||
|
maxx = Math.max(x, maxx);
|
||||||
|
maxy = Math.max(y, maxy);
|
||||||
|
}
|
|
@ -17,15 +17,13 @@
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div id="map" style="height: 400px"></div>
|
<div id="map" style="height: 400px"></div>
|
||||||
<script>
|
{{initMap}}
|
||||||
var map = L.map('map').setView([5, 5], 13);
|
{{- range $race, $civs := .Civilizations }}
|
||||||
|
{{- range $civs }}
|
||||||
|
{{- range .Sites }}
|
||||||
|
{{ addSite . }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
var imageUrl = '$suburi/map'
|
|
||||||
var imageBounds = [[0, 0],
|
|
||||||
[10, 10]];
|
|
||||||
|
|
||||||
var imageLayer = L.imageOverlay(imageUrl, imageBounds, { opacity: 0.5 });
|
|
||||||
imageLayer.addTo(map);
|
|
||||||
|
|
||||||
</script>
|
|
||||||
{{- end }}
|
{{- end }}
|
|
@ -88,7 +88,6 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
var hash = document.location.hash;
|
var hash = document.location.hash;
|
||||||
console.log("hah", hash)
|
|
||||||
if (hash && hash.startsWith("#nav-")) {
|
if (hash && hash.startsWith("#nav-")) {
|
||||||
var hashPieces = hash.split('?');
|
var hashPieces = hash.split('?');
|
||||||
activeTab = $('.nav-link[data-bs-target="' + hashPieces[0] + '"]');
|
activeTab = $('.nav-link[data-bs-target="' + hashPieces[0] + '"]');
|
||||||
|
|
Loading…
Reference in New Issue