Files
MonsterCards/docs/ImportFromMonster.md

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 .monster filename.
  • Android Mobile Browsers & DownloadManager: Because the Blob uses MIME type text/plain;charset=utf-8, Android file handlers append a .txt extension, creating .monster.txt files.

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

  1. 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)) where dieSize is 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 CommonMarkHelper to format inline HTML/Markdown for display.
  2. Persistence (MonsterImportFragment.java):

    • When the user taps the Import action menu button (R.id.menu_action_import_monster):
      1. Assigns a new UUID to monster.id.
      2. Calls MonsterRepository.addMonster(monster) which executes an INSERT into the Room database asynchronously on an IO thread via RxJava3.
      3. Shows a Snackbar confirming import success and navigates to the library/detail view for the imported monster.

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: true if the creature can speak it; false if it only understands it.