diff --git a/src/main/java/betterquesting/api2/storage/AbstractDatabase.java b/src/main/java/betterquesting/api2/storage/AbstractDatabase.java new file mode 100644 index 000000000..b414e9e62 --- /dev/null +++ b/src/main/java/betterquesting/api2/storage/AbstractDatabase.java @@ -0,0 +1,127 @@ +package betterquesting.api2.storage; + +import java.util.Collections; +import java.util.List; +import java.util.TreeMap; + +public abstract class AbstractDatabase implements IDatabase { + + /** + * If the cache size would somehow exceed 24MB (on 64bit machines) we stop. + */ + public static int CACHE_MAX_SIZE = 24 * 1024 * 1024 / 8; + + /** + * If {@code mapDB.size < SPARSE_RATIO * (mapDB.lastKey() - mapDB.firstKey())} the database will be considered + * sparse and an cache array won't be built to save memory. + *

+ * Under this sparsity a 10k element database will roughly result in a 0.5MB cache which is more than enough reasonable. + */ + public static double SPARSE_RATIO = 0.15d; + + final TreeMap mapDB = new TreeMap<>(); + + private LookupLogicType type = null; + private LookupLogic logic = null; + + private LookupLogic getLookupLogic() { + if (type != null) + return logic; + LookupLogicType newType = LookupLogicType.determine(this); + type = newType; + logic = newType.get(this); + return logic; + } + + private void updateLookupLogic() { + if (type == null) + return; + LookupLogicType newType = LookupLogicType.determine(this); + if (newType != type) { + type = null; + logic = null; + } else { + logic.onDataChange(); + } + } + + @Override + public synchronized DBEntry add(int id, T value) { + if (value == null) { + throw new NullPointerException("Value cannot be null"); + } else if (id < 0) { + throw new IllegalArgumentException("ID cannot be negative"); + } else { + if (mapDB.putIfAbsent(id, value) == null) { + updateLookupLogic(); + return new DBEntry<>(id, value); + } else { + throw new IllegalArgumentException("ID or value is already contained within database"); + } + } + } + + @Override + public synchronized boolean removeID(int key) { + if (key < 0) + return false; + + if (mapDB.remove(key) != null) { + updateLookupLogic(); + return true; + } + return false; + } + + @Override + public synchronized boolean removeValue(T value) { + return value != null && removeID(getID(value)); + } + + @Override + public synchronized int getID(T value) { + if (value == null) + return -1; + + for (DBEntry entry : getEntries()) { + if (entry.getValue() == value) + return entry.getID(); + } + + return -1; + } + + @Override + public synchronized T getValue(int id) { + if (id < 0 || mapDB.size() <= 0) + return null; + return mapDB.get(id); + } + + @Override + public synchronized int size() { + return mapDB.size(); + } + + @Override + public synchronized void reset() { + mapDB.clear(); + type = null; + logic = null; + } + + @Override + public synchronized List> getEntries() { + return mapDB.isEmpty() ? Collections.emptyList() : getLookupLogic().getRefCache(); + } + + /** + * First try to use array cache. + * If memory usage would be too high try use sort merge join if keys is large. + * Otherwise look up each key separately via {@link TreeMap#get(Object)}. + */ + @Override + public synchronized List> bulkLookup(int... keys) { + return mapDB.isEmpty() || keys.length == 0 ? Collections.emptyList() : getLookupLogic().bulkLookup(keys); + } +} diff --git a/src/main/java/betterquesting/api2/storage/ArrayCacheLookupLogic.java b/src/main/java/betterquesting/api2/storage/ArrayCacheLookupLogic.java index 7fc2a7886..04ed51ec2 100644 --- a/src/main/java/betterquesting/api2/storage/ArrayCacheLookupLogic.java +++ b/src/main/java/betterquesting/api2/storage/ArrayCacheLookupLogic.java @@ -8,8 +8,8 @@ class ArrayCacheLookupLogic extends LookupLogic { private DBEntry[] cache = null; private int offset = -1; - public ArrayCacheLookupLogic(SimpleDatabase simpleDatabase) { - super(simpleDatabase); + public ArrayCacheLookupLogic(AbstractDatabase abstractDatabase) { + super(abstractDatabase); } @Override @@ -21,7 +21,8 @@ public void onDataChange() { @Override public List> getRefCache() { - if (refCache != null) return refCache; + if (refCache != null) + return refCache; if (cache == null) { return super.getRefCache(); } else { @@ -35,7 +36,8 @@ public List> bulkLookup(int[] keys) { computeCache(); List> list = new ArrayList<>(keys.length); for (int k : keys) { - if (k - offset >= cache.length) continue; + if (k - offset >= cache.length) + continue; final DBEntry element = cache[k - offset]; if (element != null) { // it shouldn't place too much allocation/gc pressure since there aren't too many keys to look up anyway @@ -47,11 +49,12 @@ public List> bulkLookup(int[] keys) { @SuppressWarnings("unchecked") private void computeCache() { - if (cache != null) return; - cache = new DBEntry[simpleDatabase.mapDB.lastKey() - simpleDatabase.mapDB.firstKey() + 1]; - offset = simpleDatabase.mapDB.firstKey(); + if (cache != null) + return; + cache = new DBEntry[abstractDatabase.mapDB.lastKey() - abstractDatabase.mapDB.firstKey() + 1]; + offset = abstractDatabase.mapDB.firstKey(); if (refCache == null) { - for (Map.Entry entry : simpleDatabase.mapDB.entrySet()) { + for (Map.Entry entry : abstractDatabase.mapDB.entrySet()) { cache[entry.getKey() - offset] = new DBEntry<>(entry.getKey(), entry.getValue()); } } else { diff --git a/src/main/java/betterquesting/api2/storage/EmptyLookupLogic.java b/src/main/java/betterquesting/api2/storage/EmptyLookupLogic.java index f52d98582..e816f3264 100644 --- a/src/main/java/betterquesting/api2/storage/EmptyLookupLogic.java +++ b/src/main/java/betterquesting/api2/storage/EmptyLookupLogic.java @@ -5,8 +5,8 @@ public class EmptyLookupLogic extends LookupLogic { - public EmptyLookupLogic(SimpleDatabase simpleDatabase) { - super(simpleDatabase); + public EmptyLookupLogic(AbstractDatabase abstractDatabase) { + super(abstractDatabase); } @Override diff --git a/src/main/java/betterquesting/api2/storage/LookupLogic.java b/src/main/java/betterquesting/api2/storage/LookupLogic.java index 695959f4c..e1beede44 100644 --- a/src/main/java/betterquesting/api2/storage/LookupLogic.java +++ b/src/main/java/betterquesting/api2/storage/LookupLogic.java @@ -7,11 +7,11 @@ abstract class LookupLogic { - protected final SimpleDatabase simpleDatabase; + protected final AbstractDatabase abstractDatabase; protected List> refCache = null; - public LookupLogic(SimpleDatabase simpleDatabase) { - this.simpleDatabase = simpleDatabase; + public LookupLogic(AbstractDatabase abstractDatabase) { + this.abstractDatabase = abstractDatabase; } public void onDataChange() { @@ -19,7 +19,8 @@ public void onDataChange() { } public List> getRefCache() { - if (refCache != null) return refCache; + if (refCache != null) + return refCache; computeRefCache(); return refCache; } @@ -28,7 +29,7 @@ public List> getRefCache() { protected void computeRefCache() { List> temp = new ArrayList<>(); - for (Map.Entry entry : simpleDatabase.mapDB.entrySet()) { + for (Map.Entry entry : abstractDatabase.mapDB.entrySet()) { temp.add(new DBEntry<>(entry.getKey(), entry.getValue())); } refCache = Collections.unmodifiableList(temp); diff --git a/src/main/java/betterquesting/api2/storage/LookupLogicType.java b/src/main/java/betterquesting/api2/storage/LookupLogicType.java index 034c16ed6..1c91e6fe1 100644 --- a/src/main/java/betterquesting/api2/storage/LookupLogicType.java +++ b/src/main/java/betterquesting/api2/storage/LookupLogicType.java @@ -11,15 +11,15 @@ enum LookupLogicType { Empty(db -> db.mapDB.isEmpty(), EmptyLookupLogic::new), ArrayCache(db -> db.mapDB.size() < CACHE_MAX_SIZE && db.mapDB.size() > SPARSE_RATIO * (db.mapDB.lastKey() - db.mapDB.firstKey()), ArrayCacheLookupLogic::new), Naive(db -> true, NaiveLookupLogic::new); - private final Predicate> shouldUse; - private final Function, LookupLogic> factory; + private final Predicate> shouldUse; + private final Function, LookupLogic> factory; - LookupLogicType(Predicate> shouldUse, Function, LookupLogic> factory) { + LookupLogicType(Predicate> shouldUse, Function, LookupLogic> factory) { this.shouldUse = shouldUse; this.factory = factory; } - static LookupLogicType determine(SimpleDatabase db) { + static LookupLogicType determine(AbstractDatabase db) { for (LookupLogicType type : values()) { if (type.shouldUse.test(db)) return type; @@ -28,7 +28,7 @@ static LookupLogicType determine(SimpleDatabase db) { } @SuppressWarnings("unchecked") - LookupLogic get(SimpleDatabase db) { + LookupLogic get(AbstractDatabase db) { return (LookupLogic) factory.apply(db); } } diff --git a/src/main/java/betterquesting/api2/storage/NaiveLookupLogic.java b/src/main/java/betterquesting/api2/storage/NaiveLookupLogic.java index 1d889d64e..1d5c101f0 100644 --- a/src/main/java/betterquesting/api2/storage/NaiveLookupLogic.java +++ b/src/main/java/betterquesting/api2/storage/NaiveLookupLogic.java @@ -10,8 +10,8 @@ class NaiveLookupLogic extends LookupLogic { private TIntObjectMap> backingMap; - public NaiveLookupLogic(SimpleDatabase simpleDatabase) { - super(simpleDatabase); + public NaiveLookupLogic(AbstractDatabase abstractDatabase) { + super(abstractDatabase); } @Override @@ -23,7 +23,7 @@ public void onDataChange() { @Override public List> bulkLookup(int[] keys) { if (backingMap == null) { - backingMap = new TIntObjectHashMap<>(simpleDatabase.mapDB.size()); + backingMap = new TIntObjectHashMap<>(abstractDatabase.mapDB.size()); for (DBEntry entry : getRefCache()) { backingMap.put(entry.getID(), entry); } diff --git a/src/main/java/betterquesting/api2/storage/RandomIndexDatabase.java b/src/main/java/betterquesting/api2/storage/RandomIndexDatabase.java new file mode 100644 index 000000000..c493486c1 --- /dev/null +++ b/src/main/java/betterquesting/api2/storage/RandomIndexDatabase.java @@ -0,0 +1,22 @@ +package betterquesting.api2.storage; + +import java.util.Random; + +public class RandomIndexDatabase extends AbstractDatabase { + + private final Random random = new Random(); + + @Override + public synchronized int nextID() { + int id; + do { + // id >= 0 + id = random.nextInt() & 0x7fff_ffff; + } + // The new id doesn't conflict with existing ones. + // However, new ids created by different players could conflict with each other. + while (mapDB.containsKey(id)); + return id; + } + +} diff --git a/src/main/java/betterquesting/api2/storage/SimpleDatabase.java b/src/main/java/betterquesting/api2/storage/SimpleDatabase.java index fd2e9c7f2..ff177a864 100644 --- a/src/main/java/betterquesting/api2/storage/SimpleDatabase.java +++ b/src/main/java/betterquesting/api2/storage/SimpleDatabase.java @@ -5,45 +5,9 @@ import java.util.List; import java.util.TreeMap; -public class SimpleDatabase implements IDatabase { - - /** - * If the cache size would somehow exceed 24MB (on 64bit machines) we stop. - */ - public static int CACHE_MAX_SIZE = 24 * 1024 * 1024 / 8; - - /** - * If {@code mapDB.size < SPARSE_RATIO * (mapDB.lastKey() - mapDB.firstKey())} the database will be considered - * sparse and an cache array won't be built to save memory. - *

- * Under this sparsity a 10k element database will roughly result in a 0.5MB cache which is more than enough reasonable. - */ - public static double SPARSE_RATIO = 0.15d; - - final TreeMap mapDB = new TreeMap<>(); +public class SimpleDatabase extends AbstractDatabase { private final BitSet idMap = new BitSet(); - private LookupLogicType type = null; - private LookupLogic logic = null; - - private LookupLogic getLookupLogic() { - if (type != null) return logic; - LookupLogicType newType = LookupLogicType.determine(this); - type = newType; - logic = newType.get(this); - return logic; - } - - private void updateLookupLogic() { - if (type == null) return; - LookupLogicType newType = LookupLogicType.determine(this); - if (newType != type) { - type = null; - logic = null; - } else { - logic.onDataChange(); - } - } @Override public synchronized int nextID() { @@ -52,80 +16,24 @@ public synchronized int nextID() { @Override public synchronized DBEntry add(int id, T value) { - if (value == null) { - throw new NullPointerException("Value cannot be null"); - } else if (id < 0) { - throw new IllegalArgumentException("ID cannot be negative"); - } else { - if (mapDB.putIfAbsent(id, value) == null) { - idMap.set(id); - updateLookupLogic(); - return new DBEntry<>(id, value); - } else { - throw new IllegalArgumentException("ID or value is already contained within database"); - } - } + DBEntry result = super.add(id, value); + // Don't add when an exception is thrown + idMap.set(id); + return result; } @Override public synchronized boolean removeID(int key) { - if (key < 0) return false; - - if (mapDB.remove(key) != null) { + boolean result = super.removeID(key); + if (result) idMap.clear(key); - updateLookupLogic(); - return true; - } - return false; - } - - @Override - public synchronized boolean removeValue(T value) { - return value != null && removeID(getID(value)); - } - - @Override - public synchronized int getID(T value) { - if (value == null) return -1; - - for (DBEntry entry : getEntries()) { - if (entry.getValue() == value) return entry.getID(); - } - - return -1; - } - - @Override - public synchronized T getValue(int id) { - if (id < 0 || mapDB.size() <= 0) return null; - return mapDB.get(id); - } - - @Override - public synchronized int size() { - return mapDB.size(); + return result; } @Override public synchronized void reset() { - mapDB.clear(); + super.reset(); idMap.clear(); - type = null; - logic = null; - } - - @Override - public synchronized List> getEntries() { - return mapDB.isEmpty() ? Collections.emptyList() : getLookupLogic().getRefCache(); } - /** - * First try to use array cache. - * If memory usage would be too high try use sort merge join if keys is large. - * Otherwise look up each key separately via {@link TreeMap#get(Object)}. - */ - @Override - public synchronized List> bulkLookup(int... keys) { - return mapDB.isEmpty() || keys.length == 0 ? Collections.emptyList() : getLookupLogic().bulkLookup(keys); - } } diff --git a/src/main/java/betterquesting/client/toolbox/tools/ToolboxToolCopy.java b/src/main/java/betterquesting/client/toolbox/tools/ToolboxToolCopy.java index 556945938..5130a245f 100644 --- a/src/main/java/betterquesting/client/toolbox/tools/ToolboxToolCopy.java +++ b/src/main/java/betterquesting/client/toolbox/tools/ToolboxToolCopy.java @@ -177,25 +177,10 @@ public boolean onMouseClick(int mx, int my, int click) { } private int[] getNextIDs(int num) { - List> listDB = QuestDatabase.INSTANCE.getEntries(); int[] nxtIDs = new int[num]; - - if (listDB.size() <= 0 || listDB.get(listDB.size() - 1).getID() == listDB.size() - 1) { - for (int i = 0; i < num; i++) nxtIDs[i] = listDB.size() + i; - return nxtIDs; - } - - int n1 = 0; - int n2 = 0; for (int i = 0; i < num; i++) { - while (n2 < listDB.size() && listDB.get(n2).getID() == n1) { - n1++; - n2++; - } - - nxtIDs[i] = n1++; + nxtIDs[i] = QuestDatabase.INSTANCE.nextID(); } - return nxtIDs; } diff --git a/src/main/java/betterquesting/importers/ftbq/FTBQQuestImporter.java b/src/main/java/betterquesting/importers/ftbq/FTBQQuestImporter.java index 2ab692aa6..b8f76f030 100644 --- a/src/main/java/betterquesting/importers/ftbq/FTBQQuestImporter.java +++ b/src/main/java/betterquesting/importers/ftbq/FTBQQuestImporter.java @@ -165,7 +165,14 @@ private void startImport(IQuestDatabase questDB, IQuestLineDatabase lineDB, NBTT // === QUEST DATA === String hexID = questFile.getName().substring(0, questFile.getName().length() - (isSnbt ? ".snbt".length() : ".nbt".length())); - int questID = questDB.nextID(); + int questID; + try { + questID = Integer.parseInt(hexID, 16) & 0x7fff_ffff; + if (lineDB.getValue(questID) != null) + questID = questDB.nextID(); + } catch (Exception e) { + questID = questDB.nextID(); + } IQuest quest = questDB.createNew(questID); IQuestLineEntry qle = questLine.createNew(questID); ID_MAP.put(hexID, new FTBEntry(questID, quest, FTBEntryType.QUEST)); // Add this to the weird ass ID mapping @@ -253,21 +260,21 @@ private void startImport(IQuestDatabase questDB, IQuestLineDatabase lineDB, NBTT } if (qTag.hasKey("dependency_requirement")) { - switch (qTag.getString("dependency_requirement")){ - case "all_completed":{ + switch (qTag.getString("dependency_requirement")) { + case "all_completed": { quest.setProperty(NativeProps.LOGIC_QUEST, EnumLogic.AND); break; } - case "one_completed":{ + case "one_completed": { quest.setProperty(NativeProps.LOGIC_QUEST, EnumLogic.OR); break; } // BetterQuesting has no "started" options. - case "all_started":{ + case "all_started": { quest.setProperty(NativeProps.LOGIC_QUEST, EnumLogic.AND); break; } - case "one_started":{ + case "one_started": { quest.setProperty(NativeProps.LOGIC_QUEST, EnumLogic.OR); break; } diff --git a/src/main/java/betterquesting/importers/hqm/HQMQuestImporter.java b/src/main/java/betterquesting/importers/hqm/HQMQuestImporter.java index 7303ed903..5d6ff5b3d 100644 --- a/src/main/java/betterquesting/importers/hqm/HQMQuestImporter.java +++ b/src/main/java/betterquesting/importers/hqm/HQMQuestImporter.java @@ -19,6 +19,7 @@ import betterquesting.importers.hqm.converters.rewards.HQMRewardStandard; import betterquesting.importers.hqm.converters.tasks.*; import com.google.gson.*; +import java.util.UUID; import net.minecraft.init.Items; import net.minecraft.nbt.NBTTagList; import org.apache.logging.log4j.Level; @@ -122,41 +123,53 @@ private static JsonArray ReadArrayFromFile(File file) { } private void LoadReputations(JsonArray jsonRoot) { - if (jsonRoot == null || jsonRoot.size() <= 0) return; + if (jsonRoot == null || jsonRoot.size() <= 0) + return; int i = -1; for (JsonElement e : jsonRoot) { - if (!(e instanceof JsonObject)) continue; + if (!(e instanceof JsonObject)) + continue; JsonObject jRep = e.getAsJsonObject(); String repName = "Reputation(" + i + ")"; - if (jRep.has("Name")) repName = JsonHelper.GetString(jRep, "Name", repName); - if (jRep.has("name")) repName = JsonHelper.GetString(jRep, "name", repName); + if (jRep.has("Name")) + repName = JsonHelper.GetString(jRep, "Name", repName); + if (jRep.has("name")) + repName = JsonHelper.GetString(jRep, "name", repName); String repId = "" + (++i); - if (jRep.has("Id")) repId = JsonHelper.GetNumber(jRep, "Id", i).toString(); - if (jRep.has("id")) repId = JsonHelper.GetString(jRep, "id", repId); + if (jRep.has("Id")) + repId = JsonHelper.GetNumber(jRep, "Id", i).toString(); + if (jRep.has("id")) + repId = JsonHelper.GetString(jRep, "id", repId); HQMRep repObj = new HQMRep(repName); JsonArray mrkAry = null; - if (jRep.has("Markers")) mrkAry = JsonHelper.GetArray(jRep, "Markers"); - if (mrkAry == null) mrkAry = JsonHelper.GetArray(jRep, "markers"); + if (jRep.has("Markers")) + mrkAry = JsonHelper.GetArray(jRep, "Markers"); + if (mrkAry == null) + mrkAry = JsonHelper.GetArray(jRep, "markers"); for (int m = 0; m < mrkAry.size(); m++) { JsonElement e2 = mrkAry.get(m); - if (!(e2 instanceof JsonObject)) continue; + if (!(e2 instanceof JsonObject)) + continue; JsonObject jMark = e2.getAsJsonObject(); int mId = m; - if (jMark.has("Id")) mId = JsonHelper.GetNumber(jMark, "Id", mId).intValue(); + if (jMark.has("Id")) + mId = JsonHelper.GetNumber(jMark, "Id", mId).intValue(); int mVal = 0; - if (jMark.has("Value")) mVal = JsonHelper.GetNumber(jMark, "Value", mVal).intValue(); - if (jMark.has("value")) mVal = JsonHelper.GetNumber(jMark, "value", mVal).intValue(); + if (jMark.has("Value")) + mVal = JsonHelper.GetNumber(jMark, "Value", mVal).intValue(); + if (jMark.has("value")) + mVal = JsonHelper.GetNumber(jMark, "value", mVal).intValue(); repObj.addMarker(mId, mVal); } @@ -169,7 +182,15 @@ private IQuest GetNewQuest(String oldID, IQuestDatabase qdb) { if (idMap.containsKey(oldID)) { return idMap.get(oldID); } else { - IQuest quest = qdb.createNew(qdb.nextID()); + int newID; + try { + newID = (int) (UUID.fromString(oldID).getMostSignificantBits() & 0x7fff_ffff); + if (qdb.getValue(newID) != null) + newID = qdb.nextID(); + } catch (Exception e) { + newID = qdb.nextID(); + } + IQuest quest = qdb.createNew(newID); idMap.put(oldID, quest); return quest; } @@ -286,7 +307,9 @@ private void ImportQuestLine(IQuestDatabase questDB, IQuestLineDatabase lineDB, if (tsks != null && tsks.length > 0) { IDatabaseNBT taskReg = quest.getTasks(); - for (ITask t : tsks) taskReg.add(taskReg.nextID(), t); + for (ITask t : tsks) { + taskReg.add(taskReg.nextID(), t); + } } } @@ -321,12 +344,16 @@ private void ImportQuestLine(IQuestDatabase questDB, IQuestLineDatabase lineDB, } private boolean containsReq(IQuest quest, int id) { - for (int reqID : quest.getRequirements()) if (id == reqID) return true; + for (int reqID : quest.getRequirements()) { + if (id == reqID) + return true; + } return false; } private void addReq(IQuest quest, int id) { - if (containsReq(quest, id)) return; + if (containsReq(quest, id)) + return; int[] orig = quest.getRequirements(); int[] added = Arrays.copyOf(orig, orig.length + 1); added[orig.length] = id; diff --git a/src/main/java/betterquesting/questing/QuestDatabase.java b/src/main/java/betterquesting/questing/QuestDatabase.java index 37377d96a..2b010a50d 100644 --- a/src/main/java/betterquesting/questing/QuestDatabase.java +++ b/src/main/java/betterquesting/questing/QuestDatabase.java @@ -3,7 +3,7 @@ import betterquesting.api.questing.IQuest; import betterquesting.api.questing.IQuestDatabase; import betterquesting.api2.storage.DBEntry; -import betterquesting.api2.storage.SimpleDatabase; +import betterquesting.api2.storage.RandomIndexDatabase; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; @@ -11,55 +11,68 @@ import java.util.List; import java.util.UUID; -public final class QuestDatabase extends SimpleDatabase implements IQuestDatabase { +public final class QuestDatabase extends RandomIndexDatabase implements IQuestDatabase { public static final QuestDatabase INSTANCE = new QuestDatabase(); @Override public synchronized IQuest createNew(int id) { IQuest quest = new QuestInstance(); - if (id >= 0) this.add(id, quest); + if (id >= 0) + this.add(id, quest); return quest; } @Override public synchronized boolean removeID(int id) { boolean success = super.removeID(id); - if (success) for (DBEntry entry : getEntries()) removeReq(entry.getValue(), id); + if (success) + for (DBEntry entry : getEntries()) { + removeReq(entry.getValue(), id); + } return success; } @Override public synchronized boolean removeValue(IQuest value) { int id = this.getID(value); - if (id < 0) return false; + if (id < 0) + return false; boolean success = this.removeValue(value); - if (success) for (DBEntry entry : getEntries()) removeReq(entry.getValue(), id); + if (success) + for (DBEntry entry : getEntries()) { + removeReq(entry.getValue(), id); + } return success; } private void removeReq(IQuest quest, int id) { int[] orig = quest.getRequirements(); - if (orig.length <= 0) return; + if (orig.length <= 0) + return; boolean hasRemoved = false; int[] rem = new int[orig.length - 1]; for (int i = 0; i < orig.length; i++) { if (!hasRemoved && orig[i] == id) { hasRemoved = true; continue; - } else if (!hasRemoved && i >= rem.length) break; + } else if (!hasRemoved && i >= rem.length) + break; rem[!hasRemoved ? i : (i - 1)] = orig[i]; } - if (hasRemoved) quest.setRequirements(rem); + if (hasRemoved) + quest.setRequirements(rem); } @Override public synchronized NBTTagList writeToNBT(NBTTagList json, @Nullable List subset) { for (DBEntry entry : this.getEntries()) { - if (subset != null && !subset.contains(entry.getID())) continue; + if (subset != null && !subset.contains(entry.getID())) + continue; NBTTagCompound jq = entry.getValue().writeToNBT(new NBTTagCompound()); - if (subset != null && jq.isEmpty()) continue; + if (subset != null && jq.isEmpty()) + continue; jq.setInteger("questID", entry.getID()); json.appendTag(jq); } @@ -69,16 +82,19 @@ public synchronized NBTTagList writeToNBT(NBTTagList json, @Nullable List