121 lines
2.8 KiB
Go
121 lines
2.8 KiB
Go
package vn
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
// FlightCheckResult contains script integrity validation results.
|
|
type FlightCheckResult struct {
|
|
Errors []string
|
|
}
|
|
|
|
func (r *FlightCheckResult) OK() bool {
|
|
return len(r.Errors) == 0
|
|
}
|
|
|
|
func (r *FlightCheckResult) Summary(texts *Texts) string {
|
|
if r.OK() {
|
|
return texts.FlightCheckPassed
|
|
}
|
|
if len(r.Errors) == 1 {
|
|
return fmt.Sprintf(texts.FlightCheckOneFmt, r.Errors[0])
|
|
}
|
|
return fmt.Sprintf(texts.FlightCheckManyFmt, len(r.Errors))
|
|
}
|
|
|
|
func RunFlightCheck(script *Script, texts *Texts) *FlightCheckResult {
|
|
result := &FlightCheckResult{}
|
|
|
|
seenFiles := map[string]bool{}
|
|
for _, file := range script.LoadedFiles {
|
|
if seenFiles[file] {
|
|
continue
|
|
}
|
|
seenFiles[file] = true
|
|
if _, err := os.Stat(file); err != nil {
|
|
result.Errors = append(result.Errors, fmt.Sprintf(texts.FlightMissingScriptFmt, file))
|
|
}
|
|
}
|
|
|
|
sceneByID := map[string]Scene{}
|
|
for _, scene := range script.Scenes {
|
|
if _, ok := sceneByID[scene.ID]; ok {
|
|
result.Errors = append(result.Errors, fmt.Sprintf(texts.FlightDuplicateSceneFmt, scene.ID))
|
|
continue
|
|
}
|
|
sceneByID[scene.ID] = scene
|
|
}
|
|
if _, ok := sceneByID[script.Start]; !ok {
|
|
result.Errors = append(result.Errors, fmt.Sprintf(texts.FlightStartMissingFmt, script.Start))
|
|
}
|
|
|
|
assets := map[string]bool{}
|
|
var walk func(sceneID string, cmds []Command)
|
|
walk = func(sceneID string, cmds []Command) {
|
|
for _, cmd := range cmds {
|
|
switch strings.ToLower(cmd.Type) {
|
|
case "goto":
|
|
if cmd.Target != "" {
|
|
if _, ok := sceneByID[cmd.Target]; !ok {
|
|
result.Errors = append(result.Errors, fmt.Sprintf(texts.FlightGotoMissingFmt, sceneID, cmd.Target))
|
|
}
|
|
}
|
|
case "choice":
|
|
for _, c := range cmd.Choices {
|
|
if _, ok := sceneByID[c.Target]; !ok {
|
|
result.Errors = append(result.Errors, fmt.Sprintf(texts.FlightChoiceMissingFmt, sceneID, c.Target))
|
|
}
|
|
}
|
|
case "if":
|
|
walk(sceneID, cmd.Then)
|
|
walk(sceneID, cmd.Else)
|
|
case "menu":
|
|
for _, item := range cmd.MenuItems {
|
|
if item.Sprite != "" {
|
|
assets[item.Sprite] = true
|
|
}
|
|
walk(sceneID, item.Commands)
|
|
}
|
|
}
|
|
|
|
if cmd.BackgroundImage != "" {
|
|
assets[cmd.BackgroundImage] = true
|
|
}
|
|
if looksLikeImagePath(cmd.Background) {
|
|
assets[cmd.Background] = true
|
|
}
|
|
if cmd.Sprite != "" {
|
|
assets[cmd.Sprite] = true
|
|
}
|
|
}
|
|
}
|
|
|
|
for _, scene := range script.Scenes {
|
|
walk(scene.ID, scene.Commands)
|
|
}
|
|
|
|
keys := make([]string, 0, len(assets))
|
|
for a := range assets {
|
|
keys = append(keys, a)
|
|
}
|
|
sort.Strings(keys)
|
|
for _, rel := range keys {
|
|
if strings.Contains(rel, "{") {
|
|
continue
|
|
}
|
|
path := rel
|
|
if !filepath.IsAbs(path) {
|
|
path = filepath.Join(script.BaseDir, rel)
|
|
}
|
|
if _, err := os.Stat(path); err != nil {
|
|
result.Errors = append(result.Errors, fmt.Sprintf(texts.FlightMissingAssetFmt, rel))
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|