cfb-dynasty

module
v0.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 8, 2026 License: MIT

README

cfb-dynasty

Go library and CLI for reading EA Sports College Football dynasty save files on PC and exporting structured league data as JSON.

Status: feature-complete for read-only export. Against CFB 27 PC dynasty saves (with a matching schema bundle such as C27_468_2.gz), the tool covers the main dynasty surfaces: season/teams/rosters, schedule and per-game stats, recruiting, coaches, injuries, depth charts, awards, and the full record book. Remaining gaps are narrow (see Known limitations); writing or editing saves is intentionally out of scope.

Install

go install github.com/leaguelines/cfb-dynasty/cmd/cfb-dynasty@latest

Or add the library to your project:

go get github.com/leaguelines/cfb-dynasty/dynasty

What exports today

Area Coverage
Season / teams Year, week, phase; schools with conference, W–L, poll ranks
Rosters Active players with ratings, archetypes, skill-group caps
Games Schedule, scores, team box scores, attributed player lines (offense / defense / special teams)
Season stats Player and team season totals
Recruiting Board + player attributes; pursuit state, NIL, visits, top school
Staff / roster mgmt Coaches, injuries, depth charts, leaving / graduation pipeline
History Player awards, league awards, conference champions, full record book (league / conference / team × career / season / game)

Stable Team.TeamIndex IDs are used throughout for joins (see Team IDs).

Schema bundles

Table decoding requires a gzip-compressed JSON schema bundle derived from the game install. Each bundle lists thousands of table definitions (field names, types, enums) used by the FranTk-style save format.

File format and naming

Bundles use the same JSON layout as madden-franchise .gz schemas:

{
  "meta": { "major": 468, "minor": 2, "gameYear": 27 },
  "schemas": [ ... ],
  "schemaMap": { ... }
}

Place one or more files in a directory and pass it to --schema-dir. Recognized filenames:

Pattern Example Meaning
C{year}_{major}_{minor}.gz C27_468_2.gz CFB, game year 27, bundle major 468, minor 2
{major}_{minor}.gz 468_2.gz Major/minor only (game year optional)
M{year}_{major}_{minor}.gz M27_468_2.gz Madden-style prefix also accepted

inspect prints the schema version embedded in your save and which bundle was loaded:

cfb-dynasty inspect -schema-dir ./schemas /path/to/Dynasty1
# schema:         major=809 minor=1      ← from save header
# loaded schema:  major=468 minor=2 ...  ← picked bundle

The save header version and the bundle meta version use different numbering (for example save 809.1 vs bundle 468.2). When several bundles are present, the loader picks the closest major/minor match; with only one file in the directory, that file is used. Prefer the newest CFB 27 bundle you have — older majors (for example 441.0) mis-decode team and roster fields.

How to obtain a bundle

You need a legal copy of the game on PC. Schema data lives inside the install assets; it is not shipped with this repository.

1. Extract raw schema assets (Frosty)

The Madden modding workflow applies to CFB as well:

  1. Install Frosty Editor and point it at your College Football 27 install.
  2. Open Legacy Explorer and search for franchise / FranTk schema assets (Madden uses franchise-schemas.ftx under common → franchise; CFB paths are still being mapped — see internal RE notes).
  3. Export the schema .ftx / .xml files to a folder on disk.

2. Convert to gzip JSON

The CLI expects the evaluated .gz bundle, not raw .ftx. The usual path is the madden-franchise schema generator (same engine family):

  • Use madden-franchise FranchiseSchema / schemaGenerator to load the extracted .ftx and emit a .gz JSON bundle, or
  • Use tooling from the Madden Franchise Editor ecosystem (schemaSearchService can pull schemas from CAS/LZ4 game assets).

3. Name and verify

Rename the output to match your game year and bundle meta (for example C27_468_2.gz), then confirm decoding works:

cfb-dynasty inspect -schema-dir ./schemas /path/to/Dynasty1
cfb-dynasty export -schema-dir ./schemas --teams /path/to/Dynasty1 | head

If you already have a working bundle (like C27_468_2.gz from local RE), you can use it directly — no re-extraction needed until EA ships a patch that changes table layouts.

Should schema bundles be committed to git?

No — do not commit them to a public repository.

Concern Notes
Copyright Bundles are derived from EA game assets (table/field names, types, enums). Redistributing them is likely outside EA's terms, even though the files are not executable game content.
Size ~3 MB compressed, ~30 MB inflated — poor fit for git history.
Patch churn EA title updates can change schema major/minor; bundles go stale quickly.

Recommended approach: keep bundles in a local data/ or schemas/ directory (gitignored), document extraction steps (this section), and let each developer generate or copy their own from an owned game install. Integration tests already skip when a local schema bundle / test save is absent.

For private teams, a shared drive or internal artifact bucket is fine; just avoid publishing the files in the open-source repo or release tarballs.

CLI

Inspect a save
cfb-dynasty inspect /path/to/Dynasty1
cfb-dynasty inspect -schema-dir ./schemas /path/to/Dynasty1
cfb-dynasty inspect -json /path/to/Dynasty1

Shows compression, format, size, SHA-256, and table marker counts without full parsing.

Export to JSON
# Full export (all sections)
cfb-dynasty export -schema-dir ./schemas /path/to/Dynasty1 -o dynasty.json

# Selective export — only the listed sections are included
cfb-dynasty export -schema-dir ./schemas --teams --rosters /path/to/Dynasty1
cfb-dynasty export -schema-dir ./schemas --games --no-game-stats /path/to/Dynasty1
Export sections
Flag JSON fields Contents
(default) all below Everything when no section flags are set
--season season Current year, week, phase
--teams teams Schools, records, poll ranks
--rosters rosters Active rosters with player ratings
--games games Schedule, scores, optional per-game stats
--recruits recruits Recruiting board + nested player attributes
--recruiting recruiting Pursuit state, NIL, visits, top school interest
--season-stats seasonPlayerStats, seasonTeamStats Season stat totals
--coaches coaches Staff, contracts, career records
--leaving-players leavingPlayers Graduation / exit pipeline
--injuries injuries Active injuries
--depth-charts depthCharts Depth chart slots by team
--history playerAwards, leagueAwards, conferenceChampions, recordBook Awards and the full stat record book

Additional flags:

  • --no-game-stats — omit team/player stat lines from game exports
  • -o path — write JSON to a file (stdout if omitted)
  • --pretty=false — compact JSON

Run cfb-dynasty -h or cfb-dynasty export -h for full usage.

Team IDs

Exported teamId / teams[].id / player.teamIndex values are the game's stable Team.TeamIndex IDs (Akron = 1, Alabama = 2, … Sacramento State = 137), not the Team table row order. Newer programs keep high TeamIndex values while sitting earlier in the table (for example Appalachian State is row 3 with id 125), so row numbers must not be used as join keys. Air Force is id 0. FCS placeholder slots (TeamIndex 255) are omitted.

Example: recruits with jq
cfb-dynasty export -schema-dir ./schemas --recruits /path/to/Dynasty1 | \
  jq '.recruits[] | select(.nationalRank != null and .player != null) |
      {rank: .nationalRank, name: "\(.player.firstName) \(.player.lastName)",
       position: .player.position, archetype: .player.archetypeLabel, overall: .player.overall,
       skillCaps: .player.skillGroupCaps, skillCapTotal: .player.skillGroupCapTotal}'
Skill group caps

