diff options
Diffstat (limited to 'internal/validate/validate.go')
| -rw-r--r-- | internal/validate/validate.go | 37 |
1 files changed, 27 insertions, 10 deletions
diff --git a/internal/validate/validate.go b/internal/validate/validate.go index 6a05eb6..d77eafa 100644 --- a/internal/validate/validate.go +++ b/internal/validate/validate.go @@ -35,6 +35,18 @@ type CourseView struct { ID string StartRoom int ObstacleRooms []int + // OnFailRooms are the authored on_fail destinations (>0). The runtime + // teleports to them unconditionally on an obstacle failure. + OnFailRooms []int +} + +// KnownFieldTarget lets the game package contribute its own content types to +// the KnownFields decode pass; the validate package cannot import game +// without a cycle. +type KnownFieldTarget struct { + SubDir string + Label string + NewDef func() any } // TechView is the subset of a tech definition needed for validation. @@ -64,6 +76,13 @@ type Source struct { // ModuleDestinations maps module id to destination room for transport // modules. A destination that is not a real room soft-locks the player. ModuleDestinations map[string]int + // TransportModules is the set of transport-category module IDs, so a + // transport module whose destination is omitted or <= 0 is still + // reported (the runtime saves the player into room 0). + TransportModules map[string]bool + // KnownFieldTargets are game-owned content types (techs, modules, + // courses, help) included in the strict KnownFields decode pass. + KnownFieldTargets []KnownFieldTarget } // Run executes all checks and returns the collected issues. @@ -79,7 +98,7 @@ func Run(s Source) []Issue { issues = append(issues, validateIDs(s.DataDir, dir.sub, dir.label)...) } - issues = append(issues, validateKnownFields(s.DataDir)...) + issues = append(issues, validateKnownFields(s.DataDir, s.KnownFieldTargets)...) issues = append(issues, validateRoomFilenames(s.DataDir)...) issues = append(issues, validateRooms(s)...) @@ -126,31 +145,29 @@ func validateRoomFilenames(dataDir string) []Issue { // silently discarded by yaml.Unmarshal. Only package-owned content types are // covered (world/object/item/behavior); game-owned definitions are checked by // their own loaders. -func validateKnownFields(dataDir string) []Issue { - targets := []struct { - subDir string - label string - newDef func() any - }{ +func validateKnownFields(dataDir string, extra []KnownFieldTarget) []Issue { + targets := []KnownFieldTarget{ {"rooms", "room", func() any { return new(world.Room) }}, {"mobs", "mob", func() any { return new(world.MobDef) }}, {"objects", "object", func() any { return new(object.ObjectDef) }}, {"items", "item", func() any { return new(item.ItemDef) }}, {"drops", "drop table", func() any { return new(behavior.DropTableDef) }}, {"hazards", "hazard", func() any { return new(world.HazardDef) }}, + {"triggers", "trigger", func() any { return new(behavior.Trigger) }}, } + targets = append(targets, extra...) var issues []Issue for _, t := range targets { - dir := filepath.Join(dataDir, t.subDir) + dir := filepath.Join(dataDir, t.SubDir) _ = behavior.WalkYAMLDir(dir, func(path, id string, data []byte) error { dec := yaml.NewDecoder(bytes.NewReader(data)) dec.KnownFields(true) - if err := dec.Decode(t.newDef()); err != nil { + if err := dec.Decode(t.NewDef()); err != nil { rel := strings.TrimPrefix(path, dataDir+"/") issues = append(issues, Issue{ Level: "ERROR", Type: "unknown-field", - Message: fmt.Sprintf("%s %s: %v", t.label, rel, err), + Message: fmt.Sprintf("%s %s: %v", t.Label, rel, err), }) } return nil |
