diff options
| author | historia <[not public]> | 2026-09-18 16:13:49 -0400 |
|---|---|---|
| committer | historia <[not public]> | 2026-09-18 16:13:49 -0400 |
| commit | 194164a77eb4f2479b94c19e6f0e1278ab608781 (patch) | |
| tree | 53413add8ed6f32a34d1733397e380cc98ef70ef /internal/behavior/store.go | |
| parent | 67e01aab85607b9e601185c7d62dff576af3bb43 (diff) | |
| download | thehouseoficarus-194164a77eb4f2479b94c19e6f0e1278ab608781.tar.gz | |
fix: more casino, economy, gameplay, security, and world data hardening gaps
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 != "" { |
