速查 › 資料檔總覽 database
資料檔總覽 database
球員能力、成績、名單、球隊資料,全部在 data\database\ 這一個資料夾裡。
好消息是:23 個檔案裡有 19 個是純文字,記事本就打得開,
而且每個檔自己會說明每一欄是什麼。
23 是剛安裝好的原版的數量。你自己的資料夾可能更多 ——
模組、工具、你自己的備份都會在這裡留下檔案。
本站測試機就有 26 個,多出來的三個是一份舊匯出、一個 .bak、
還有一個模組留下的資料夾。多出來的檔不是遊戲的,遊戲也不讀它們。
先說清楚這頁的數字是從哪一份遊戲量的
本頁兩份都量,不是只量一份:〈19 個純文字檔各裝什麼〉與〈全部 18 個檔的完整欄位表〉 量的是剛安裝好的原版(23 個檔);〈先看規模〉那一節、 以及表格裡標「裝過模組那台」的欄位,量的是一台裝過台灣模組的遊戲。 用到另一份的地方,該節會再說一次,頁尾也整理了一次。
格式與結構的部分兩邊一樣,那是遊戲程式決定的; 會變的是「有幾個」—— 站上別頁量到的臉皮 504 對 894、大頭照 1,487 對 6,638、 語音號碼 1,673 對 4,343 就是這樣來的。完整對照見 原版與這台機器差在哪。
⚠️ 跟名單內容有關的數字,你的會不一樣
本站測試機的球員名單被模組換過,裝的是一份混了大聯盟與台灣球員的名單。
(2026-09-05 訂正:這裡原本寫「attrib.dat 檔案日期 2026 年 4 月」。
那個檔的內容沒變 —— 本站 2026-04-14 那份快照裡的 attrib.dat
與現役這一份 sha256 相同 —— 但檔案日期後來被本站自己的動作蓋掉了,
現在量到的日期不是換名單的日期,所以這句話拿掉。)
所以「幾位球員」「某某球員是幾號」這類數字,你自己跑會得到別的結果。
不會變的是格式 —— 表頭怎麼寫、每一格怎麼標編號、資料怎麼分隔,那是遊戲程式決定的。
⚠️ 會變的不只是數量,還有欄位的順序:本站實測 46 個欄位裡有 27 個在原版與社群名冊之間位置不同(skin_tone 從第 12 欄搬到第 38 欄,中間的欄位各前移一格)。所以永遠不要記欄號,要在執行時從表頭找欄位名。
先看規模
| 項目 | 數字 | 備註 |
|---|---|---|
| 檔案數 | 25 個 | 合計 5.1 MB |
| 純文字檔 | 20 個 | 可以直接讀、直接改 |
封裝檔(.big) | 4 個 | schedule(賽程)、rookie、progress,加一個備份 |
| 二進位檔 | 1 個 | hist.dat,結構已解,欄位意義多半未解 |
| 純文字檔的資料筆數 | 40,697 筆 | 20 個檔加總 |
上面每個數字都是把 data\database\ 現場打開數出來的,不是引用他人資料。
量的是本站測試機那一份:25 個檔案,加上模組留下的那個資料夾就是開頭講的 26 個;
剛安裝好的原版是 23 個檔(測試機多出來的兩個檔是一份舊匯出 attrib.dat.csv 與一個
schedule.big.bak)。「純文字檔 20 個」同理 ——
遊戲自己的 19 個,加上那份不是遊戲的 attrib.dat.csv。
表頭自己會說明每一欄是什麼
這是這個資料夾最好用的地方。每個純文字檔的第一行長這樣:
0 first_name,1 last_name,2 playerattrib_jerseynum,3 playerattrib_bats,...;
│ │ │
│ │ └ 第 2 欄:背號
│ └────────────── 第 1 欄:姓
└─────────────────────────── 第 0 欄:名
欄位編號直接寫在名字裡
你不必自己數到第幾欄 —— 名字前面那個數字就是它的欄位編號。
想找「背號」在第幾欄,用文字編輯器搜尋 jerseynum 就看到 2。
本站檢查了全部 18 個以編號開頭的檔案:表頭全部以分號 ; 結尾,
格式完全一致。
資料格也帶編號,不只表頭
這是最容易看漏的地方。每一格資料本身也寫著自己的欄位編號:
表頭 0 first_name,1 last_name,2 playerattrib_jerseynum,...;
資料 0fff0f559,0 Shohei,1 Ohtani,2 17,...
│ └───────┴─ 每一格都是「編號 空格 值」
└─────────────────── 行首多一個 9 碼識別碼
所以取值要先把編號前綴切掉。本站檢查了 18 個檔案的每一格: 帶編號的比例 100%,零例外。
⚠️ 但不要「照編號」建表 —— 有一個檔會讓你靜默取錯
看到每一格都帶編號,很自然會想「那我照編號建一張對照表就好,不必管位置」。 那個做法在一個檔上會出錯,而且不會報錯。
本站 2026-08-28 實測 tstat.dat(球隊戰績表,126 列):
| 編號對不上的格 | |
|---|---|
| 剛安裝好的原版(英文與中文) | 0 個 |
| 社群名冊(含本站測試機) | 252 個(126 列 × 2) |
表頭寫的是 3 team_wins_2ndhalf、4 team_losses_2ndhalf,
但每一筆資料的那兩格掛的編號是 1 和 2 ——
那是上半季那兩欄的編號。
照編號建表的後果:下半季的勝敗會把上半季的蓋掉, 下半季那兩個編號整個消失,而程式一句話都不會說。 你會拿到一張看起來完整、其實錯的表。
正確做法:照位置讀,把編號當校驗碼用。
取第 N 格,然後檢查它掛的編號是不是 N;對不上就停下來問人,不要猜。
本站的 mvp_swap_face.py、mvp_new_face.py、
mvp_swap_portrait.py、mvp_edit_speed.py、
mvp_swap_chant.py 這五支是這樣寫的 ——
也因為這樣,它們在這個檔上會直接告訴你有問題,而不是靜靜給你錯的值。
(2026-09-05 訂正:這裡原本寫「本站每一支讀名冊的腳本都是這樣寫的」,
那是全稱句而且不成立。本站至少還有三支
—— mvp_player.py、mvp_ratings.py、mvp_edit_stance.py
—— 走的正是上面警告的「照編號建表」那條路。
它們讀的是 attrib.dat 與 pitcher.dat、不碰 tstat.dat,
所以目前不會踩到這個坑;但那是剛好沒踩到,不是有東西擋著。)
這是模組產生工具寫壞的,不是 EA 的格式性質: 三份剛安裝好的原版都是乾淨的。
兩個會讓你取錯值的陷阱
一、資料列比表頭多一格。行首那個 9 碼識別碼(像 0f58f3c1b)
表頭沒有對應的欄,所以直接切開取第 22 格會整個錯開一位。
二、取到的是「22 3」不是「3」。
忘了切掉編號前綴,數字就變成字串。
旁證:attrib.dat.csv 這個 2017 年的匯出版,
表頭第一欄多了一個叫 hex 的欄位 —— 那正是行首那個識別碼的名字。
完整的踩雷說明在球員資料檔那頁。
行首那個識別碼是把各表串起來的鑰匙
它不只是流水號。原版 attrib.dat 的 2,921 列沒有一個重複,
pitcher.dat 的 1,430 列也是。而且其他表會用它來指向球員或球隊:
| 對照 | 原版 | 裝過模組那台 |
|---|---|---|
roster.dat 欄位 0 → team.dat 的識別碼 |
2,970 / 2,970 | 3,004 / 3,004 |
roster.dat 欄位 1 → attrib.dat 的識別碼 |
2,970 / 2,970 | 3,004 / 3,004 |
pitcher.dat 的識別碼是否都出現在 attrib.dat |
1,430 / 1,430 | 1,618 / 1,618 |
兩份都是 100%。這件事換名單也不會壞 —— 模組作者換掉整份球員名單,這些對照關係還是全中, 代表它不是巧合,是遊戲要求的。
最後一列的意思是:投手也是球員。
兩張表用同一個識別碼描述同一個人,
attrib.dat 記他的打擊與體格,pitcher.dat 記他的投球能力。
串起來實際長這樣
拿 roster.dat 的一列,用兩個識別碼分別去 attrib.dat
與 team.dat 查,就得到完整資訊:
roster.dat 第 000000015 列
欄位0 = 00b87d5f5 欄位1 = 0fff0f559 欄位2 = SP3
│ │
│ └→ attrib.dat 的這一列 = Shohei Ohtani
└──────────────────────→ team.dat 的這一列 = Los Angeles Angels
結果:大谷翔平 · 天使隊 · 先發輪值第 3 號
這就是為什麼不能隨便改行首那個識別碼 —— 改了它,這位球員就從名單上消失了。
名字不唯一,識別碼才唯一
實測本站測試機的 attrib.dat 裡有 10 組同名同姓的球員(剛安裝好的原版是 0 組)。
所以絕對不要用名字當識別依據,會改到別人。
而且同名不一定是不同人。以 Shohei Ohtani 為例,兩筆都是他本人:
| 識別碼 | 主要守位 | 在 pitcher.dat | 身分 |
|---|---|---|---|
| 0fff0f536 | 8 | 否 | 打者那一份 |
| 0fff0f559 | 0 | 是 | 投手那一份 |
投打二刀流的球員在球員表裡佔兩列,各自帶一套能力。
但反過來不成立:那 10 組同名裡,有 4 組是真的不同人剛好同名
(例如兩位 Luis Castillo 都在 pitcher.dat 裡)。
所以看到同名,不能直接假設是同一個人的兩份資料。
已解 org.dat 的欄位 1~4 是編號沒錯(像 193451509),本站上線時寫「對不到 team.dat,是另一套編號系統」——那是錯的。它就是 team.dat 那串十六進位識別碼的十進位寫法:193451509 = 0xb87d5f5 = team.dat 的 00b87d5f5。實測 124 個非零的值,124 個全部對得上。對出來的內容也合理:第一列是天使,往下依序是它的 3A、2A、1A 農場球隊。完整說明見為什麼你加不了新球隊。
19 個純文字檔各裝什麼
下表最後一列 attrib.dat.csv 不是遊戲的檔,
剛安裝好的原版資料夾裡沒有它。列出來是因為很多人的資料夾裡會有,
看到它不用緊張,也不要把它當成能改的目標。
| 檔案 | 欄位 | 資料列 | 裝什麼 |
|---|---|---|---|
| attrib.dat | 46 | 2,921 | 打者能力。改能力前務必先讀避雷頁。playerattrib_face 這一欄指向
3D 臉皮編號(照名字找,欄號會因名冊而異) |
| pitcher.dat | 29 | 1,430 | 投手能力 |
| roster.dat | 10 | 2,970 | 名單與打序,見下方說明 |
| team.dat | 55 | 126 | 球隊資料(最多欄位的一個檔) |
| tstat.dat | 5 | 126 | 球隊上下半季勝敗 |
| org.dat | 14 | 34 | 球團與 3A/2A/1A 的隸屬關係 |
| manager.dat | 21 | 34 | 總教練 |
| bstats.dat | 6 | 2,921 | 打擊成績 |
| pstats.dat | 15 | 1,430 | 投球成績 |
| fbstats.dat | 6 | 2,921 | 守備成績 |
| career.dat | 9 | 2,921 | 打者生涯累計 |
| careerp.dat | 11 | 1,430 | 投手生涯累計 |
| lhattrib.dat | 28 | 2,921 | 對左投/右投分開記錄的能力與成績,見下方說明 |
| rhattrib.dat | 29 | 2,921 | |
| lhbstats.dat | 14 | 2,921 | |
| rhbstats.dat | 14 | 2,921 | |
| lhpstats.dat | 13 | 1,430 | |
| rhpstats.dat | 13 | 1,430 | |
| attrib.dat.csv | 46 | 3,167 | 不在原版安裝裡。一份 2017 年的舊匯出版,遊戲不讀它 |
| resign.csv | — | 140 | 年齡與明星等級對應的續約機率表 |
資料列數自己會分群
注意上表的「資料列」欄,只有四個數字反覆出現:
2,921 → 全部球員(8 個檔) ·
1,430 → 只有投手(5 個檔)
126 → 球隊(2 個檔) ·
34 → 球團(2 個檔)
所以拿到一個不認識的檔,看它有幾列就大概知道它在描述誰。
拿這張表去驗你自己那份名單被換過沒
本站同時打開剛安裝好的原版與一台裝了模組的機器,把每個檔量了兩次:
| 檔 | 欄位 原版 | 欄位 裝過模組 |
資料列 原版 | 資料列 裝過模組 |
|---|---|---|---|---|
| attrib.dat | 46 | 46 | 2,921 | 3,247 |
| pitcher.dat | 29 | 29 | 1,430 | 1,618 |
| roster.dat | 10 | 10 | 2,970 | 3,004 |
| team.dat | 55 | 55 | 126 | 126 |
| org.dat | 14 | 14 | 34 | 34 |
| manager.dat | 21 | 21 | 34 | 34 |
| resign.csv | — | — | 140 | 140 |
兩件事同時成立
① 欄位數 19 個檔全部一模一樣,一個都沒差。 換名單不會改變結構 —— 這就是為什麼本站敢說 「這一頁講的規則對你成立」。
② 只要跟球員有關的檔,列數就變了。 球隊(126)、球團(34)、續約機率表(140)完全沒動, 因為模組換的是球員不是聯盟結構。
所以你可以拿這個當最快的檢查:
打開你的 attrib.dat,看它有幾行。
不是 2,921 就是被換過了(要扣掉第一行表頭)。
更完整的說明在 怎麼看出哪些檔還沒被動過那一課。
lh 與 rh:對左投跟對右投是分開記的
六個檔名以 lh/rh 開頭,內容是同一批球員面對左投與右投的分開數據。
成對的三組:能力(attrib)、打擊成績(bstats)、投球成績(pstats)。
有一個不對稱的地方
三組裡有兩組左右欄位完全相同,但能力那一組不是:
lhattrib.dat 28 欄 ·
rhattrib.dat 29 欄
多出來的那一欄叫 lrattrib_chasehardbreak,只有右邊那個檔有。
未確認 為什麼只記一邊,本站沒有查出來。
⚠️ 比「欄位數不一樣」更會咬人的是:編號整個位移了
多出來那一欄不是加在最後面,是插在中間第 22 格。 所以從第 22 欄開始,同一個編號在兩個檔裡指的是不同的東西:
| 編號 | lhattrib.dat | rhattrib.dat |
|---|---|---|
| 0 – 21 | 兩邊完全一樣(22 個欄位) | |
| 22 | lrattrib_takefb | lrattrib_chasehardbreak |
| 23 | lrattrib_takeslowbreak | lrattrib_takefb |
| 24 | lrattrib_takehardbreak | lrattrib_takeslowbreak |
| 25 | lrattrib_missfb | lrattrib_takehardbreak |
| 26 | lrattrib_missslowbreak | lrattrib_missfb |
| 27 | lrattrib_misshardbreak | lrattrib_missslowbreak |
| 28 | (沒有這一欄) | lrattrib_misshardbreak |
規則很乾淨:lh 的第 N 欄 = rh 的第 N+1 欄,
N ≥ 22 時六個欄位全部成立。
這代表什麼:如果你寫一支工具「讀 lhattrib 的第 25 欄、
照樣寫到 rhattrib 的第 25 欄」,你會把
missfb(沒揮到速球)的值寫進
takehardbreak(放掉大幅度變化球)那一格。
不會報錯,不會壞檔,只會讓那個球員的能力變成另一回事。
本站原本只寫「欄位數不一樣,不能假設一樣」—— 那句話對,但不足以擋住這個錯:一個小心的人會去比對欄位數, 發現 28 vs 29,然後想「那我只處理前 28 欄就好」—— 而那正好會踩到位移。要比對的是欄位名,不是欄位數。
roster.dat:一支球隊有四套先發名單
這個檔的欄位結構跟其他檔都不一樣:
0 roster_teamid 哪一隊
1 roster_playerid 哪一位球員
2 rh_roster_al_position 3 rh_roster_al_battingorder 對右投 · 美聯
4 rh_roster_nl_position 5 rh_roster_nl_battingorder 對右投 · 國聯
6 lh_roster_al_position 7 lh_roster_al_battingorder 對左投 · 美聯
8 lh_roster_nl_position 9 lh_roster_nl_battingorder 對左投 · 國聯
守備位置與打序各有四套,按「對手投手是左投還是右投」乘上「美聯還是國聯」分開存。 兩聯盟要分開,是因為指定打擊的規則不同。
改名單時要記得改四份
只改其中一組,換一個聯盟或換一個左右手的先發投手,你的調整就不見了。 這跟介面版面檔「同一個元件有很多份」是同一類陷阱。
全部 18 個檔的完整欄位表
站上另一頁列了 attrib.dat 的 46 欄
與 pitcher.dat 的 29 欄,那是最常改的兩個。
但那只是 75 / 338。
先看規模
純文字的 .dat | 18 個 |
| 欄位總數 | 338 |
| 不重複的欄位名 | 261 |
| 出現在最多檔案裡的名字 | first_name / last_name(各 14 個檔) |
下面整份表是程式直接從每個檔的第一行讀出來的,不是人抄的。
讀的是剛安裝好的原版 —— 所以 attrib.dat 那張表的欄號只對原版成立。
社群名冊(含本站測試機)46 欄裡有 27 欄編號不同
(speed 在第 22 欄不是 23、audioid 在第 16 欄不是 17、
skin_tone 在第 38 欄不是 12),對照見
欄號會因名冊而異。
你自己跑一次,會得到你手上那一份的欄序:
python -c "print(open(r'你的遊戲資料夾\data\database\attrib.dat').readline())"
把 attrib.dat 換成任何一個 .dat 都可以。
hist.dat 除外 —— 那個是二進位的。
attrib.dat —— 46 欄
共同前綴 playerattrib_ 已省略。
| 0 | first_name | 1 | last_name | 2 | jerseynum | 3 | bats |
| 4 | throws | 5 | primary_position | 6 | secondary_position | 7 | height |
| 8 | weight | 9 | boneprofile | 10 | face | 11 | face2004style |
| 12 | skin_tone | 13 | hairstyle | 14 | haircolour | 15 | facialhair |
| 16 | bodytype | 17 | audioid | 18 | photo | 19 | platediscipline |
| 20 | bunting | 21 | stealing_aggressive | 22 | baserunning | 23 | speed |
| 24 | fielding | 25 | range | 26 | throwstrength | 27 | throwaccuracy |
| 28 | durability | 29 | battingstance | 30 | swingtype | 31 | batcolour |
| 32 | batglove | 33 | wristband | 34 | elbowguard | 35 | shinguard |
| 36 | socks | 37 | catchermask | 38 | fieldglovecolour | 39 | ditty |
| 40 | salary | 41 | contract_length | 42 | starpower | 43 | topprospect |
| 44 | hidden | 45 | birthday | — | — |
bstats.dat —— 6 欄
共同前綴 batstat_ 已省略。
| 0 | first_name | 1 | last_name | 2 | g | 3 | r |
| 4 | sb | 5 | cs | — | — |
career.dat —— 9 欄
共同前綴 batcareerstats_ 已省略。
| 0 | first_name | 1 | last_name | 2 | g | 3 | ab |
| 4 | h | 5 | hr | 6 | rbi | 7 | r |
| 8 | sb | — | — | — |
careerp.dat —— 11 欄
共同前綴 pitchcareer_ 已省略。
| 0 | first_name | 1 | last_name | 2 | g | 3 | ip |
| 4 | pip | 5 | er | 6 | w | 7 | l |
| 8 | sv | 9 | so | 10 | bb | — |
fbstats.dat —— 6 欄
共同前綴 fieldstat_ 已省略。
| 0 | first_name | 1 | last_name | 2 | g | 3 | po |
| 4 | a | 5 | e | — | — |
lhattrib.dat —— 28 欄
共同前綴 lrattrib_ 已省略。
| 0 | first_name | 1 | last_name | 2 | contact | 3 | power |
| 4 | hit_ul | 5 | hit_um | 6 | hit_ur | 7 | hit_cl |
| 8 | hit_cm | 9 | hit_cr | 10 | hit_ll | 11 | hit_lm |
| 12 | hit_lr | 13 | lf_pct | 14 | cf_pct | 15 | rf_pct |
| 16 | hr_pct | 17 | fb_pct | 18 | ld_pct | 19 | gb_pct |
| 20 | chasefb | 21 | chaseslowbreak | 22 | takefb | 23 | takeslowbreak |
| 24 | takehardbreak | 25 | missfb | 26 | missslowbreak | 27 | misshardbreak |
lhbstats.dat —— 14 欄
共同前綴 lrbatstat_ 已省略。
| 0 | first_name | 1 | last_name | 2 | 1b | 3 | 2b |
| 4 | 3b | 5 | hr | 6 | rbi | 7 | so |
| 8 | bb | 9 | ibb | 10 | sh | 11 | sf |
| 12 | hbp | 13 | tpa | — | — |
lhpstats.dat —— 13 欄
共同前綴 lrpitchstat_ 已省略。
| 0 | first_name | 1 | last_name | 2 | so | 3 | bb |
| 4 | ibb | 5 | hbp | 6 | sf | 7 | sh |
| 8 | 1b | 9 | 2b | 10 | 3b | 11 | hr |
| 12 | tpa | — | — | — |
manager.dat —— 21 欄
共同前綴 manager_ 已省略。
| 0 | first_name | 1 | last_name | 2 | jerseynum | 3 | audioid |
| 4 | height | 5 | weight | 6 | boneprofile | 7 | face |
| 8 | face2004style | 9 | skintone | 10 | hairstyle | 11 | haircolour |
| 12 | facialhair | 13 | bodytype | 14 | hitting | 15 | baserunning |
| 16 | fielding | 17 | pitching | 18 | salary | 19 | reallife |
| 20 | birthday | — | — | — |
org.dat —— 14 欄
共同前綴 org_ 已省略。
| 0 | unique_team | 1 | team_mlb | 2 | team_aaa | 3 | team_aa |
| 4 | team_a | 5 | is_franchise | 6 | spring | 7 | budget |
| 8 | penalty1 | 9 | penalty2 | 10 | penalty3 | 11 | penalty4 |
| 12 | mlb_manager | 13 | minors_manager | — | — |
pitcher.dat —— 29 欄
共同前綴 pitchattrib_ 已省略。
| 0 | first_name | 1 | last_name | 2 | stamina | 3 | pickoff |
| 4 | fastball_movement | 5 | fastball_description | 6 | fastball_control | 7 | fastball_velocity |
| 8 | pitch2_type | 9 | pitch2_movement | 10 | pitch2_description | 11 | pitch2_control |
| 12 | pitch2_velocity | 13 | pitch3_type | 14 | pitch3_movement | 15 | pitch3_description |
| 16 | pitch3_control | 17 | pitch3_velocity | 18 | pitch4_type | 19 | pitch4_movement |
| 20 | pitch4_description | 21 | pitch4_control | 22 | pitch4_velocity | 23 | pitch5_type |
| 24 | pitch5_movement | 25 | pitch5_description | 26 | pitch5_control | 27 | pitch5_velocity |
| 28 | pitcher_delivery | — | — | — |
pstats.dat —— 15 欄
共同前綴 pitchstat_ 已省略。
| 0 | first_name | 1 | last_name | 2 | g | 3 | gs |
| 4 | r | 5 | er | 6 | w | 7 | l |
| 8 | sv | 9 | blsv | 10 | cg | 11 | sho |
| 12 | pk | 13 | ip | 14 | pip | — |
rhattrib.dat —— 29 欄
共同前綴 lrattrib_ 已省略。
| 0 | first_name | 1 | last_name | 2 | contact | 3 | power |
| 4 | hit_ul | 5 | hit_um | 6 | hit_ur | 7 | hit_cl |
| 8 | hit_cm | 9 | hit_cr | 10 | hit_ll | 11 | hit_lm |
| 12 | hit_lr | 13 | lf_pct | 14 | cf_pct | 15 | rf_pct |
| 16 | hr_pct | 17 | fb_pct | 18 | ld_pct | 19 | gb_pct |
| 20 | chasefb | 21 | chaseslowbreak | 22 | chasehardbreak | 23 | takefb |
| 24 | takeslowbreak | 25 | takehardbreak | 26 | missfb | 27 | missslowbreak |
| 28 | misshardbreak | — | — | — |
rhbstats.dat —— 14 欄
共同前綴 lrbatstat_ 已省略。
| 0 | first_name | 1 | last_name | 2 | 1b | 3 | 2b |
| 4 | 3b | 5 | hr | 6 | rbi | 7 | so |
| 8 | bb | 9 | ibb | 10 | sh | 11 | sf |
| 12 | hbp | 13 | tpa | — | — |
rhpstats.dat —— 13 欄
共同前綴 lrpitchstat_ 已省略。
| 0 | first_name | 1 | last_name | 2 | so | 3 | bb |
| 4 | ibb | 5 | hbp | 6 | sf | 7 | sh |
| 8 | 1b | 9 | 2b | 10 | 3b | 11 | hr |
| 12 | tpa | — | — | — |
roster.dat —— 10 欄
| 0 | roster_teamid | 1 | roster_playerid | 2 | rh_roster_al_position | 3 | rh_roster_al_battingorder |
| 4 | rh_roster_nl_position | 5 | rh_roster_nl_battingorder | 6 | lh_roster_al_position | 7 | lh_roster_al_battingorder |
| 8 | lh_roster_nl_position | 9 | lh_roster_nl_battingorder | — | — |
team.dat —— 55 欄
共同前綴 team_ 已省略。
| 0 | unique_team | 1 | location | 2 | long_name | 3 | short_name |
| 4 | league | 5 | division | 6 | artid | 7 | climatezone |
| 8 | homeintensity | 9 | vs_ana | 10 | vs_oak | 11 | vs_sea |
| 12 | vs_tex | 13 | vs_cws | 14 | vs_cle | 15 | vs_det |
| 16 | vs_kc | 17 | vs_min | 18 | vs_bal | 19 | vs_bos |
| 20 | vs_nyy | 21 | vs_tam | 22 | vs_tor | 23 | vs_ari |
| 24 | vs_col | 25 | vs_la | 26 | vs_sdp | 27 | vs_sfg |
| 28 | vs_cub | 29 | vs_cin | 30 | vs_hou | 31 | vs_mil |
| 32 | vs_pit | 33 | vs_stl | 34 | vs_atl | 35 | vs_fla |
| 36 | vs_mon | 37 | vs_nym | 38 | vs_phi | 39 | vs_al |
| 40 | vs_nl | 41 | pinchhitter | 42 | pinchrunner | 43 | pitchersub |
| 44 | defensivesub | 45 | defensivealign | 46 | takepitch | 47 | sacbunt |
| 48 | buntforhit | 49 | pickoff | 50 | int_walks | 51 | hitandrun |
| 52 | steals | 53 | advancebases | 54 | suicidesqueeze | — |
⭐ team_climatezone 的三個值(2026-08-28 解開)
一支社群編輯器附的設定檔給了名字,而遊戲自己的球隊表可以把它驗到滿分:
| 值 | 設定檔寫的 | 原版有幾支 |
|---|---|---|
| 0 | Indoors 室內 | 35 |
| 1 | Southern 南方 | 67 |
| 2 | Northern 北方 | 24 |
怎麼驗的:把「室內」那一組的大聯盟球隊列出來。 剛安裝好的原版裡是這八支 ——
Mariners Twins Devil Rays Blue Jays
Diamondbacks Astros Brewers Nationals
前七支正好就是那個年代全部有巨蛋或開合式屋頂的球場,一支不多一支不少。 這不是數量吻合,是名單本身對得上現實。
另外兩組也對得起來:「北方」那組是白襪、印地安人、老虎、金鶯、紅襪、洋基、 小熊、紅人、海盜、大都會、費城人;「南方」那組是天使、運動家、遊騎兵、皇家、 落磯、道奇、教士、巨人、紅雀、勇士、馬林魚。 三組是 8+11+11,剛好就是大聯盟 30 隊,大體上照地理分。
(2026-09-05 訂正:本站原本在「南方」那組漏列了皇家, 只列出 10 支,三組加起來湊不滿 30 隊;而且原本寫「照地理分,沒有一支放錯邊」。 補上之後看,邊界其實沒那麼乾淨 —— 「南方」那組的科羅拉多, 緯度比「北方」那組的辛辛那提還要北。)
第八支很有意思:華盛頓為什麼被標成「室內」
2005 年華盛頓打的是 RFK 球場,那是露天的。
最可能的解釋是:這支球隊 2005 年才從蒙特婁搬過去, 而蒙特婁的奧林匹克球場是巨蛋。EA 把名字跟所在地改了, 氣候區那一格沒跟著改。原版的球隊表裡也找不到任何一列還叫博覽會隊 —— 那一列是被覆蓋掉的,不是新增的。
推論 本站沒有直接證據把這一格跟搬家連起來, 能量到的只有「它被標成室內」與「RFK 是露天球場」這兩件事。
tstat.dat —— 5 欄
共同前綴 team_ 已省略。
| 0 | unique_team | 1 | wins_1sthalf | 2 | losses_1sthalf | 3 | wins_2ndhalf |
| 4 | losses_2ndhalf | — | — | — |
看這張表要注意兩件事
一、同名不代表同義。
lhattrib.dat 與 rhattrib.dat 的欄位名幾乎一樣,
但編號從第 22 欄起整個位移一格(見上面那一節)。
二、這張表只說「叫什麼」,沒說「值代表什麼」。 守位、慣用手、球種、姿勢那些數字的意義在 代號對照那一頁; 身高、生日、薪水三個編碼很怪的欄位在 球員資料檔全欄位。
剩下那 5 個檔
| 檔案 | 格式 | 說明 |
|---|---|---|
| schedule.big | 已解 | 賽程。有教學與腳本 |
| schedule.big.bak | — | 賽程的備份副本 |
| rookie.big | 未解 | 封裝檔,內容本站未解讀 |
| progress.big | 未解 | 封裝檔,內容本站未解讀 |
| hist.dat | ✓ 結構已解 | 唯一的二進位資料檔。結構與每一筆 25 個位元組全部解開了 ——往下看 |
hist.dat:唯一的二進位檔,結構解開了
這是 database\ 底下唯一不是純文字的資料檔。本站 2026-08-28 把它的外層結構解開:
開頭 4 個位元組 筆數(32 位元,小端序) 接下來 筆數 × 25 個位元組,定長,沒有分隔符號
驗算方法很硬:(檔案大小 − 4) ÷ 筆數 必須剛好等於 25。三份檔案都成立:
| 來源 | 檔案大小 | 宣告筆數 | 每筆 |
|---|---|---|---|
| 剛安裝好的英文版原版 | 299,729 | 11,989 | 25.0000 |
| 剛安裝好的中文版原版 | 299,729 | 11,989 | 25.0000 |
| 本站測試機(社群名冊) | 78,504 | 3,140 | 25.0000 |
對照組:把筆數那一欄當成 big-endian 讀會得到 35 億筆,除出來 0.0001 —— 所以那一欄確實是小端序,不是猜的。
25 個位元組裡,解出來的只有一個欄位(2026-08-28 當時)
| 位置 | 是什麼 | 怎麼確認的 |
|---|---|---|
| 9–10 | 球季年份(16 位元小端序) | 原版 11,989 筆全部落在 1890–2004,零例外,而且 2004 年最多(1,954 筆)往前遞減。 同一個位置拿社群名冊解:2003–2022,2021 最多往前遞減。 同一個位元組位置,在兩份不同年代的名冊上各自解出合理但不同的分布 |
| 0–3 | 某種識別碼(32 位元) | 原版有 1,304 個相異值,平均每個出現 9.2 次。 未解 它識別的是什麼,本站沒有答案 |
| 4–8、22–24 | 原版裡永遠是同一個值 | 逐位元組統計,相異值數量都是 1 |
| 11–21 | 會變,意義不明 | 未解 |
(2026-09-05 註:上面這張表是 2026-08-28 當天的狀態。 位置 11 是球隊、12 是打擊/投球的來源標記、13–21 是成績欄位, 都在隔天解開了 —— 見下面〈25 個位元組全部填滿了〉那一節。)
一個差點被寫成結論的推測
樣本前幾筆長這樣:同一個識別碼配上 1990、1991、1992 三個連續年份。 看起來就是「同一個人的連續球季」,很想直接寫下去。
但全部算過之後不成立:出現一次以上的 1,209 個識別碼裡, 年份剛好連續的只有 27.1%,而且有 827 個識別碼年份是重複的。 所以它不是「一個識別碼一年一筆」。
能寫的只有:這是一張「識別碼 + 年份」的表,每個識別碼有多筆。 至於為什麼同一年會有多筆(換隊?分項成績?),本站沒有答案。
⭐ 2026-08-29:25 個位元組全部填滿了
上一節停在「位元組 11 到 21 會變,意義不明」。現在整張表填完了, 而且方法跟聲音格式那次是同一個:先找到一份能說「你錯了」的標準答案。
⚠️ 先說口徑:這一節換了一份名冊,數字跟上一節對不起來是正常的
上一節量的是剛安裝好的原版。這一節為了拿到年代更長、球隊更多的成績樣本,
量的是一份 2009 年的台灣名冊(hist.dat 237,229 個位元組、宣告 9,489 筆)。
| 剛安裝好的原版 | 本節這份 2009 名冊 | |
|---|---|---|
| 筆數 | 11,989 | 9,489 |
| 年份範圍(位元組 9–10) | 1890–2004 | 1890–2009 |
| 球隊(位元組 11)相異值 | 31 種 | 102 種 |
| 129 打擊/130 投球 | 8,040/3,949 | 6,173/3,316 |
格式是同一套,會變的是筆數與分布。把下面這套切法拿回原版那 11,989 筆重跑, 四條必然關係一樣站得住(安打 ≤ 打數 8,039/8,040、全壘打 ≤ 安打 8,040/8,040、 打點 ≥ 全壘打 8,040/8,040、打數 ≤ 出賽×8 8,040/8,040), 整體打擊率 .2754、防禦率 3.84, 跟這一節用 2009 名冊算出來的 .2774 / 3.74 在同一個位置。
這次的標準答案是棒球史本身
成績那 9 個位元組沒有對齊位元組邊界,硬猜切法會有幾百種可能。 但棒球給了兩種免費的檢驗:
- 必然成立的關係 —— 安打不可能多於打數,全壘打不可能多於安打。 切錯的話,六千筆裡一定會有一大堆違反。
- 史上單季紀錄 —— 一個欄位的上限,不可能超過人類做過的最好成績。
每一筆 25 個位元組
| 位置 | 是什麼 | 怎麼確認的 |
|---|---|---|
| 0–3 | 球員碼 | 跟名冊純文字檔每列開頭的十六進位數對得上 |
| 4 | 永遠是 1 | 逐位元組統計,相異值只有 1 種 |
| 5–8、22–24 | 永遠是 0 | |
| 9–10 | 球季年份 | 16 位元小端序,1890–2009(這份名冊;原版是 1890–2004) |
| 11 | 球隊 | 102 種相異值(這份名冊;原版是 31 種) |
| 12 | 129 = 打擊 130 = 投球 | 來自母檔的兩張表合併時留下的標記 |
| 13–21 | 成績(9 個位元組=72 位元) | 見下面兩張表,打擊與投球的欄位配置不一樣 |
打擊(第 12 個位元組 = 129,共 6,173 筆)
| 位元 | 寬 | 欄位 | 本檔上限 | 大聯盟單季紀錄 |
|---|---|---|---|---|
| 0–9 | 10 | 打數 | 716 | 716 |
| 10–17 | 8 | 出賽 | 163 | 165 |
| 18–24 | 7 | 盜壘 | 126 | 138 |
| 25–31 | 7 | 盜壘失敗推測 | 53 | — |
| 32–40 | 9 | 安打 | 262 | 262 |
| 41–48 | 8 | 打點 | 184 | 191 |
| 49–56 | 8 | 得分 | 177 | 198 |
| 57–63 | 7 | 全壘打 | 60 | 73 |
| 64–71 | 8 | 沒有用到(永遠 0) | — | — |
兩個欄位的上限剛好各自等於一項真實的大聯盟紀錄: 打數 716(Jimmy Rollins,2007)、安打 262(鈴木一朗,2004)。
投球(第 12 個位元組 = 130,共 3,316 筆)
| 位元 | 寬 | 欄位 | 本檔上限 | 大聯盟單季紀錄 |
|---|---|---|---|---|
| 0–7 | 8 | 自責分 | 179 | 186 |
| 8–15 | 8 | 保送 | 208 | 289 |
| 16–24 | 9 | 三振 | 383 | 383 |
| 25–31 | 7 | 出賽 | 94 | 106 |
| 32–40 | 9 | 投球局數 | 453 | 680 |
| 41–42 | 2 | 不明(只有 0/1/2 三種值)未解 | 2 | — |
| 43–48 | 6 | 勝 | 29 | 59 |
| 49–54 | 6 | 敗 | 25 | 48 |
| 55–63 | 9 | 沒有用到(永遠 0) | — | — |
| 64–71 | 8 | 救援成功 | 62 | 62 |
三振上限 383 是 Nolan Ryan 1973 年的紀錄,救援 62 是 Francisco Rodríguez 2008 年的紀錄。
⭐ 決定性的一筆:兩個人,各一年,七個欄位同時對上
光靠上限還不夠 —— 那只是兩個點。真正釘死它的是從資料裡找出一筆 成績完全可查的球季,把每個欄位跟史實逐一比對。
| 1911 年那一筆(打擊) | 解出來 | 史實 | 1973 年那一筆(投球) | 解出來 | 史實 |
|---|---|---|---|---|---|
| 打數 | 591 | 591 | 自責分 | 104 | 104 |
| 出賽 | 146 | 146 | 保送 | 162 | 162 |
| 盜壘 | 83 | 83 | 三振 | 383 | 383 |
| 安打 | 248 | 248 | 出賽 | 41 | 41 |
| 打點 | 127 | 127 | 局數 | 326 | 326 |
| 得分 | 147 | 147 | 勝 | 21 | 21 |
| 全壘打 | 8 | 8 | 敗 | 16 | 16 |
各七個欄位,全部命中。而且年份欄位是獨立解出來的 (1911 與 1973),不是本站挑的。
全體檢驗
| 檢驗 | 成立比例 |
|---|---|
| 安打 ≤ 打數 | 6,173/6,173 = 100.00% |
| 全壘打 ≤ 安打 | 6,173/6,173 = 100.00% |
| 打點 ≥ 全壘打 | 6,173/6,173 = 100.00% |
| 打數 ≤ 出賽×8 | 6,173/6,173 = 100.00% |
| 得分 ≥ 全壘打 | 6,172/6,173 = 99.98% |
| 勝+敗 ≤ 出賽 | 3,315/3,316 = 99.97% |
| 整體打擊率(總安打 ÷ 總打數) | .2774 2001–2008 各年 .2696–.2747 |
| 整體防禦率(自責分×9 ÷ 局數,局數≥50) | 3.74 |
打擊率 .27 上下、防禦率 3.7 上下,那是真實棒球一百年來的位置。 切錯位元的話這兩個數字會是隨機的。
⚠️ 那 1 筆「得分 < 全壘打」在物理上不可能(每支全壘打至少得一分)。 本站判斷那是名冊本身的一筆錯誤資料,不是解碼錯誤 —— 因為其他四條關係在同一批資料上都是 100%。但這是判斷,不是證明。
⭐ 反過來也學到一件事:這個遊戲不記二壘打與三壘打
1911 年那位打了 47 支二壘打、24 支三壘打, 而 72 個位元裡找不到這兩個數字。投球那邊同樣找不到先發場次、完投、被安打、失分。
兩邊都只記八項。缺的那些不是本站沒解出來,是檔案裡就沒有。
方法:讓資料自己說出欄位邊界
不用猜切法。把六千筆的同一個位元拿出來,算它是 1 的機率:
位元 0 1 2 3 4 5 6 7 8 9 │ 10 11 12 …
44 41 40 37 35 32 30 23 20 17 │ 50 50 45 …
↑
一路遞減到 17%,然後跳回 50%
一個數字的低位元接近一半機率是 1,高位元越來越少。 機率從遞減轉為上升的那一格,就是欄位邊界。 第一個邊界落在位元 10,而打數的合理範圍正好是 0–1023。
這 19 個檔是從哪裡來的:一個 Access 資料庫
社群做名冊時,不是直接編這 19 個文字檔。
他們編的是一個副檔名叫 .mbe 的母檔,改完再匯出成 .dat。
那個 .mbe 是微軟 Access 的資料庫,只是換了副檔名。
檔案開頭第 5 到第 19 個位元組直接寫著 Standard Jet DB:
| 檔案日期 | 大小 | 是 4096 的倍數 | 找得到的表名 |
|---|---|---|---|
| 2006-01 | 790,528 | ✅ | 20 |
| 2006-08 | 6,656,000 | ✅ | 20 |
| 2006-11 | 6,496,256 | ✅ | 20 |
| 2008-06 | 5,410,816 | ✅ | 20 |
| 2016-09 | 5,746,688 | ✅ | 20 |
| 2019-01 | 5,361,664 | ✅ | 20 |
七個檔全部以 00 01 00 00 開頭、全部是 4,096 個位元組的整數倍
(Jet 資料庫的分頁大小)。這不是數量吻合 —— 檔案自己寫著格式名稱。
⭐ 十三年,同一份表結構
上面那六個檔橫跨 2006 到 2019,是不同人在不同年份做的, 而它們的表名完全相同,一個不多一個不少:
attrib bstats career careerp fbstats
histb histp lhattrib lhbstats lhpstats
manager org pitcher pstats rhattrib
rhbstats rhpstats roster team tstat
20 張表,但 data\database\ 只有 19 個 .dat。
多出來的那一張就是上面標亮的兩個:母檔裡
histb(打擊)與 histp(投球)是分開的兩張表,
匯出時才合併成一個 hist.dat。
這正好解釋了 hist.dat 裡那個
只有 129 與 130 兩個值的位元組 ——
它是合併時留下的來源標記。
為什麼社群的名冊檔大小都差不多,這也有答案了: 它們是同一個母檔範本改出來的,表結構一樣,只有列數不同。 上表六個檔裡,最大的五個都落在 5.3 到 6.7 MB; 最小的那一個只有 0.79 MB,明顯不在這個區間,本站沒有進一步分析它。
⚠️ 例外要講清楚:第七個檔(2013 年、245,760 個位元組)只找得到 3 個表名。 本站沒有進一步分析它,只知道它同樣是 Jet 資料庫。
這對你有什麼用
- 你不需要 Access。要改名冊,改那 19 個純文字
.dat就好 —— 本站所有教學走的都是這條路 - 但知道母檔存在,可以解釋兩件事:為什麼欄位順序在不同名冊之間會變 (匯出工具的欄序不一定跟母檔一致),以及 為什麼有些名冊檔的欄位比別的多
- 本站不提供任何
.mbe檔,也不教怎麼用它
⭐ 2026-08-28:上面那個問號有答案了 —— 換隊跟分項成績,兩個都是
⚠️ 這張卡是 2026-08-28 寫的,比上面〈25 個位元組全部填滿了〉那一節早一天, 排在這裡是因為它接的是同一節的問題,不是因為它比較新。 它量的是剛安裝好的原版(11,989 筆), 所以筆數與相異值跟那一節的 2009 名冊不同 —— 位元組 12 的意義(129 打擊/130 投球)兩份都一樣,沒有被推翻。
那一段結尾問「為什麼同一年會有多筆」。當天稍晚把 25 個位元組逐格重數, 其中一格立刻跳出來:
| 位置 | 相異值 | 是什麼 |
|---|---|---|
| 12 | 只有兩個:129(8,040 筆)、130(3,949 筆) | 打擊成績/投球成績 |
| 0–3 | 1,304 個 | 球員碼(跟純文字檔行首那一串是同一個) |
| 11 | 31 個 | 球隊 |
怎麼確定 130 是投球(錨點):用 130 的 651 位球員裡,
有 649 位出現在 pitcher.dat。
用 129 的 1,281 位裡有 1,275 位在 attrib.dat。
球員碼是直接拿去比對的,不是猜的 ——
純文字檔每一列開頭那九位十六進位數,就是這裡的 0–3 位元組。
四個欄位合起來就是唯一鍵: (球員碼,年份,129/130,球隊)在 11,989 筆裡零重複。 所以同一年多筆的兩個原因是:
- 同一位球員同一年既有打擊成績也有投球成績(628 人兩種都有 —— 投手也要打擊)
- 同一位球員同一年待過不只一支球隊(球季中被交易)
還有一個外部佐證。社群當年用來編名冊的母檔是
Access 資料庫,那裡面有 20 張表,
而 data\database\ 只有 19 個 .dat。
多出來的一張正是:母檔把它拆成 histb 與 histp 兩張表,
匯出時才合併成一個 hist.dat。
那個 129/130 就是合併時留下的來源標記。
已解 位置 13–21 那 9 個位元組(成績數字本身) 在寫這張卡的當下還沒解開 —— 它們沒有對齊位元組邊界,是把好幾個欄位擠在一起。 隔天(2026-08-29)解開了:切法與逐欄驗證見上面 〈25 個位元組全部填滿了〉那一節。
動手之前
純文字不等於可以隨便改
這些檔讀很安全,寫要非常小心:
· 行首那個編號不能動
· 欄位數量不能變
· 換行符要保持原樣(跟版面檔同理)
· 大部分能力欄位不是 0-99 的分數,寫錯值會破壞欄位語意
改能力之前,球員資料檔那頁一定要先讀完。
📌 重點整理
- 一句話 球員能力、成績、名單、球隊資料全在
data\database\這一個資料夾,而且純文字檔的表頭自己會說明每一欄是什麼,記事本就打得開。 - 規模 純文字檔的資料筆數合計 40,697 筆(本站測試機 20 個檔加總);18 個純文字
.dat的欄位總數是 338 個,不重複的欄位名 261 個。反覆出現的資料列數只有四個:2,921(全部球員)、1,430(只有投手)、126(球隊)、34(球團),所以看列數就大概知道一個檔在描述誰。 - 編號自帶,但不要照編號建表 表頭與每一格資料都寫著欄位編號,18 個檔逐格檢查帶編號比例 100%。可是
tstat.dat在社群名冊上有 252 格(126 列 × 2)掛錯編號,剛安裝好的原版是 0 格。要照位置讀,把編號當校驗碼,否則下半季勝敗會靜靜蓋掉上半季,程式一句話都不會說。 - 行首那 9 碼識別碼才是鑰匙
roster.dat指向team.dat與attrib.dat,原版 2,970 筆全中、裝過模組那台 3,004 筆全中,換名單也不會壞。名字不能當識別依據,實測本站測試機有 10 組同名同姓(剛安裝好的原版是 0 組),其中 4 組是真的不同人剛好同名。 - 最會咬人的是欄位位移
lhattrib.dat28 欄、rhattrib.dat29 欄,多的那一欄插在第 22 格,從那裡起同一個編號在兩個檔裡指不同的東西。attrib.dat的 46 欄裡也有 27 欄在原版與社群名冊之間位置不同 —— 本頁那張 46 欄的表列的是原版的欄號。永遠在執行時從表頭比對欄位名,不要記欄號。 - 本頁訂正過自己好幾次
org.dat欄位 1 到 4 上線時寫成「對不到team.dat,是另一套編號系統」,那是錯的,它其實是同一串識別碼的十進位寫法,124 個非零值全部對得上。另一處原本只寫「lh 跟 rh 欄位數不一樣」,那句話對卻擋不住錯,因為一個小心的人會決定「只處理前 28 欄」,剛好踩到位移。2026-09-05 又訂正一批:南方氣候區漏列皇家、hist.dat位元組 13–21 已在同一頁解開卻還掛著「未解」、欄位表沒標它量的是原版、以及一句「本站每一支讀名冊的腳本都是這樣寫的」的全稱句。 - 2026-08-29:
hist.dat的 25 個位元組全部填滿了 打數上限 716、安打 262、三振 383、救援 62,各自等於一項真實的大聯盟單季紀錄;1911 與 1973 那兩筆各七個欄位全部命中史實;整體打擊率 .2774、防禦率 3.74。社群當年的母檔是換了副檔名的 Access 資料庫,六份跨 2006 到 2019 的檔表名一模一樣,histb與histp合併時才留下那個 129/130 的來源標記。 - 本站沒驗的
rookie.big與progress.big未解;rhattrib.dat為什麼只多記一邊未確認;投球那段的位元 41 到 42 未解、盜壘失敗只是推測;華盛頓被標成「室內」的搬家解釋是推論,沒有直接證據;唯一那筆「得分少於全壘打」被判斷成名冊本身的錯誤資料,本站也寫明那是判斷不是證明。
接下來
- 球員資料檔 attrib / pitcher —— 能力欄位的完整避雷
- 把賽程換到任何年份 —— 這個資料夾裡唯一有完整教學的檔
- 遊戲檔案地圖 —— 其他資料放在哪裡