Need a "pause" between consecutive calls of "removeAllTagsFrom" from tags events
Zifiv opened this issue ยท 2 comments
Minecraft Version
1.19.2
KubeJS Version
1902.6.0-build.142
Rhino Version
1902.2.2-build.264
Architectury Version
6.5.69
Forge/Fabric Version
Fabric 0.14.18
Describe your issue
In a script kubejs/sever_script/main.js
with the content of :
ServerEvents.tags('item', event => {
['mythicmetals:silver_ingot',
'mythicmetals:raw_silver',
'mythicmetals:silver_nugget',
'mythicmetals:silver_helmet',
'mythicmetals:silver_chestplate',
'mythicmetals:silver_leggings',
'mythicmetals:silver_boots'].each(item => event.removeAllTagsFrom(item));
});
It will throw the error Error occurred while handling event 'ServerEvents.tags': java.lang.IllegalStateException
(with the complete logs is in the file below).
But if I add a wait (of 500ms for example) in the loop it works most of the time, but sometimes it throws the same error :
ServerEvents.tags('item', event => {
['mythicmetals:silver_ingot',
'mythicmetals:raw_silver',
'mythicmetals:silver_nugget',
'mythicmetals:silver_helmet',
'mythicmetals:silver_chestplate',
'mythicmetals:silver_leggings',
'mythicmetals:silver_boots'].each(item => {
event.removeAllTagsFrom(item);
var date = new Date();
var curDate = null;
do { curDate = new Date(); }
while(curDate - date < 500);
});
});
I'm testing this code in a big modpack with more than 160 mods.
Crash report/logs
I've changed my code to pass the array in the removeAllTagsFrom(any)
, it seems to work well like this, but I've the same errors while I try to use the removeAllTagsFrom(any)
in ServerEvents.tags for item and block in the same script :
ServerEvents.tags('item', event => {
event.removeAllTagsFrom([
'mythicmetals:silver_ingot',
'mythicmetals:raw_silver',
'mythicmetals:silver_nugget',
'mythicmetals:silver_helmet',
'mythicmetals:silver_chestplate',
'mythicmetals:silver_leggings',
'mythicmetals:silver_boots'
]);
});
ServerEvents.tags('block', event => {
event.removeAllTagsFrom([
'mythicmetals:silver_ore',
'mythicmetals:raw_silver_block',
'mythicmetals:silver_block',
'mythicmetals:silver_anvil'
]);
});
Same error throws but if I add a wait (of 1 secs this time) in start of the method for the tags event of type block, it works well.
(PS : sorry for my english if it is poor and bad, I think I'm understandable, but do not hesitate to tell me if you do not understand something.)
I got some interesting findings on this. Talked it over with ArugChief a bit on discord and we both think it is likely a race condition.
I was only having this error once in a great while (which is inline with typical race condition shenanigans), and was able to ignore it for a bit. However almost out of nowhere it started doing it consistently which forced me to look into it.
I found that removing and adding tags to items based on an ID regex match would also cause this issue. For example:
// priority: 0
ServerEvents.tags('block', e =>
{
// Make some things need ironwood tools
let ironwood_blocks = [
// Livingrock
/botania:(?!apothecary_).*livingrock.*/,
'botania:shimmerrock',
// Deepslate
/.*:(?!reinforced_|apothecary_).*deepslate(?!_brick_waystone).*/ // line 11
]
e.remove('minecraft:needs_stone_tool', ironwood_blocks) // line 13
e.remove('minecraft:needs_iron_tool', ironwood_blocks)
e.add('twilightforest:needs_ironwood_tool', ironwood_blocks)
// Make obsidian need manasteel
let obsidians = e.get('c:obsidian').getObjectIds().toArray()
e.remove('minecraft:needs_diamond_tool', obsidians)
e.add('botania:needs_manasteel_tool', obsidians) // line 20
})
This was causing the same error Zifiv posted above. However the JS code line mentioned in the error always relates to the lowest line of code (line 20, in this case). However, if you comment it out, then line 19 is blamed, so on so forth all the way up to line 13. I found that commenting out line 11 would get rid of the issue. So this regex in specific was causing the issue, likely because it has many many items that match its regex (over 100 in my game) thus having higher chances for the race condition to happen.
I then discovered what seems to be a temporary workaround, at least from what I have seen so far. Instead of modifying the tags for the regex as a whole, iterating over all items matching the regex and doing it per-item seems to work for me. Here's a working example of my first snippet:
// priority: 0
ServerEvents.tags('block', e =>
{
// Make some things need ironwood tools
let ironwood_blocks = [
// Livingrock
/botania:(?!apothecary_).*livingrock.*/,
'botania:shimmerrock',
// Deepslate
/.*:(?!reinforced_|apothecary_).*deepslate(?!_brick_waystone).*/
]
ironwood_blocks.map(item => Ingredient.of(item).itemIds).forEach(items => items.forEach(item =>
{
e.remove('minecraft:needs_stone_tool', item)
e.remove('minecraft:needs_iron_tool', item)
e.add('twilightforest:needs_ironwood_tool', item)
}))
// Make obsidian need manasteel
let obsidians = e.get('c:obsidian').getObjectIds().toArray()
e.remove('minecraft:needs_diamond_tool', obsidians)
e.add('botania:needs_manasteel_tool', obsidians)
})
For those who want a simple workaround function to copy paste, use the below code. regex
accepts either an array of regexes or a single regex.
const forEachItemMatchingRegex = (regex, callback) =>
{
let regexes = Array.isArray(regex) ? regex : [regex]
regexes.map(r => Ingredient.of(r).itemIds).forEach(items => items.forEach(item => callback(item)))
}