Files
ainovel-clients/state/characters.go

85 lines
2.3 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package state
import (
"fmt"
"os"
"strings"
"github.com/voocel/ainovel-cli/domain"
)
// SaveCharacters 同时保存 characters.json 和 characters.md。
func (s *Store) SaveCharacters(chars []domain.Character) error {
if err := s.writeJSON("characters.json", chars); err != nil {
return err
}
return s.writeMarkdown("characters.md", renderCharacters(chars))
}
// LoadCharacters 从 characters.json 读取角色档案。
func (s *Store) LoadCharacters() ([]domain.Character, error) {
var chars []domain.Character
if err := s.readJSON("characters.json", &chars); err != nil {
if os.IsNotExist(err) {
return nil, nil
}
return nil, err
}
return chars, nil
}
// SaveCharacterSnapshots 保存角色状态快照到 meta/snapshots/v{vol}a{arc}.json。
func (s *Store) SaveCharacterSnapshots(volume, arc int, snapshots []domain.CharacterSnapshot) error {
return s.writeJSON(fmt.Sprintf("meta/snapshots/v%02da%02d.json", volume, arc), snapshots)
}
// LoadSnapshots 读取指定卷弧的角色快照。
func (s *Store) LoadSnapshots(volume, arc int) ([]domain.CharacterSnapshot, error) {
var snapshots []domain.CharacterSnapshot
if err := s.readJSON(fmt.Sprintf("meta/snapshots/v%02da%02d.json", volume, arc), &snapshots); err != nil {
if os.IsNotExist(err) {
return nil, nil
}
return nil, err
}
return snapshots, nil
}
// LoadLatestSnapshots 加载最近一次角色快照(按卷弧倒序查找)。
// 从分层大纲获取实际卷弧数量,避免盲扫。
func (s *Store) LoadLatestSnapshots() ([]domain.CharacterSnapshot, error) {
volumes, _ := s.LoadLayeredOutline()
if len(volumes) == 0 {
return nil, nil
}
for vi := len(volumes) - 1; vi >= 0; vi-- {
v := volumes[vi]
for ai := len(v.Arcs) - 1; ai >= 0; ai-- {
snaps, err := s.LoadSnapshots(v.Index, v.Arcs[ai].Index)
if err != nil {
return nil, err
}
if len(snaps) > 0 {
return snaps, nil
}
}
}
return nil, nil
}
func renderCharacters(chars []domain.Character) string {
var b strings.Builder
b.WriteString("# 角色档案\n\n")
for _, c := range chars {
fmt.Fprintf(&b, "## %s%s\n\n", c.Name, c.Role)
fmt.Fprintf(&b, "%s\n\n", c.Description)
if c.Arc != "" {
fmt.Fprintf(&b, "**角色弧线**%s\n\n", c.Arc)
}
if len(c.Traits) > 0 {
fmt.Fprintf(&b, "**特征**%s\n\n", strings.Join(c.Traits, "、"))
}
}
return b.String()
}