zenno/doc/mdb: start the mdb doc

For #12.
This commit is contained in:
2026-07-31 22:12:38 -04:00
parent 48118efeeb
commit aaa7c6d5b5
3 changed files with 271 additions and 0 deletions
+9
View File
@@ -0,0 +1,9 @@
<script lang="ts">
import type { SvelteHTMLElements } from 'svelte/elements';
let { children, ...rest }: SvelteHTMLElements['span'] = $props();
</script>
<span class="bg-mist-300 font-mono hyphens-none dark:bg-mist-900" {...rest}>
{@render children?.()}
</span>
+257
View File
@@ -0,0 +1,257 @@
<script lang="ts">
import Article from '../Article.svelte';
import Sec from '../Sec.svelte';
import Mono from '../Mono.svelte';
const supportCardEffects = [
[1, 'Friendship Bonus'],
[2, 'Mood Effect'],
[3, 'Speed Bonus'],
[4, 'Stamina Bonus'],
[5, 'Power Bonus'],
[6, 'Guts Bonus'],
[7, 'Wit Bonus'],
[8, 'Training Effectiveness'],
[9, 'Initial Speed'],
[10, 'Initial Stamina'],
[11, 'Initial Power'],
[12, 'Initial Guts'],
[13, 'Initial Wit'],
[14, 'Initial Friendship Gauge'],
[15, 'Race Bonus'],
[16, 'Fan Bonus'],
[17, 'Hint Levels'],
[18, 'Hint Frequency'],
[19, 'Specialty Priority'],
[20, 'Max Speed'],
[21, 'Max Stamina'],
[22, 'Max Power'],
[23, 'Max Guts'],
[24, 'Max Wit'],
[25, 'Event Recovery'],
[26, 'Event Effectiveness'],
[27, 'Failure Protection'],
[28, 'Energy Cost Reduction'],
[29, 'Minigame Effectiveness'],
[30, 'Skill Point Bonus'],
[31, 'Wit Friendship Recovery'],
] as const;
</script>
<Article>
{#snippet head()}
<Sec h={1} id="top" class="text-center">Master Data</Sec>
<p>
This article is my personal notes on Umamusume's master data, a.k.a. master.mdb or just "the mdb." Most of the notes are
oriented toward my work on this website. It is an in-progress translation of <a
href="https://git.sunturtle.xyz/zephyr/horse/src/branch/main/doc">my broader but more sparse notes</a
>
into a more agreeable, navigable, and consistent form.
</p>
<p>
master.mdb is an SQLite database that the game downloads to your device. On Windows, you can find it at <Mono
>%USERPROFILE%\AppData\LocalLow\Cygames\Umamusume\master\master.mdb</Mono
>. Hakuraku has a
<a href="https://hakuraku.moe/masterdata" target="_blank" rel="noopener noreferrer">master data explorer</a> that you can use
on the website.
</p>
<p>
Generally speaking, I am only documenting what I feel is important, both in terms of tables and columns. That does
occasionally include documenting some things as being unimportant.
</p>
<p>
Roughly speaking, master data contains all the numbers needed to display the game's user interface, including during races.
Skill data, support card effects, Grand Concert lesson definitions, and so on are in there. If trying to access some data
in-game shows a "Connecting..." indicator while it loads, it probably isn't in the mdb. Notably, this includes everything
related to career event outcomes. (Event information on sites like GameTora and GameWith are massive crowd-sourced efforts.)
</p>
<p>
This document is oriented toward programmers with understanding of SQL databases. Mentions of <Mono>Gallop::</Mono> are references
to types visible in decompilations of the game, but no C# knowledge is needed.
</p>
{/snippet}
<Sec h={2} id="text_data">text_data</Sec>
<p>
The <Mono>text_data</Mono> table contains most non-story strings in the game. Queries look up entries by <Mono>category</Mono> and
<Mono>index</Mono>, i.e. <Mono>SELECT "text" FROM text_data WHERE category=? AND "index"=?</Mono>.
</p>
<p>Some important categories:</p>
<ul class="ml-4 list-disc pb-4">
<li>6 is character names, 4 is [variant] character name, 5 is [variant], 14 is clothing names.</li>
<li>47 is skill names, 48 is skill descriptions.</li>
<li>75 is support card names including variant, 76 is support card variant, 77 is support card character.</li>
<li>147 is spark names, 172 is spark descriptions.</li>
<li>33 is race name by race ID, 28 is race name by race instance ID, 31 is race courses, 111 is saddle names.</li>
<li>65 is player titles, 66 is title descriptions.</li>
<li>
119 is scenario full titles (e.g. <Mono>The Beginning: URA Finale</Mono>), 120 is scenario descriptions, 237 is scenario
names (e.g. <Mono>URA Finale</Mono>).
</li>
<li>130 is epithet names, 131 is epithet descriptions.</li>
</ul>
<p>
Other categories are usually easy enough to figure out by inspection. Text data categories have proper names given in <Mono
>Gallop::MasterString.Category</Mono
>, but a few categories that have useful strings are missing from there.
</p>
<Sec h={2} id="supports">Support cards</Sec>
<p>
Relevant <Mono>text_data</Mono> categories include 75 for name including variant, 76 for variant alone, 77 for character name. Category
151 gives support card effect names, 154 gives effect descriptions, 150 gives unique effect names, and 155 gives unique effect descriptions.
</p>
<p>
Queries should join with <Mono>support_card_data</Mono> inside.
</p>
<ul class="ml-4 list-disc pb-4">
<li>Support card ID is just <Mono>id</Mono>.</li>
<li>
<Mono>chara_id</Mono> links to character. Implements the "no supporting yourself" and "no duplicated characters" rules.
</li>
<li><Mono>rarity</Mono> is 1 for R, 2 for SR, 3 for SSR.</li>
<li><Mono>exchange_item_id</Mono> is the type of item you get for exchanging duplicates.</li>
<li><Mono>effect_table_id</Mono> joins <Mono>support_card_effect_table</Mono>.</li>
<li><Mono>unique_effect_id</Mono> joins <Mono>support_card_unique_effect</Mono>.</li>
<li>
<Mono>command_type</Mono> is generally 1 for normal support cards and 0 for pals and groups, but Throne is 1 as well. Probably
not important.
</li>
<li>
<Mono>command_id</Mono> gives the specialty type: 101 for speed, 102 for power, 103 for guts, 105 for stamina, 106 for wit, 0
for pal and group. There is no 104.
</li>
<li><Mono>support_card_type</Mono> is 1 for normal cards, 2 for pal, 3 for group.</li>
<li>
<Mono>skill_set_id</Mono> gives the hint list via <Mono
>support_card_data sc JOIN single_mode_hint_gain h ON sc.skill_set_id = h.hint_id AND sc.support_card_id =
h.support_card_id</Mono
>. Given that you have to use the support card ID anyway, this seems redundant.
</li>
<li><Mono>outing_max</Mono> is the number of recreation events with the card, for pals and groups.</li>
<li><Mono>effect_id</Mono> is the specific instance of Pure Passion the card can grant, for groups.</li>
</ul>
<p>
<Mono>support_card_effect_table</Mono> gives progressions of support card stats. There is one row per stat per support card. Unique
effects are not included.
</p>
<ul class="ml-4 list-disc pb-4">
<li><Mono>id</Mono> joins with support card ID.</li>
<li>
<Mono>type</Mono> is the stat type (<Mono>text_data</Mono> category 151):
<table class="table-fixed border text-center">
<thead>
<tr>
<th scope="col" class="px-2">Type ID</th>
<th scope="col" class="px-2">Effect</th>
</tr>
</thead>
<tbody>
{#each supportCardEffects as [typ, name] (typ)}
<tr class="even:bg-mist-300 dark:even:bg-mist-900">
<td class="px-2">{typ}</td>
<td class="px-2">{name}</td>
</tr>
{/each}
</tbody>
</table>
</li>
<li>
<Mono>init</Mono> is the card's value at level 1, then there are subsequent <Mono>limit_lv5</Mono>, <Mono>limit_lv10</Mono>,
&c. up to <Mono>limit_lv50</Mono>. Each value is either a threshold value for the corresponding level, or -1 to indicate
that the value should interpolate per level between the previous positive value (defaulting to 0) and the next (defaulting
to no interpolation).
</li>
</ul>
<p>Unique effect data is in <Mono>support_card_unique_effect</Mono>.</p>
<ul class="ml-4 list-disc pb-4">
<li>
<Mono>id</Mono> joins with <Mono>support_card_data.unique_effect_id</Mono>, but it's also always the same as the support
card ID, never deduplicated or anything. (This ID is also used for unique effect name lookup, after all.)
</li>
<li><Mono>lv</Mono> gives the level at which the unique effect becomes active, one of 25, 30, 35, or 40.</li>
<li>
<Mono>type_0</Mono> and <Mono>type_1</Mono> give the effect type ID with the corresponding magnitude in <Mono>value_0</Mono> or
<Mono>value_1</Mono>, largely same as for <Mono>support_card_effect_table.type</Mono>. However, there are some extra types:
<ul class="ml-8 list-[reset]">
<li>
101 is a friendship gauge check. <Mono>value_0</Mono> is the threshold value, and then <Mono>value_0_1</Mono> and <Mono
>value_0_3</Mono
> give the effects that become active at that threshold with their magnitudes in <Mono>value_0_2</Mono> and <Mono
>value_0_4</Mono
>, respectively.
</li>
<li>
102 is Guts Bakushin's special effect of Training Effectiveness (magnitude in <Mono>value_0_1</Mono>) when both above a
friendship threshold (<Mono>value_0</Mono>) and not on her own specialty.
</li>
<li>
103 is Agnes Ditigal's special effect of Training Effectiveness (magnitude in <Mono>value_0_1</Mono>) when the deck has
at least <Mono>value_0</Mono> different colors.
</li>
<li>
104 is Narita Top Road's special effect of Training Effectiveness of maximum magnitude <Mono>value_0_1</Mono> divided by each
group of <Mono>value_0</Mono> fans.
</li>
<li>
105 is +<Mono>value_0</Mono> initial stat to the specialty of each card in the deck and +<Mono>value_0</Mono> initial all
stats per pal and group card.
</li>
<li>
106 is stacking effect per rainbow training, where <Mono>value_0</Mono> is the maximum number of stacks, <Mono
>value_0_1</Mono
> is the effect type granted by the stack, and <Mono>value_0_2</Mono> is the value per stack.
</li>
<li>
107 is scaling with how low energy is. <Mono>value_0</Mono> is obviously the effect type ID that scales, but the other parameters
are unclear. Currently only Bamboo Memory Guts has this, with <Mono>value_0_1&el;4</Mono> being (10, 30, 15, 5).
</li>
<li>
108 is scaling with maximum energy. Similar to 107, <Mono>value_0</Mono> is the effect type ID that scales, but the rest is
unclear, with values of (100, 75, 5, 20) for Pearl.
</li>
<li>
109 is scaling with total friendship across all cards. <Mono>value_0</Mono> is the effect type ID that scales, <Mono
>value_0_1</Mono
> is the amount of bond required to increase the effect by 1.
</li>
<li>
110 is scaling with the number of cards at the training. <Mono>value_0</Mono> is the effect type ID that scales, <Mono
>value_0_1</Mono
> is the amount per card.
</li>
<li>
110 is scaling with the number of cards at the training. <Mono>value_0</Mono> is the effect type ID that scales, <Mono
>value_0_1</Mono
> is the amount per card.
</li>
<li>
111 is scaling with training facility level. <Mono>value_0</Mono> is the effect type ID that scales, <Mono
>value_0_1</Mono
> is the amount per level.
</li>
<li>112 is Nakayama Festa Wit's 20% chance to disable failure chance.</li>
<li>
113 is an additional effect active for rainbow training. <Mono>value_0</Mono> is the additional effect ID, <Mono
>value_0_1</Mono
> is its value.
</li>
</ul>
Certainly more types will follow.
</li>
<li>
<Mono>idle_mode_sub_rate</Mono> is uncertain, but it is likely related to Independent Training (called idle single mode internally,
where "single mode" is in turn the internal name for career). It takes only a few values:
<ul class="ml-8 list-[reset]">
<li>For unique effects that don't vary, it is always 0.</li>
<li>For those that vary with the deck composition (Agnes Digital, Satono Diamond Wit), it is 10.</li>
<li>For effects that activate with 80+ friendship, it has a value of 20.</li>
<li>
For 100+ friendship effects, fan count scaling, rainbow training stacking effects, effects scaling with energy or max
energy, scaling with number of cards trained with, scaling with training level, and scaling with total deck friendship,
it has a value of 30.
</li>
</ul>
</li>
</ul>
</Article>