Immensely reduce lag on sorting large recipe lists

This commit is contained in:
Buurazu authored and GitHub committed 2021-11-17 12:21:18 -05:00
1 parent fcdfbe33f4
commit f50cffcf8d
1 file changed
+90 -54
+90 -54
View File
@@ -176,6 +176,22 @@ local lockedRecipes = {}
--If the seed changes, the above two tables will be wiped --If the seed changes, the above two tables will be wiped
local lastSeedUsed = 0 local lastSeedUsed = 0
--A list of item IDs, sorted by quality, then by name, to help with sorting our recipe list faster
local sortedIDs = {}
for i = 1, EID.XMLMaxItemID do
if EID.XMLItemQualities[i] ~= nil then
table.insert(sortedIDs, i)
end
end
table.sort(sortedIDs, function(a, b)
if EID.XMLItemQualities[a] == EID.XMLItemQualities[b] then
return (EID:getObjectName(5, 100, a) < EID:getObjectName(5, 100, b))
else
return (EID.XMLItemQualities[a] > EID.XMLItemQualities[b])
end
end)
local customRNGSeed = 0x77777770 local customRNGSeed = 0x77777770
local customRNGShift = {0,0,0} local customRNGShift = {0,0,0}
@@ -457,6 +473,7 @@ end
local randResultCache = {} local randResultCache = {}
local calcResultCache = {} local calcResultCache = {}
local numResults = 0
EID.bagOfCraftingOffset = 0 EID.bagOfCraftingOffset = 0
EID.bagOfCraftingCurPickupCount = -1 EID.bagOfCraftingCurPickupCount = -1
@@ -593,6 +610,7 @@ function EID:handleBagOfCraftingRendering()
elseif calcResultCache[queryString] == nil or EID.refreshNextTick then elseif calcResultCache[queryString] == nil or EID.refreshNextTick then
--build on top of our previous recipe lists, if possible --build on top of our previous recipe lists, if possible
local randResults = randResultCache[queryString] or {} local randResults = randResultCache[queryString] or {}
local newResults = {}
local skipRandom = false local skipRandom = false
--check every single possible recipe for our highest value pickups --check every single possible recipe for our highest value pickups
--limit it in the options, since the number of total combinations quickly grows (nCr): --limit it in the options, since the number of total combinations quickly grows (nCr):
@@ -625,7 +643,11 @@ function EID:handleBagOfCraftingRendering()
local startPos = startPos or 1 local startPos = startPos or 1
local tempResult = tempResult or {} local tempResult = tempResult or {}
if (length == 0) then if (length == 0) then
randResults[table.concat(tempResult,",")] = {table.unpack(tempResult)} local resultString = table.concat(tempResult,",")
if (randResults[resultString] == nil) then
randResults[resultString] = {table.unpack(tempResult)}
newResults[resultString] = {table.unpack(tempResult)}
end
return return
end end
for i = startPos, #arr-length+1 do for i = startPos, #arr-length+1 do
@@ -646,49 +668,54 @@ function EID:handleBagOfCraftingRendering()
table.remove(tableCopy, pos) table.remove(tableCopy, pos)
end end
table.sort(newTable, qualitySort) table.sort(newTable, qualitySort)
randResults[table.concat(newTable,",")] = newTable local resultString = table.concat(newTable,",")
if (randResults[resultString] == nil) then
randResults[resultString] = {table.unpack(newTable)}
newResults[resultString] = {table.unpack(newTable)}
end
end end
end end
local calcResults = {} local sortedResults = {}
for k, v in pairs(randResults) do if (calcResultCache[queryString]) then
sortedResults = calcResultCache[queryString]
else
for k, v in ipairs(sortedIDs) do
sortedResults[v] = {}
end
end
for k, v in pairs(newResults) do
local resultID, lockedAchievementID = EID:calculateBagOfCrafting(v) local resultID, lockedAchievementID = EID:calculateBagOfCrafting(v)
if resultID ~= lockedAchievementID then if resultID ~= lockedAchievementID then
table.insert(calcResults, {v, resultID, lockedAchievementID}) table.insert(sortedResults[resultID], {v, resultID, lockedAchievementID})
else else
table.insert(calcResults, {v, resultID}) table.insert(sortedResults[resultID], {v, resultID})
end end
end end
calcResultCache[queryString] = calcResults calcResultCache[queryString] = sortedResults
randResultCache[queryString] = randResults randResultCache[queryString] = randResults
results = calcResults results = sortedResults
--sort our final results by quality, then alphabetical item name
table.sort(results, function(a, b) numResults = 0
if EID.XMLItemQualities[a[2]] == EID.XMLItemQualities[b[2]] then for k,v in ipairs(sortedIDs) do
return (EID:getObjectName(5, 100, a[2]) < EID:getObjectName(5, 100, b[2])) if (EID.refreshNextTick and EID.bagOfCraftingOffset > 0 and v == EID.refreshPosition) then
else --jump to the item we were looking at before, so you can more easily refresh for variants of recipes
return (EID.XMLItemQualities[a[2]] > EID.XMLItemQualities[b[2]]) EID.bagOfCraftingOffset = numResults
end end
end) numResults = numResults + #results[v]
end
if not EID.refreshNextTick then if not EID.refreshNextTick then
EID.bagOfCraftingOffset = 0 EID.bagOfCraftingOffset = 0
EID.bagOfCraftingRefreshes = 0 EID.bagOfCraftingRefreshes = 0
--jump to the item we were looking at before, so you can more easily refresh for variants of recipes
elseif EID.bagOfCraftingOffset > 0 then
for k,v in ipairs(results) do
if (v[2] == EID.refreshPosition) then
EID.bagOfCraftingOffset = k-1
break
end
end
end end
EID.refreshNextTick = false EID.refreshNextTick = false
else else
results = calcResultCache[queryString] results = calcResultCache[queryString]
end end
if #results == 0 then if numResults == 0 then
EID.bagOfCraftingOffset = 0 EID.bagOfCraftingOffset = 0
return false return false
end end
@@ -726,7 +753,7 @@ function EID:handleBagOfCraftingRendering()
if Input.IsActionPressed(EID.Config["BagOfCraftingToggleKey"], EID.player.ControllerIndex) then if Input.IsActionPressed(EID.Config["BagOfCraftingToggleKey"], EID.player.ControllerIndex) then
EID.player:SetShootingCooldown(2) EID.player:SetShootingCooldown(2)
if Input.IsActionTriggered(ButtonAction.ACTION_SHOOTDOWN, EID.player.ControllerIndex) then if Input.IsActionTriggered(ButtonAction.ACTION_SHOOTDOWN, EID.player.ControllerIndex) then
EID.bagOfCraftingOffset = math.min(#results-(#results%EID.Config["BagOfCraftingResults"]), EID.bagOfCraftingOffset + EID.Config["BagOfCraftingResults"]) EID.bagOfCraftingOffset = math.min(numResults-(numResults%EID.Config["BagOfCraftingResults"]), EID.bagOfCraftingOffset + EID.Config["BagOfCraftingResults"])
EID.downHeld = Isaac.GetTime() EID.downHeld = Isaac.GetTime()
elseif Input.IsActionTriggered(ButtonAction.ACTION_SHOOTUP, EID.player.ControllerIndex) then elseif Input.IsActionTriggered(ButtonAction.ACTION_SHOOTUP, EID.player.ControllerIndex) then
EID.bagOfCraftingOffset = math.max(0, EID.bagOfCraftingOffset - EID.Config["BagOfCraftingResults"]) EID.bagOfCraftingOffset = math.max(0, EID.bagOfCraftingOffset - EID.Config["BagOfCraftingResults"])
@@ -739,12 +766,11 @@ function EID:handleBagOfCraftingRendering()
elseif Input.IsActionTriggered(ButtonAction.ACTION_SHOOTRIGHT, EID.player.ControllerIndex) then elseif Input.IsActionTriggered(ButtonAction.ACTION_SHOOTRIGHT, EID.player.ControllerIndex) then
if (EID.lockedResults == nil) then if (EID.lockedResults == nil) then
EID.refreshNextTick = true EID.refreshNextTick = true
if (results[EID.bagOfCraftingOffset+1]) then EID.refreshPosition = results[EID.bagOfCraftingOffset+1][2] end
end end
end end
--scroll pages quickly if the button is held --scroll pages quickly if the button is held
if Input.IsActionPressed(ButtonAction.ACTION_SHOOTDOWN, EID.player.ControllerIndex) and Isaac.GetTime() - EID.downHeld > 750 then if Input.IsActionPressed(ButtonAction.ACTION_SHOOTDOWN, EID.player.ControllerIndex) and Isaac.GetTime() - EID.downHeld > 750 then
EID.bagOfCraftingOffset = math.min(#results-(#results%EID.Config["BagOfCraftingResults"]), EID.bagOfCraftingOffset + EID.Config["BagOfCraftingResults"]) EID.bagOfCraftingOffset = math.min(numResults-(numResults%EID.Config["BagOfCraftingResults"]), EID.bagOfCraftingOffset + EID.Config["BagOfCraftingResults"])
EID.downHeld = Isaac.GetTime() - 700 EID.downHeld = Isaac.GetTime() - 700
elseif Input.IsActionPressed(ButtonAction.ACTION_SHOOTUP, EID.player.ControllerIndex) and Isaac.GetTime() - EID.upHeld > 750 then elseif Input.IsActionPressed(ButtonAction.ACTION_SHOOTUP, EID.player.ControllerIndex) and Isaac.GetTime() - EID.upHeld > 750 then
EID.bagOfCraftingOffset = math.max(0, EID.bagOfCraftingOffset - EID.Config["BagOfCraftingResults"]) EID.bagOfCraftingOffset = math.max(0, EID.bagOfCraftingOffset - EID.Config["BagOfCraftingResults"])
@@ -752,7 +778,7 @@ function EID:handleBagOfCraftingRendering()
end end
end end
--fix bug with being allowed to go to an empty page if recipe count = multiple of page size (or if we refresh on last page) --fix bug with being allowed to go to an empty page if recipe count = multiple of page size (or if we refresh on last page)
if (EID.bagOfCraftingOffset >= #results) then EID.bagOfCraftingOffset = EID.bagOfCraftingOffset - EID.Config["BagOfCraftingResults"] end if (EID.bagOfCraftingOffset >= numResults) then EID.bagOfCraftingOffset = EID.bagOfCraftingOffset - EID.Config["BagOfCraftingResults"] end
local prevItem = 0 local prevItem = 0
@@ -762,38 +788,48 @@ function EID:handleBagOfCraftingRendering()
prefix = "#{{Trinket159}} " prefix = "#{{Trinket159}} "
end end
--results is now sorted by quality and item name, and doesn't iterate over the entire table, instead starting at the page offset --results is now a table of tables for each item, so we have to iterate over the table using sortedIDs
if (EID.bagOfCraftingOffset > 0) then if (EID.bagOfCraftingOffset > 0) then
customDescObj.Description = customDescObj.Description.. prefix .. "...+"..EID.bagOfCraftingOffset.." more" customDescObj.Description = customDescObj.Description.. prefix .. "...+"..EID.bagOfCraftingOffset.." more"
end end
for i=EID.bagOfCraftingOffset+1,EID.bagOfCraftingOffset+EID.Config["BagOfCraftingResults"] do local curOffset = 0
local v = results[i] EID.refreshPosition = -1
if not v then break end for k,id in ipairs(sortedIDs) do
if (curOffset + #results[id] <= EID.bagOfCraftingOffset) then curOffset = curOffset + #results[id]
if not EID.Config["BagOfCraftingDisplayNames"] then
customDescObj.Description = customDescObj.Description.."# {{Collectible"..v[2].."}} "
--tack on the secondary recipe image to achievement-locked recipes
if v[3] then customDescObj.Description = customDescObj.Description.."({{Collectible" .. v[3] .. "}})" end
--color the equals sign with the item quality, so the order of the list can make sense
customDescObj.Description = customDescObj.Description.. qualities[EID.XMLItemQualities[v[2]]] .. "={{CR}}"
--only display the item name if it's the first occurrence
else else
if prevItem ~= v[2] then if (EID.refreshPosition == -1) then EID.refreshPosition = id end
--substring the first 18 characters of the item name so it fits on one line; is there a way to get around desc line length limits? for k2, v in ipairs(results[id]) do
customDescObj.Description = customDescObj.Description.."# {{Collectible"..v[2].."}} ".. qualities[EID.XMLItemQualities[v[2]]] .. curOffset = curOffset + 1
string.sub(EID:getObjectName(5, 100, v[2]),1,18).."#" if (curOffset > EID.bagOfCraftingOffset+EID.Config["BagOfCraftingResults"]) then break end
else if not v then break end
customDescObj.Description = customDescObj.Description.."#" if (curOffset > EID.bagOfCraftingOffset) then
if not EID.Config["BagOfCraftingDisplayNames"] then
customDescObj.Description = customDescObj.Description.."# {{Collectible"..v[2].."}} "
--tack on the secondary recipe image to achievement-locked recipes
if v[3] then customDescObj.Description = customDescObj.Description.."({{Collectible" .. v[3] .. "}})" end
--color the equals sign with the item quality, so the order of the list can make sense
customDescObj.Description = customDescObj.Description.. qualities[EID.XMLItemQualities[v[2]]] .. "={{CR}}"
--only display the item name if it's the first occurrence
else
if prevItem ~= v[2] then
--substring the first 18 characters of the item name so it fits on one line; is there a way to get around desc line length limits?
customDescObj.Description = customDescObj.Description.."# {{Collectible"..v[2].."}} ".. qualities[EID.XMLItemQualities[v[2]]] ..
string.sub(EID:getObjectName(5, 100, v[2]),1,18).."#"
else
customDescObj.Description = customDescObj.Description.."#"
end
--replace recipe bulletpoint with the secondary recipe on achievement-locked recipes
if v[3] then customDescObj.Description = customDescObj.Description.." {{Collectible" .. v[3] .. "}} " end
end
customDescObj.Description = customDescObj.Description..EID:tableToCraftingIconsMerged(v[1])
prevItem = v[2]
end
end end
--replace recipe bulletpoint with the secondary recipe on achievement-locked recipes
if v[3] then customDescObj.Description = customDescObj.Description.." {{Collectible" .. v[3] .. "}} " end
end end
customDescObj.Description = customDescObj.Description..EID:tableToCraftingIconsMerged(v[1])
prevItem = v[2]
end end
if (EID.bagOfCraftingOffset + EID.Config["BagOfCraftingResults"] < #results) then if (EID.bagOfCraftingOffset + EID.Config["BagOfCraftingResults"] < numResults) then
customDescObj.Description = customDescObj.Description.. prefix .. "...+"..(#results-EID.Config["BagOfCraftingResults"]-EID.bagOfCraftingOffset).." more" customDescObj.Description = customDescObj.Description.. prefix .. "...+"..(numResults-EID.Config["BagOfCraftingResults"]-EID.bagOfCraftingOffset).." more"
end end
EID:printDescription(customDescObj) EID:printDescription(customDescObj)