Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
191 changes: 103 additions & 88 deletions app/src/androidTest/java/dnd/jon/spellbook/InstrumentTest.java

Large diffs are not rendered by default.

379 changes: 379 additions & 0 deletions app/src/main/assets/2014_to_2024_uuids.java

Large diffs are not rendered by default.

2,856 changes: 1,428 additions & 1,428 deletions app/src/main/assets/Spells_en.json

Large diffs are not rendered by default.

27,811 changes: 27,811 additions & 0 deletions app/src/main/assets/Spells_en_backup.json

Large diffs are not rendered by default.

1,992 changes: 996 additions & 996 deletions app/src/main/assets/Spells_pt.json

Large diffs are not rendered by default.

26,703 changes: 26,703 additions & 0 deletions app/src/main/assets/Spells_pt_backup.json

Large diffs are not rendered by default.

943 changes: 943 additions & 0 deletions app/src/main/assets/Spells_uuid_map.java

Large diffs are not rendered by default.

943 changes: 943 additions & 0 deletions app/src/main/assets/Spells_uuid_map.json

Large diffs are not rendered by default.

22 changes: 13 additions & 9 deletions app/src/main/java/dnd/jon/spellbook/CharacterProfile.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.function.Function;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -265,7 +266,7 @@ private static CharacterProfile fromJSONOld(JSONObject json) throws JSONExceptio
spellStatusNameMap.put(spellName, status);
}
}
final Map<Integer,SpellStatus> spellStatusMap = convertStatusMap(spellStatusNameMap);
final Map<UUID,SpellStatus> spellStatusMap = convertStatusMap(spellStatusNameMap);

// Get the first sort field, if present
final SortField firstSortField = json.has(sort1Key) ? SortField.fromInternalName(json.getString(sort1Key)) : SortField.NAME;
Expand Down Expand Up @@ -333,14 +334,17 @@ private static CharacterProfile fromJSONNew(JSONObject json, Version version) th
// Get the second sort field, if present
final SortField secondSortField = json.has(sort2Key) ? SortField.fromInternalName(json.getString(sort2Key)) : SortField.NAME;

final Map<Integer, SpellStatus> spellStatusMap = new HashMap<>();
final Map<UUID, SpellStatus> spellStatusMap = new HashMap<>();
if (json.has(spellsKey)) {
final JSONArray jsonArray = json.getJSONArray(spellsKey);
for (int i = 0; i < jsonArray.length(); ++i) {
final JSONObject jsonObject = jsonArray.getJSONObject(i);

// Get the name and array of statuses
final Integer spellID = jsonObject.getInt(spellIDKey);
final int maybeIntID = jsonObject.optInt(spellIDKey, -1);
final UUID spellID = (maybeIntID == -1) ?
UUID.fromString(jsonObject.getString(spellIDKey)) :
Spellbook.uuidForID(maybeIntID);

// Load the spell statuses
final boolean fav = jsonObject.getBoolean(favoriteKey);
Expand Down Expand Up @@ -452,7 +456,7 @@ private static CharacterProfile fromJSONPre2_10(JSONObject json) throws JSONExce
spellStatusNameMap.put(spellName, status);
}
}
final Map<Integer,SpellStatus> spellStatusMap = convertStatusMap(spellStatusNameMap);
final Map<UUID,SpellStatus> spellStatusMap = convertStatusMap(spellStatusNameMap);

// Get the first sort field, if present
final SortField firstSortField = json.has(sort1Key) ? SortField.fromInternalName(json.getString(sort1Key)) : SortField.NAME;
Expand Down Expand Up @@ -531,26 +535,26 @@ private static CharacterProfile fromJSONPre2_10(JSONObject json) throws JSONExce
return new CharacterProfile(charName, spellFilterStatus, sortFilterStatus, spellSlotStatus);
}

