A Swift package providing reusable core logic for role-playing games. It is a work in progress — capabilities are added incrementally.
The short-term goal is to cover the key moving parts of a tabletop RPG character: species, class, background, ability scores, skills, spells, equipment, and the random-generation plumbing that ties them together. The architecture is designed to be flexible enough to support Open Game Content and similar game systems, and to minimize upstream dependencies.
The library is a generic Swift Package. The included CharacterGenerator example app demonstrates iOS/macOS usage with a full SwiftUI character-builder workflow.
RolePlayingCore depends on SwiftDice, which provides the Rollable protocol, dice types (Dice, CompoundDice, …), and a dice-notation parser.
The source code is grouped into the following modules under Sources/RolePlayingCore:
| Group | What's inside |
|---|---|
| Common | Height, Weight, CharacterNames, Named & DisplayOrdered protocols |
| Configuration | GameData, GameDataFiles, GameDataError, Bundle+JSONFile |
| Currency | UnitCurrency, Money, Currencies |
| Items | Item, Weapon, Armor, Gear, Tool, EquipmentOptions, InventoryEntry, damage types, weapon properties |
| Player | Player, Players, PlayerAppearance, AppearanceTraitKey, DescriptiveTraitKey, Ability, Alignment, ClassTraits/Classes, SpeciesTraits/Species, BackgroundTraits/Backgrounds, Skill/Skills, FeatTraits/Feats, Spell/Spells, SubclassTraits, UnarmoredDefense, CreatureSize, CreatureType, Initiative |
| CharacterGenerator | CharacterGenerator, NameGenerator |
Examples/CharacterGenerator is a SwiftUI iOS/macOS app that demonstrates the full library. It loads all game data from JSON at launch via GameData and provides:
- A character builder — a step-by-step navigation flow for choosing species, class, background, ability scores, skills, and spells, finishing with a name
- A player list with a detail sheet showing abilities, skills, inventory, and spells
- Random character generation using
CharacterGenerator
All game content is stored in JSON files and decoded at launch by GameData. The configuration entry point is a manifest JSON (e.g. Configuration.json) that lists the file names to load for each content type:
{
"currencies": ["Currencies"],
"skills": ["Skills"],
"feats": ["Feats"],
"spells": ["Spells"],
"items": ["Items"],
"backgrounds": ["Backgrounds"],
"creature types": ["CreatureTypes"],
"species": ["Species"],
"classes": ["Classes"]
}Collection types (Backgrounds, Classes, Species) decode via Apple's CodableWithConfiguration protocol, which threads the partially-loaded GameData context through the decoder so nested types (equipment, skills, spells) can resolve cross-references during decoding.
Collections support an optional "display order" key in their JSON. When present, allByDisplayOrder returns elements in that order (with alphabetical fallback for unlisted names). This is exposed through the DisplayOrdered protocol, which Backgrounds, Classes, and Species all conform to.
Each class entry in Classes.json can carry an optional "default background" key. The character builder uses this to pre-select the most thematically appropriate background when a class is chosen.
Named— protocol requiringvar name: String. Adopted byBackgroundTraits,ClassTraits, andSpeciesTraits.DisplayOrdered— protocol for collections that have adisplayOrder: [String]and anall: [Element]array. Provides a defaultallByDisplayOrdercomputed property that sorts by the display order array and falls back alphabetically.Height/Weight— typealiases and string-parsing helpers built onFoundation.Measurement.CharacterNames— loads first and last name lists from JSON for use byNameGenerator.
GameData— the top-level loader. Initialized with a bundle and a manifest filename; loads all content types in dependency order. Content is accessed via properties such asgameData.classes,gameData.backgrounds,gameData.spells.GameDataFiles—Decodablemanifest struct describing which JSON files to load for each content type.GameDataError— typed errors thrown during loading (missing file, decode failure, etc.).
UnitCurrency— aFoundation.Dimensionsubclass that converts between denominations (cp, sp, ep, gp, pp).Money— aFoundation.Measurement<UnitCurrency>with formatting and arithmetic.Currencies— collection loaded from JSON; provides lookup by abbreviation.
Item— base item with name, weight, value, and quantity.Weapon— adds damage roll, properties (finesse, thrown, …), range, and proficiency category.Armor— adds AC formula, weight category, and dexterity modifier rule.Gear/Tool— general equipment variants.EquipmentOptions— a list of item-choice alternatives (e.g. "Option A or Option B"), decoded from nested JSON arrays. Used for class and background starting equipment.InventoryEntry— pairs anItemwith a quantity and equipped flag; used byPlayer.WeaponProficiency— represents a proficiency by category (simple, martial) or specific weapon name.
Player— the main character class. Holds species, class, background, ability scores, skill proficiencies, inventory, prepared spells, and physical appearance.baseHeightis the intrinsic height; the computedheightproperty is the hook for future spell effects (Enlarge/Reduce).sizeis derived fromheightviaCreatureSize. Can compute AC, HP, initiative, ability modifiers, and proficiency bonus.Players— aCodableWithConfigurationcollection ofPlayerinstances.PlayerAppearance— dictionary-backed cosmetic appearance struct (traits: [String: String]). Typed computed properties (hairColor,eyeColor,skinColor,age,birthdate,gender) wrap standard keys. Any additional trait can be stored and retrieved via a subscript keyed byAppearanceTraitKey. TheGenderenum is defined here. Codable via a single-value container that encodes the dictionary directly.AppearanceTraitKey— aHashablestruct wrapping a raw string key. Standard keys are defined as static constants; clients can add domain-specific keys via extension without modifying the library.allStandardKeysenumerates the library-defined keys for use in builder UIs.DescriptiveTraitKey—CaseIterableenum of narrative trait keys:personalityTrait,ideal,bond,flaw, andbackstory. Physical appearance traits are intentionally excluded — those belong toPlayerAppearance.CreatureSize— size category (tiny through gargantuan) derived from aPlayer's height. Provides space, squares occupied, and a random-height range per size.Ability— named ability (Strength, Dexterity, …) with ascoreModifierextension onIntthat computes the standard floor-divided modifier.AbilityScores— a keyed container for the six base scores with roll-4d6-drop-lowest support.CharacterAlignment— ethics × morals enumeration with associated display names.ClassTraits— describes a class: hit dice, primary ability, saving throws, skill and weapon proficiencies, armor training, starting equipment, spellcasting ability and type, spell slots, cantrips/spells known, subclass details, and an optional suggesteddefaultBackground.Classes—CodableWithConfiguration,DisplayOrderedcollection ofClassTraits. Supports an optional shared experience-points table and a"display order"array.SubclassTraits— describes a subclass with its own descriptive traits.SpeciesTraits— describes a species: lifespan, size, speed, darkvision, creature type, traits, and optional subspecies. TheparentNameproperty links subspecies to their parent.Species—CodableWithConfiguration,DisplayOrderedcollection. Custom decoder stitches subspecies into the flatallSpeciesdictionary; encoder writes only root species (with embedded subspecies).BackgroundTraits— describes a background: ability scores, feat, skill proficiencies, tool proficiency, and equipment options.Backgrounds—CodableWithConfiguration,DisplayOrderedcollection ofBackgroundTraits. Supports a"display order"array.Skill/Skills— named skill with associated ability.FeatTraits/Feats— feat with name and optional prerequisites.Spell/Spells— spell with school, level, casting time, range, components, duration, and class lists.UnarmoredDefense— computes AC from a list of ability modifiers (e.g. Barbarian's CON bonus).CreatureType/CreatureTypes— creature type taxonomy (humanoid, beast, …).Initiative— computed initiative value with optional tiebreaker.
CharacterGenerator— generates randomisedPlayerinstances by sampling from the loadedGameData. UsesSwiftDicefor all die rolls.NameGenerator— produces random names by combining first and last names loaded fromCharacterNames.json.
Currently in development as a Swift package that depends on RolePlayingCore:
- Dungeon: Document wrapper for
Mapinstances - DungeonMap:
Map,Room,Door,Hallway, geometry primitives
To learn about the origin of the dice types that power random generation, see the three-part series on Medium:
For background on why Codable was applied across this repository: