From 2f81b826524599859ce4c8bf6164bab83debf662 Mon Sep 17 00:00:00 2001 From: Ben Culkin Date: Thu, 2 Jul 2020 16:01:39 -0400 Subject: Implement affix grouping by contents Implements a basic way to 'group' affixes together. An affix group is a collection of affixes which generally provide the same benefits, but at varying levels. For example, '+2 strength' and '+4 strength' would be considered grouped affixes, assuming that they were spawning on the same items and such --- src/main/java/tlIItools/Affix.java | 57 ++++++++++++++++++++-- src/main/java/tlIItools/AffixLister.java | 19 +++++--- src/main/java/tlIItools/AffixSet.java | 41 +++++++++++++--- src/main/java/tlIItools/Effect.java | 82 ++++++++++++++++++++++++++++++-- 4 files changed, 177 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/main/java/tlIItools/Affix.java b/src/main/java/tlIItools/Affix.java index 7afb32b6..ffec66d9 100644 --- a/src/main/java/tlIItools/Affix.java +++ b/src/main/java/tlIItools/Affix.java @@ -1,6 +1,7 @@ package tlIItools; import java.util.ArrayList; +import java.util.Comparator; import java.util.List; import java.util.Scanner; @@ -112,7 +113,7 @@ public class Affix { * * For instance, an affix that granted +2 strength, and one that granted +4 * strength would be considered to be in the same affix group (assuming that - * both of those strength bonuses had the same effect name. + * both of those strength bonuses had the same effect name). * * @param afx * The affix to check if we are in an affix group with. @@ -137,8 +138,6 @@ public class Affix { return false; } else if (!equipTypes.equals(afx.equipTypes)) return false; - if (inNonEquip != afx.inNonEquip) - return false; if (isEnchantment != afx.isEnchantment) return false; if (isPerson != afx.isPerson) @@ -158,8 +157,51 @@ public class Affix { return true; } + /** + * Gets the name of the 'affix group' that this affix is in. + * + * By 'affix group', what we mean is that it is essentially the same affix, with + * generally just differing levels/values. + * + * For instance, an affix that granted +2 strength, and one that granted +4 + * strength would be considered to be in the same affix group (assuming that + * both of those strength bonuses had the same effect name, and applied to the + * same sorts of items). + * + * @return The name of the affix group + */ + public String getAffixGroupName() { + StringBuilder sb = new StringBuilder(); + + for (Effect eft : effects) { + sb.append(eft.getEffectGroup()); + } + + for (String enchantSource : enchantSources) { + sb.append(enchantSource); + } + + for (String equipType : equipTypes) { + sb.append(equipType); + } + + for (String nonEquipType : nonequipTypes) { + sb.append(nonEquipType); + } + + for (String socketableType : socketableTypes) { + sb.append(socketableType); + } + + return sb.toString(); + } + /* * Are invalid equip types being added? + * + * NOTE: This is kinda bad practice. It should really be handled via two + * separate affix methods, one to add a valid affix, one to add an invalid, w/ + * the caller keeping tracking/calling the right one. */ private boolean inNonEquip; @@ -319,7 +361,11 @@ public class Affix { } sb.append("\n"); } - + + sb.append("Affix Group: "); + sb.append(getAffixGroupName()); + sb.append("\n"); + return sb.toString(); } @@ -409,6 +455,9 @@ public class Affix { afx.effects.add(eft); } } + // Sort effects, so that they are in a stable order, even if specified out of + // order + afx.effects.sort(Comparator.comparingInt((val) -> val.hashCode())); long endTime = System.nanoTime(); if (doTiming) { diff --git a/src/main/java/tlIItools/AffixLister.java b/src/main/java/tlIItools/AffixLister.java index 3cb1f4b6..1138a7bc 100644 --- a/src/main/java/tlIItools/AffixLister.java +++ b/src/main/java/tlIItools/AffixLister.java @@ -4,11 +4,12 @@ import java.io.IOException; import java.io.FileReader; import java.io.PrintStream; -import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Scanner; +import java.util.Set; /** * Lists randomly generated affixes for Torchlight II gear. @@ -77,7 +78,7 @@ public class AffixLister { * The names of the files to read affix data from. */ public static AffixSet listAffixes(String[] args) { - AffixSet afst = new AffixSet(); + AffixSet affixSetByName = new AffixSet(); boolean doingArgs = true; @@ -91,9 +92,9 @@ public class AffixLister { int zeroCount = 0; int groupCount = 0; - Map> groupContents = afst.affixGroups; + Map> groupContents = affixSetByName.affixGroups; - List nonGroupContents = afst.ungroupedAffixes; + Set nonGroupContents = affixSetByName.ungroupedAffixes; NameFileReader nfr = new NameFileReader(false); nfr.groupRx = ".*/mods/([^/]+)/*"; @@ -240,6 +241,8 @@ public class AffixLister { } } + AffixSet affixSetByContents = new AffixSet(); + for (Entry> fGroup : nfr.fNames.entrySet()) { if (fGroup.getValue().size() == 0) continue; normOut.printf("\nFile Group '%s' starting\n", fGroup.getKey()); @@ -248,6 +251,8 @@ public class AffixLister { Scanner sc = new Scanner(fr); Affix afx = Affix.loadAffix(sc, fName); + affixSetByContents.addAffixByContents(afx); + effectCount += afx.effects.size(); if (afx.intName != null && afx.weight != 0) { @@ -262,7 +267,7 @@ public class AffixLister { if (hasGroup) { // errOut.printf("\tTRACE: Counted actual group %s from %s\n", groupName, afx.intName); - groupContents.put(groupName, new ArrayList<>()); + groupContents.put(groupName, new HashSet<>()); } else { nonGroupContents.add(afx); } @@ -301,7 +306,7 @@ public class AffixLister { } errOut.println("\nGroup Contents: "); - for (Entry> ent: groupContents.entrySet()) { + for (Entry> ent: groupContents.entrySet()) { errOut.printf("\t%s: %s\n", ent.getKey(), ent.getValue()); } errOut.println(); @@ -311,6 +316,6 @@ public class AffixLister { errOut.printf("\nProcessed %,d affixes (%,d named, %,d unnamed, %,d zero-weight) (%,d effects) (%,d distinct groups, %,d actual groups, %,d nongrouped affixes) out of %,d files (%,d groups) in %,d nanoseconds (%.2f seconds)\n", nfr.fCount, namedCount, unnamedCount, zeroCount, effectCount, groupCount, groupContents.size(), nonGroupContents.size(), nfr.fCount, nfr.fNames.size(), endTime - startTime, ((double)(endTime - startTime) / 1000000000)); errOut.printf("\tOptions: Name Mode: %s, Special-case zero weight: %s, Noting zero-weight in special case: %s\n", nameMode, !listZeros, !omitZeros); - return afst; + return affixSetByName; } } diff --git a/src/main/java/tlIItools/AffixSet.java b/src/main/java/tlIItools/AffixSet.java index 8f59d7b4..569649ec 100644 --- a/src/main/java/tlIItools/AffixSet.java +++ b/src/main/java/tlIItools/AffixSet.java @@ -1,9 +1,9 @@ package tlIItools; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; +import java.util.HashSet; import java.util.Map; +import java.util.Set; /** * Container of a set of affixes. * @@ -13,15 +13,15 @@ public class AffixSet { /** * All of the affix groups contained in this set. * - * An affix group is a set of affixs that generally have the same or - * similiar effects, but have different intensities or spawn levels. + * An affix group is a set of affixes that generally have the same or + * similar effects, but have different intensities or spawn levels. */ - public Map> affixGroups; + public Map> affixGroups; /** * All of the ungrouped affixes contained in this set. */ - public List ungroupedAffixes; + public Set ungroupedAffixes; /** * Create a new blank affix set. @@ -29,6 +29,33 @@ public class AffixSet { public AffixSet() { affixGroups = new HashMap<>(); - ungroupedAffixes = new ArrayList<>(); + ungroupedAffixes = new HashSet<>(); + } + + /** + * Add an affix to this set. + * + * @param afx The affix to add. + */ + public void addAffixByContents(Affix afx) { + String afxGroup = afx.getAffixGroupName(); + + if (afxGroup.equals("")) { + ungroupedAffixes.add(afx); + } else { + affixGroups.compute(afxGroup, (key, val) -> { + if (val == null) { + Set afxSet = new HashSet<>(); + + afxSet.add(afx); + + return afxSet; + } else { + val.add(afx); + + return val; + } + }); + } } } diff --git a/src/main/java/tlIItools/Effect.java b/src/main/java/tlIItools/Effect.java index 9075b490..d641b112 100644 --- a/src/main/java/tlIItools/Effect.java +++ b/src/main/java/tlIItools/Effect.java @@ -147,6 +147,34 @@ public class Effect { } + /** + * Gets the 'effect group' this effect belongs to. + * + * An 'effect group is essentially any other effect that is the same general sort of effect, just with different details. + * + * For instance, an effect that grants +4 strength would group with one granting +8 strength, + * assuming that most other details were equal. + * + * @return The 'effect group' this effect belongs to. + */ + public String getEffectGroup() { + StringBuilder sb = new StringBuilder(); + + sb.append(name); + sb.append(type); + sb.append(damageType); + sb.append(hasDuration); + sb.append(statName); + sb.append(isStatBonus); + sb.append(ownerLevel); + sb.append(graphOverride); + sb.append(useGraph); + sb.append(exclusive); + sb.append(isTransfer); + + return sb.toString(); + } + @Override public String toString() { StringBuilder sb = new StringBuilder(); @@ -247,23 +275,45 @@ public class Effect { return sb.toString(); } - + @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((damageType == null) ? 0 : damageType.hashCode()); + long temp; + temp = Double.doubleToLongBits(duration); + result = prime * result + (int) (temp ^ (temp >>> 32)); result = prime * result + (exclusive ? 1231 : 1237); - result = prime * result + ((graphOverride == null) ? 0 : graphOverride.hashCode()); + result = prime * result + + ((graphOverride == null) ? 0 : graphOverride.hashCode()); result = prime * result + (hasDuration ? 1231 : 1237); result = prime * result + (isStatBonus ? 1231 : 1237); result = prime * result + (isTransfer ? 1231 : 1237); + result = prime * result + level; + temp = Double.doubleToLongBits(maxCount); + result = prime * result + (int) (temp ^ (temp >>> 32)); + temp = Double.doubleToLongBits(maxPer); + result = prime * result + (int) (temp ^ (temp >>> 32)); + temp = Double.doubleToLongBits(maxValue); + result = prime * result + (int) (temp ^ (temp >>> 32)); + temp = Double.doubleToLongBits(minPer); + result = prime * result + (int) (temp ^ (temp >>> 32)); + temp = Double.doubleToLongBits(minValue); + result = prime * result + (int) (temp ^ (temp >>> 32)); result = prime * result + ((name == null) ? 0 : name.hashCode()); result = prime * result + (ownerLevel ? 1231 : 1237); - long temp; + temp = Double.doubleToLongBits(pulse); + result = prime * result + (int) (temp ^ (temp >>> 32)); + temp = Double.doubleToLongBits(range); + result = prime * result + (int) (temp ^ (temp >>> 32)); + temp = Double.doubleToLongBits(resist); + result = prime * result + (int) (temp ^ (temp >>> 32)); temp = Double.doubleToLongBits(soakScale); result = prime * result + (int) (temp ^ (temp >>> 32)); result = prime * result + ((statName == null) ? 0 : statName.hashCode()); + temp = Double.doubleToLongBits(statPercent); + result = prime * result + (int) (temp ^ (temp >>> 32)); result = prime * result + ((type == null) ? 0 : type.hashCode()); result = prime * result + (useGraph ? 1231 : 1237); return result; @@ -283,6 +333,8 @@ public class Effect { return false; } else if (!damageType.equals(other.damageType)) return false; + if (Double.doubleToLongBits(duration) != Double.doubleToLongBits(other.duration)) + return false; if (exclusive != other.exclusive) return false; if (graphOverride == null) { @@ -296,6 +348,18 @@ public class Effect { return false; if (isTransfer != other.isTransfer) return false; + if (level != other.level) + return false; + if (Double.doubleToLongBits(maxCount) != Double.doubleToLongBits(other.maxCount)) + return false; + if (Double.doubleToLongBits(maxPer) != Double.doubleToLongBits(other.maxPer)) + return false; + if (Double.doubleToLongBits(maxValue) != Double.doubleToLongBits(other.maxValue)) + return false; + if (Double.doubleToLongBits(minPer) != Double.doubleToLongBits(other.minPer)) + return false; + if (Double.doubleToLongBits(minValue) != Double.doubleToLongBits(other.minValue)) + return false; if (name == null) { if (other.name != null) return false; @@ -303,13 +367,23 @@ public class Effect { return false; if (ownerLevel != other.ownerLevel) return false; - if (Double.doubleToLongBits(soakScale) != Double.doubleToLongBits(other.soakScale)) + if (Double.doubleToLongBits(pulse) != Double.doubleToLongBits(other.pulse)) + return false; + if (Double.doubleToLongBits(range) != Double.doubleToLongBits(other.range)) + return false; + if (Double.doubleToLongBits(resist) != Double.doubleToLongBits(other.resist)) + return false; + if (Double.doubleToLongBits(soakScale) + != Double.doubleToLongBits(other.soakScale)) return false; if (statName == null) { if (other.statName != null) return false; } else if (!statName.equals(other.statName)) return false; + if (Double.doubleToLongBits(statPercent) + != Double.doubleToLongBits(other.statPercent)) + return false; if (type == null) { if (other.type != null) return false; -- cgit v1.2.3