diff --git a/Changes.md b/Changes.md index 50a2106..72ea78a 100644 --- a/Changes.md +++ b/Changes.md @@ -58,6 +58,12 @@ Miscellaneous changes: user levels _now_. * For the doodads JavaScript API: `time.Since()` is now available (from the Go standard library) +* Fix a cosmetic bug where doodads scrolling off the top or left edges + of the level were being drawn incorrectly. +* Fix the Editor's status bar where it shows your cursor position + relative to the level and absolute to the app window to show the + correct values of each (they were reversed before). +* The developer shell now has a chatbot in it powered by RiveScript. ## v0.10.0 (Dec 30 2021) diff --git a/assets/rivescript/begin.rive b/assets/rivescript/begin.rive index 5ca5fe1..d22c162 100644 --- a/assets/rivescript/begin.rive +++ b/assets/rivescript/begin.rive @@ -6,7 +6,7 @@ < begin // Bot Variables -! var name = Boy +! var name = Aiden ! var age = 15 ! var sex = male ! var location = Michigan diff --git a/go.mod b/go.mod index 198730b..2fdf324 100644 --- a/go.mod +++ b/go.mod @@ -19,12 +19,8 @@ require ( github.com/tomnomnom/xtermcolor v0.0.0-20160428124646-b78803f00a7e // indirect github.com/urfave/cli/v2 v2.3.0 github.com/veandco/go-sdl2 v0.4.10 - github.com/vmihailenco/msgpack v4.0.4+incompatible golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 // indirect golang.org/x/image v0.0.0-20211028202545-6944b10bf410 - golang.org/x/net v0.0.0-20220107192237-5cfca573fb4d // indirect golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect - google.golang.org/protobuf v1.27.1 // indirect - gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect ) diff --git a/go.sum b/go.sum index 4926321..aea287c 100644 --- a/go.sum +++ b/go.sum @@ -122,7 +122,6 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -137,7 +136,6 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= @@ -197,10 +195,8 @@ github.com/kirsle/configdir v0.0.0-20170128060238-e45d2f54772f/go.mod h1:4rEELDS github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= @@ -274,8 +270,6 @@ github.com/veandco/go-sdl2 v0.4.1/go.mod h1:FB+kTpX9YTE+urhYiClnRzpOXbiWgaU3+5F2 github.com/veandco/go-sdl2 v0.4.8/go.mod h1:OROqMhHD43nT4/i9crJukyVecjPNYYuCofep6SNiAjY= github.com/veandco/go-sdl2 v0.4.10 h1:8QoD2bhWl7SbQDflIAUYWfl9Vq+mT8/boJFAUzAScgY= github.com/veandco/go-sdl2 v0.4.10/go.mod h1:OROqMhHD43nT4/i9crJukyVecjPNYYuCofep6SNiAjY= -github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI= -github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -382,8 +376,6 @@ golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLd golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220107192237-5cfca573fb4d h1:62NvYBuaanGXR2ZOfwDFkhhl6X1DUgf8qg3GuQvxZsE= -golang.org/x/net v0.0.0-20220107192237-5cfca573fb4d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -527,7 +519,6 @@ golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= @@ -557,7 +548,6 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -632,12 +622,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= diff --git a/pkg/doodads/doodad.go b/pkg/doodads/doodad.go index 51a3788..b25906c 100644 --- a/pkg/doodads/doodad.go +++ b/pkg/doodads/doodad.go @@ -20,7 +20,7 @@ type Doodad struct { Tags map[string]string `json:"data"` // arbitrary key/value data storage // Undo history, temporary live data not persisted to the level file. - UndoHistory *drawtool.History `json:"-" msgpack:"-"` + UndoHistory *drawtool.History `json:"-"` } // Layer holds a layer of drawing data for a Doodad. diff --git a/pkg/editor_ui.go b/pkg/editor_ui.go index 8a26264..2005cf5 100644 --- a/pkg/editor_ui.go +++ b/pkg/editor_ui.go @@ -282,10 +282,10 @@ func (u *EditorUI) Loop(ev *event.State) error { // Update status bar labels. { - u.StatusMouseText = fmt.Sprintf("Rel:(%d,%d) Abs:(%s)", + u.StatusMouseText = fmt.Sprintf("Rel:(%s) Abs:(%d,%d)", + *u.Scene.debWorldIndex, ev.CursorX, ev.CursorY, - *u.Scene.debWorldIndex, ) u.StatusPaletteText = fmt.Sprintf("%s Tool", u.Canvas.Tool, diff --git a/pkg/level/chunk.go b/pkg/level/chunk.go index e506b85..22a22c6 100644 --- a/pkg/level/chunk.go +++ b/pkg/level/chunk.go @@ -12,7 +12,6 @@ import ( "git.kirsle.net/apps/doodle/pkg/shmem" "git.kirsle.net/go/render" "github.com/google/uuid" - "github.com/vmihailenco/msgpack" ) // Types of chunks. @@ -42,9 +41,9 @@ type Chunk struct { // JSONChunk holds a lightweight (interface-free) copy of the Chunk for // unmarshalling JSON files from disk. type JSONChunk struct { - Type int `json:"type" msgpack:"0"` - Data json.RawMessage `json:"data" msgpack:"-"` - BinData interface{} `json:"-" msgpack:"1"` + Type int `json:"type"` + Data json.RawMessage `json:"data"` + BinData interface{} `json:"-"` } // Accessor provides a high-level API to interact with absolute pixel coordinates @@ -59,9 +58,6 @@ type Accessor interface { Len() int MarshalJSON() ([]byte, error) UnmarshalJSON([]byte) error - // MarshalMsgpack() ([]byte, error) - // UnmarshalMsgpack([]byte) error - // Serialize() interface{} } // NewChunk creates a new chunk. @@ -312,66 +308,3 @@ func (c *Chunk) UnmarshalJSON(b []byte) error { return fmt.Errorf("Chunk.UnmarshalJSON: unsupported chunk type '%d'", c.Type) } } - -func (c *Chunk) EncodeMsgpack(enc *msgpack.Encoder) error { - data := c.Accessor - - generic := &JSONChunk{ - Type: c.Type, - BinData: data, - } - - return enc.Encode(generic) -} - -func (c *Chunk) DecodeMsgpack(dec *msgpack.Decoder) error { - generic := &JSONChunk{} - err := dec.Decode(generic) - if err != nil { - return fmt.Errorf("Chunk.DecodeMsgpack: %s", err) - } - - switch c.Type { - case MapType: - c.Accessor = generic.BinData.(MapAccessor) - default: - return fmt.Errorf("Chunk.DecodeMsgpack: unsupported chunk type '%d'", c.Type) - } - - return nil -} - -// // MarshalMsgpack writes the chunk to msgpack format. -// func (c *Chunk) MarshalMsgpack() ([]byte, error) { -// // data, err := c.Accessor.MarshalMsgpack() -// // if err != nil { -// // return []byte{}, err -// // } -// data := c.Accessor -// -// generic := &JSONChunk{ -// Type: c.Type, -// BinData: data, -// } -// b, err := msgpack.Marshal(generic) -// return b, err -// } -// -// // UnmarshalMsgpack loads the chunk from msgpack format. -// func (c *Chunk) UnmarshalMsgpack(b []byte) error { -// // Parse it generically so we can hand off the inner "data" object to the -// // right accessor for unmarshalling. -// generic := &JSONChunk{} -// err := msgpack.Unmarshal(b, generic) -// if err != nil { -// return fmt.Errorf("Chunk.UnmarshalMsgpack: failed to unmarshal into generic JSONChunk type: %s", err) -// } -// -// switch c.Type { -// case MapType: -// c.Accessor = NewMapAccessor() -// return c.Accessor.UnmarshalMsgpack(generic.Data) -// default: -// return fmt.Errorf("Chunk.UnmarshalMsgpack: unsupported chunk type '%d'", c.Type) -// } -// } diff --git a/pkg/level/chunk_map.go b/pkg/level/chunk_map.go index 8ea49ac..60a3f09 100644 --- a/pkg/level/chunk_map.go +++ b/pkg/level/chunk_map.go @@ -6,7 +6,6 @@ import ( "fmt" "git.kirsle.net/go/render" - "github.com/vmihailenco/msgpack" ) // MapAccessor implements a chunk accessor by using a map of points to their @@ -128,65 +127,3 @@ func (a MapAccessor) UnmarshalJSON(b []byte) error { return nil } - -// // MarshalMsgpack serializes for msgpack. -// func (a MapAccessor) MarshalMsgpack() ([]byte, error) { -// dict := map[string]int{} -// for point, sw := range a { -// dict[point.String()] = sw.Index() -// } -// return msgpack.Marshal(dict) -// } -// -// // Serialize converts the chunk accessor to a map for serialization. -// func (a MapAccessor) Serialize() interface{} { -// dict := map[string]int{} -// for point, sw := range a { -// dict[point.String()] = sw.Index() -// } -// return dict -// } -// -// // UnmarshalMsgpack decodes from msgpack format. -// func (a MapAccessor) UnmarshalMsgpack(b []byte) error { -// var dict map[string]int -// err := msgpack.Unmarshal(b, &dict) -// if err != nil { -// return err -// } -// -// for coord, index := range dict { -// point, err := render.ParsePoint(coord) -// if err != nil { -// return fmt.Errorf("MapAccessor.UnmarshalJSON: %s", err) -// } -// a[point] = NewSparseSwatch(index) -// } -// -// return nil -// } - -func (a MapAccessor) EncodeMsgpack(enc *msgpack.Encoder) error { - dict := map[string]int{} - for point, sw := range a { - dict[point.String()] = sw.Index() - } - return enc.Encode(dict) -} - -func (a MapAccessor) DecodeMsgpack(dec *msgpack.Decoder) error { - v, err := dec.DecodeMap() - if err != nil { - return fmt.Errorf("MapAccessor.DecodeMsgpack: %s", err) - } - dict := v.(map[string]int) - - for coord, index := range dict { - point, err := render.ParsePoint(coord) - if err != nil { - return fmt.Errorf("MapAccessor.UnmarshalJSON: %s", err) - } - a[point] = NewSparseSwatch(index) - } - return nil -} diff --git a/pkg/level/chunker.go b/pkg/level/chunker.go index 569691f..9408003 100644 --- a/pkg/level/chunker.go +++ b/pkg/level/chunker.go @@ -7,7 +7,6 @@ import ( "git.kirsle.net/apps/doodle/pkg/log" "git.kirsle.net/go/render" - "github.com/vmihailenco/msgpack" ) // Chunker is the data structure that manages the chunks of a level, and @@ -336,14 +335,3 @@ func (c ChunkMap) MarshalJSON() ([]byte, error) { out, err := json.Marshal(dict) return out, err } - -// MarshalMsgpack to convert the chunk map to binary. -func (c ChunkMap) MarshalMsgpack() ([]byte, error) { - dict := map[string]*Chunk{} - for point, chunk := range c { - dict[point.String()] = chunk - } - - out, err := msgpack.Marshal(dict) - return out, err -} diff --git a/pkg/level/fmt_binary.go b/pkg/level/fmt_binary.go deleted file mode 100644 index d226b17..0000000 --- a/pkg/level/fmt_binary.go +++ /dev/null @@ -1,67 +0,0 @@ -package level - -import ( - "bytes" - "fmt" - "io/ioutil" - "os" - - "git.kirsle.net/apps/doodle/pkg/filesystem" - "github.com/vmihailenco/msgpack" -) - -// ToBinary serializes the level to binary format. -func (m *Level) ToBinary() ([]byte, error) { - header := filesystem.MakeHeader(filesystem.BinLevelType) - out := bytes.NewBuffer(header) - encoder := msgpack.NewEncoder(out) - err := encoder.Encode(m) - return out.Bytes(), err -} - -// WriteBinary writes a level to binary format on disk. -func (m *Level) WriteBinary(filename string) error { - bin, err := m.ToBinary() - if err != nil { - return fmt.Errorf("Level.WriteBinary: encode error: %s", err) - } - - err = ioutil.WriteFile(filename, bin, 0755) - if err != nil { - return fmt.Errorf("Level.WriteBinary: WriteFile error: %s", err) - } - - return nil -} - -// LoadBinary loads a map from binary file on disk. -func LoadBinary(filename string) (*Level, error) { - fh, err := os.Open(filename) - if err != nil { - return nil, err - } - defer fh.Close() - - // Read and verify the file header from the binary format. - err = filesystem.ReadHeader(filesystem.BinLevelType, fh) - if err != nil { - return nil, err - } - - // Decode the file from disk. - m := New() - decoder := msgpack.NewDecoder(fh) - err = decoder.Decode(&m) - if err != nil { - return m, fmt.Errorf("level.LoadBinary: decode error: %s", err) - } - - // Fill in defaults. - if m.Wallpaper == "" { - m.Wallpaper = DefaultWallpaper - } - - // Inflate the chunk metadata to map the pixels to their palette indexes. - m.Inflate() - return m, err -} diff --git a/pkg/level/fmt_readwrite.go b/pkg/level/fmt_readwrite.go index 5d07850..92e662e 100644 --- a/pkg/level/fmt_readwrite.go +++ b/pkg/level/fmt_readwrite.go @@ -77,14 +77,7 @@ func LoadFile(filename string) (*Level, error) { return FromJSON(filename, jsonData) } - // Try the binary format. - if level, err := LoadBinary(filename); err == nil { - return level, nil - } else { - log.Warn(err.Error()) - } - - // Then the JSON format. + // Load as JSON. if level, err := LoadJSON(filename); err == nil { return level, nil } else { diff --git a/pkg/level/types.go b/pkg/level/types.go index 6935aac..f1bc074 100644 --- a/pkg/level/types.go +++ b/pkg/level/types.go @@ -17,39 +17,39 @@ var ( // Base provides the common struct keys that are shared between Levels and // Doodads. type Base struct { - Version int `json:"version" msgpack:"0"` // File format version spec. - GameVersion string `json:"gameVersion" msgpack:"1"` // Game version that created the level. - Title string `json:"title" msgpack:"2"` - Author string `json:"author" msgpack:"3"` - Locked bool `json:"locked" msgpack:"4"` + Version int `json:"version"` // File format version spec. + GameVersion string `json:"gameVersion"` // Game version that created the level. + Title string `json:"title"` + Author string `json:"author"` + Locked bool `json:"locked"` // Every drawing type is able to embed other files inside of itself. - Files FileSystem `json:"files" msgpack:"5"` + Files FileSystem `json:"files"` } // Level is the container format for Doodle map drawings. type Level struct { Base - Password string `json:"passwd" msgpack:"10"` + Password string `json:"passwd"` // Chunked pixel data. - Chunker *Chunker `json:"chunks" msgpack:"12"` + Chunker *Chunker `json:"chunks"` // The Palette holds the unique "colors" used in this map file, and their // properties (solid, fire, slippery, etc.) - Palette *Palette `json:"palette" msgpack:"13"` + Palette *Palette `json:"palette"` // Page boundaries and wallpaper settings. - PageType PageType `json:"pageType" msgpack:"14"` - MaxWidth int64 `json:"boundedWidth" msgpack:"15"` // only if bounded or bordered - MaxHeight int64 `json:"boundedHeight" msgpack:"16"` - Wallpaper string `json:"wallpaper" msgpack:"17"` + PageType PageType `json:"pageType"` + MaxWidth int64 `json:"boundedWidth"` // only if bounded or bordered + MaxHeight int64 `json:"boundedHeight"` + Wallpaper string `json:"wallpaper"` // Actors keep a list of the doodad instances in this map. - Actors ActorMap `json:"actors" msgpack:"18"` + Actors ActorMap `json:"actors"` // Undo history, temporary live data not persisted to the level file. - UndoHistory *drawtool.History `json:"-" msgpack:"-"` + UndoHistory *drawtool.History `json:"-"` } // New creates a blank level object with all its members initialized. diff --git a/pkg/uix/canvas.go b/pkg/uix/canvas.go index 8a7874a..ee03994 100644 --- a/pkg/uix/canvas.go +++ b/pkg/uix/canvas.go @@ -24,6 +24,11 @@ type Canvas struct { ui.Frame Palette *level.Palette + // Parent Canvas widget, e.g. for Actors inside of a Level so they can + // find the parent canvas and see where they are drawing in relation to + // it (to handle top/left edge cropping on scroll) + parent *Canvas + // Editable and Scrollable go hand in hand and, if you initialize a // NewCanvas() with editable=true, they are both enabled. Editable bool // Clicking will edit pixels of this canvas. diff --git a/pkg/uix/canvas_actors.go b/pkg/uix/canvas_actors.go index ffdb9c8..87b6a97 100644 --- a/pkg/uix/canvas_actors.go +++ b/pkg/uix/canvas_actors.go @@ -28,6 +28,7 @@ func (w *Canvas) InstallActors(actors level.ActorMap) error { // Create the "live" Actor to exist in the world, and set its world // position to the Point defined in the level data. liveActor := NewActor(id, actor, doodad) + liveActor.Canvas.parent = w liveActor.MoveTo(actor.Point) w.actors = append(w.actors, liveActor) @@ -183,7 +184,6 @@ func (w *Canvas) drawActors(e render.Engine, p render.Point) { // Hitting the top edge. Cap the Y coord and shrink the height. delta := p.Y - drawAt.Y drawAt.Y = p.Y - // scrollTo.Y -= delta // TODO resizeTo.H -= delta } diff --git a/pkg/uix/canvas_present.go b/pkg/uix/canvas_present.go index 2782d4c..6144614 100644 --- a/pkg/uix/canvas_present.go +++ b/pkg/uix/canvas_present.go @@ -30,6 +30,15 @@ func (w *Canvas) Present(e render.Engine, p render.Point) { H: S.H - w.BoxThickness(2), }) + // If we are an Actor canvas as part of a Level, get the absolute position of + // the parent (Level) canvas so we can compare where the Actor is drawn on-screen + // and detect if we are at the Top or Left edges of the parent, to crop and adjust + // the texture accordingly. + var ParentPosition render.Point + if w.parent != nil { + ParentPosition = ui.AbsolutePosition(w.parent) + } + // Draw the wallpaper. if w.wallpaper.Valid() { err := w.PresentWallpaper(e, p) @@ -88,7 +97,7 @@ func (w *Canvas) Present(e render.Engine, p render.Point) { // Zoom in the texture. var ( texSize = tex.Size() - texSizeOrig = tex.Size() + texSizeOrig = texSize ) if w.Zoom != 0 { @@ -136,14 +145,14 @@ func (w *Canvas) Present(e render.Engine, p render.Point) { // - Find the delta how much it exceeds as negative (800 - 890 == -90) // - Lower the Source and Dest rects by that delta size so they // stay proportional and don't scale or anything dumb. - if dst.X+src.W > p.X+S.W { + if dst.X+src.W > p.X+S.W+w.BoxThickness(1) { // NOTE: delta is a negative number, // so it will subtract from the width. delta := (p.X + S.W - w.BoxThickness(1)) - (dst.W + dst.X) src.W += delta dst.W += delta } - if dst.Y+src.H > p.Y+S.H { + if dst.Y+src.H > p.Y+S.H+w.BoxThickness(1) { // NOTE: delta is a negative number delta := (p.Y + S.H - w.BoxThickness(1)) - (dst.H + dst.Y) src.H += delta @@ -160,18 +169,19 @@ func (w *Canvas) Present(e render.Engine, p render.Point) { // - Set destination X to p.X to constrain it there: 20 // - Subtract the delta from destination W so we don't scale it. // - Add 20 to X of the source: the left edge of source is not visible - if dst.X < p.X { + // + // Note: the +w.BoxThickness works around a bug if the Actor Canvas has + // a border on it (e.g. in the Actor/Link Tool mouse-over or debug setting) + if dst.X == ParentPosition.X+w.BoxThickness(1) { // NOTE: delta is a positive number, // so it will add to the destination coordinates. - delta := p.X - dst.X + delta := texSizeOrig.W - src.W dst.X = p.X + w.BoxThickness(1) - dst.W -= delta src.X += delta } - if dst.Y < p.Y { - delta := p.Y - dst.Y + if dst.Y == ParentPosition.Y+w.BoxThickness(1) { + delta := texSizeOrig.H - src.H dst.Y = p.Y + w.BoxThickness(1) - dst.H -= delta src.Y += delta }