private static Map<Integer,SpellStatus> convertStatusMap(Map<String,SpellStatus> oldMap) {
final Set<String> scagCantrips = new HashSet<String>() {{
private static Map<UUID,SpellStatus> convertStatusMap(Map<String,SpellStatus> oldMap) {
final Set<String> scagCantrips = new HashSet<>() {{
add("Booming Blade");
add("Green-Flame Blade");
add("Lightning Lure");
add("Sword Burst");
}};
final List<Spell> englishSpells = SpellbookViewModel.allEnglishSpells();
final Map<String,Integer> idMap = new HashMap<>();
final Map<String,UUID> idMap = new HashMap<>();
for (Spell spell : englishSpells) {
idMap.put(spell.getName(), spell.getID());
}
final Map<Integer,SpellStatus> newMap = new HashMap<>();
final Map<UUID,SpellStatus> newMap = new HashMap<>();
for (Map.Entry<String,SpellStatus> entry : oldMap.entrySet()) {
String name = entry.getKey();
final SpellStatus status = entry.getValue();
if (scagCantrips.contains(name)) {
name = name + " (SCAG)";
}
final Integer id = idMap.get(name);
final UUID id = idMap.get(name);
if (id != null) {
newMap.put(id, status);
}
Expand Down
22 changes: 19 additions & 3 deletions app/src/main/java/dnd/jon/spellbook/SortFilterStatus.java
Original file line number Diff line number Diff line change
Expand Up @@ -665,10 +665,24 @@ private <T extends QuantityType> void setExtremeUnit(Class<T> type, Unit unit, C
static SortFilterStatus fromJSON(JSONObject json) throws JSONException {
final SortFilterStatus status = new SortFilterStatus();

status.setStatusFilterField(json.has(statusFilterKey) ? StatusFilterField.fromDisplayName(json.getString(statusFilterKey)) : StatusFilterField.ALL);
StatusFilterField statusFilterField = null;
if (json.has(statusFilterKey)) {
statusFilterField = StatusFilterField.fromDisplayName(json.getString(statusFilterKey));
}
status.setStatusFilterField(SpellbookUtils.coalesce(statusFilterField, StatusFilterField.ALL));

SortField firstSortField = null;
if (json.has(sort1Key)) {
firstSortField = SortField.fromInternalName(json.getString(sort1Key));
}
status.setFirstSortField(SpellbookUtils.coalesce(firstSortField, SortField.NAME));

SortField secondSortField = null;
if (json.has(sort2Key)) {
secondSortField = SortField.fromInternalName(json.getString(sort2Key));
}
status.setSecondSortField(SpellbookUtils.coalesce(secondSortField, SortField.NAME));

status.setFirstSortField(json.has(sort1Key) ? SortField.fromInternalName(json.getString(sort1Key)) : SortField.NAME);
status.setSecondSortField(json.has(sort2Key) ? SortField.fromInternalName(json.getString(sort2Key)) : SortField.NAME);
status.setFirstSortReverse(json.optBoolean(reverse1Key));
status.setSecondSortReverse(json.optBoolean(reverse2Key));

Expand Down Expand Up @@ -723,6 +737,8 @@ static SortFilterStatus fromJSON(JSONObject json) throws JSONException {
public JSONObject toJSON() throws JSONException {
final JSONObject json = new JSONObject();

json.put(statusFilterKey, statusFilterField);

json.put(sort1Key, firstSortField.getInternalName());
json.put(sort2Key, secondSortField.getInternalName());
json.put(reverse1Key, firstSortReverse);
Expand Down
17 changes: 9 additions & 8 deletions app/src/main/java/dnd/jon/spellbook/Spell.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.UUID;

public class Spell implements Parcelable {

// Member values
private final int id;
private final UUID id;
private final String name;
private final String description;
private final String higherLevel;
Expand All @@ -38,7 +39,7 @@ public class Spell implements Parcelable {

// Getters
// No setters - once created, spells are immutable
public final int getID() { return id; }
public final UUID getID() { return id; }
public final String getName() { return name; }
public final String getDescription() { return description; }
public final String getHigherLevel() { return higherLevel; }
Expand Down Expand Up @@ -115,7 +116,7 @@ public int describeContents() {
// Write a spell to a parcel
@Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeInt(id);
parcel.writeSerializable(id);
parcel.writeString(name);
parcel.writeString(description);
parcel.writeString(higherLevel);
Expand Down Expand Up @@ -166,7 +167,7 @@ public void writeToParcel(Parcel parcel, int i) {

// Create a spell from a Parcel
protected Spell(Parcel in) {
id = in.readInt();
id = (UUID) in.readSerializable();
name = in.readString();
description = in.readString();
higherLevel = in.readString();
Expand Down Expand Up @@ -213,7 +214,7 @@ protected Spell(Parcel in) {

}

Spell(int idIn, String nameIn, String descriptionIn, String higherLevelIn, Range rangeIn, boolean[] componentsIn, String materialIn, String royaltyIn,
Spell(UUID idIn, String nameIn, String descriptionIn, String higherLevelIn, Range rangeIn, boolean[] componentsIn, String materialIn, String royaltyIn,
boolean ritualIn, Duration durationIn, boolean concentrationIn, CastingTime castingTimeIn,
int levelIn, School schoolIn, SortedSet<CasterClass> classesIn, SortedSet<Subclass> subclassesIn,
SortedSet<CasterClass> tashasExpandedClassesIn, Map<Source,Integer> locationsIn, Ruleset rulesetIn) {
Expand All @@ -239,10 +240,10 @@ protected Spell(Parcel in) {
}

protected Spell() {
this(0, "", "", "", new Range(), new boolean[]{false, false, false, false}, "", "", false, new Duration(), false, new CastingTime(), 0, School.ABJURATION, new TreeSet<>(), new TreeSet<>(), new TreeSet<>(), new HashMap<>(), RULES_2014);
this(UUID.randomUUID(), "", "", "", new Range(), new boolean[]{false, false, false, false}, "", "", false, new Duration(), false, new CastingTime(), 0, School.ABJURATION, new TreeSet<>(), new TreeSet<>(), new TreeSet<>(), new HashMap<>(), RULES_2014);
}

Spell clone(int newID) {
Spell clone(UUID newID) {
return new Spell(
newID, name, description, higherLevel, range, components,
material, royalty, ritual, duration, concentration,
Expand All @@ -254,7 +255,7 @@ Spell clone(int newID) {
@Override
public boolean equals(Object other) {
if (!(other instanceof Spell otherSpell)) { return false; }
return id == otherSpell.getID();
return id.equals(otherSpell.getID());
}

@Override
Expand Down
7 changes: 4 additions & 3 deletions app/src/main/java/dnd/jon/spellbook/SpellBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.UUID;

class SpellBuilder {

Expand Down Expand Up @@ -37,7 +38,7 @@ class SpellBuilder {
private final Collator collator;

// Member values for spell-building
private int id;
private UUID id;
private String name;
private String description;
private String higherLevel;
Expand All @@ -58,7 +59,7 @@ class SpellBuilder {
private Ruleset ruleset;

// Setters
SpellBuilder setID(int idIn) { id = idIn; return this; }
SpellBuilder setID(UUID idIn) { id = idIn; return this; }
SpellBuilder setName(String nameIn) {name = nameIn; return this;}
SpellBuilder setDescription(String descriptionIn) {description = descriptionIn; return this;}
SpellBuilder setHigherLevelDesc(String higherLevelIn) {higherLevel = higherLevelIn; return this;}
Expand Down Expand Up @@ -88,7 +89,7 @@ Spell build() {
}

void reset() {
id = 0;
id = UUID.randomUUID();
name = "";
description = "";
higherLevel = "";
Expand Down
40 changes: 37 additions & 3 deletions app/src/main/java/dnd/jon/spellbook/SpellCodec.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package dnd.jon.spellbook;

import android.content.Context;
import android.util.Log;

import androidx.annotation.Nullable;

Expand All @@ -12,6 +13,7 @@
import java.util.ArrayList;
import java.util.Locale;
import java.util.Map;
import java.util.UUID;
import java.util.function.Function;

class SpellCodec {
Expand All @@ -38,6 +40,8 @@ class SpellCodec {
private static final String LOCATIONS_KEY = "locations";
private static final String RULESET_KEY = "ruleset";

private static final String SPELL_CODEC_TAG = "SPELL_CODEC";

private static final String[] COMPONENT_STRINGS = { "V", "S", "M", "R" };

// TODO: Is there a better way to do this?
Expand Down Expand Up @@ -79,8 +83,7 @@ Spell parseSpell(JSONObject json, SpellBuilder b, boolean useInternal) throws JS
final Function<String, Subclass> subclassGetter = Subclass::fromDisplayName;

// Set the values that need no/trivial parsing
b.setID(json.getInt(ID_KEY))
.setName(json.getString(NAME_KEY))
b.setName(json.getString(NAME_KEY))
.setRange(rangeGetter.apply(json.getString(RANGE_KEY)))
.setRitual(json.optBoolean(RITUAL_KEY, false))
.setLevel(json.getInt(LEVEL_KEY))
Expand All @@ -90,6 +93,37 @@ Spell parseSpell(JSONObject json, SpellBuilder b, boolean useInternal) throws JS
.setHigherLevelDesc(json.optString(HIGHER_LEVEL_KEY, ""))
.setSchool(schoolGetter.apply(json.getString(SCHOOL_KEY)));


// Previously spells had integer IDs
// If we run into a spell serialized like this, we need to handle that case
// So the logic here is:
// - If there's an integer ID, try to look up the corresponding UUID
// - Otherwise, if the string value exists, use that
// - In either case, if this fails, use a random UUID

UUID spellID = null;
final int maybeIntID = json.optInt(ID_KEY, -1);
if (maybeIntID == -1) {
try {
final String maybeStringUUID = json.getString(ID_KEY);
spellID = UUID.fromString(maybeStringUUID);
} catch (IllegalArgumentException e) {
Log.e(SPELL_CODEC_TAG, "Invalid UUID string");
}
} else {
final UUID maybeID = Spellbook.uuidForID(maybeIntID);
if (maybeID != null) {
spellID = maybeID;
} else {
spellID = UUID.randomUUID();
Spellbook.setUUIDForInt(maybeIntID, spellID);
}
}
if (spellID == null) {
spellID = UUID.randomUUID();
}
b.setID(spellID);

// Locations
final JSONArray locationsArray = json.getJSONArray(LOCATIONS_KEY);
for (int i = 0; i < locationsArray.length(); i++) {
Expand Down Expand Up @@ -211,7 +245,7 @@ JSONObject toJSON(Spell spell, Context context) throws JSONException {

final JSONObject json = new JSONObject();

json.put(ID_KEY, spell.getID());
json.put(ID_KEY, spell.getID().toString());
json.put(NAME_KEY, spell.getName());
json.put(DESCRIPTION_KEY, spell.getDescription());
json.put(HIGHER_LEVEL_KEY, spell.getHigherLevel());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.UUID;
import java.util.function.Function;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -389,7 +390,7 @@ void createOrUpdateSpell() {

// Once we've passed all of the checks, create the spell
final SpellBuilder spellBuilder = new SpellBuilder(activity);
final int id = spell != null ? spell.getID() : viewModel.newSpellID();
final UUID id = spell != null ? spell.getID() : viewModel.newSpellID();
spellBuilder
.setID(id)
.setName(name)
Expand Down
5 changes: 3 additions & 2 deletions app/src/main/java/dnd/jon/spellbook/SpellFilter.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import java.util.List;
import java.util.ArrayList;
import java.util.Set;
import java.util.UUID;
import java.util.function.BiFunction;
import java.util.function.Function;

Expand Down Expand Up @@ -178,7 +179,7 @@ protected FilterResults performFiltering(CharSequence constraint) {

synchronized (sharedLock) {

final Set<Integer> keptIDs = new HashSet<>();
final Set<UUID> keptIDs = new HashSet<>();

// Filter the list of spells
final String searchText = (constraint != null) ? constraint.toString() : "";
Expand Down Expand Up @@ -220,7 +221,7 @@ protected FilterResults performFiltering(CharSequence constraint) {
if (spell.getRuleset() != rulesetToIgnore) {
return false;
}
final Integer linkedID = Spellbook.linkedSpellID(spell);
final UUID linkedID = Spellbook.linkedSpellID(spell);
return linkedID != null && keptIDs.contains(linkedID);
});
}
Expand Down
Loading
Loading