Noah Petherbridge
7093b102e3
* 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.
95 lines
2.5 KiB
Go
95 lines
2.5 KiB
Go
/*
|
|
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
|
|
}
|