feat(persona): 人格系统(YAML loader / 角色人格注册+记忆隔离 / 情绪状态机+好感度)
This commit is contained in:
1 parent
653c2489bf
commit
70fd915242
11 files changed
+1568
No files matched your search
@@ -0,0 +1,90 @@
|
||||
package emotion
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// ErrUnknownPersona is returned by Manager when an operation targets a persona
|
||||
// id that was never registered.
|
||||
var ErrUnknownPersona = errors.New("emotion: unknown persona")
|
||||
|
||||
// entry binds a persona's machine and affection together so whatever happens to
|
||||
// one persona never leaks into another.
|
||||
type entry struct {
|
||||
machine *Machine
|
||||
affection *Affection
|
||||
}
|
||||
|
||||
// Manager owns per-persona emotion and affection. Each persona id maps to its
|
||||
// own Machine and Affection, which is what makes emotion follow the persona
|
||||
// rather than a behavior mode. All methods are safe for concurrent use.
|
||||
type Manager struct {
|
||||
mu sync.RWMutex
|
||||
items map[string]*entry
|
||||
}
|
||||
|
||||
// NewManager returns an empty Manager.
|
||||
func NewManager() *Manager {
|
||||
return &Manager{items: make(map[string]*entry)}
|
||||
}
|
||||
|
||||
// Set registers (or replaces) the machine and affection for id.
|
||||
func (m *Manager) Set(id string, machine *Machine, affection *Affection) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
m.items[id] = &entry{machine: machine, affection: affection}
|
||||
}
|
||||
|
||||
// Get returns the machine and affection for id, and whether it is registered.
|
||||
func (m *Manager) Get(id string) (*Machine, *Affection, bool) {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
e, ok := m.items[id]
|
||||
if !ok {
|
||||
return nil, nil, false
|
||||
}
|
||||
return e.machine, e.affection, true
|
||||
}
|
||||
|
||||
// Remove deletes the entry for id, reporting whether an entry was present.
|
||||
func (m *Manager) Remove(id string) bool {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
if _, ok := m.items[id]; !ok {
|
||||
return false
|
||||
}
|
||||
delete(m.items, id)
|
||||
return true
|
||||
}
|
||||
|
||||
// Transition moves the persona identified by id into the given emotion state.
|
||||
func (m *Manager) Transition(id string, to EmotionState) error {
|
||||
machine, _, ok := m.Get(id)
|
||||
if !ok {
|
||||
return fmt.Errorf("emotion: transition for %q: %w", id, ErrUnknownPersona)
|
||||
}
|
||||
if err := machine.Transition(to); err != nil {
|
||||
return fmt.Errorf("emotion: transition persona %q to %q: %w", id, to, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AdjustAffection applies a signed delta to the persona's affection. It returns
|
||||
// the before and after values and an error for unknown personas.
|
||||
func (m *Manager) AdjustAffection(id string, delta int) (before, after int, err error) {
|
||||
_, affection, ok := m.Get(id)
|
||||
if !ok {
|
||||
return 0, 0, fmt.Errorf("emotion: affection for %q: %w", id, ErrUnknownPersona)
|
||||
}
|
||||
before, after = affection.Adjust(delta)
|
||||
return before, after, nil
|
||||
}
|
||||
|
||||
// Count reports how many personas are currently tracked.
|
||||
func (m *Manager) Count() int {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
return len(m.items)
|
||||
}
|
||||
Reference in new issue
Block a user