Files
flutter-rimworld-modman/lib/mod_list_troubleshooter.dart
2025-03-16 23:48:32 +01:00

107 lines
2.9 KiB
Dart

import 'dart:async';
import 'package:rimworld_modman/logger.dart';
import 'package:rimworld_modman/mod.dart';
import 'package:rimworld_modman/mod_list.dart';
/// A class that helps find the minimum set of mods that exhibit a bug.
///
/// Provides two main algorithms:
/// - Binary search / bisect: Divides mods into smaller subsets to find problematic ones quickly.
/// - Linear search / batching: Tests mods in small groups to systematically identify issues.
///
/// These approaches help RimWorld mod users identify which mods are causing problems
/// when many mods are installed.
class ModListTroubleshooter {
final ModList originalModList;
ModList currentModList;
int _startIndex = 0;
int _endIndex = 0;
ModListTroubleshooter(ModList modList)
: originalModList = modList,
currentModList = modList.copyWith(),
_startIndex = 0,
_endIndex = modList.activeMods.length;
ModList binaryForward() {
final midIndex = (_startIndex + _endIndex) ~/ 2;
final subset = originalModList.activeMods.keys.toList().sublist(
midIndex,
_endIndex,
);
currentModList.disableAll();
currentModList.enableMods(subset);
_startIndex = midIndex;
return currentModList;
}
ModList binaryBackward() {
final midIndex = ((_startIndex + _endIndex) / 2).ceil();
final subset = originalModList.activeMods.keys.toList().sublist(
_startIndex,
midIndex,
);
currentModList.disableAll();
currentModList.enableMods(subset);
_endIndex = midIndex;
return currentModList;
}
ModList linearForward({int stepSize = 20}) {
final totalMods = originalModList.activeMods.length;
if (_startIndex >= totalMods || _startIndex == _endIndex) {
int newStart = totalMods - stepSize;
if (newStart < 0) {
newStart = 0;
}
_startIndex = newStart;
}
_startIndex = _startIndex.clamp(0, totalMods);
_endIndex = (_startIndex + stepSize).clamp(0, totalMods);
final subset = originalModList.activeMods.keys.toList().sublist(
_startIndex,
_endIndex,
);
currentModList.disableAll();
currentModList.enableMods(subset);
_startIndex = _endIndex;
return currentModList;
}
ModList linearBackward({int stepSize = 20}) {
final totalMods = originalModList.activeMods.length;
if (_endIndex <= 0 || _startIndex == _endIndex) {
int newEnd = stepSize;
if (newEnd > totalMods) {
newEnd = totalMods;
}
_endIndex = newEnd;
}
_endIndex = _endIndex.clamp(0, totalMods);
_startIndex = (_endIndex - stepSize).clamp(0, _endIndex);
final subset = originalModList.activeMods.keys.toList().sublist(
_startIndex,
_endIndex,
);
currentModList.disableAll();
currentModList.enableMods(subset);
_endIndex = _startIndex;
return currentModList;
}
void reset() {
currentModList = originalModList.copyWith();
}
}