diff options
Diffstat (limited to 'internal/behavior/store.go')
| -rw-r--r-- | internal/behavior/store.go | 27 |
1 files changed, 21 insertions, 6 deletions
diff --git a/internal/behavior/store.go b/internal/behavior/store.go index cd7a6b7..a558f87 100644 --- a/internal/behavior/store.go +++ b/internal/behavior/store.go @@ -95,23 +95,27 @@ func SuccessChance(cfg SuccessFormula, level int, requiredLevel int) float64 { } var ( - dropIndex map[string]string + dropIndexes = map[string]map[string]string{} dropIndexMu sync.Mutex ) func loadDropIndex(dataDir string) map[string]string { dropIndexMu.Lock() defer dropIndexMu.Unlock() - if dropIndex == nil { - dropIndex = BuildPathIndex(filepath.Join(dataDir, "drops")) - } - return dropIndex + // Keyed by dataDir: a single process can host more than one data dir + // (tests), and a shared index would resolve ids against the first one. + if idx, ok := dropIndexes[dataDir]; ok { + return idx + } + idx := BuildPathIndex(filepath.Join(dataDir, "drops")) + dropIndexes[dataDir] = idx + return idx } func ClearDropIndex() { dropIndexMu.Lock() defer dropIndexMu.Unlock() - dropIndex = nil + dropIndexes = map[string]map[string]string{} } func LoadDropTable(dataDir, id string) (*DropTableDef, error) { @@ -161,6 +165,11 @@ func pickWeighted(drops []DropEntry) *DropEntry { // cycles at startup. const maxDropTableDepth = 32 +// maxDropRolls bounds a table-reference entry's `quantity` (how many times the +// referenced table is rolled). An accidental large value would run that many +// weighted picks on the owner tick and stall the whole world. +const maxDropRolls = 64 + func ResolveDrop(dataDir string, drops []DropEntry) *DropEntry { return resolveDrop(dataDir, drops, 0) } @@ -227,6 +236,12 @@ func resolveDropList(dataDir string, drops []DropEntry, depth int) []DropEntry { if rolls <= 0 { rolls = 1 } + // Bound authored quantities: an accidental `quantity: 1000000000` on a + // table reference would otherwise run a billion weighted picks on the + // owner tick and stall the whole world. + if rolls > maxDropRolls { + rolls = maxDropRolls + } var out []DropEntry for i := 0; i < rolls; i++ { if resolved := resolveDrop(dataDir, sub.Drops, depth+1); resolved != nil && resolved.ItemID != "" { |
