Skip to content

Commit 480fa6d

Browse files
authored
Mod List Sorting System (#971)
* Add mod list sorting system ModsFolder.getModsList now has an optional parameter to describe the various sorting options. Excluding this option produces rather legacy behavior and should be backwards-compatible. Sorted mod lists get cached under a so-called "sort forge," which writes the key to use in the cache. If a cache hit occurs, then ModsFolder.getModsList will use the hit. Currently, there is support for ascending/descending order and two modes: clean and alphabetical sorting. Clean mode provides legacy behavior using this new system, and alphabetical sorting uses CoolUtil to sort the list. ModSwitchMenu has been updated to use this new system, but really, the only noticeable change should just be additional memory overhead. * Integrate mod sorting mode as abstract enum * Add delimiter for mods in sort forge * Polish up mod sorting Most notably, the cache for mod sorting can now be publicly accessed (although it will be hidden when generating documentation). This additionally removes a trace that used to be done, and the raw forge will be used as the key in the cache instead of being hashed in SHA-256 first (I don't remember why I did that, and to me it seems fairly useless).
1 parent dbcac9e commit 480fa6d

2 files changed

Lines changed: 76 additions & 2 deletions

File tree

source/funkin/backend/assets/ModsFolder.hx

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package funkin.backend.assets;
22

33
import flixel.util.FlxSignal.FlxTypedSignal;
44
import funkin.backend.system.MainState;
5+
import funkin.backend.utils.CoolUtil;
6+
import haxe.ds.StringMap;
57
import haxe.io.Path;
68
import lime.text.Font;
79
import openfl.text.Font as OpenFLFont;
@@ -42,6 +44,8 @@ class ModsFolder {
4244
* Whenever its the first time mods has been reloaded.
4345
*/
4446
private static var __firstTime:Bool = true;
47+
48+
@:dox(hide) public static var modsListSortCache:StringMap<Array<String>> = new StringMap();
4549

4650
/**
4751
* Initializes `mods` folder.
@@ -94,7 +98,7 @@ class ModsFolder {
9498
#end
9599
}
96100

97-
public static function getModsList():Array<String> {
101+
public static function getModsList(?sortingOptions:ModSortingOptions):Array<String> {
98102
var mods:Array<String> = [];
99103
#if MOD_SUPPORT
100104
// Mods directory does not exist yet, create it
@@ -108,6 +112,28 @@ class ModsFolder {
108112
if (FileSystem.isDirectory(modsPath + modFolder)) mods.push(modFolder);
109113
else if (Flags.ALLOWED_ZIP_EXTENSIONS.contains(Path.extension(modFolder))) mods.push(Path.withoutExtension(modFolder));
110114
}
115+
116+
if (sortingOptions != null) {
117+
var sortForge:StringBuf = new StringBuf();
118+
for (i in mods) {
119+
sortForge.add(i);
120+
sortForge.add("::");
121+
}
122+
123+
sortForge.add(Std.string(sortingOptions.descending ? 1 : 0));
124+
125+
sortForge.add(sortingOptions.mode);
126+
127+
final sortForgePure:String = sortForge.toString();
128+
129+
if (modsListSortCache.exists(sortForgePure))
130+
mods = modsListSortCache.get(sortForgePure);
131+
if (mods.length > 0 && mods[mods.length - 1] == null) mods.pop();
132+
else {
133+
ModSortingController.sort(sortingOptions, mods);
134+
modsListSortCache.set(sortForgePure, mods);
135+
}
136+
}
111137
#end
112138
return mods;
113139
}
@@ -167,3 +193,48 @@ class ModsFolder {
167193
}
168194
#end
169195
}
196+
197+
/**
198+
* Describes how mods should be sorted when getting the mods list.
199+
*/
200+
typedef ModSortingOptions = {
201+
/**
202+
* Whether or not the list should go in descending order (e.g. `[2, 1, 0]`).
203+
*/
204+
var descending:Bool;
205+
/**
206+
* The sorting mode to use.
207+
*/
208+
var mode:ModSortingMode;
209+
}
210+
211+
/**
212+
* This class performs the actual sorting for the mods list.
213+
*/
214+
class ModSortingController {
215+
/**
216+
* Sort the mods list, according to the provided sorting options.
217+
*/
218+
public static function sort(sortingOptions:ModSortingOptions, list:Array<String>):Void {
219+
switch (sortingOptions.mode) {
220+
case ModSortingMode.CLEAN: {}
221+
case ModSortingMode.ALPHABETICAL: CoolUtil.sortAlphabetically(list);
222+
}
223+
if (sortingOptions.descending) list.reverse();
224+
}
225+
}
226+
227+
/**
228+
* The mods list can be sorted in all of the ways provided by this enum.
229+
*/
230+
enum abstract ModSortingMode(String) {
231+
/**
232+
* Use the original list received from reading the directory. This may depend
233+
* on the current platform, but remains for legacy purposes.
234+
*/
235+
var CLEAN;
236+
/**
237+
* The list should be in alphabetical order.
238+
*/
239+
var ALPHABETICAL;
240+
}

source/funkin/menus/ModSwitchMenu.hx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,10 @@ class ModSwitchMenu extends MusicBeatSubstate {
2929
bg.alpha = 0;
3030
FlxTween.tween(bg, {alpha: 0.5}, 0.25, {ease: FlxEase.cubeOut});
3131

32-
mods = ModsFolder.getModsList();
32+
mods = ModsFolder.getModsList({
33+
descending: false,
34+
mode: CLEAN,
35+
});
3336
mods.push(null);
3437

3538
alphabets = new FlxTypedGroup<Alphabet>();

0 commit comments

Comments
 (0)