速查 › 資料檔總覽 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 個可以直接讀、直接改
封裝檔(.big4 個 schedule(賽程)、rookieprogress,加一個備份
二進位檔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_2ndhalf4 team_losses_2ndhalf, 但每一筆資料的那兩格掛的編號是 12 —— 那是上半季那兩欄的編號。

照編號建表的後果:下半季的勝敗會把上半季的蓋掉, 下半季那兩個編號整個消失,而程式一句話都不會說。 你會拿到一張看起來完整、其實錯的表。

正確做法:照位置讀,把編號當校驗碼用。 取第 N 格,然後檢查它掛的編號是不是 N;對不上就停下來問人,不要猜。 本站的 mvp_swap_face.pymvp_new_face.pymvp_swap_portrait.pymvp_edit_speed.pymvp_swap_chant.py 這五支是這樣寫的 —— 也因為這樣,它們在這個檔上會直接告訴你有問題,而不是靜靜給你錯的值。

(2026-09-05 訂正:這裡原本寫「本站每一支讀名冊的腳本都是這樣寫的」, 那是全稱句而且不成立。本站至少還有三支 —— mvp_player.pymvp_ratings.pymvp_edit_stance.py —— 走的正是上面警告的「照編號建表」那條路。 它們讀的是 attrib.datpitcher.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,9703,004 / 3,004
roster.dat 欄位 1 → attrib.dat 的識別碼 2,970 / 2,9703,004 / 3,004
pitcher.dat 的識別碼是否都出現在 attrib.dat 1,430 / 1,4301,618 / 1,618

兩份都是 100%。這件事換名單也不會壞 —— 模組作者換掉整份球員名單,這些對照關係還是全中, 代表它不是巧合,是遊戲要求的。

最後一列的意思是:投手也是球員。 兩張表用同一個識別碼描述同一個人, attrib.dat 記他的打擊與體格,pitcher.dat 記他的投球能力。

串起來實際長這樣

roster.dat 的一列,用兩個識別碼分別去 attrib.datteam.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身分
0fff0f5368打者那一份
0fff0f5590投手那一份

投打二刀流的球員在球員表裡佔兩列,各自帶一套能力。

但反過來不成立:那 10 組同名裡,有 4 組是真的不同人剛好同名 (例如兩位 Luis Castillo 都在 pitcher.dat 裡)。 所以看到同名,不能直接假設是同一個人的兩份資料。

已解 org.dat 的欄位 1~4 是編號沒錯(像 193451509),本站上線時寫「對不到 team.dat,是另一套編號系統」——那是錯的。它就是 team.dat 那串十六進位識別碼的十進位寫法193451509 = 0xb87d5f5 = team.dat00b87d5f5。實測 124 個非零的值,124 個全部對得上。對出來的內容也合理:第一列是天使,往下依序是它的 3A、2A、1A 農場球隊。完整說明見為什麼你加不了新球隊

19 個純文字檔各裝什麼

下表最後一列 attrib.dat.csv 不是遊戲的檔, 剛安裝好的原版資料夾裡沒有它。列出來是因為很多人的資料夾裡會有, 看到它不用緊張,也不要把它當成能改的目標

檔案欄位資料列裝什麼
attrib.dat462,921 打者能力。改能力前務必先讀避雷頁
playerattrib_face 這一欄指向 3D 臉皮編號(照名字找,欄號會因名冊而異
pitcher.dat291,430 投手能力
roster.dat102,970名單與打序,見下方說明
team.dat55126球隊資料(最多欄位的一個檔)
tstat.dat5126球隊上下半季勝敗
org.dat1434球團與 3A/2A/1A 的隸屬關係
manager.dat2134總教練
bstats.dat62,921打擊成績
pstats.dat151,430投球成績
fbstats.dat62,921守備成績
career.dat92,921打者生涯累計
careerp.dat111,430投手生涯累計
lhattrib.dat282,921 左投/右投分開記錄的能力與成績,見下方說明
rhattrib.dat292,921
lhbstats.dat142,921
rhbstats.dat142,921
lhpstats.dat131,430
rhpstats.dat131,430
attrib.dat.csv463,167 不在原版安裝裡。一份 2017 年的舊匯出版,遊戲不讀它
resign.csv140 年齡與明星等級對應的續約機率表

資料列數自己會分群

注意上表的「資料列」欄,只有四個數字反覆出現:

2,921 → 全部球員(8 個檔) · 1,430 → 只有投手(5 個檔)
126 → 球隊(2 個檔) · 34 → 球團(2 個檔)

所以拿到一個不認識的檔,看它有幾列就大概知道它在描述誰

拿這張表去驗你自己那份名單被換過沒

本站同時打開剛安裝好的原版一台裝了模組的機器,把每個檔量了兩次:

欄位
原版
欄位
裝過模組
資料列
原版
資料列
裝過模組
attrib.dat4646 2,9213,247
pitcher.dat2929 1,4301,618
roster.dat1010 2,9703,004
team.dat5555 126126
org.dat1414 3434
manager.dat2121 3434
resign.csv 140140

兩件事同時成立

① 欄位數 19 個檔全部一模一樣,一個都沒差。 換名單不會改變結構 —— 這就是為什麼本站敢說 「這一頁講的規則對你成立」。

② 只要跟球員有關的檔,列數就變了。 球隊(126)、球團(34)、續約機率表(140)完全沒動, 因為模組換的是球員不是聯盟結構

所以你可以拿這個當最快的檢查: 打開你的 attrib.dat,看它有幾行。 不是 2,921 就是被換過了(要扣掉第一行表頭)。

更完整的說明在 怎麼看出哪些檔還沒被動過那一課。

lhrh:對左投跟對右投是分開記的

六個檔名以 lhrh 開頭,內容是同一批球員面對左投與右投的分開數據。 成對的三組:能力(attrib)、打擊成績(bstats)、投球成績(pstats)。

有一個不對稱的地方

三組裡有兩組左右欄位完全相同,但能力那一組不是

lhattrib.dat 28 欄 · rhattrib.dat 29 欄

多出來的那一欄叫 lrattrib_chasehardbreak只有右邊那個檔有

未確認 為什麼只記一邊,本站沒有查出來。

⚠️ 比「欄位數不一樣」更會咬人的是:編號整個位移了

多出來那一欄不是加在最後面,是插在中間第 22 格。 所以從第 22 欄開始,同一個編號在兩個檔裡指的是不同的東西:

編號lhattrib.datrhattrib.dat
0 – 21兩邊完全一樣(22 個欄位)
22lrattrib_takefblrattrib_chasehardbreak
23lrattrib_takeslowbreaklrattrib_takefb
24lrattrib_takehardbreaklrattrib_takeslowbreak
25lrattrib_missfblrattrib_takehardbreak
26lrattrib_missslowbreaklrattrib_missfb
27lrattrib_misshardbreaklrattrib_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

先看規模

純文字的 .dat18 個
欄位總數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_ 已省略。

0first_name1last_name2jerseynum3bats
4throws5primary_position6secondary_position7height
8weight9boneprofile10face11face2004style
12skin_tone13hairstyle14haircolour15facialhair
16bodytype17audioid18photo19platediscipline
20bunting21stealing_aggressive22baserunning23speed
24fielding25range26throwstrength27throwaccuracy
28durability29battingstance30swingtype31batcolour
32batglove33wristband34elbowguard35shinguard
36socks37catchermask38fieldglovecolour39ditty
40salary41contract_length42starpower43topprospect
44hidden45birthday

bstats.dat —— 6 欄

共同前綴 batstat_ 已省略。

0first_name1last_name2g3r
4sb5cs

career.dat —— 9 欄

共同前綴 batcareerstats_ 已省略。

0first_name1last_name2g3ab
4h5hr6rbi7r
8sb

careerp.dat —— 11 欄

共同前綴 pitchcareer_ 已省略。

0first_name1last_name2g3ip
4pip5er6w7l
8sv9so10bb

fbstats.dat —— 6 欄

共同前綴 fieldstat_ 已省略。

0first_name1last_name2g3po
4a5e

lhattrib.dat —— 28 欄

共同前綴 lrattrib_ 已省略。

0first_name1last_name2contact3power
4hit_ul5hit_um6hit_ur7hit_cl
8hit_cm9hit_cr10hit_ll11hit_lm
12hit_lr13lf_pct14cf_pct15rf_pct
16hr_pct17fb_pct18ld_pct19gb_pct
20chasefb21chaseslowbreak22takefb23takeslowbreak
24takehardbreak25missfb26missslowbreak27misshardbreak

lhbstats.dat —— 14 欄

共同前綴 lrbatstat_ 已省略。

0first_name1last_name21b32b
43b5hr6rbi7so
8bb9ibb10sh11sf
12hbp13tpa

lhpstats.dat —— 13 欄

共同前綴 lrpitchstat_ 已省略。

0first_name1last_name2so3bb
4ibb5hbp6sf7sh
81b92b103b11hr
12tpa

manager.dat —— 21 欄

共同前綴 manager_ 已省略。

0first_name1last_name2jerseynum3audioid
4height5weight6boneprofile7face
8face2004style9skintone10hairstyle11haircolour
12facialhair13bodytype14hitting15baserunning
16fielding17pitching18salary19reallife
20birthday

org.dat —— 14 欄

共同前綴 org_ 已省略。

0unique_team1team_mlb2team_aaa3team_aa
4team_a5is_franchise6spring7budget
8penalty19penalty210penalty311penalty4
12mlb_manager13minors_manager

pitcher.dat —— 29 欄

共同前綴 pitchattrib_ 已省略。

0first_name1last_name2stamina3pickoff
4fastball_movement5fastball_description6fastball_control7fastball_velocity
8pitch2_type9pitch2_movement10pitch2_description11pitch2_control
12pitch2_velocity13pitch3_type14pitch3_movement15pitch3_description
16pitch3_control17pitch3_velocity18pitch4_type19pitch4_movement
20pitch4_description21pitch4_control22pitch4_velocity23pitch5_type
24pitch5_movement25pitch5_description26pitch5_control27pitch5_velocity
28pitcher_delivery

pstats.dat —— 15 欄

共同前綴 pitchstat_ 已省略。

0first_name1last_name2g3gs
4r5er6w7l
8sv9blsv10cg11sho
12pk13ip14pip

rhattrib.dat —— 29 欄

共同前綴 lrattrib_ 已省略。

0first_name1last_name2contact3power
4hit_ul5hit_um6hit_ur7hit_cl
8hit_cm9hit_cr10hit_ll11hit_lm
12hit_lr13lf_pct14cf_pct15rf_pct
16hr_pct17fb_pct18ld_pct19gb_pct
20chasefb21chaseslowbreak22chasehardbreak23takefb
24takeslowbreak25takehardbreak26missfb27missslowbreak
28misshardbreak

rhbstats.dat —— 14 欄

共同前綴 lrbatstat_ 已省略。

0first_name1last_name21b32b
43b5hr6rbi7so
8bb9ibb10sh11sf
12hbp13tpa

rhpstats.dat —— 13 欄

共同前綴 lrpitchstat_ 已省略。

0first_name1last_name2so3bb
4ibb5hbp6sf7sh
81b92b103b11hr
12tpa

roster.dat —— 10 欄

0roster_teamid1roster_playerid2rh_roster_al_position3rh_roster_al_battingorder
4rh_roster_nl_position5rh_roster_nl_battingorder6lh_roster_al_position7lh_roster_al_battingorder
8lh_roster_nl_position9lh_roster_nl_battingorder

team.dat —— 55 欄

共同前綴 team_ 已省略。

0unique_team1location2long_name3short_name
4league5division6artid7climatezone
8homeintensity9vs_ana10vs_oak11vs_sea
12vs_tex13vs_cws14vs_cle15vs_det
16vs_kc17vs_min18vs_bal19vs_bos
20vs_nyy21vs_tam22vs_tor23vs_ari
24vs_col25vs_la26vs_sdp27vs_sfg
28vs_cub29vs_cin30vs_hou31vs_mil
32vs_pit33vs_stl34vs_atl35vs_fla
36vs_mon37vs_nym38vs_phi39vs_al
40vs_nl41pinchhitter42pinchrunner43pitchersub
44defensivesub45defensivealign46takepitch47sacbunt
48buntforhit49pickoff50int_walks51hitandrun
52steals53advancebases54suicidesqueeze

team_climatezone 的三個值(2026-08-28 解開)

一支社群編輯器附的設定檔給了名字,而遊戲自己的球隊表可以把它驗到滿分

設定檔寫的原版有幾支
0Indoors 室內35
1Southern 南方67
2Northern 北方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_ 已省略。

0unique_team1wins_1sthalf2losses_1sthalf3wins_2ndhalf
4losses_2ndhalf

看這張表要注意兩件事

一、同名不代表同義。 lhattrib.datrhattrib.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,72911,98925.0000
剛安裝好的中文版原版299,72911,98925.0000
本站測試機(社群名冊)78,5043,14025.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,9899,489
年份範圍(位元組 9–10)1890–20041890–2009
球隊(位元組 11)相異值31 種102 種
129 打擊/130 投球8,040/3,9496,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 個位元組沒有對齊位元組邊界,硬猜切法會有幾百種可能。 但棒球給了兩種免費的檢驗:

  1. 必然成立的關係 —— 安打不可能多於打數,全壘打不可能多於安打。 切錯的話,六千筆裡一定會有一大堆違反。
  2. 史上單季紀錄 —— 一個欄位的上限,不可能超過人類做過的最好成績。

每一筆 25 個位元組

位置是什麼怎麼確認的
0–3球員碼跟名冊純文字檔每列開頭的十六進位數對得上
4永遠是 1逐位元組統計,相異值只有 1 種
5–8、22–24永遠是 0
9–10球季年份16 位元小端序,1890–2009(這份名冊;原版是 1890–2004)
11球隊102 種相異值(這份名冊;原版是 31 種)
12129 = 打擊 130 = 投球 來自母檔的兩張表合併時留下的標記
13–21成績(9 個位元組=72 位元) 見下面兩張表,打擊與投球的欄位配置不一樣

打擊(第 12 個位元組 = 129,共 6,173 筆)

位元欄位本檔上限大聯盟單季紀錄
0–910打數 716716
10–178出賽163165
18–247盜壘126138
25–317盜壘失敗推測 53
32–409安打 262262
41–488打點184191
49–568得分177198
57–637全壘打6073
64–718沒有用到(永遠 0)

兩個欄位的上限剛好各自等於一項真實的大聯盟紀錄: 打數 716(Jimmy Rollins,2007)、安打 262(鈴木一朗,2004)。

投球(第 12 個位元組 = 130,共 3,316 筆)

位元欄位本檔上限大聯盟單季紀錄
0–78自責分179186
8–158保送208289
16–249三振 383383
25–317出賽94106
32–409投球局數453680
41–422不明(只有 0/1/2 三種值)未解 2
43–4862959
49–5462548
55–639沒有用到(永遠 0)
64–718救援成功 6262

三振上限 383 是 Nolan Ryan 1973 年的紀錄,救援 62 是 Francisco Rodríguez 2008 年的紀錄。

⭐ 決定性的一筆:兩個人,各一年,七個欄位同時對上

光靠上限還不夠 —— 那只是兩個點。真正釘死它的是從資料裡找出一筆 成績完全可查的球季,把每個欄位跟史實逐一比對

1911 年那一筆(打擊)解出來史實 1973 年那一筆(投球)解出來史實
打數591591 自責分104104
出賽146146 保送162162
盜壘8383 三振383383
安打248248 出賽4141
打點127127 局數326326
得分147147 2121
全壘打88 1616

各七個欄位,全部命中。而且年份欄位是獨立解出來的 (1911 與 1973),不是本站挑的。

全體檢驗

檢驗成立比例
安打 ≤ 打數6,173/6,173 = 100.00%
全壘打 ≤ 安打6,173/6,173 = 100.00%
打點 ≥ 全壘打6,173/6,173 = 100.00%
打數 ≤ 出賽×86,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-01790,52820
2006-086,656,00020
2006-116,496,25620
2008-065,410,81620
2016-095,746,68820
2019-015,361,66420

七個檔全部以 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 資料庫。

這對你有什麼用

⭐ 2026-08-28:上面那個問號有答案了 —— 換隊跟分項成績,兩個都是

⚠️ 這張卡是 2026-08-28 寫的,比上面〈25 個位元組全部填滿了〉那一節早一天, 排在這裡是因為它接的是同一節的問題,不是因為它比較新。 它量的是剛安裝好的原版(11,989 筆), 所以筆數與相異值跟那一節的 2009 名冊不同 —— 位元組 12 的意義(129 打擊/130 投球)兩份都一樣,沒有被推翻。

那一段結尾問「為什麼同一年會有多筆」。當天稍晚把 25 個位元組逐格重數, 其中一格立刻跳出來:

位置相異值是什麼
12只有兩個:129(8,040 筆)、130(3,949 筆) 打擊成績/投球成績
0–31,304 個球員碼(跟純文字檔行首那一串是同一個)
1131 個球隊

怎麼確定 130 是投球(錨點):用 130 的 651 位球員裡, 有 649 位出現在 pitcher.dat。 用 129 的 1,281 位裡有 1,275 位在 attrib.dat球員碼是直接拿去比對的,不是猜的 —— 純文字檔每一列開頭那九位十六進位數,就是這裡的 0–3 位元組。

四個欄位合起來就是唯一鍵: (球員碼,年份,129/130,球隊)在 11,989 筆裡零重複。 所以同一年多筆的兩個原因是:

還有一個外部佐證。社群當年用來編名冊的母檔是 Access 資料庫,那裡面有 20 張表, 而 data\database\ 只有 19 個 .dat。 多出來的一張正是:母檔把它拆成 histbhistp 兩張表, 匯出時才合併成一個 hist.dat那個 129/130 就是合併時留下的來源標記。

已解 位置 13–21 那 9 個位元組(成績數字本身) 在寫這張卡的當下還沒解開 —— 它們沒有對齊位元組邊界,是把好幾個欄位擠在一起。 隔天(2026-08-29)解開了:切法與逐欄驗證見上面 〈25 個位元組全部填滿了〉那一節。

動手之前

純文字不等於可以隨便改

這些檔很安全,要非常小心:

· 行首那個編號不能動
· 欄位數量不能變
· 換行符要保持原樣(跟版面檔同理)
· 大部分能力欄位不是 0-99 的分數,寫錯值會破壞欄位語意

改能力之前,球員資料檔那頁一定要先讀完。

📌 重點整理

接下來