The issue is that Guide is an ASH script which is periodically polled or refreshed by the browser. Since every browser request runs in its own thread, this can happen while KoLmafia is doing other things in response to actions in the Relay Browser or GUI or gCLI.
In this case, Guide was looking up an item by name. This looks at ItemDatabase.canonicalNames, an array of Strings.
"Simultaneously", bang potion identification was entering a new name into that array ("potion of detection", for example) and sorting it.
There are two ways to deal with this. Either change this:
Code:
private static final void saveCanonicalNames()
{
ItemDatabase.canonicalNames = new String[ ItemDatabase.itemIdByName.size() ];
// *** right here, probably, is where Guide tried to look up the item in this array
ItemDatabase.itemIdByName.keySet().toArray( ItemDatabase.canonicalNames );
Arrays.sort( ItemDatabase.canonicalNames );
}
to this:
Code:
private static final void saveCanonicalNames()
{
String newArray = new String[ ItemDatabase.itemIdByName.size() ];
ItemDatabase.itemIdByName.keySet().toArray( newArray );
Arrays.sort( newArray );
ItemDatabase.canonicalNames = newArray;
}
With this, Guide will look up the item in a table which does not include the just-added bang potion while the new array is being generated.
Or, change this:
Code:
private static final void saveCanonicalNames()
{
ItemDatabase.canonicalNames = new String[ ItemDatabase.itemIdByName.size() ];
ItemDatabase.itemIdByName.keySet().toArray( ItemDatabase.canonicalNames );
Arrays.sort( ItemDatabase.canonicalNames );
}
public static final List<String> getMatchingNames( final String substring )
{
return StringUtilities.getMatchingNames( ItemDatabase.canonicalNames, substring );
}
to this:
Code:
private static final void saveCanonicalNames()
{
synchronized ( ItemDatabase.canonicalNames )
{
ItemDatabase.canonicalNames = new String[ ItemDatabase.itemIdByName.size() ];
ItemDatabase.itemIdByName.keySet().toArray( ItemDatabase.canonicalNames );
Arrays.sort( ItemDatabase.canonicalNames );
}
}
public static final List<String> getMatchingNames( final String substring )
{
synchronized ( ItemDatabase.canonicalNames )
{
return StringUtilities.getMatchingNames( ItemDatabase.canonicalNames, substring );
}
}
To be honest, this is no better; the new bang potion could still have already been added to ItemDatabase.itemIdByName map but just not yet been added to the canonical name array.
I'm going to go with the first one.