// Here's the plan: // This class will take an instance of ModList and manipulate it in various ways // What we want to achieve is two things: // A) a binary search / bisect algorithm to find the minimum set of mods // that exhibit a bug // B) a linear search / batching algorithm for the same purpose // Why both? I think B will be most useful most often but A theoretically // should be faster // Why I think A might not always be faster is because it takes us a very long // time to load a lot of mods // So say it takes us 30 minutes to load 300 mods // Via bisect we would be loading 30 + 15 + 7.5 + ... = some 50 minutes // Via linear search we would be loading say 30 mods at a time // Which would be 3 minutes per batch for 10 batches // ie. 30 minutes // Reality is a little bit more complicated than that but that is the theory // Now - how should this class do what I detailed it to do // Keep the original ModList and copy it for every iteration // Whether that be an iteration of bisect or a batch of linear search // For every new batch make sure all its dependencies are loaded (ModList.loadRequired()) // Then try run game and proceed to next batch (or don't) // Progressively our ModList will shrink (or not, regardless) // And we should keep a registry of tested (say Good) mods and ones we haven't gotten to yet // Maybe even make sure each batch contains N untested mods // And that we don't test the same mod twice (unless it's a library) import 'package:flutter_test/flutter_test.dart'; import 'package:rimworld_modman/mod.dart'; import 'package:rimworld_modman/mod_list.dart'; import 'package:rimworld_modman/mod_list_troubleshooter.dart'; Mod makeDummy() { return Mod( name: 'Dummy Mod', id: 'dummy', path: '', versions: ["1.5"], description: '', dependencies: [], loadAfter: [], loadBefore: [], incompatibilities: [], size: 0, isBaseGame: false, isExpansion: false, enabled: false, ); } void main() { group('ModListTroubleshooter Bisect Tests', () { late ModList modList; setUp(() { modList = ModList(); // Add some base mods for (int i = 0; i < 20; i++) { final modId = 'test.mod$i'; final mod = makeDummy().copyWith(name: 'Test Mod $i', id: modId); modList.mods[modId] = mod; } // Add some mods with dependencies for (int i = 20; i < 30; i++) { final modId = 'test.mod$i'; final mod = makeDummy().copyWith( name: 'Test Mod $i', id: modId, dependencies: ['test.mod${i - 20}'], // Depend on earlier mods ); modList.mods[modId] = mod; } }); modList.enableAll(); test( 'Bisect search should end up with half the mods every iteration until 1', () { final troubleshooter = ModListTroubleshooter(modList); final result = troubleshooter.binaryForward(); // Half of our initial 30 expect(result.activeMods.length, equals(15)); final result2 = troubleshooter.binaryBackward(); // Half of our previous result expect(result2.activeMods.length, equals(7)); }, ); }); }