diff options
Diffstat (limited to 'internal/action')
| -rw-r--r-- | internal/action/action.go | 23 | ||||
| -rw-r--r-- | internal/action/behavior.go | 6 | ||||
| -rw-r--r-- | internal/action/recipe.go | 110 | ||||
| -rw-r--r-- | internal/action/store.go | 107 |
4 files changed, 71 insertions, 175 deletions
diff --git a/internal/action/action.go b/internal/action/action.go index 44f27f8..5e66708 100644 --- a/internal/action/action.go +++ b/internal/action/action.go @@ -1,5 +1,28 @@ package action +import "strings" + +func WordPrefixMatch(input, name string) bool { + inputWords := strings.Fields(strings.ToLower(input)) + if len(inputWords) == 0 { + return false + } + nameWords := strings.Fields(strings.ToLower(name)) + for _, iw := range inputWords { + found := false + for _, nw := range nameWords { + if strings.HasPrefix(nw, iw) || strings.HasPrefix(iw, nw) { + found = true + break + } + } + if !found { + return false + } + } + return true +} + type Action struct { Type string TargetID string diff --git a/internal/action/behavior.go b/internal/action/behavior.go index e1a79e3..4071f0d 100644 --- a/internal/action/behavior.go +++ b/internal/action/behavior.go @@ -91,9 +91,3 @@ type UseConfig struct { Level int `yaml:"level"` XP int `yaml:"xp"` } - -type ToggleConfig struct { - Message string `yaml:"message"` - SetFlags map[string]any `yaml:"set_flags"` - Check *Condition `yaml:"check"` -} diff --git a/internal/action/recipe.go b/internal/action/recipe.go index d1acaa5..c1f30fb 100644 --- a/internal/action/recipe.go +++ b/internal/action/recipe.go @@ -1,7 +1,6 @@ package action import ( - "fmt" "os" "path/filepath" @@ -34,13 +33,52 @@ type RecipeDef struct { type RecipeStore struct { dataDir string + cache map[string][]RecipeDef } func NewRecipeStore(dataDir string) *RecipeStore { - return &RecipeStore{dataDir: dataDir} + return &RecipeStore{dataDir: dataDir, cache: make(map[string][]RecipeDef)} } func (s *RecipeStore) LoadAll() ([]RecipeDef, error) { + return s.LoadByType("") +} + +func (s *RecipeStore) LoadByType(recipeType string) ([]RecipeDef, error) { + if recipeType == "" { + recipeType = "_all" + } + if cached, ok := s.cache[recipeType]; ok { + result := make([]RecipeDef, len(cached)) + copy(result, cached) + return result, nil + } + + all, err := s.loadAllRaw() + if err != nil { + return nil, err + } + + if recipeType == "_all" { + s.cache[recipeType] = all + result := make([]RecipeDef, len(all)) + copy(result, all) + return result, nil + } + + var filtered []RecipeDef + for _, r := range all { + if r.Type == recipeType { + filtered = append(filtered, r) + } + } + s.cache[recipeType] = filtered + result := make([]RecipeDef, len(filtered)) + copy(result, filtered) + return result, nil +} + +func (s *RecipeStore) loadAllRaw() ([]RecipeDef, error) { dir := filepath.Join(s.dataDir, "recipes") entries, err := os.ReadDir(dir) if err != nil { @@ -76,14 +114,11 @@ func (r *RecipeDef) MatchesEntry(itemID string) bool { } func (s *RecipeStore) FindByInput(recipeType string, itemID string) *RecipeDef { - all, err := s.LoadAll() + all, err := s.LoadByType(recipeType) if err != nil { return nil } for i := range all { - if recipeType != "" && all[i].Type != recipeType { - continue - } for _, e := range all[i].Consume { for _, id := range e.Items { if id == itemID { @@ -95,54 +130,9 @@ func (s *RecipeStore) FindByInput(recipeType string, itemID string) *RecipeDef { return nil } -func (s *RecipeStore) FindByItem(itemID, recipeType string) ([]RecipeDef, error) { - all, err := s.LoadAll() - if err != nil { - return nil, err - } - var matches []RecipeDef - for _, r := range all { - if recipeType != "" && r.Type != recipeType { - continue - } - if r.MatchesEntry(itemID) { - matches = append(matches, r) - } - } - return matches, nil -} - -func (s *RecipeStore) FindByItems(a, b string) ([]RecipeDef, error) { - all, err := s.LoadAll() - if err != nil { - return nil, err - } - var matches []RecipeDef - for _, r := range all { - if len(r.Consume) < 2 { - continue - } - aEntry := -1 - bEntry := -1 - for ei, e := range r.Consume { - for _, id := range e.Items { - if id == a && aEntry < 0 { - aEntry = ei - } - if id == b && bEntry < 0 { - bEntry = ei - } - } - } - if aEntry >= 0 && bEntry >= 0 && aEntry != bEntry { - matches = append(matches, r) - } - } - return matches, nil -} func (s *RecipeStore) FindByStation(itemID string, stationIDs []string, recipeType string) ([]RecipeDef, error) { - all, err := s.LoadAll() + all, err := s.LoadByType(recipeType) if err != nil { return nil, err } @@ -181,21 +171,7 @@ func (r *RecipeDef) EffectiveSkill() string { return r.Type } -func (s *RecipeStore) FindByNameOrID(query string, recipeType string) (*RecipeDef, error) { - all, err := s.LoadAll() - if err != nil { - return nil, err - } - for _, r := range all { - if recipeType != "" && r.Type != recipeType { - continue - } - if r.ID == query || r.Output == query { - return &r, nil - } - } - return nil, fmt.Errorf("recipe not found: %s", query) -} + func (r *RecipeDef) FirstItemName(load func(string) (string, bool)) string { for _, e := range r.Consume { diff --git a/internal/action/store.go b/internal/action/store.go index fd58281..a8db9df 100644 --- a/internal/action/store.go +++ b/internal/action/store.go @@ -5,107 +5,10 @@ import ( "math/rand" "os" "path/filepath" - "sync" "gopkg.in/yaml.v3" ) -type Store struct { - dataDir string - mu sync.Mutex - cache map[string]*RawBehavior -} - -type RawBehavior struct { - ID string - Type string - Raw map[string]any -} - -func NewStore(dataDir string) *Store { - return &Store{ - dataDir: dataDir, - cache: make(map[string]*RawBehavior), - } -} - -func (s *Store) Load(id string) (*RawBehavior, error) { - s.mu.Lock() - if b, ok := s.cache[id]; ok { - s.mu.Unlock() - return b, nil - } - s.mu.Unlock() - - path := filepath.Join(s.dataDir, "behaviors", id+".yaml") - data, err := os.ReadFile(path) - if err != nil { - return nil, fmt.Errorf("read behavior %s: %w", id, err) - } - - var raw map[string]any - if err := yaml.Unmarshal(data, &raw); err != nil { - return nil, fmt.Errorf("parse behavior %s: %w", id, err) - } - - rb := &RawBehavior{ID: id, Raw: raw} - if t, ok := raw["type"].(string); ok { - rb.Type = t - } - if rid, ok := raw["id"].(string); ok { - rb.ID = rid - } - - s.mu.Lock() - s.cache[id] = rb - s.mu.Unlock() - return rb, nil -} - -func unmarshalRaw[T any](rb *RawBehavior, expectedType string) (*T, error) { - if rb.Type != expectedType { - return nil, fmt.Errorf("behavior %s is type %s, expected %s", rb.ID, rb.Type, expectedType) - } - var cfg T - raw, _ := yaml.Marshal(rb.Raw) - if err := yaml.Unmarshal(raw, &cfg); err != nil { - return nil, fmt.Errorf("parse %s config %s: %w", expectedType, rb.ID, err) - } - return &cfg, nil -} - -func (s *Store) LoadGather(id string) (*GatherConfig, error) { - rb, err := s.Load(id) - if err != nil { - return nil, err - } - return unmarshalRaw[GatherConfig](rb, "gather") -} - -func (s *Store) LoadTalk(id string) (*TalkConfig, error) { - rb, err := s.Load(id) - if err != nil { - return nil, err - } - return unmarshalRaw[TalkConfig](rb, "talk") -} - -func (s *Store) LoadUse(id string) (*UseConfig, error) { - rb, err := s.Load(id) - if err != nil { - return nil, err - } - return unmarshalRaw[UseConfig](rb, "use") -} - -func (s *Store) LoadToggle(id string) (*ToggleConfig, error) { - rb, err := s.Load(id) - if err != nil { - return nil, err - } - return unmarshalRaw[ToggleConfig](rb, "toggle") -} - func SuccessChance(cfg SuccessFormula, level int, requiredLevel int) float64 { chance := cfg.Base + float64(level-requiredLevel)*cfg.PerLevel if chance > cfg.Cap { @@ -117,8 +20,8 @@ func SuccessChance(cfg SuccessFormula, level int, requiredLevel int) float64 { return chance } -func (s *Store) LoadDropTable(id string) (*DropTableDef, error) { - path := filepath.Join(s.dataDir, "drops", id+".yaml") +func LoadDropTable(dataDir, id string) (*DropTableDef, error) { + path := filepath.Join(dataDir, "drops", id+".yaml") data, err := os.ReadFile(path) if err != nil { return nil, fmt.Errorf("read drop table %s: %w", id, err) @@ -130,7 +33,7 @@ func (s *Store) LoadDropTable(id string) (*DropTableDef, error) { return &dt, nil } -func (s *Store) ResolveDrop(drops []DropEntry) *DropEntry { +func ResolveDrop(dataDir string, drops []DropEntry) *DropEntry { if len(drops) == 0 { return nil } @@ -147,9 +50,9 @@ func (s *Store) ResolveDrop(drops []DropEntry) *DropEntry { cumulative += drops[i].Weight if roll < cumulative { if drops[i].Table != "" { - sub, err := s.LoadDropTable(drops[i].Table) + sub, err := LoadDropTable(dataDir, drops[i].Table) if err == nil { - if resolved := s.ResolveDrop(sub.Drops); resolved != nil { + if resolved := ResolveDrop(dataDir, sub.Drops); resolved != nil { qty := drops[i].Quantity if qty <= 0 { qty = resolved.Quantity |
