优化模组加载器检测机制 (#4622)
This commit is contained in:
@@ -191,7 +191,7 @@ public final class LauncherHelper {
|
||||
LaunchOptions launchOptions = repository.getLaunchOptions(
|
||||
selectedVersion, javaVersionRef.get(), profile.getGameDir(), javaAgents, javaArguments, scriptFile != null);
|
||||
|
||||
LOG.info("Here's the structure of game mod directory:\n" + FileUtils.printFileStructure(repository.getModManager(selectedVersion).getModsDirectory(), 10));
|
||||
LOG.info("Here's the structure of game mod directory:\n" + FileUtils.printFileStructure(repository.getModsDirectory(selectedVersion), 10));
|
||||
|
||||
return new HMCLGameLauncher(
|
||||
repository,
|
||||
|
||||
@@ -149,6 +149,11 @@ public class DefaultGameRepository implements GameRepository {
|
||||
return getVersionRoot(id).resolve("natives-" + platform);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getModsDirectory(String id) {
|
||||
return getRunDirectory(id).resolve("mods");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getVersionRoot(String id) {
|
||||
return getBaseDirectory().resolve("versions/" + id);
|
||||
|
||||
@@ -131,6 +131,12 @@ public interface GameRepository extends VersionProvider {
|
||||
*/
|
||||
Path getNativeDirectory(String id, Platform platform);
|
||||
|
||||
/// Get the directory for placing mod files.
|
||||
///
|
||||
/// @param id instance id
|
||||
/// @return the mods directory
|
||||
Path getModsDirectory(String id);
|
||||
|
||||
/**
|
||||
* Get minecraft jar
|
||||
*
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
package org.jackhuang.hmcl.mod;
|
||||
|
||||
import com.google.gson.JsonParseException;
|
||||
import org.jackhuang.hmcl.download.LibraryAnalyzer;
|
||||
import org.jackhuang.hmcl.game.GameRepository;
|
||||
import org.jackhuang.hmcl.mod.modinfo.*;
|
||||
import org.jackhuang.hmcl.util.Pair;
|
||||
@@ -30,34 +31,39 @@ import java.io.IOException;
|
||||
import java.nio.file.*;
|
||||
import java.util.*;
|
||||
|
||||
import static org.jackhuang.hmcl.util.Pair.pair;
|
||||
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
|
||||
|
||||
public final class ModManager {
|
||||
@FunctionalInterface
|
||||
private interface ModMetadataReader {
|
||||
LocalModFile fromFile(ModManager modManager, Path modFile, FileSystem fs) throws IOException, JsonParseException;
|
||||
}
|
||||
|
||||
private static final Map<String, Pair<ModMetadataReader[], String>> READERS;
|
||||
private static final Map<String, List<Pair<ModMetadataReader, Set<ModLoaderType>>>> READERS;
|
||||
|
||||
static {
|
||||
TreeMap<String, Pair<ModMetadataReader[], String>> readers = new TreeMap<>();
|
||||
readers.put("zip", Pair.pair(new ModMetadataReader[]{
|
||||
ForgeOldModMetadata::fromFile,
|
||||
ForgeNewModMetadata::fromFile,
|
||||
FabricModMetadata::fromFile,
|
||||
QuiltModMetadata::fromFile,
|
||||
PackMcMeta::fromFile,
|
||||
}, ""));
|
||||
readers.put("jar", readers.get("zip"));
|
||||
readers.put("litemod", Pair.pair(new ModMetadataReader[]{
|
||||
LiteModMetadata::fromFile
|
||||
}, "LiteLoader Mod"));
|
||||
READERS = Collections.unmodifiableMap(readers);
|
||||
var map = new HashMap<String, List<Pair<ModMetadataReader, Set<ModLoaderType>>>>();
|
||||
var zipReaders = List.<Pair<ModMetadataReader, Set<ModLoaderType>>>of(
|
||||
pair(ForgeNewModMetadata::fromFile, EnumSet.of(ModLoaderType.FORGE, ModLoaderType.NEO_FORGED)),
|
||||
pair(ForgeOldModMetadata::fromFile, EnumSet.of(ModLoaderType.FORGE)),
|
||||
pair(FabricModMetadata::fromFile, EnumSet.of(ModLoaderType.FABRIC)),
|
||||
pair(QuiltModMetadata::fromFile, EnumSet.of(ModLoaderType.QUILT)),
|
||||
pair(PackMcMeta::fromFile, EnumSet.of(ModLoaderType.PACK))
|
||||
);
|
||||
|
||||
map.put("zip", zipReaders);
|
||||
map.put("jar", zipReaders);
|
||||
map.put("litemod", List.of(pair(LiteModMetadata::fromFile, EnumSet.of(ModLoaderType.LITE_LOADER))));
|
||||
|
||||
READERS = map;
|
||||
}
|
||||
|
||||
private final GameRepository repository;
|
||||
private final String id;
|
||||
private final TreeSet<LocalModFile> localModFiles = new TreeSet<>();
|
||||
private final HashMap<LocalMod, LocalMod> localMods = new HashMap<>();
|
||||
private LibraryAnalyzer analyzer;
|
||||
|
||||
private boolean loaded = false;
|
||||
|
||||
@@ -70,12 +76,12 @@ public final class ModManager {
|
||||
return repository;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
public String getInstanceId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public Path getModsDirectory() {
|
||||
return repository.getRunDirectory(id).resolve("mods");
|
||||
return repository.getModsDirectory(id);
|
||||
}
|
||||
|
||||
public LocalMod getLocalMod(String id, ModLoaderType modLoaderType) {
|
||||
@@ -83,44 +89,82 @@ public final class ModManager {
|
||||
}
|
||||
|
||||
private void addModInfo(Path file) {
|
||||
try {
|
||||
LocalModFile localModFile = getModInfo(file);
|
||||
if (!localModFile.isOld()) {
|
||||
localModFiles.add(localModFile);
|
||||
}
|
||||
} catch (IllegalArgumentException ignore) {
|
||||
}
|
||||
}
|
||||
|
||||
public LocalModFile getModInfo(Path modFile) {
|
||||
String fileName = StringUtils.removeSuffix(FileUtils.getName(modFile), DISABLED_EXTENSION, OLD_EXTENSION);
|
||||
String fileName = StringUtils.removeSuffix(FileUtils.getName(file), DISABLED_EXTENSION, OLD_EXTENSION);
|
||||
String extension = fileName.substring(fileName.lastIndexOf(".") + 1);
|
||||
Pair<ModMetadataReader[], String> currentReader = READERS.get(extension);
|
||||
if (currentReader == null) {
|
||||
throw new IllegalArgumentException("File " + modFile + " is not a mod file.");
|
||||
|
||||
List<Pair<ModMetadataReader, Set<ModLoaderType>>> readersMap = READERS.get(extension);
|
||||
if (readersMap == null) {
|
||||
// Is not a mod file.
|
||||
return;
|
||||
}
|
||||
|
||||
try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(modFile)) {
|
||||
for (ModMetadataReader reader : currentReader.getKey()) {
|
||||
Set<ModLoaderType> modLoaderTypes = analyzer.getModLoaders();
|
||||
|
||||
var supportedReaders = new ArrayList<ModMetadataReader>();
|
||||
var unsupportedReaders = new ArrayList<ModMetadataReader>();
|
||||
|
||||
for (Pair<ModMetadataReader, Set<ModLoaderType>> reader : readersMap) {
|
||||
boolean supported = false;
|
||||
for (ModLoaderType type : reader.getValue()) {
|
||||
if (modLoaderTypes.contains(type)) {
|
||||
supported = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (supported) {
|
||||
supportedReaders.add(reader.getKey());
|
||||
} else {
|
||||
unsupportedReaders.add(reader.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
LocalModFile modInfo = null;
|
||||
|
||||
try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(file)) {
|
||||
for (ModMetadataReader reader : supportedReaders) {
|
||||
try {
|
||||
return reader.fromFile(this, modFile, fs);
|
||||
modInfo = reader.fromFile(this, file, fs);
|
||||
break;
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
|
||||
if (modInfo == null) {
|
||||
for (ModMetadataReader reader : unsupportedReaders) {
|
||||
try {
|
||||
modInfo = reader.fromFile(this, file, fs);
|
||||
break;
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.warning("Failed to open mod file " + file, e);
|
||||
}
|
||||
|
||||
return new LocalModFile(this,
|
||||
getLocalMod(FileUtils.getNameWithoutExtension(modFile), ModLoaderType.UNKNOWN),
|
||||
modFile,
|
||||
FileUtils.getNameWithoutExtension(modFile),
|
||||
new LocalModFile.Description(currentReader.getValue())
|
||||
);
|
||||
if (modInfo == null) {
|
||||
String fileNameWithoutExtension = FileUtils.getNameWithoutExtension(file);
|
||||
|
||||
modInfo = new LocalModFile(this,
|
||||
getLocalMod(fileNameWithoutExtension, ModLoaderType.UNKNOWN),
|
||||
file,
|
||||
fileNameWithoutExtension,
|
||||
new LocalModFile.Description("litemod".equals(extension) ? "LiteLoader Mod" : "")
|
||||
);
|
||||
}
|
||||
|
||||
if (!modInfo.isOld()) {
|
||||
localModFiles.add(modInfo);
|
||||
}
|
||||
}
|
||||
|
||||
public void refreshMods() throws IOException {
|
||||
localModFiles.clear();
|
||||
localMods.clear();
|
||||
|
||||
analyzer = LibraryAnalyzer.analyze(getRepository().getResolvedPreservingPatchesVersion(id), null);
|
||||
|
||||
if (Files.isDirectory(getModsDirectory())) {
|
||||
try (DirectoryStream<Path> modsDirectoryStream = Files.newDirectoryStream(getModsDirectory())) {
|
||||
for (Path subitem : modsDirectoryStream) {
|
||||
|
||||
@@ -138,7 +138,7 @@ public final class CurseCompletionTask extends Task<Void> {
|
||||
.collect(Collectors.toList()));
|
||||
JsonUtils.writeToJsonFile(root.resolve("manifest.json"), newManifest);
|
||||
|
||||
Path versionRoot = repository.getVersionRoot(modManager.getVersion());
|
||||
Path versionRoot = repository.getVersionRoot(modManager.getInstanceId());
|
||||
Path resourcePacksRoot = versionRoot.resolve("resourcepacks");
|
||||
Path shaderPacksRoot = versionRoot.resolve("shaderpacks");
|
||||
finished.set(0);
|
||||
|
||||
@@ -273,7 +273,7 @@ public class McbbsModpackCompletionTask extends CompletableFutureTask<Void> {
|
||||
@Nullable
|
||||
private Path getFilePath(McbbsModpackManifest.File file) {
|
||||
if (file instanceof McbbsModpackManifest.AddonFile) {
|
||||
return modManager.getRepository().getRunDirectory(modManager.getVersion()).resolve(((McbbsModpackManifest.AddonFile) file).getPath());
|
||||
return modManager.getRepository().getRunDirectory(modManager.getInstanceId()).resolve(((McbbsModpackManifest.AddonFile) file).getPath());
|
||||
} else if (file instanceof McbbsModpackManifest.CurseFile) {
|
||||
String fileName = ((McbbsModpackManifest.CurseFile) file).getFileName();
|
||||
if (fileName == null) return null;
|
||||
|
||||
Reference in New Issue
Block a user