Implement everything...

This commit is contained in:
2025-03-16 12:52:55 +01:00
parent c2e6d5a491
commit 2cd9d585e6
2 changed files with 204 additions and 3 deletions

View File

@@ -194,6 +194,207 @@ class ModList {
});
return sortedMods;
}
List<List<String>> checkIncompatibilities() {
List<List<String>> conflicts = [];
List<String> activeModIds = activeMods.keys.toList();
// Only check each pair once
for (int i = 0; i < activeModIds.length; i++) {
String modId = activeModIds[i];
Mod mod = mods[modId]!;
for (String incompId in mod.incompatibilities) {
// Only process if other mod is active and we haven't checked this pair yet
if (activeMods.containsKey(incompId) && modId.compareTo(incompId) < 0) {
conflicts.add([modId, incompId]);
}
}
}
return conflicts;
}
/// Generate a load order for active mods
List<String> generateLoadOrder() {
// Check for incompatibilities first
List<List<String>> conflicts = checkIncompatibilities();
if (conflicts.isNotEmpty) {
throw Exception(
"Incompatible mods selected: ${conflicts.map((c) => "${c[0]} and ${c[1]}").join(', ')}",
);
}
// Reset all marks for topological sort
for (Mod mod in mods.values) {
mod.visited = false;
mod.mark = false;
mod.position = -1;
}
List<String> result = [];
int position = 0;
// Topological sort
void visit(Mod mod) {
if (mod.mark) {
List<String> cyclePath =
mods.values.where((m) => m.mark).map((m) => m.name).toList();
throw Exception(
"Cyclic dependency detected: ${cyclePath.join(' -> ')}",
);
}
if (!mod.visited) {
mod.mark = true;
// Visit all dependencies
for (String depId in mod.dependencies) {
if (activeMods.containsKey(depId)) {
visit(mods[depId]!);
}
}
mod.mark = false;
mod.visited = true;
mod.position = position++;
result.add(mod.id);
}
}
// Visit all nodes
for (Mod mod in mods.values) {
if (!mod.visited) {
visit(mod);
}
}
// Optimize for soft constraints
return _optimizeSoftConstraints(result);
}
/// Calculate how many soft constraints are satisfied
Map<String, int> _calculateSoftConstraintsScore(List<String> order) {
Map<String, int> positions = {};
for (int i = 0; i < order.length; i++) {
positions[order[i]] = i;
}
int satisfied = 0;
int total = 0;
for (String modId in order) {
Mod mod = mods[modId]!;
// Check "load before" preferences
for (String beforeId in mod.loadBefore) {
if (positions.containsKey(beforeId)) {
total++;
if (positions[modId]! < positions[beforeId]!) {
satisfied++;
}
}
}
// Check "load after" preferences
for (String afterId in mod.loadAfter) {
if (positions.containsKey(afterId)) {
total++;
if (positions[modId]! > positions[afterId]!) {
satisfied++;
}
}
}
}
return {'satisfied': satisfied, 'total': total};
}
/// Optimize for soft constraints using a greedy approach
List<String> _optimizeSoftConstraints(
List<String> initialOrder, {
int maxIterations = 5,
}) {
List<String> bestOrder = List.from(initialOrder);
Map<String, int> scoreInfo = _calculateSoftConstraintsScore(bestOrder);
int bestScore = scoreInfo['satisfied']!;
int total = scoreInfo['total']!;
if (total == 0 || bestScore == total) {
return bestOrder; // All constraints satisfied or no constraints
}
// Use a limited number of improvement passes
for (int iteration = 0; iteration < maxIterations; iteration++) {
bool improved = false;
// Try moving each mod to improve score
for (int i = 0; i < bestOrder.length; i++) {
String modId = bestOrder[i];
Mod mod = mods[modId]!;
// Calculate current local score for this mod
Map<String, int> currentPositions = {};
for (int idx = 0; idx < bestOrder.length; idx++) {
currentPositions[bestOrder[idx]] = idx;
}
// Try moving this mod to different positions
for (int newPos = 0; newPos < bestOrder.length; newPos++) {
if (newPos == i) continue;
// Skip if move would break hard dependencies
bool skip = false;
if (newPos < i) {
// Moving earlier
// Check if any mod between newPos and i depends on this mod
for (int j = newPos; j < i; j++) {
String depModId = bestOrder[j];
if (mods[depModId]!.dependencies.contains(modId)) {
skip = true;
break;
}
}
} else {
// Moving later
// Check if this mod depends on any mod between i and newPos
for (int j = i + 1; j <= newPos; j++) {
String depModId = bestOrder[j];
if (mod.dependencies.contains(depModId)) {
skip = true;
break;
}
}
}
if (skip) continue;
// Create a new order with the mod moved
List<String> newOrder = List.from(bestOrder);
newOrder.removeAt(i);
newOrder.insert(newPos, modId);
// Calculate new score
Map<String, int> newScoreInfo = _calculateSoftConstraintsScore(
newOrder,
);
int newScore = newScoreInfo['satisfied']!;
if (newScore > bestScore) {
bestScore = newScore;
bestOrder = newOrder;
improved = true;
break; // Break inner loop, move to next mod
}
}
if (improved) break; // If improved, start a new iteration
}
if (!improved) break; // If no improvements in this pass, stop
}
return bestOrder;
}
}
String _expansionNameFromId(String id) {