clone

an offline map explorer where each world, from a game map to a city's open data, ships as one .atlas file

feat: let tiles and generate read captures from either source

Dami committed 8de3de7
Both tools pick the latest snapshot and decode it as MapGenie's schema;
now the snapshot's kind is read alongside its hash, and a capture from
another source is translated into that schema on the way in. The
translation is one call at the one place each tool opens a snapshot, so
everything downstream -- frame derivation, pyramid building, cataloguing,
bundling -- carries a wikimap without knowing it is one.

Tile records group into layers by the path segment of their URLs, which
until now was only ever cut after MapGenie's /games/ marker; IGN's
/wikimaps/ joins it.
commit
8de3de73f137982d492018b6b1e370ad0a2bf6ef
parent
90ea57d21af9699876a45bf037a00f030963709f
author
Dami <dami.etoile@gmail.com>
2 files changed, +40 -14
Mtools/generate/main.go14+++++++++--
Mtools/tiles/main.go40+++++++++++++++++++++---------
M tools/generate/main.go +12 -2
M tools/tiles/main.go +28 -12
@@ -21,6 +21,8 @@ import (
2121 "sort"2222 "strconv"2323 "strings"24+25+ "github.com/FelineStateMachine/atlas/internal/ignmap"2426 )2527 2628 const (
@@ -100,6 +102,7 @@ type archiveGame struct {
100102 type snapshotIndex struct {101103 CapturedAt string `json:"capturedAt"`102104 ContentHash string `json:"contentHash"`105+ Kind string `json:"kind"`103106 }104107 105108 type rawMap struct {
@@ -436,9 +439,18 @@ func inspectMap(mapDir string) ([]tilePlan, string, string, error) {
436439 }437440 sort.Slice(snapshots, func(i, j int) bool { return snapshots[i].CapturedAt < snapshots[j].CapturedAt })438441 439- var raw rawMap442+ // A capture from another source is translated into the MapGenie shape on443+ // the way in; a MapGenie snapshot passes through untouched.440444 latest := snapshots[len(snapshots)-1]441- if err := readJSON(filepath.Join(mapDir, "snapshots", "map", latest.ContentHash+".json"), &raw); err != nil {445+ doc, err := os.ReadFile(filepath.Join(mapDir, "snapshots", "map", latest.ContentHash+".json"))446+ if err != nil {447+ return nil, "", "", err448+ }449+ if doc, err = ignmap.MaybeTranslate(latest.Kind, doc); err != nil {450+ return nil, "", "", err451+ }452+ var raw rawMap453+ if err := json.Unmarshal(doc, &raw); err != nil {442454 return nil, "", "", err443455 }444456 if len(raw.Config.TileSets) == 0 {
@@ -971,18 +983,22 @@ func sourceTilePath(mapDir string, record tileRecord) (string, error) {
971983 return matches[0], nil972984 }973985 986+// tileSetPath recovers the layer path a record belongs to: everything between987+// the source's marker segment and "/<zoom>/". MapGenie serves tiles under988+// /games/, IGN under /wikimaps/.974989 func tileSetPath(rawURL string, zoom int) string {975- const marker = "/games/"976- start := strings.Index(rawURL, marker)977- if start < 0 {978- return ""979- }980- path := rawURL[start+len(marker):]981- end := strings.Index(path, "/"+strconv.Itoa(zoom)+"/")982- if end < 0 {983- return ""990+ for _, marker := range []string{"/games/", "/wikimaps/"} {991+ _, rest, found := strings.Cut(rawURL, marker)992+ if !found {993+ continue994+ }995+ path, _, found := strings.Cut(rest, "/"+strconv.Itoa(zoom)+"/")996+ if !found {997+ continue998+ }999+ return path9841000 }985- return path[:end]1001+ return ""9861002 }9871003 9881004 func tilePath(root, assetPath string, zoom, x, y int, format string) string {