14 KiB
Import Process & Schema Documentation
Platform Note: This documentation describes the import process and internal database schema for the Android Application (
com.majinnaibu.monstercards).
1. Overview of the Import Process
The Monster Cards Android application can import monster stat blocks formatted in JSON from .monster or .monster.txt files shared or opened from other applications (such as file managers, messaging apps, or browsers).
+-------------------------------------------------------+
| External .monster / .monster.txt file (JSON Payload) |
+-------------------------------------------------------+
|
v
+-------------------------------------------------------+
| MainActivity (Intent Handling: ACTION_VIEW / SEND) |
| - Extracts raw JSON string from Content/File URI |
+-------------------------------------------------------+
|
v
+-------------------------------------------------------+
| MonsterImportFragment & MonsterImportViewModel |
| - MonsterImportHelper.fromJSON(json) parses JSON |
| - Maps JSON fields to internal Monster domain model |
| - Renders UI preview with calculated AC, HP, & Markdown|
+-------------------------------------------------------+
|
v
+-------------------------------------------------------+
| User clicks "Import" Menu Action |
| - Generates new UUID |
| - Persists Monster to Room Database (monsters table) |
| - Rebuilds FTS index (monsters_fts) |
+-------------------------------------------------------+
2. Source Format (.monster / .monster.txt) & File Extension Behavior
The .monster file format is generated by Tetra-cube's D&D 5e Statblock Generator (statblock-script.js).
File Saving Behavior (SavedData.SaveToFile)
SaveToFile: () => saveAs(new Blob([JSON.stringify(mon)], {
type: "text/plain;charset=utf-8"
}), mon.name.toLowerCase() + ".monster")
- Desktop Browsers: Save the file with the specified
.monsterfilename. - Android Mobile Browsers & DownloadManager: Because the
Blobuses MIME typetext/plain;charset=utf-8, Android file handlers append a.txtextension, creating.monster.txtfiles.
3. JSON Parsing & Field Mapping (MonsterImportHelper.java)
MonsterImportHelper.fromJSON(String json) uses Gson's JsonParser to parse the root JSON object and populate a Monster instance.
Complete Field Mapping Reference
| JSON Field Name | Target Monster Field |
Type / Default | Description / Conversion Logic |
|---|---|---|---|
name |
monster.name |
String |
Monster name |
size |
monster.size |
String |
Size string (e.g., "medium", "large") |
type |
monster.type |
String |
Creature type (e.g., "humanoid", "dragon") |
tag |
monster.subtype |
String |
Subtype / tag (e.g., "elf", "shapechanger") |
alignment |
monster.alignment |
String |
Alignment string (e.g., "neutral good") |
hitDice |
monster.hitDice |
int (default 1) |
Number of hit dice |
armorName |
monster.armorType |
ArmorType |
Converted via ArmorTypeConverter.armorTypeFromStringValue() |
shieldBonus |
monster.shieldBonus |
int |
Shield AC bonus (+2 if present) |
natArmorBonus |
monster.naturalArmorBonus |
int |
Additional natural armor AC bonus |
otherArmorDesc |
monster.otherArmorDescription |
String |
Custom armor description string |
speed |
monster.walkSpeed |
int |
Walking speed in feet |
burrowSpeed |
monster.burrowSpeed |
int |
Burrowing speed in feet |
climbSpeed |
monster.climbSpeed |
int |
Climbing speed in feet |
flySpeed |
monster.flySpeed |
int |
Flying speed in feet |
hover |
monster.canHover |
boolean |
Whether flying creature can hover |
swimSpeed |
monster.swimSpeed |
int |
Swimming speed in feet |
customHP |
monster.hasCustomHP |
boolean |
Flag for override custom HP string |
customSpeed |
monster.hasCustomSpeed |
boolean |
Flag for override custom speed string |
hpText |
monster.customHPDescription |
String |
Custom HP text description |
speedDesc |
monster.customSpeedDescription |
String |
Custom speed text description |
strPoints |
monster.strengthScore |
int (default 10) |
Strength ability score |
dexPoints |
monster.dexterityScore |
int (default 10) |
Dexterity ability score |
conPoints |
monster.constitutionScore |
int (default 10) |
Constitution ability score |
intPoints |
monster.intelligenceScore |
int (default 10) |
Intelligence ability score |
wisPoints |
monster.wisdomScore |
int (default 10) |
Wisdom ability score |
chaPoints |
monster.charismaScore |
int (default 10) |
Charisma ability score |
blindsight |
monster.senses |
Set<String> |
Added as "blindsight <N> ft." if N > 0 |
darkvision |
monster.senses |
Set<String> |
Added as "darkvision <N> ft." if N > 0 |
tremorsense |
monster.senses |
Set<String> |
Added as "tremorsense <N> ft." if N > 0 |
truesight |
monster.senses |
Set<String> |
Added as "truesight <N> ft." if N > 0 |
telepathy |
monster.telepathyRange |
int |
Telepathy range in feet |
cr |
monster.challengeRating |
ChallengeRating |
Converted via ChallengeRatingConverter |
customCr |
monster.customChallengeRatingDescription |
String |
Custom CR text |
customProf |
monster.customProficiencyBonus |
int |
Custom proficiency bonus override |
abilities |
monster.abilities |
List<Trait> |
List of JSON objects { "name": "...", "desc": "..." } |
actions |
monster.actions |
List<Trait> |
List of JSON objects { "name": "...", "desc": "..." } |
bonusActions |
monster.actions (Future) |
List<Trait> |
Bonus actions array |
reactions |
monster.reactions |
List<Trait> |
List of JSON objects { "name": "...", "desc": "..." } |
legendaries |
monster.legendaryActions |
List<Trait> |
List of JSON objects { "name": "...", "desc": "..." } |
mythics |
monster.legendaryActions (Future) |
List<Trait> |
Mythic actions array |
lairs |
monster.lairActions |
List<Trait> |
List of JSON objects { "name": "...", "desc": "..." } |
regionals |
monster.regionalActions |
List<Trait> |
List of JSON objects { "name": "...", "desc": "..." } |
sthrows |
Saving throw proficiencies | ProficiencyType |
Array of objects { "name": "str"|"dex"|"con"|"int"|"wis"|"cha" }. Sets proficiency to PROFICIENT. |
skills |
monster.skills |
Set<Skill> |
Array of { "name": "...", "stat": "...", "note": " (ex)" }. note == " (ex)" sets EXPERTISE. |
damageTypes, specialdamage |
Immunities / Resistances / Vulnerabilities | Set<String> |
Array of { "name": "...", "type": "i"|"r"|"v" }. Sorted into immunities ("i"), resistances ("r"), or vulnerabilities ("v"). |
conditions |
monster.conditionImmunities |
Set<String> |
Array of { "name": "..." } |
languages |
monster.languages |
Set<Language> |
Array of { "name": "...", "speaks": true|false } |
understandsBut |
monster.understandsButDescription |
String |
Language qualifier text |
4. Preview & Database Persistence
-
ViewModel Computation (
MonsterImportViewModel.java):- Computes calculated stat block values:
- AC: Calculated based on
armorType, dexterity modifier, shield bonus, natural armor bonus, or custom description. - HP: Calculated as
floor(hitDice * ((dieSize + 1) / 2 + conModifier))wheredieSizeis derived from size (e.g., Medium = d8, Large = d10). - Dynamic Placeholders: Replaces placeholders in trait descriptions (e.g.,
[STR ATK],[WIS SAVE]) with computed attack bonuses and spell save DCs based on ability scores and proficiency bonuses. - Markdown Rendering: Trait and action descriptions are parsed through
CommonMarkHelperto format inline HTML/Markdown for display.
- AC: Calculated based on
- Computes calculated stat block values:
-
Persistence (
MonsterImportFragment.java):- When the user taps the Import action menu button (
R.id.menu_action_import_monster):- Assigns a new
UUIDtomonster.id. - Calls
MonsterRepository.addMonster(monster)which executes anINSERTinto the Room database asynchronously on an IO thread via RxJava3. - Shows a
Snackbarconfirming import success and navigates to the library/detail view for the imported monster.
- Assigns a new
- When the user taps the Import action menu button (
5. Internal Database Schema (monsters Table)
The app uses Room Database (Database Name: monsters, Version: 5).
Table: monsters
| Column Name | SQLite Data Type | Default Value | Description / Room TypeConverter |
|---|---|---|---|
id |
TEXT |
Primary Key | UUID string (UUIDConverter) |
name |
TEXT |
"" |
Monster name |
size |
TEXT |
"" |
Size category (e.g. "medium") |
type |
TEXT |
"" |
Creature type |
subtype |
TEXT |
"" |
Creature tag / subtype |
alignment |
TEXT |
"" |
Alignment |
strength_score |
INTEGER |
10 |
Strength score |
strength_saving_throw_advantage |
TEXT |
"none" |
Advantage type ("none", "advantage", "disadvantage") |
strength_saving_throw_proficiency |
TEXT |
"none" |
Proficiency type ("none", "proficient", "expertise") |
dexterity_score |
INTEGER |
10 |
Dexterity score |
dexterity_saving_throw_advantage |
TEXT |
"none" |
Dexterity saving throw advantage |
dexterity_saving_throw_proficiency |
TEXT |
"none" |
Dexterity saving throw proficiency |
constitution_score |
INTEGER |
10 |
Constitution score |
constitution_saving_throw_advantage |
TEXT |
"none" |
Constitution saving throw advantage |
constitution_saving_throw_proficiency |
TEXT |
"none" |
Constitution saving throw proficiency |
intelligence_score |
INTEGER |
10 |
Intelligence score |
intelligence_saving_throw_advantage |
TEXT |
"none" |
Intelligence saving throw advantage |
intelligence_saving_throw_proficiency |
TEXT |
"none" |
Intelligence saving throw proficiency |
wisdom_score |
INTEGER |
10 |
Wisdom score |
wisdom_saving_throw_advantage |
TEXT |
"none" |
Wisdom saving throw advantage |
wisdom_saving_throw_proficiency |
TEXT |
"none" |
Wisdom saving throw proficiency |
charisma_score |
INTEGER |
10 |
Charisma score |
charisma_saving_throw_advantage |
TEXT |
"none" |
Charisma saving throw advantage |
charisma_saving_throw_proficiency |
TEXT |
"none" |
Charisma saving throw proficiency |
armor_type |
TEXT |
"none" |
String representation of ArmorType (ArmorTypeConverter) |
shield_bonus |
INTEGER |
0 |
Shield AC bonus |
natural_armor_bonus |
INTEGER |
0 |
Natural armor bonus |
other_armor_description |
TEXT |
"" |
Custom armor description |
hit_dice |
INTEGER |
1 |
Hit dice count |
has_custom_hit_points |
INTEGER |
0 |
Boolean flag (0 = false, 1 = true) |
custom_hit_points_description |
TEXT |
"" |
Override HP string |
walk_speed |
INTEGER |
0 |
Walk speed in ft |
burrow_speed |
INTEGER |
0 |
Burrow speed in ft |
climb_speed |
INTEGER |
0 |
Climb speed in ft |
fly_speed |
INTEGER |
0 |
Fly speed in ft |
can_hover |
INTEGER |
0 |
Boolean flag |
swim_speed |
INTEGER |
0 |
Swim speed in ft |
has_custom_speed |
INTEGER |
0 |
Boolean flag |
custom_speed_description |
TEXT |
NULL | Override speed string |
challenge_rating |
TEXT |
"1" |
String representation of ChallengeRating (ChallengeRatingConverter) |
custom_challenge_rating_description |
TEXT |
"" |
Custom CR text |
custom_proficiency_bonus |
INTEGER |
0 |
Custom proficiency bonus override |
telepathy_range |
INTEGER |
0 |
Telepathy range in ft |
understands_but_description |
TEXT |
"" |
Language qualifier description |
senses |
TEXT |
"[]" |
JSON array of strings (SetOfStringConverter) |
skills |
TEXT |
"[]" |
JSON array of Skill objects (SetOfSkillConverter) |
damage_immunities |
TEXT |
"[]" |
JSON array of strings (SetOfStringConverter) |
damage_resistances |
TEXT |
"[]" |
JSON array of strings (SetOfStringConverter) |
damage_vulnerabilities |
TEXT |
"[]" |
JSON array of strings (SetOfStringConverter) |
condition_immunities |
TEXT |
"[]" |
JSON array of strings (SetOfStringConverter) |
languages |
TEXT |
"[]" |
JSON array of Language objects (SetOfLanguageConverter) |
abilities |
TEXT |
"[]" |
JSON array of Trait objects (ListOfTraitsConverter) |
actions |
TEXT |
"[]" |
JSON array of Trait objects (ListOfTraitsConverter) |
reactions |
TEXT |
"[]" |
JSON array of Trait objects (ListOfTraitsConverter) |
lair_actions |
TEXT |
"[]" |
JSON array of Trait objects (ListOfTraitsConverter) |
legendary_actions |
TEXT |
"[]" |
JSON array of Trait objects (ListOfTraitsConverter) |
regional_actions |
TEXT |
"[]" |
JSON array of Trait objects (ListOfTraitsConverter) |
Virtual FTS Table: monsters_fts
Used for full-text search indexing:
CREATE VIRTUAL TABLE IF NOT EXISTS `monsters_fts`
USING FTS4(`name` TEXT, `size` TEXT, `type` TEXT, `subtype` TEXT, `alignment` TEXT, content=`monsters`);
6. Component Objects Schema (JSON Serialized in DB)
1. Trait
Used in abilities, actions, reactions, lair_actions, legendary_actions, and regional_actions:
{
"name": "Keen Smell",
"description": "The monster has advantage on Wisdom (Perception) checks that rely on smell."
}
2. Skill
Used in skills:
{
"name": "Perception",
"abilityScore": "WISDOM",
"advantageType": "NONE",
"proficiencyType": "PROFICIENT"
}
abilityScore:"STRENGTH","DEXTERITY","CONSTITUTION","INTELLIGENCE","WISDOM","CHARISMA".advantageType:"NONE","ADVANTAGE","DISADVANTAGE".proficiencyType:"NONE","PROFICIENT","EXPERTISE".
3. Language
Used in languages:
{
"mName": "Common",
"mSpeaks": true
}
mName: Name of the language (e.g.,"Elvish").mSpeaks:trueif the creature can speak it;falseif it only understands it.