Every player (including a recruit's linked player) exports its six skill-group caps read straight from the save:

  • skillGroupCaps — the six positional caps (SkillGroupCap1..6).
  • skillGroupCapTotal — their sum (a strong proxy for a recruit's ceiling / star tier).

The caps are exported as opaque, positional values — the array is ordered by SkillGroupCap1..6 as stored in the save. The game buckets these into six position-specific skill groups, but the group names are not present in the dynasty save (they live in the tuning FTC, which is not yet extractable for CFB 27). Rather than guess at labels, the export intentionally leaves the slots unnamed until definitive names are available. Note also that only the per-group cap is known — the individual ratings inside each group are tuning-driven and not in the save.

Per-game player stats

When game stats are included (--games, on by default), each game carries a playerGameStats list. Each entry is one player's line for that game:

  • playerId — the player's row index (join to rosters for the full record).
  • player — a lightweight identity (firstName, lastName, position, jersey, teamIndex) so lines are readable without a join.
  • offense / defense — the stat line(s); a player with both merges into one entry.
  • specialTeams — kick/punt return line (attempts, yards, longest, TDs) when the player returned kicks or punts that game.

The game-stat rows themselves store no player reference — ownership lives on the Player side via a GameStats[] array store that points at each player's rows. The exporter inverts those arrays to attribute every stat line, and rows are bucketed into games by their direct SeasonGame record index (stale references to other seasons are dropped).

Kick/punt returns live in separate KPReturnStats tables (the box-score TeamStats table has no special-teams TD field, so team totals cover yardage only). The same GameStats[] / SeasonStats[] array stores link those rows back to their players, and the specialTeams block appears on both per-game (playerGameStats) and per-season (seasonPlayerStats) lines.

Record book

--history exports the complete stat record book as a flat recordBook list. The game keeps a record book for three scopes — the whole FBS (league), each conference, and every team — and three periods (career, season, game). Each entry carries:

  • scope — league, conference, or team.
  • scopeName — the conference or team the board belongs to (empty for league).
  • period — career, season, or game.
  • statType, statValue, rank — the record and its rank within the board.
  • firstName, lastName, position, teamName, calendarYear — the holder.

League boards are ranked top-N per category; conference and team boards store a single holder (rank 1) per category. Positions come straight from the record row when present and are otherwise inferred from the stat category (the game leaves lower league ranks at the schema default).

# Every team's career passing-yards record holder
cfb-dynasty export -schema-dir ./schemas --history /path/to/Dynasty1 | \
  jq '.recordBook[] | select(.scope=="team" and .period=="career" and .statType=="PassYards") |
      {team: .scopeName, holder: "\(.firstName) \(.lastName)", yards: .statValue}'

Library

package main

import (
	"fmt"
	"log"

	"github.com/leaguelines/cfb-dynasty/dynasty"
)

func main() {
	settings := dynasty.DefaultSettings()
	settings.SchemaDir = "/path/to/schemas"
	settings.AutoParse = true

	file, err := dynasty.Open("/path/to/Dynasty1", &settings)
	if err != nil {
		log.Fatal(err)
	}

	info, err := file.Inspect()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("size=%d compressed=%v format=%q\n", info.Size, info.Compressed, info.Format)

	// Parse is called automatically when AutoParse is true.
	// Otherwise: if err := file.Parse(); err != nil { ... }

	export, err := file.ExportWithOptions(dynasty.ExportOptions{
		Sections: dynasty.ExportSections{
			Teams:   true,
			Rosters: true,
			Games:   true,
		},
	})
	if err != nil {
		log.Fatal(err)
	}

	data, err := export.ToJSON()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("exported %d bytes\n", len(data))
}

Lower-level access to parsed tables:

team, ok := file.PrimaryTableByName("Team")
if ok {
	_ = team.ReadRecords()
	for _, row := range team.Records {
		_ = row.Get("LongName")
	}
}
Package layout
Package Purpose
dynasty Public API — open saves, parse tables, export data
internal/binary Low-level byte scanning helpers
internal/bitview Bitfield read helpers for record decoding
internal/compress Decompression (zlib)
cmd/cfb-dynasty Command-line tool

Expected save location (PC)

%USERPROFILE%\Documents\College Football 27\Saves\

Dynasty saves are typically named like Dynasty1.

Known limitations

  • Schema required — export and record decoding need a matching C27_*_*.gz bundle (not shipped here).
  • Read-only — no save writing or editing.
  • Recruiting depth — each prospect’s topSchool exports; the full multi-school interest list is not expanded yet.
  • Skill group names — caps export as ordered skillGroupCaps[6]; UI bucket names live in game tuning assets, not the save.
  • Record-book team names — league ranks below #1 often omit a stored team name in the save (the exporter does not invent one).
  • Unplayed saves — game and season player stats may be empty until games are simmed.
  • Large exports — full exports with --recruits and --rosters can be tens of MB; use section flags to trim output.

Goals

  1. Reliable read-only parsing of local PC dynasty saves.
  2. Export the full set of league surfaces listed above as stable JSON for apps, bots, and pipelines.
  3. Stay headless-friendly: copy save → parse → JSON → sync elsewhere.

Non-goals

  • Console save extraction
  • Writing, repairing, or live-editing save files
  • Redistributing EA schema bundles or other game assets
Project Notes
madden-franchise Reference parser for Madden FranTk-style table DBs
Madden Franchise Editor Desktop editor built on madden-franchise

CFB shares the broad EA engine family with Madden, but dynasty saves are a distinct format with their own schema bundles.

Development

go build ./...
go test ./...
go run ./cmd/cfb-dynasty export -schema-dir ./schemas --help

Place test saves and schema bundles in a local data/ directory. Dynasty saves may contain personal league data; schema bundles are game-derived assets — neither should be committed (see Schema bundles).

Contributing

Issues and PRs welcome. Useful contributions include schema version coverage after EA patches, filling the remaining limitations above, better docs/examples, and regression tests against real saves.

License

MIT

Directories

Path Synopsis
cmd
cfb-dynasty command
Package dynasty reads EA Sports College Football dynasty save files and exposes parsed league data for export.
Package dynasty reads EA Sports College Football dynasty save files and exposes parsed league data for export.
internal
binary
Package binary provides low-level helpers for scanning dynasty save bytes.
Package binary provides low-level helpers for scanning dynasty save bytes.
bitview
Package bitview reads big-endian bit fields from FranTk table records.
Package bitview reads big-endian bit fields from FranTk table records.
compress
Package compress unpacks dynasty save containers.
Package compress unpacks dynasty save containers.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL