Implement loading dependencies for mods
This commit is contained in:
@@ -5,13 +5,13 @@ import 'package:rimworld_modman/mod.dart';
|
|||||||
import 'package:xml/xml.dart';
|
import 'package:xml/xml.dart';
|
||||||
|
|
||||||
class ModList {
|
class ModList {
|
||||||
final String configPath;
|
String configPath = '';
|
||||||
final String modsPath;
|
String modsPath = '';
|
||||||
// O(1) lookup
|
// O(1) lookup
|
||||||
Map<String, bool> activeMods = {};
|
Map<String, bool> activeMods = {};
|
||||||
Map<String, Mod> mods = {};
|
Map<String, Mod> mods = {};
|
||||||
|
|
||||||
ModList({required this.configPath, required this.modsPath});
|
ModList({this.configPath = '', this.modsPath = ''});
|
||||||
|
|
||||||
Stream<Mod> loadAvailable() async* {
|
Stream<Mod> loadAvailable() async* {
|
||||||
final logger = Logger.instance;
|
final logger = Logger.instance;
|
||||||
@@ -184,6 +184,18 @@ class ModList {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void enableAll() {
|
||||||
|
for (final mod in mods.values) {
|
||||||
|
setEnabled(mod.id, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void disableAll() {
|
||||||
|
for (final mod in mods.values) {
|
||||||
|
setEnabled(mod.id, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
List<List<String>> checkIncompatibilities() {
|
List<List<String>> checkIncompatibilities() {
|
||||||
List<List<String>> conflicts = [];
|
List<List<String>> conflicts = [];
|
||||||
List<String> activeModIds = activeMods.keys.toList();
|
List<String> activeModIds = activeMods.keys.toList();
|
||||||
@@ -387,6 +399,20 @@ class ModList {
|
|||||||
|
|
||||||
return bestOrder;
|
return bestOrder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<String> loadRequired() {
|
||||||
|
final toEnable = <String>[];
|
||||||
|
for (final modid in activeMods.keys) {
|
||||||
|
final mod = mods[modid]!;
|
||||||
|
for (final dep in mod.dependencies) {
|
||||||
|
toEnable.add(dep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (final modid in toEnable) {
|
||||||
|
setEnabled(modid, true);
|
||||||
|
}
|
||||||
|
return generateLoadOrder();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String _expansionNameFromId(String id) {
|
String _expansionNameFromId(String id) {
|
||||||
|
@@ -8,7 +8,7 @@ const configRoot = '$root/AppData/RimWorld by Ludeon Studios/Config';
|
|||||||
const configPath = '$configRoot/ModsConfig.xml';
|
const configPath = '$configRoot/ModsConfig.xml';
|
||||||
const logsPath = '$root/ModManager';
|
const logsPath = '$root/ModManager';
|
||||||
|
|
||||||
void main() {
|
Map<String, Mod> generateDummyMods() {
|
||||||
final dummyMod = Mod(
|
final dummyMod = Mod(
|
||||||
name: 'Dummy Mod',
|
name: 'Dummy Mod',
|
||||||
id: 'dummy',
|
id: 'dummy',
|
||||||
@@ -32,6 +32,13 @@ void main() {
|
|||||||
loadBefore: ["ludeon.rimworld"],
|
loadBefore: ["ludeon.rimworld"],
|
||||||
size: 47,
|
size: 47,
|
||||||
),
|
),
|
||||||
|
'prepatcher': dummyMod.copyWith(
|
||||||
|
name: 'Prepatcher',
|
||||||
|
id: 'prepatcher',
|
||||||
|
loadAfter: ["ludeon.rimworld"],
|
||||||
|
dependencies: ["harmony"],
|
||||||
|
size: 47,
|
||||||
|
),
|
||||||
'ludeon.rimworld': dummyMod.copyWith(
|
'ludeon.rimworld': dummyMod.copyWith(
|
||||||
name: 'RimWorld',
|
name: 'RimWorld',
|
||||||
id: 'ludeon.rimworld',
|
id: 'ludeon.rimworld',
|
||||||
@@ -56,11 +63,14 @@ void main() {
|
|||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
final dummyList = ModList(configPath: configPath, modsPath: modsRoot);
|
return dummyMods;
|
||||||
dummyList.mods.addAll(dummyMods);
|
}
|
||||||
for (final mod in dummyMods.keys) {
|
|
||||||
dummyList.setEnabled(mod, true);
|
void main() {
|
||||||
}
|
final dummyMods = generateDummyMods();
|
||||||
|
final dummyList = ModList();
|
||||||
|
dummyList.mods = dummyMods;
|
||||||
|
dummyList.enableAll();
|
||||||
dummyList.setEnabled('disabledDummy', false);
|
dummyList.setEnabled('disabledDummy', false);
|
||||||
dummyList.setEnabled('incompatible', false);
|
dummyList.setEnabled('incompatible', false);
|
||||||
final sortedMods = dummyList.generateLoadOrder();
|
final sortedMods = dummyList.generateLoadOrder();
|
||||||
@@ -71,6 +81,13 @@ void main() {
|
|||||||
final rimworldIndex = sortedMods.indexOf('ludeon.rimworld');
|
final rimworldIndex = sortedMods.indexOf('ludeon.rimworld');
|
||||||
expect(harmonyIndex, lessThan(rimworldIndex));
|
expect(harmonyIndex, lessThan(rimworldIndex));
|
||||||
});
|
});
|
||||||
|
test('Prepatcher should load after Harmony and RimWorld', () {
|
||||||
|
final prepatcherIndex = sortedMods.indexOf('prepatcher');
|
||||||
|
final harmonyIndex = sortedMods.indexOf('harmony');
|
||||||
|
final rimworldIndex = sortedMods.indexOf('ludeon.rimworld');
|
||||||
|
expect(prepatcherIndex, greaterThan(harmonyIndex));
|
||||||
|
expect(prepatcherIndex, greaterThan(rimworldIndex));
|
||||||
|
});
|
||||||
test('RimWorld should load before Anomaly', () {
|
test('RimWorld should load before Anomaly', () {
|
||||||
final rimworldIndex = sortedMods.indexOf('ludeon.rimworld');
|
final rimworldIndex = sortedMods.indexOf('ludeon.rimworld');
|
||||||
final anomalyIndex = sortedMods.indexOf('ludeon.rimworld.anomaly');
|
final anomalyIndex = sortedMods.indexOf('ludeon.rimworld.anomaly');
|
||||||
@@ -85,9 +102,32 @@ void main() {
|
|||||||
final yuuugeIndex = sortedMods.indexOf('yuuuge');
|
final yuuugeIndex = sortedMods.indexOf('yuuuge');
|
||||||
expect(yuuugeIndex, lessThan(smolIndex));
|
expect(yuuugeIndex, lessThan(smolIndex));
|
||||||
});
|
});
|
||||||
dummyList.setEnabled('incompatible', true);
|
|
||||||
test('Error generating load order with incompatible mods', () {
|
test('Error generating load order with incompatible mods', () {
|
||||||
|
dummyList.setEnabled('incompatible', true);
|
||||||
expect(() => dummyList.generateLoadOrder(), throwsException);
|
expect(() => dummyList.generateLoadOrder(), throwsException);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
final dummyMods2 = generateDummyMods();
|
||||||
|
final dummyList2 = ModList();
|
||||||
|
dummyList2.mods = dummyMods2;
|
||||||
|
dummyList2.disableAll();
|
||||||
|
dummyList2.setEnabled('prepatcher', true);
|
||||||
|
final sortedMods2 = dummyList2.loadRequired();
|
||||||
|
group('Test loadRequired', () {
|
||||||
|
test(
|
||||||
|
'Harmony should get enabled by loadRequired as a dependency of prepatcher',
|
||||||
|
() {
|
||||||
|
final harmonyIndex = sortedMods2.indexOf('harmony');
|
||||||
|
expect(harmonyIndex, isNot(-1));
|
||||||
|
},
|
||||||
|
);
|
||||||
|
test('No other mods should get enabled', () {
|
||||||
|
for (final mod in dummyMods2.keys) {
|
||||||
|
if (mod != 'prepatcher' && mod != 'harmony') {
|
||||||
|
expect(sortedMods2.indexOf(mod), isNegative);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user