Start investigating the maps
This commit is contained in:
150
internal/maps/maps.go
Normal file
150
internal/maps/maps.go
Normal file
@@ -0,0 +1,150 @@
|
||||
package maps
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
expectedMagic = []byte("\x08\x00WHMAP\x00")
|
||||
expectedSetNameOffset = uint32(0x34)
|
||||
notImplemented = fmt.Errorf("Not implemented")
|
||||
)
|
||||
|
||||
type Header struct {
|
||||
IsCampaignMap uint32 // Tentatively: 0 = no, 1 = yes
|
||||
MinWidth uint32
|
||||
MinLength uint32
|
||||
MaxWidth uint32
|
||||
MaxLength uint32
|
||||
Unknown1 uint32
|
||||
Unknown2 uint32
|
||||
Unknown3 uint32
|
||||
Unknown4 uint32
|
||||
Magic [8]byte // "\x08\x00WHMAP\x00"
|
||||
Unknown5 uint32
|
||||
Unknown6 uint32
|
||||
SetName [8]byte // Or is it a null-terminated string?
|
||||
}
|
||||
|
||||
func (h Header) Check() []error {
|
||||
var out []error
|
||||
if h.IsCampaignMap > 1 {
|
||||
out = append(out, fmt.Errorf("Expected 0 or 1 for IsCampaignMap, got %v", h.IsCampaignMap))
|
||||
}
|
||||
|
||||
if bytes.Compare(expectedMagic, h.Magic[:]) != 0 {
|
||||
out = append(out, fmt.Errorf("Unexpected magic value: %v", h.Magic))
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
type GameMap struct {
|
||||
Header
|
||||
|
||||
// TODO: parse this into sections
|
||||
Text string
|
||||
}
|
||||
|
||||
// A game map contains a .txt and a .map. If they're in the same directory,
|
||||
// just pass the directory + basename to load both
|
||||
func LoadGameMap(prefix string) (*GameMap, error) {
|
||||
for _, mapExt := range []string{".MAP", ".map"} {
|
||||
for _, txtExt := range []string{".TXT", ".txt"} {
|
||||
out, err := LoadGameMapByFiles(prefix+mapExt, prefix+txtExt)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
return out, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("Couldn't find %s.{map,txt}, even ignoring case", prefix)
|
||||
}
|
||||
|
||||
// A game map is composed of two files: .map and .txt
|
||||
func LoadGameMapByFiles(mapFile, txtFile string) (*GameMap, error) {
|
||||
out, err := loadMapFile(mapFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO: load text and parse into sections
|
||||
txt, err := ioutil.ReadFile(txtFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out.Text = string(txt)
|
||||
|
||||
for _, err := range out.Check() {
|
||||
log.Printf("%s: %v", mapFile, err)
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func LoadGameMaps(dir string) (map[string]*GameMap, error) {
|
||||
fis, err := ioutil.ReadDir(dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
out := make(map[string]*GameMap)
|
||||
|
||||
for _, fi := range fis {
|
||||
filename := filepath.Join(dir, fi.Name())
|
||||
basename := filepath.Base(filename)
|
||||
extname := filepath.Ext(filename)
|
||||
|
||||
// Only pay attention to .MAP files. Assume they will have a .txt too
|
||||
if !strings.EqualFold(extname, ".MAP") {
|
||||
continue
|
||||
}
|
||||
|
||||
prefix := filename[0 : len(filename)-4]
|
||||
|
||||
gameMap, err := LoadGameMap(prefix)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error processing %v: %s", filename, err)
|
||||
}
|
||||
|
||||
out[basename] = gameMap
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func loadMapFile(filename string) (*GameMap, error) {
|
||||
var out GameMap
|
||||
|
||||
mf, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer mf.Close()
|
||||
|
||||
zr, err := gzip.NewReader(mf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer zr.Close()
|
||||
|
||||
if err := binary.Read(zr, binary.LittleEndian, &out.Header); err != nil {
|
||||
return nil, fmt.Errorf("Error parsing %s: %v", filename, err)
|
||||
}
|
||||
|
||||
return &out, nil
|
||||
}
|
Reference in New Issue
Block a user