mirror of
https://github.com/loot/libloot.git
synced 2026-07-27 14:16:01 -07:00
The new logic is conceptually simpler, with fewer special cases to handle. Unlike the old implementation, the new approach avoids cycles. It basically does depth-first searches through the group graph, adding edges from each group's plugins to the plugins in the group's successors. This involved reversing the direction of edges in the group graph, as this switches the logic from trying to find predecessors to trying to successors: the new direction matches that of plugin graph edges, so it's less confusing. I can't think of a situation in which the iteration order of plugins within a group matters. I tested it manually with my test load order of ~1600 plugins, and saw no difference when the order was randomly shuffled. I've added a test case but it's a relatively simple scenario and there may be a more complex scenario where it would matter that I haven't thought of. A buffer is used to hold the plugins in the previous groups in the current path, because that's noticeably faster than just recording the path and looking up the plugins for each group in the path. It does duplicate the group vectors, but that's an insignificant amount of memory used. The new approach has a negative performance impact, with sorting now 15% slower than before. A more efficient solution could be to implement a custom DFS algorithm that doesn't stop when it reaches a vertex it's already visited (which would be fine since the graph has already been validated to be acyclic), as then only the root vertices would need to be searched from.