Resolve canonical parties with campaign configuration

This commit is contained in:
2026-08-30 14:01:51 +00:00
parent 7e4ceb3d48
commit 61000a9466
18 changed files with 607 additions and 45 deletions

View File

@@ -0,0 +1,93 @@
package config
import (
"fmt"
"path/filepath"
"strings"
"gitea.maximumdirect.net/eric/narratio/internal/fileops"
)
const maxPartyDocumentBytes = 8 << 20
func resolvePartyInput(input ResolvedInputFile) (ResolvedParty, error) {
configuredPath := strings.TrimSpace(input.Path)
if configuredPath == "" {
return ResolvedParty{}, fmt.Errorf("party input path is required")
}
configPath := strings.TrimSpace(input.ConfigPath)
if configPath == "" {
return ResolvedParty{}, fmt.Errorf("party input %q has no declaring configuration path", configuredPath)
}
path := configuredPath
if !filepath.IsAbs(path) {
path = filepath.Join(filepath.Dir(configPath), path)
}
path = filepath.Clean(path)
raw, err := fileops.ReadRegularFile(path, maxPartyDocumentBytes)
if err != nil {
return ResolvedParty{}, fmt.Errorf("read party input %q: %w", path, err)
}
document, err := ParseParty(raw)
if err != nil {
return ResolvedParty{}, fmt.Errorf("parse party input %q: %w", path, err)
}
resolved := ResolvedParty{
Mode: document.Mode,
Source: PartySource{
Path: path,
ConfigPath: configPath,
Source: input.Source,
},
Canonical: document.Canonical,
}
if document.IsCanonical() {
return resolved, nil
}
return resolveLegacyParty(resolved)
}
func campaignPartyInput(campaignPath string, campaign *CampaignConfig) (ResolvedInputFile, error) {
if campaign == nil {
return ResolvedInputFile{}, fmt.Errorf("campaign config is required")
}
if strings.TrimSpace(campaign.Inputs.PartyFile) == "" {
return ResolvedInputFile{}, fmt.Errorf("campaign.inputs.party_file is required")
}
return ResolvedInputFile{
Path: campaign.Inputs.PartyFile,
ConfigPath: campaignPath,
Source: "campaign_config",
}, nil
}
func resolveCampaignParty(campaignPath string, campaign *CampaignConfig) (ResolvedParty, error) {
input, err := campaignPartyInput(campaignPath, campaign)
if err != nil {
return ResolvedParty{}, err
}
return resolvePartyInput(input)
}
func validateCanonicalPartySelection(campaign *CampaignConfig, session *SessionConfig) error {
if campaign == nil {
return fmt.Errorf("campaign config is required")
}
if strings.TrimSpace(campaign.Inputs.PlayersFile) != "" {
return fmt.Errorf("campaign.inputs.players_file is not allowed with a canonical party")
}
if session == nil {
return nil
}
if strings.TrimSpace(session.Inputs.PlayersFile) != "" {
return fmt.Errorf("session.inputs.players_file is not allowed with a canonical party")
}
if strings.TrimSpace(session.Inputs.PartyFile) != "" {
return fmt.Errorf("session.inputs.party_file cannot override a canonical campaign party")
}
return nil
}
func virtualPlayersInput() ResolvedInputFile {
return ResolvedInputFile{Source: "derived_from_party"}
}