Embeddable Doodads In Levels
* The Publisher is all hooked up. No native Save File dialogs yet, so uses the dev shell Prompt() to ask for output filename. * Custom-only or builtin doodads too can be stored in the level's file data, at "assets/doodads/*.doodad" * When loading the embedded level in the Editor: it gets its custom doodads out of its file, and you can drag and drop them elsehwere, link them, Play Mode can use them, etc. but they won't appear in the Doodad Dropper if they are not installed in your local doodads directory. * Fleshed out serialization API for the Doodad files: - LoadFromEmbeddable() looks to load a doodad from embeddable file data in addition to the usual places. - Serialize() returns the doodad in bytes, for easy access to embed into level data. - Deserialize() to parse and return from bytes. * When loading a level that references doodads not found in its embedded data or the filesystem: an Alert modal appears listing the missing doodads. The rest of the level loads fine, but the actors referenced by these doodads don't load.
This commit is contained in:
parent
d9bca2152a
commit
7093b102e3
|
@ -14,15 +14,15 @@ var (
|
||||||
ScrollboxHoz = 256 // horizontal px from window border to start scrol
|
ScrollboxHoz = 256 // horizontal px from window border to start scrol
|
||||||
ScrollboxVert = 160
|
ScrollboxVert = 160
|
||||||
// NEW: set scrollbox bounds by percents
|
// NEW: set scrollbox bounds by percents
|
||||||
ScrollboxHozPercent float64 = 0.25
|
ScrollboxHozPercent float64 = 0.25
|
||||||
ScrollboxVertPercent float64 = 0.40
|
ScrollboxVertPercent float64 = 0.40
|
||||||
|
|
||||||
// Player speeds
|
// Player speeds
|
||||||
PlayerMaxVelocity float64 = 6
|
PlayerMaxVelocity float64 = 6
|
||||||
PlayerAcceleration float64 = 0.9
|
PlayerAcceleration float64 = 0.9
|
||||||
Gravity float64 = 6
|
Gravity float64 = 6
|
||||||
GravityAcceleration float64 = 0.2
|
GravityAcceleration float64 = 0.2
|
||||||
SlopeMaxHeight = 8 // max pixel height for player to walk up a slope
|
SlopeMaxHeight = 8 // max pixel height for player to walk up a slope
|
||||||
|
|
||||||
// Default chunk size for canvases.
|
// Default chunk size for canvases.
|
||||||
ChunkSize = 128
|
ChunkSize = 128
|
||||||
|
@ -57,8 +57,12 @@ var (
|
||||||
|
|
||||||
// Level attachment filename for the custom wallpaper.
|
// Level attachment filename for the custom wallpaper.
|
||||||
// NOTE: due to hard-coded "assets/wallpapers/" prefix in uix/canvas.go#LoadLevel.
|
// NOTE: due to hard-coded "assets/wallpapers/" prefix in uix/canvas.go#LoadLevel.
|
||||||
CustomWallpaperFilename = "custom.b64img"
|
CustomWallpaperFilename = "custom.b64img"
|
||||||
CustomWallpaperEmbedPath = "assets/wallpapers/custom.b64img"
|
CustomWallpaperEmbedPath = "assets/wallpapers/custom.b64img"
|
||||||
|
|
||||||
|
// Publishing: Doodads-embedded-within-levels.
|
||||||
|
EmbeddedDoodadsBasePath = "assets/doodads/"
|
||||||
|
EmbeddedWallpaperBasePath = "assets/wallpapers/"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Edit Mode Values
|
// Edit Mode Values
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
package doodads
|
package doodads
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"git.kirsle.net/apps/doodle/pkg/balance"
|
||||||
"git.kirsle.net/apps/doodle/pkg/bindata"
|
"git.kirsle.net/apps/doodle/pkg/bindata"
|
||||||
"git.kirsle.net/apps/doodle/pkg/branding"
|
"git.kirsle.net/apps/doodle/pkg/branding"
|
||||||
"git.kirsle.net/apps/doodle/pkg/enum"
|
"git.kirsle.net/apps/doodle/pkg/enum"
|
||||||
|
@ -16,6 +18,11 @@ import (
|
||||||
"git.kirsle.net/apps/doodle/pkg/wasm"
|
"git.kirsle.net/apps/doodle/pkg/wasm"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Errors.
|
||||||
|
var (
|
||||||
|
ErrNotFound = errors.New("file not found")
|
||||||
|
)
|
||||||
|
|
||||||
// ListDoodads returns a listing of all available doodads between all locations,
|
// ListDoodads returns a listing of all available doodads between all locations,
|
||||||
// including user doodads.
|
// including user doodads.
|
||||||
func ListDoodads() ([]string, error) {
|
func ListDoodads() ([]string, error) {
|
||||||
|
@ -106,7 +113,20 @@ func ListBuiltin() ([]string, error) {
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LoadFromEmbeddable reads a doodad file, checking a level's embeddable
|
||||||
|
// file data in addition to the usual places.
|
||||||
|
func LoadFromEmbeddable(filename string, fs filesystem.Embeddable) (*Doodad, error) {
|
||||||
|
if bin, err := fs.GetFile(balance.EmbeddedDoodadsBasePath + filename); err == nil {
|
||||||
|
log.Debug("doodads.LoadFromEmbeddable: found %s", filename)
|
||||||
|
return Deserialize(filename, bin)
|
||||||
|
}
|
||||||
|
return LoadFile(filename)
|
||||||
|
}
|
||||||
|
|
||||||
// LoadFile reads a doodad file from disk, checking a few locations.
|
// LoadFile reads a doodad file from disk, checking a few locations.
|
||||||
|
//
|
||||||
|
// It checks for embedded bindata, system-level doodads on the filesystem,
|
||||||
|
// and then user-owned doodads in their profile folder.
|
||||||
func LoadFile(filename string) (*Doodad, error) {
|
func LoadFile(filename string) (*Doodad, error) {
|
||||||
if !strings.HasSuffix(filename, enum.DoodadExt) {
|
if !strings.HasSuffix(filename, enum.DoodadExt) {
|
||||||
filename += enum.DoodadExt
|
filename += enum.DoodadExt
|
||||||
|
@ -177,3 +197,24 @@ func (d *Doodad) WriteFile(filename string) error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Serialize encodes a doodad to bytes and returns them, instead
|
||||||
|
// of writing to a file.
|
||||||
|
// WriteFile saves a doodad to disk in the user's config directory.
|
||||||
|
func (d *Doodad) Serialize() ([]byte, error) {
|
||||||
|
// Set the version information.
|
||||||
|
d.Version = 1
|
||||||
|
d.GameVersion = branding.Version
|
||||||
|
|
||||||
|
bin, err := d.ToJSON()
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return bin, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deserialize loads a doodad from its bytes format.
|
||||||
|
func Deserialize(filename string, bin []byte) (*Doodad, error) {
|
||||||
|
return FromJSON(filename, bin)
|
||||||
|
}
|
||||||
|
|
|
@ -279,6 +279,7 @@ func (s *EditorScene) LoadLevel(filename string) error {
|
||||||
|
|
||||||
log.Info("Installing %d actors into the drawing", len(level.Actors))
|
log.Info("Installing %d actors into the drawing", len(level.Actors))
|
||||||
if err := s.UI.Canvas.InstallActors(level.Actors); err != nil {
|
if err := s.UI.Canvas.InstallActors(level.Actors); err != nil {
|
||||||
|
modal.Alert("This level references some doodads that were not found:\n\n%s", err).WithTitle("Level Errors")
|
||||||
return fmt.Errorf("EditorScene.LoadLevel: InstallActors: %s", err)
|
return fmt.Errorf("EditorScene.LoadLevel: InstallActors: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ func (u *EditorUI) startDragActor(doodad *doodads.Doodad, actor *level.Actor) {
|
||||||
|
|
||||||
if doodad == nil {
|
if doodad == nil {
|
||||||
if actor != nil {
|
if actor != nil {
|
||||||
obj, err := doodads.LoadFile(actor.Filename)
|
obj, err := doodads.LoadFromEmbeddable(actor.Filename, u.Scene.Level)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("startDragExistingActor: actor doodad name %s not found: %s", actor.Filename, err)
|
log.Error("startDragExistingActor: actor doodad name %s not found: %s", actor.Filename, err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -2,9 +2,13 @@ package doodle
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"git.kirsle.net/apps/doodle/pkg/doodads"
|
"git.kirsle.net/apps/doodle/pkg/doodads"
|
||||||
"git.kirsle.net/apps/doodle/pkg/level"
|
"git.kirsle.net/apps/doodle/pkg/level"
|
||||||
|
"git.kirsle.net/apps/doodle/pkg/level/publishing"
|
||||||
"git.kirsle.net/apps/doodle/pkg/log"
|
"git.kirsle.net/apps/doodle/pkg/log"
|
||||||
"git.kirsle.net/apps/doodle/pkg/modal"
|
"git.kirsle.net/apps/doodle/pkg/modal"
|
||||||
"git.kirsle.net/apps/doodle/pkg/windows"
|
"git.kirsle.net/apps/doodle/pkg/windows"
|
||||||
|
@ -114,13 +118,27 @@ func (u *EditorUI) SetupPopups(d *Doodle) {
|
||||||
Engine: d.Engine,
|
Engine: d.Engine,
|
||||||
Level: scene.Level,
|
Level: scene.Level,
|
||||||
|
|
||||||
OnPublish: func() {
|
OnPublish: func(includeBuiltins bool) {
|
||||||
modal.Alert("Not Yet Implemented")
|
log.Debug("OnPublish: include builtins=%+v", includeBuiltins)
|
||||||
// filename, err := native.SaveFile("Save your level", "*.level")
|
cwd, _ := os.Getwd()
|
||||||
// if err != nil {
|
d.Prompt(fmt.Sprintf("File name (relative to %s)> ", cwd), func(answer string) {
|
||||||
// modal.Alert(err.Error())
|
if answer == "" {
|
||||||
// }
|
d.Flash("A file name is required to publish this level.")
|
||||||
// log.Info("Write to: %s", filename)
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.HasSuffix(answer, ".level") {
|
||||||
|
answer += ".level"
|
||||||
|
}
|
||||||
|
|
||||||
|
answer = filepath.Join(cwd, answer)
|
||||||
|
log.Debug("call with includeBuiltins=%+v", includeBuiltins)
|
||||||
|
if _, err := publishing.Publish(scene.Level, answer, includeBuiltins); err != nil {
|
||||||
|
modal.Alert("Error when publishing the level: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
d.Flash("Exported published level to: %s", answer)
|
||||||
|
})
|
||||||
},
|
},
|
||||||
OnCancel: func() {
|
OnCancel: func() {
|
||||||
u.publishWindow.Hide()
|
u.publishWindow.Hide()
|
||||||
|
|
|
@ -3,6 +3,7 @@ package level
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FileSystem embeds a map of files inside a parent drawing.
|
// FileSystem embeds a map of files inside a parent drawing.
|
||||||
|
@ -64,3 +65,17 @@ func (l *Level) ListFiles() []string {
|
||||||
sort.Strings(files)
|
sort.Strings(files)
|
||||||
return files
|
return files
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListFilesAt returns the list of files having a common prefix.
|
||||||
|
func (l *Level) ListFilesAt(prefix string) []string {
|
||||||
|
var (
|
||||||
|
files = l.ListFiles()
|
||||||
|
match = []string{}
|
||||||
|
)
|
||||||
|
for _, name := range files {
|
||||||
|
if strings.HasPrefix(name, prefix) {
|
||||||
|
match = append(match, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return match
|
||||||
|
}
|
||||||
|
|
94
pkg/level/publishing/publishing.go
Normal file
94
pkg/level/publishing/publishing.go
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
/*
|
||||||
|
Package publishing contains functionality for "publishing" a Level, which
|
||||||
|
involves the writing and reading of custom doodads embedded inside
|
||||||
|
the levels.
|
||||||
|
|
||||||
|
Free tiers of the game will not read or write embedded doodads into
|
||||||
|
levels.
|
||||||
|
*/
|
||||||
|
package publishing
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
|
||||||
|
"git.kirsle.net/apps/doodle/pkg/balance"
|
||||||
|
"git.kirsle.net/apps/doodle/pkg/doodads"
|
||||||
|
"git.kirsle.net/apps/doodle/pkg/level"
|
||||||
|
"git.kirsle.net/apps/doodle/pkg/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
Level "Publishing" functions, involving the writing and reading of embedded
|
||||||
|
doodads within level files.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Publish writes a published level file, with embedded doodads included.
|
||||||
|
func Publish(lvl *level.Level, filename string, includeBuiltins bool) (*level.Level, error) {
|
||||||
|
// Get and embed the doodads.
|
||||||
|
builtins, customs := GetUsedDoodadNames(lvl)
|
||||||
|
if includeBuiltins {
|
||||||
|
log.Debug("including builtins: %+v", builtins)
|
||||||
|
customs = append(customs, builtins...)
|
||||||
|
}
|
||||||
|
for _, filename := range customs {
|
||||||
|
log.Debug("Embed filename: %s", filename)
|
||||||
|
doodad, err := doodads.LoadFromEmbeddable(filename, lvl)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("couldn't load doodad %s: %s", filename, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
bin, err := doodad.Serialize()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("couldn't serialize doodad %s: %s", filename, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Embed it.
|
||||||
|
lvl.SetFile(balance.EmbeddedDoodadsBasePath+filename, bin)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Publish: write file to %s", filename)
|
||||||
|
err := lvl.WriteFile(filename)
|
||||||
|
return lvl, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUsedDoodadNames returns the lists of doodad filenames in use in a level,
|
||||||
|
// bucketed by built-in or custom user doodads.
|
||||||
|
func GetUsedDoodadNames(lvl *level.Level) (builtin []string, custom []string) {
|
||||||
|
// Collect all the doodad names in use in this level.
|
||||||
|
unique := map[string]interface{}{}
|
||||||
|
names := []string{}
|
||||||
|
if lvl != nil {
|
||||||
|
for _, actor := range lvl.Actors {
|
||||||
|
if _, ok := unique[actor.Filename]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
unique[actor.Filename] = nil
|
||||||
|
names = append(names, actor.Filename)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Identify which of the doodads are built-ins.
|
||||||
|
// builtin = []string{}
|
||||||
|
builtinMap := map[string]interface{}{}
|
||||||
|
// custom := []string{}
|
||||||
|
if builtins, err := doodads.ListBuiltin(); err == nil {
|
||||||
|
for _, filename := range builtins {
|
||||||
|
if _, ok := unique[filename]; ok {
|
||||||
|
builtin = append(builtin, filename)
|
||||||
|
builtinMap[filename] = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, name := range names {
|
||||||
|
if _, ok := builtinMap[name]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
custom = append(custom, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Strings(builtin)
|
||||||
|
sort.Strings(custom)
|
||||||
|
|
||||||
|
return builtin, custom
|
||||||
|
}
|
|
@ -150,12 +150,12 @@ func (w *Canvas) LoadLevel(e render.Engine, level *level.Level) {
|
||||||
w.Load(level.Palette, level.Chunker)
|
w.Load(level.Palette, level.Chunker)
|
||||||
|
|
||||||
// TODO: wallpaper paths
|
// TODO: wallpaper paths
|
||||||
filename := "assets/wallpapers/" + level.Wallpaper
|
filename := balance.EmbeddedWallpaperBasePath + level.Wallpaper
|
||||||
if runtime.GOOS != "js" {
|
if runtime.GOOS != "js" {
|
||||||
// Check if the wallpaper wasn't found. Check bindata and file system.
|
// Check if the wallpaper wasn't found. Check bindata and file system.
|
||||||
if _, err := filesystem.FindFileEmbedded(filename, level); err != nil {
|
if _, err := filesystem.FindFileEmbedded(filename, level); err != nil {
|
||||||
log.Error("LoadLevel: wallpaper %s did not appear to exist, default to notebook.png", filename)
|
log.Error("LoadLevel: wallpaper %s did not appear to exist, default to notebook.png", filename)
|
||||||
filename = "assets/wallpapers/notebook.png"
|
filename = balance.EmbeddedWallpaperBasePath + "notebook.png"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ package uix
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"strings"
|
||||||
|
|
||||||
"git.kirsle.net/apps/doodle/pkg/doodads"
|
"git.kirsle.net/apps/doodle/pkg/doodads"
|
||||||
"git.kirsle.net/apps/doodle/pkg/level"
|
"git.kirsle.net/apps/doodle/pkg/level"
|
||||||
|
@ -14,11 +14,14 @@ import (
|
||||||
// InstallActors adds external Actors to the canvas to be superimposed on top
|
// InstallActors adds external Actors to the canvas to be superimposed on top
|
||||||
// of the drawing.
|
// of the drawing.
|
||||||
func (w *Canvas) InstallActors(actors level.ActorMap) error {
|
func (w *Canvas) InstallActors(actors level.ActorMap) error {
|
||||||
|
var errs []string
|
||||||
|
|
||||||
w.actors = make([]*Actor, 0)
|
w.actors = make([]*Actor, 0)
|
||||||
for id, actor := range actors {
|
for id, actor := range actors {
|
||||||
doodad, err := doodads.LoadFile(actor.Filename)
|
doodad, err := doodads.LoadFromEmbeddable(actor.Filename, w.level)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("InstallActors: %s", err)
|
errs = append(errs, err.Error())
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the "live" Actor to exist in the world, and set its world
|
// Create the "live" Actor to exist in the world, and set its world
|
||||||
|
@ -28,6 +31,10 @@ func (w *Canvas) InstallActors(actors level.ActorMap) error {
|
||||||
|
|
||||||
w.actors = append(w.actors, liveActor)
|
w.actors = append(w.actors, liveActor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(errs) > 0 {
|
||||||
|
return errors.New(strings.Join(errs, "\n"))
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -189,41 +189,41 @@ func NewOpenLevelEditor(config OpenLevelEditor) *ui.Window {
|
||||||
}
|
}
|
||||||
}(i, dd)
|
}(i, dd)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Browse button for local filesystem.
|
// Browse button for local filesystem.
|
||||||
browseDoodadFrame := ui.NewFrame("Browse Doodad Frame")
|
browseDoodadFrame := ui.NewFrame("Browse Doodad Frame")
|
||||||
frame.Pack(browseDoodadFrame, ui.Pack{
|
frame.Pack(browseDoodadFrame, ui.Pack{
|
||||||
Side: ui.N,
|
Side: ui.N,
|
||||||
Expand: true,
|
Expand: true,
|
||||||
FillX: true,
|
FillX: true,
|
||||||
PadY: 1,
|
PadY: 1,
|
||||||
})
|
})
|
||||||
|
|
||||||
browseDoodadButton := ui.NewButton("Browse Doodad", ui.NewLabel(ui.Label{
|
browseDoodadButton := ui.NewButton("Browse Doodad", ui.NewLabel(ui.Label{
|
||||||
Text: "Browse...",
|
Text: "Browse...",
|
||||||
Font: balance.MenuFont,
|
Font: balance.MenuFont,
|
||||||
}))
|
}))
|
||||||
browseDoodadButton.SetStyle(&balance.ButtonPrimary)
|
browseDoodadButton.SetStyle(&balance.ButtonPrimary)
|
||||||
browseDoodadFrame.Pack(browseDoodadButton, ui.Pack{
|
browseDoodadFrame.Pack(browseDoodadButton, ui.Pack{
|
||||||
Side: ui.W,
|
Side: ui.W,
|
||||||
})
|
})
|
||||||
|
|
||||||
browseDoodadButton.Handle(ui.Click, func(ed ui.EventData) error {
|
browseDoodadButton.Handle(ui.Click, func(ed ui.EventData) error {
|
||||||
filename, err := native.OpenFile("Choose a .doodad file", "*.doodad")
|
filename, err := native.OpenFile("Choose a .doodad file", "*.doodad")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Couldn't show file dialog: %s", err)
|
log.Error("Couldn't show file dialog: %s", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.LoadForPlay {
|
||||||
|
config.OnPlayLevel(filename)
|
||||||
|
} else {
|
||||||
|
config.OnEditLevel(filename)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
})
|
||||||
|
config.Supervisor.Add(browseDoodadButton)
|
||||||
if config.LoadForPlay {
|
}
|
||||||
config.OnPlayLevel(filename)
|
|
||||||
} else {
|
|
||||||
config.OnEditLevel(filename)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
config.Supervisor.Add(browseDoodadButton)
|
|
||||||
|
|
||||||
/******************
|
/******************
|
||||||
* Confirm/cancel buttons.
|
* Confirm/cancel buttons.
|
||||||
|
|
|
@ -3,12 +3,11 @@ package windows
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"sort"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.kirsle.net/apps/doodle/pkg/balance"
|
"git.kirsle.net/apps/doodle/pkg/balance"
|
||||||
"git.kirsle.net/apps/doodle/pkg/doodads"
|
|
||||||
"git.kirsle.net/apps/doodle/pkg/level"
|
"git.kirsle.net/apps/doodle/pkg/level"
|
||||||
|
"git.kirsle.net/apps/doodle/pkg/level/publishing"
|
||||||
"git.kirsle.net/apps/doodle/pkg/log"
|
"git.kirsle.net/apps/doodle/pkg/log"
|
||||||
"git.kirsle.net/go/render"
|
"git.kirsle.net/go/render"
|
||||||
"git.kirsle.net/go/ui"
|
"git.kirsle.net/go/ui"
|
||||||
|
@ -21,7 +20,7 @@ type Publish struct {
|
||||||
Engine render.Engine
|
Engine render.Engine
|
||||||
Level *level.Level
|
Level *level.Level
|
||||||
|
|
||||||
OnPublish func()
|
OnPublish func(builtinToo bool)
|
||||||
OnCancel func()
|
OnCancel func()
|
||||||
|
|
||||||
// Private vars.
|
// Private vars.
|
||||||
|
@ -124,39 +123,40 @@ func NewPublishWindow(cfg Publish) *ui.Window {
|
||||||
PadX: 2,
|
PadX: 2,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Collect all the doodad names in use in this level.
|
// // Collect all the doodad names in use in this level.
|
||||||
unique := map[string]interface{}{}
|
// unique := map[string]interface{}{}
|
||||||
names := []string{}
|
// names := []string{}
|
||||||
if cfg.Level != nil {
|
// if cfg.Level != nil {
|
||||||
for _, actor := range cfg.Level.Actors {
|
// for _, actor := range cfg.Level.Actors {
|
||||||
if _, ok := unique[actor.Filename]; ok {
|
// if _, ok := unique[actor.Filename]; ok {
|
||||||
continue
|
// continue
|
||||||
}
|
// }
|
||||||
unique[actor.Filename] = nil
|
// unique[actor.Filename] = nil
|
||||||
names = append(names, actor.Filename)
|
// names = append(names, actor.Filename)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
sort.Strings(names)
|
// sort.Strings(names)
|
||||||
|
|
||||||
// Identify which of the doodads are built-ins.
|
// // Identify which of the doodads are built-ins.
|
||||||
usedBuiltins := []string{}
|
// usedBuiltins := []string{}
|
||||||
builtinMap := map[string]interface{}{}
|
// builtinMap := map[string]interface{}{}
|
||||||
usedCustom := []string{}
|
// usedCustom := []string{}
|
||||||
if builtins, err := doodads.ListBuiltin(); err == nil {
|
// if builtins, err := doodads.ListBuiltin(); err == nil {
|
||||||
for _, filename := range builtins {
|
// for _, filename := range builtins {
|
||||||
if _, ok := unique[filename]; ok {
|
// if _, ok := unique[filename]; ok {
|
||||||
usedBuiltins = append(usedBuiltins, filename)
|
// usedBuiltins = append(usedBuiltins, filename)
|
||||||
builtinMap[filename] = nil
|
// builtinMap[filename] = nil
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
for _, name := range names {
|
// for _, name := range names {
|
||||||
if _, ok := builtinMap[name]; ok {
|
// if _, ok := builtinMap[name]; ok {
|
||||||
continue
|
// continue
|
||||||
}
|
// }
|
||||||
usedCustom = append(usedCustom, name)
|
// usedCustom = append(usedCustom, name)
|
||||||
}
|
// }
|
||||||
|
usedBuiltins, usedCustom := publishing.GetUsedDoodadNames(cfg.Level)
|
||||||
|
|
||||||
// Helper function to draw the button rows for a set of doodads.
|
// Helper function to draw the button rows for a set of doodads.
|
||||||
mkDoodadRows := func(filenames []string, builtin bool) []*ui.Frame {
|
mkDoodadRows := func(filenames []string, builtin bool) []*ui.Frame {
|
||||||
|
@ -201,7 +201,7 @@ func NewPublishWindow(cfg Publish) *ui.Window {
|
||||||
builtinRows = []*ui.Frame{}
|
builtinRows = []*ui.Frame{}
|
||||||
customRows = []*ui.Frame{}
|
customRows = []*ui.Frame{}
|
||||||
)
|
)
|
||||||
if len(names) > 0 {
|
if len(usedCustom) > 0 {
|
||||||
customRows = mkDoodadRows(usedCustom, false)
|
customRows = mkDoodadRows(usedCustom, false)
|
||||||
btnRows = append(btnRows, customRows...)
|
btnRows = append(btnRows, customRows...)
|
||||||
}
|
}
|
||||||
|
@ -284,7 +284,7 @@ func NewPublishWindow(cfg Publish) *ui.Window {
|
||||||
}{
|
}{
|
||||||
{"Export Level", true, func() {
|
{"Export Level", true, func() {
|
||||||
if cfg.OnPublish != nil {
|
if cfg.OnPublish != nil {
|
||||||
cfg.OnPublish()
|
cfg.OnPublish(cfg.includeBuiltins)
|
||||||
}
|
}
|
||||||
}},
|
}},
|
||||||
{"Close", false, func() {
|
{"Close", false, func() {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user