Documentation
¶
Overview ¶
Package contentpatcher reads Content Patcher content packs: the changes each patch writes, the assets they touch, which packs overlap, which pack wins each clash, and which packs nothing else needs.
Index ¶
- Constants
- Variables
- func AddAssetNames(assets map[string]bool, target string)
- func AddSettingValue(values *[]string, value string)
- func AssetBasenames(assets map[string]bool) []string
- func ConfigHolds(conditions []Config, schema map[string]Schema, config map[string]string) bool
- func ConfigValue(raw json.RawMessage) (string, bool)
- func ContentReference(_, rel string) string
- func CropPackImage(root, fromFile string, x, y, w, h int) (string, error)
- func DropParts()
- func DynamicWhenHolds(when When, tokens []TokenDefinition, present map[string]bool, ...) bool
- func Equal(a, b ModID) bool
- func FlushMapScans(mods []Mod)
- func FlushPackDiskCache(mods []Mod)
- func FlushParts()
- func Forget()
- func HoldPacks() func()
- func IsContentPatcherPack(im Mod) bool
- func IsSupportingPack(im Mod, skip bool) bool
- func IsTilesheetPack(im Mod, skip bool) bool
- func IsTilesheetTarget(target string) bool
- func LoadFileBytes(hit packHit, load Patch, target string) ([]byte, bool)
- func ModMapFiles(im Mod) (paths []string, complete bool)
- func NormalizeAsset(value string) string
- func NormalizeTarget(s string) string
- func PackSig(im Mod, pack Pack, present map[string]bool) (sig string, stable bool)
- func PartKey(skip bool, fields ...string) string
- func PreloadPacks(mods []Mod, read func(Mod) Pack)
- func PresentFor(pack Pack, present map[string]bool) map[string]bool
- func PrintableRuns(raw []byte) []string
- func ReadPackConfig(folder string) map[string]string
- func RecordMapUses(im Mod, candidates []Mod, assetsByID map[string]map[string]bool, ...) bool
- func ReleasePacks(gen int)
- func Reset()
- func ResolveLoadFile(file, target string, tokens []Patch, present map[string]bool, ...) (string, bool)
- func ScalarValue(v json.RawMessage) (string, bool)
- func SetCacheRoot(dir string)
- func SettingValueMatches(current string, condition Config) bool
- func SplitTargets(s string) []string
- func SupportingPackKeys(mods []Mod, skip bool) []string
- func TmxImageSources(raw []byte) []string
- type AssetMapPage
- type AssetTarget
- type AssetTouch
- type Config
- type Conflict
- type Dependency
- type DynamicCondition
- type Evidence
- type Extension
- type FileStamp
- type Findings
- type Fix
- type FlagCondition
- type Hint
- type MapFileList
- type MapScan
- type Mod
- type ModID
- type ModRef
- type Note
- type Pack
- type PartEntry
- type PartsRun
- type Patch
- type Request
- type Schema
- type Shadowed
- type Shape
- type TilesheetUse
- type TokenDefinition
- type When
- type WhoChangesPage
Constants ¶
const ( WinnerTop = "top" // the pack the checker ranks highest WinnerChosen = "chosen" // the user's win choices make one pack's edits stand WinnerLoadOrder = "load-order" // a dependency makes one pack load last WinnerNeither = "neither" // Content Patcher applies none of the exclusive loads WinnerUnclear = "unclear" WinnerPerEntry = "per-entry" // the user settled each clash with a different winner )
WinnerKind values of a Conflict.
Variables ¶
var FreeOSMemory = true
FreeOSMemory frees the released packs' pages with the runtime; a host that is busy may want it off.
Functions ¶
func AddAssetNames ¶
AddAssetNames records a target under its full name and its base name.
func AddSettingValue ¶
AddSettingValue appends a suggested value unless it is blank or already listed, ignoring case.
func AssetBasenames ¶
AssetBasenames are the asset names in assets that are a bare file name.
func ConfigHolds ¶
ConfigHolds reports whether the pack's current settings (config.json, else the schema Default) meet every config condition, so a patch the player switched off is not counted as a conflict.
func ConfigValue ¶
func ConfigValue(raw json.RawMessage) (string, bool)
ConfigValue is a config.json value as text: a scalar, or a list joined by ", ".
func ContentReference ¶
func DynamicWhenHolds ¶
func Equal ¶
Equal reports whether two ids name the same mod: formats compare exactly, locals by the format's rule.
func FlushMapScans ¶
func FlushMapScans(mods []Mod)
FlushMapScans drops the scans and listings of folders that are no longer installed, then saves them when any changed.
func FlushPackDiskCache ¶
func FlushPackDiskCache(mods []Mod)
func FlushParts ¶
func FlushParts()
func HoldPacks ¶
func HoldPacks() func()
HoldPacks marks a check that reads packs; the func it returns ends it and, once no check is running, releases them.
func IsContentPatcherPack ¶
func IsSupportingPack ¶
IsSupportingPack is a Content Patcher pack that supplies sheets for other mods: it loads at least one new map, tilesheet or mod asset, and otherwise only redraws images or registers chair tiles. A pack that edits a map or data, or only recolours existing sheets, is something the player chose.
func IsTilesheetPack ¶
IsTilesheetPack is a Content Patcher pack whose every patch loads new map or tilesheet assets.
func IsTilesheetTarget ¶
IsTilesheetTarget reports a target that names a map or tilesheet asset.
func ModMapFiles ¶
ModMapFiles lists the map files in mod's folder; complete is false when part of the folder could not be read.
func NormalizeAsset ¶
NormalizeAsset is a target's asset name: lower-case, slash-separated, without a leading "./" or "..", and without its extension.
func NormalizeTarget ¶
func PackSig ¶
PackSig is pack's share of a part's key; stable is false when the pack has no trusted stamps.
func PartKey ¶
PartKey also covers what every part reads besides its packs: the build and the scan depth.
func PreloadPacks ¶
PreloadPacks parses packs on every core, so the serial passes after it find them cached.
func PresentFor ¶
PresentFor narrows the enabled mods to those pack's conditions name, the only ones a check of the pack looks up.
func PrintableRuns ¶
PrintableRuns returns the distinct lower-cased runs of printable ASCII in a binary map, which is where a .tbin names its tilesheets; the tile data between them is dropped.
func ReadPackConfig ¶
ReadPackConfig reads a pack's config.json as field values by lower-case key; a missing or unreadable file is no values, so every field keeps its schema default.
func RecordMapUses ¶
func RecordMapUses(im Mod, candidates []Mod, assetsByID map[string]map[string]bool, basenamesByID map[string][]string, record func(candidate ModID)) bool
RecordMapUses reports, through record, each candidate whose map or tilesheet assets a mod's map files load. It returns false when a map could not be read, since an unread map might use any candidate.
func ReleasePacks ¶
func ReleasePacks(gen int)
ReleasePacks drops the parsed packs and map scans when no check has run since gen, but only those the disk caches already hold: a cache with unsaved changes keeps its memory until a later check saves it.
func ResolveLoadFile ¶
func ScalarValue ¶
func ScalarValue(v json.RawMessage) (string, bool)
func SetCacheRoot ¶
func SetCacheRoot(dir string)
SetCacheRoot is where the on-disk caches live, normally the app's data folder. Set it before the first read; a pack is keyed relative to it, so a moved data folder keeps its entries.
func SettingValueMatches ¶
SettingValueMatches reports whether a field's current value meets a config condition.
func SplitTargets ¶
func SupportingPackKeys ¶
SupportingPackKeys are the keys of the packs that supply sheets for other mods, switched on or off.
func TmxImageSources ¶
TmxImageSources returns the source attribute of every <image> tag. A byte scan instead of encoding/xml: thousands of maps are read per check and only this one attribute matters.
Types ¶
type AssetMapPage ¶
type AssetMapPage struct {
Targets []AssetTarget `json:"targets"`
Total int `json:"total"`
Offset int `json:"offset"`
All int `json:"all"`
}
AssetMapPage is a sorted, paged slice of touched assets. All and Shared count the assets the search matches, and those of them more than one mod changes; Total is the count the page slices.
func AssetMapOf ¶
func AssetMapOf(index []AssetTarget, filter string, shared bool, offset int) AssetMapPage
type AssetTarget ¶
type AssetTarget struct {
Target string `json:"target"`
Key string `json:"key,omitempty"`
Mods []AssetTouch `json:"mods"`
Winner ModID `json:"winner"`
}
AssetTarget is every recorded touch of one normalised asset (and optional data key).
func BuildAssetIndex ¶
func BuildAssetIndex(mods []Mod, order func([]Mod) []string) []AssetTarget
BuildAssetIndex maps every asset the profile's mods write. order is the profile's load order as folded ids; nil leaves every mod at the same rank.
type AssetTouch ¶
type AssetTouch struct {
ModID ModID `json:"modId"`
ModName string `json:"modName"`
ModKey string `json:"modKey"`
Action string `json:"action"`
Priority string `json:"priority"`
LoadOrder int `json:"loadOrder"`
Winner bool `json:"winner"`
DataKey string `json:"dataKey,omitempty"`
Source string `json:"source,omitempty"`
Index int `json:"index"`
// CanWin is set on a losing mod that loading later would make win: it ties the winner's priority and no
// other mod in the group already loads after it.
CanWin bool `json:"canWin,omitempty"`
}
AssetTouch is one mod or patch that writes a target (or a data key on that target).
type Conflict ¶
type Conflict struct {
Kind string `json:"kind"`
Target string `json:"target"`
PackIDs []ModID `json:"packIds"`
Names []string `json:"names"`
Keys []string `json:"keys"`
WinnerID ModID `json:"winnerId"`
// WinnerName is the winning pack's own name; empty when WinnerKind names no single winner.
WinnerName string `json:"winnerName"`
WinnerKind string `json:"winnerKind"`
Overridden []string `json:"overridden"`
// Cosmetic marks an edit conflict whose every overlap is harmless: shown, never counted.
Cosmetic bool `json:"cosmetic"`
// Fixes are settings that switch off every clashing edit of one pack.
Fixes []Fix `json:"fixes"`
Evidence []Evidence `json:"evidence"`
// Note is why a cosmetic conflict cannot hurt play, when one reason covers every overlap.
Note *Note `json:"note,omitempty"`
// Farms is, per pack in PackIDs order, the farm types its clashing patches are all limited to: lower-case
// FarmType values, or a custom farm's Data/AdditionalFarms id (nil for a pack that applies on any farm); nil
// when no pack is limited.
Farms [][]string `json:"farms,omitempty"`
// Cells are the 16-pixel cells, as "x,y", that every pack's clashing patches write; empty when they share none.
Cells []string `json:"cells,omitempty"`
}
Conflict is two or more enabled packs that Load the same target (hard) or edit the same image, map or data entry (soft).
type Dependency ¶
Dependency is a mod another mod needs.
type DynamicCondition ¶
type Evidence ¶
type Evidence struct {
PackName string `json:"packName"`
PackID ModID `json:"packId"`
Source string `json:"source"`
Index int `json:"index"`
Action string `json:"action"`
Target string `json:"target"`
ToArea string `json:"toArea,omitempty"`
FromArea string `json:"fromArea,omitempty"`
// When is the patch's condition, for the caller to word.
When When `json:"when"`
Priority string `json:"priority"`
FromFile string `json:"fromFile,omitempty"`
CropX int `json:"cropX"`
CropY int `json:"cropY"`
CropW int `json:"cropW"`
CropH int `json:"cropH"`
// Keys are the data entries and fields this patch sets that another pack's patch also sets.
Keys []string `json:"keys"`
}
Evidence is one clashing patch of a pack in a Conflict.
func ConflictEvidence ¶
type Extension ¶
type Extension struct {
// Hints are the caller's setting suggestions; they come before the hints that settle a clash.
Hints []Hint
}
Extension is a caller's own findings from its pass over the profile's packs.
type Findings ¶
type Findings struct {
Conflicts []Conflict
// Hints are settings that would settle a load clash.
Hints []Hint
// Shadowed are the packs whose every change later packs overwrite.
Shadowed []Shadowed
// Bundled are, by mod key, the pack by the same author that already writes everywhere each one does.
Bundled map[string]ModRef
// Supporting are the keys of mods that only supply assets for other mods.
Supporting []string
// Mentioned are the folded ids of mods the switched-on packs name in their conditions.
Mentioned []string
// Tilesheets are the packs that only load map and tilesheet assets, and which mods use them.
Tilesheets []TilesheetUse
// TilesheetsUnreadable marks a check that could not read every map, so any tilesheet might be used.
TilesheetsUnreadable bool
}
Findings is what analyzing a profile's packs finds.
type Fix ¶
type Fix struct {
Key string `json:"key"`
ID ModID `json:"id"`
Name string `json:"name"`
Field string `json:"field"`
Current string `json:"current"`
Value string `json:"value"`
}
Fix sets one on/off field of a pack (Key, ID) to Value, which turns off all of that pack's edits in the conflict; Current is the field's value now.
type FlagCondition ¶
type Hint ¶
type Hint struct {
Key string `json:"key"`
ID ModID `json:"id"`
Name string `json:"name"`
Field string `json:"field"`
Current string `json:"current"`
Suggested []string `json:"suggested"`
For []ModID `json:"for"`
ForNames []string `json:"forNames"`
Description string `json:"description"`
// Variant marks a picker (a palette, recolour or similar choice) whose values the pack maps to mods.
Variant bool `json:"variant,omitempty"`
// CurrentFor names the mod the current value is for when that mod is not enabled.
CurrentFor string `json:"currentFor,omitempty"`
// BecausePack and DeadTarget mark a setting with no effect: BecausePack loads DeadTarget over the pack's own.
BecausePack string `json:"becausePack,omitempty"`
DeadTarget string `json:"deadTarget,omitempty"`
}
Hint is a pack setting that would settle a clash. Description is the pack's own schema text; BecausePack names the pack whose load beats this one when the current value has no effect.
type MapFileList ¶
type MapFileList struct {
Stamp string `json:"stamp"`
Paths []string `json:"paths,omitempty"`
Complete bool `json:"complete"`
}
MapFileList is one mod folder's .tmx and .tbin files for its store key. A store item never changes after it is extracted, so the list holds until the folder holds another key or is itself changed; the folder's own modification time catches files added or removed at its top level.
type MapScan ¶
type MapScan struct {
Size int64 `json:"size"`
ModTime int64 `json:"modTime"`
Keys []string `json:"keys,omitempty"`
Runs []string `json:"runs,omitempty"`
// Has holds the tilesheet names already looked for in Runs.
Has map[string]bool `json:"has,omitempty"`
}
MapScan is what the tilesheet scan needs from one map file, kept across checks until the file's size or modification time changes, since maps are many and rarely change.
type Mod ¶
type Mod struct {
Key string
Name string
UniqueID ModID
Author string
Version string
// Folder is the mod's directory in the profile, where its content.json lives.
Folder string
Enabled bool
// Dependencies lists the manifests' Dependencies and ContentPackFor.
Dependencies []Dependency
// LoadAfter are the mods this one loads after when the user made it win an edit conflict.
LoadAfter []ModID
// ContentPackFor is the framework the mod is content for, empty for a code mod.
ContentPackFor ModID
}
Mod is one mod of the profile, with what the analysis reads from its manifest.
type ModID ¶
type ModID string
ModID is "<format>:<local>", for example "smapi:Pathoschild.ContentPatcher". The zero ModID is empty.
func (ModID) Fold ¶
Fold is the key an ID is mapped and compared by: SMAPI ids are case-insensitive and may carry stray spaces.
type Note ¶
Note is one reason a conflict is cosmetic. Kind "balance": the packs only set prices and costs, so one mod's prices win. Kind "day": the overlap only applies on Value, one day or festival. Kind "farm": it only applies on Value farm types, which none of the profile's saves uses.
type Pack ¶
type Pack struct {
// values are the pack's config values (schema defaults, then config.json), by lower-case key;
// used while scanning only, so not cached on disk.
Values map[string]string
Fingerprint string
Files []FileStamp
Patches []Patch
Tokens []TokenDefinition
Mentions map[string]bool
Schema map[string]Schema
Skips int
// skipImages is whether the pack's image-edit shapes were read without the pixel-overlap scan.
SkipImages bool
// farms maps the map asset of each custom farm the pack adds to Data/AdditionalFarms to the farm's id.
Farms map[string]string
}
func ReadPackForCleanup ¶
type PartsRun ¶
PartsRun is one check's use of the parts: what it found kept and what it computed. Nothing it computed is kept unless the whole check could stamp what it read (commit).
func NewPartsRun ¶
func NewPartsRun() *PartsRun
type Patch ¶
type Patch struct {
Kind string // "load" or "edit"
Target string
FromFile string
Priority string
PatchMode string
When When
Shapes []Shape // what an edit writes; see editShapes
Spouse string // the spouse the change requires, or ""
Places map[string][]string // literal values the change requires of placeTokens
Image bool // an EditImage change, which only changes how something looks
ImageDigest string
ImageFromArea string
Source string
Index int
Action string
ToArea string
// tokenValue is a dynamic token's value; a token that yields a picker value only when a mod is
// installed is how a pack says which mod that value is for.
TokenName string
TokenValue string
// extra marks a change that also does something its shapes do not show (warps, text operations,
// appended list entries, a source map's properties), which a later edit never undoes.
Extra bool
}
Patch is one Load or EditImage/EditMap change with the HasMod conditions that gate it.
type Request ¶
type Request struct {
Enabled, All []Mod
// SkipImageOverlap turns off the pixel-overlap scan of image edits, trading accuracy for speed.
SkipImageOverlap bool
// CacheRoot is the folder the on-disk caches live under; empty turns them off.
CacheRoot string
// Order is the profile's load order as folded ids, or nil for none.
Order func([]Mod) []string
// Extend is the caller's own pass over the same parsed packs, run inside the check so its reads share the
// check's stamps and part cache. Its findings merge into the library's, and are memoised with them.
Extend func(run *PartsRun, all []Mod) Extension
}
Request is the profile to analyze and where its caches live.
type Schema ¶
type Schema struct {
Key string
DefaultValue string
AllowMultiple bool
AllowValues []string
AllowBlank bool
Description string
}
func (Schema) BooleanToggle ¶
BooleanToggle reports a two-valued on/off field.
type Shadowed ¶
type Shadowed struct {
Key string `json:"key"`
ID ModID `json:"id"`
Name string `json:"name"`
By []ModRef `json:"by"`
Bundled bool `json:"bundled,omitempty"`
}
Shadowed is one enabled pack that later packs overwrite everywhere it writes.
type Shape ¶
type Shape struct {
Kind byte // 'r' area, 't' tile, 'p' property, 'w' whole
X, Y, W, H int
Cells string
Layer, Key string
// value is a property's literal value, "" when tokenized; tiny marks a whole-asset shape that is really one
// or two tiles at a position only Content Patcher can work out.
Value string
Tiny bool
}
Shape is part of a target one edit writes: an area (image pixels, or map tiles on every layer), one map tile on one layer, one map property, or the whole asset when the area cannot be known without running Content Patcher (tokens, a map patched from a file without ToArea).
type TilesheetUse ¶
type TilesheetUse struct {
Key string `json:"key"`
ID ModID `json:"id"`
Name string `json:"name"`
Enabled bool `json:"enabled,omitempty"`
Names []string `json:"names,omitempty"`
}
TilesheetUse is a pack that only loads map and tilesheet assets: Enabled when a switched-on mod uses it, and Names of the switched-off mods that do.
func TilesheetPacks ¶
func TilesheetPacks(mods []Mod, skip bool) (uses []TilesheetUse, unreadable bool)
TilesheetPacks are the enabled packs that only load new map and tilesheet assets, and which mods use each one. Unreadable is true when a map could not be read, so any of them may be in use.
type TokenDefinition ¶
type TokenDefinition struct {
Name string
Value string
When map[string]json.RawMessage
}
type When ¶
type When struct {
AnyOf [][]string `json:"anyOf,omitempty"`
NoneOf []string `json:"noneOf,omitempty"`
Config []Config `json:"config,omitempty"`
Dynamic []DynamicCondition `json:"dynamic,omitempty"`
Flags []FlagCondition `json:"flags,omitempty"`
Spouse string `json:"spouse,omitempty"`
Places map[string][]string `json:"places,omitempty"`
// Assumed are the raw keys of the conditions this scan treats as met (time, queries, events), shown with
// the conflict so the user knows it may not happen on their save.
Assumed []string `json:"assumed,omitempty"`
// Conditional is set when the change, or an Include around it, has any When condition at all, including the
// assumed ones.
Conditional bool `json:"conditional,omitempty"`
}
When holds a change's HasMod conditions: each anyOf group needs one of its mods present, and no noneOf mod may be present. Dynamic token conditions are checked with the pack and profile context; other conditions are treated as met.
type WhoChangesPage ¶
type WhoChangesPage struct {
Query string `json:"query"`
Targets []AssetTarget `json:"targets"`
}
WhoChangesPage is the fuzzy search result for WhoChanges.
func WhoChangesOf ¶
func WhoChangesOf(index []AssetTarget, query string) WhoChangesPage