package game import "sync" // FlagChangeCallback is invoked when a world flag value actually changes // (old value differs from new, or new flag is created with a truthy value). type FlagChangeCallback func(name string, value any) // FlagStore holds world flags — shared mutable state visible to all players // (e.g. opened doors, quest state). Player-specific flags live on // *player.Player.Flags instead. FlagStore is safe for concurrent use. type FlagStore struct { mu sync.Mutex flags map[string]any callbacks []FlagChangeCallback } func NewFlagStore() *FlagStore { return &FlagStore{flags: make(map[string]any)} } func (f *FlagStore) OnChange(cb FlagChangeCallback) { f.mu.Lock() defer f.mu.Unlock() f.callbacks = append(f.callbacks, cb) } func (f *FlagStore) Get(name string) (any, bool) { f.mu.Lock() defer f.mu.Unlock() v, ok := f.flags[name] return v, ok } func (f *FlagStore) Set(name string, value any) { f.mu.Lock() old, existed := f.flags[name] f.flags[name] = value cbs := f.callbacks f.mu.Unlock() if !existed || !valuesEqual(old, value) { for _, cb := range cbs { cb(name, value) } } } func (f *FlagStore) SetAll(m map[string]any) { f.mu.Lock() changed := make(map[string]any) for k, v := range m { old, existed := f.flags[k] f.flags[k] = v if !existed || !valuesEqual(old, v) { changed[k] = v } } cbs := f.callbacks f.mu.Unlock() for k, v := range changed { for _, cb := range cbs { cb(k, v) } } } func (f *FlagStore) Delete(name string) { f.mu.Lock() defer f.mu.Unlock() delete(f.flags, name) } func (f *FlagStore) All() map[string]any { f.mu.Lock() defer f.mu.Unlock() out := make(map[string]any, len(f.flags)) for k, v := range f.flags { out[k] = v } return out }