primeiro commit
This commit is contained in:
120
internal/vn/flightcheck.go
Normal file
120
internal/vn/flightcheck.go
Normal file
@@ -0,0 +1,120 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user