Skip to content

Commit

Permalink
🚧 Start working on mod discovering process and new API
Browse files Browse the repository at this point in the history
  • Loading branch information
thecatcore committed Nov 11, 2023
1 parent 08f8d3a commit 4653c3e
Show file tree
Hide file tree
Showing 10 changed files with 347 additions and 14 deletions.
17 changes: 17 additions & 0 deletions src/main/java/fr/catcore/modremapperapi/api/v1/Constants.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package fr.catcore.modremapperapi.api.v1;

import fr.catcore.modremapperapi.impl.LoaderUtils;
import net.legacyfabric.fabric.api.logger.v1.Logger;

import java.nio.file.Path;

public class Constants {
public static final Path CACHE_FOLDER = LoaderUtils.getVersionedFolder();
public static final Path LIB_FOLDER = CACHE_FOLDER.resolve("libs");
public static final Logger MAIN_LOGGER = Logger.get("ModRemappingAPI");

static {
CACHE_FOLDER.toFile().mkdirs();
LIB_FOLDER.toFile().mkdirs();
}
}
31 changes: 31 additions & 0 deletions src/main/java/fr/catcore/modremapperapi/api/v1/ModDiscoverer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package fr.catcore.modremapperapi.api.v1;

import java.nio.file.Path;

public interface ModDiscoverer {
String getId();
String getName();

String[] getModFolders();

String[] getModExtensions();

boolean isMod(String fileName);
boolean isMod(String fileName, Path filePath);

default boolean acceptAnyFile() {
return false;
}

default boolean acceptDirectories() {
return false;
}

default String getDirectoryExtension() {
return ".zip";
}

boolean addToClasspath();

boolean excludeEdits();
}
2 changes: 2 additions & 0 deletions src/main/java/fr/catcore/modremapperapi/api/v1/ModInfos.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
package fr.catcore.modremapperapi.api.v1;public interface ModInfos {
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
package fr.catcore.modremapperapi.api.v1;

public interface ModRemapper {
ModDiscoverer[] getModDiscoverers();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package fr.catcore.modremapperapi.api.v1.mapping;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({
ElementType.METHOD,
ElementType.TYPE,
ElementType.FIELD,
ElementType.PACKAGE
})
@Retention(RetentionPolicy.RUNTIME)
public @interface Renamed {
public String oldName();
}
76 changes: 76 additions & 0 deletions src/main/java/fr/catcore/modremapperapi/impl/FileUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package fr.catcore.modremapperapi.impl;

import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

public class FileUtils {
public static void emptyFolder(Path path) throws IOException {
Files.walkFileTree(path, new FileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
return FileVisitResult.CONTINUE;
}

@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Files.delete(file);
return FileVisitResult.CONTINUE;
}

@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) {
return FileVisitResult.CONTINUE;
}

@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
Files.delete(dir);
return FileVisitResult.CONTINUE;
}
});
}

public static FileSystem getJarFS(Path jar) throws URISyntaxException, IOException {
/* Define ZIP File System Properies in HashMap */
Map<String, String> zip_properties = new HashMap<>();
/* We want to read an existing ZIP File, so we set this to False */
zip_properties.put("create", "false");
/* Specify the encoding as UTF -8 */
zip_properties.put("encoding", "UTF-8");

return FileSystems.newFileSystem(new URI("jar:" + jar.toUri()), zip_properties);
}

public static void openZip(Path zip, ZipVisitor visitor) throws IOException {
InputStream fileinputstream = Files.newInputStream(zip);
ZipInputStream zipinputstream = new ZipInputStream(fileinputstream);

while (true) {
ZipEntry zipentry = zipinputstream.getNextEntry();
if (zipentry == null) {
break;
}

String s1 = zipentry.getName();
String[] ss = s1.split("/");
String s2 = ss[ss.length - 1];

if (visitor.checkEntry(zipentry, s1, s2)) break;
}

zipinputstream.close();
fileinputstream.close();
}

public interface ZipVisitor {
boolean checkEntry(ZipEntry entry, String fullName, String shortName);
}
}
35 changes: 35 additions & 0 deletions src/main/java/fr/catcore/modremapperapi/impl/LoaderUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package fr.catcore.modremapperapi.impl;

import net.fabricmc.loader.api.FabricLoader;

import java.nio.file.Path;

public class LoaderUtils {
private static Path getFabricMCPath() {
return FabricLoader.getInstance().getGameDir();
}

public static Path getMCFolder(String name) {
return getFabricMCPath().resolve(name);
}

public static Path getMainFolder() {
return getMCFolder("mod-remapping-api");
}

private static String getMCVersion() {
return FabricLoader.getInstance().getModContainer("minecraft").get().getMetadata().getVersion().getFriendlyString();
}

private static String getLoaderName() {
return "fabricloader";
}

private static String getMRAPIVersion() {
return FabricLoader.getInstance().getModContainer("mod-remapping-api").get().getMetadata().getVersion().getFriendlyString();
}

public static Path getVersionedFolder() {
return getMainFolder().resolve(getLoaderName()).resolve(getMCVersion()).resolve(getMRAPIVersion());
}
}
6 changes: 6 additions & 0 deletions src/main/java/fr/catcore/modremapperapi/impl/MRAPIImpl.java
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
package fr.catcore.modremapperapi.impl;

import fr.catcore.modremapperapi.api.v1.ModRemapper;

import java.util.ArrayList;
import java.util.List;

public class MRAPIImpl {
public static final List<ModRemapper> REMAPPERS = new ArrayList<>();
}
153 changes: 153 additions & 0 deletions src/main/java/fr/catcore/modremapperapi/impl/ModExplorer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package fr.catcore.modremapperapi.impl;

import fr.catcore.modremapperapi.api.v1.Constants;
import fr.catcore.modremapperapi.api.v1.ModDiscoverer;
import fr.catcore.modremapperapi.api.v1.ModRemapper;
import net.legacyfabric.fabric.api.logger.v1.Logger;

import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Stream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import static fr.catcore.modremapperapi.impl.FileUtils.getJarFS;
import static fr.catcore.modremapperapi.impl.FileUtils.openZip;

public class ModExplorer {
private static final Logger LOGGER = Logger.get("ModRemappingAPI", "ModExplorer");
public static void start() {
for (ModRemapper remapper : MRAPIImpl.REMAPPERS) {
for (ModDiscoverer discoverer : remapper.getModDiscoverers()) {
explore(discoverer);
}
}
}

public static void explore(ModDiscoverer discoverer) {
for (String folderName : discoverer.getModFolders()) {
Path originalPath = LoaderUtils.getMCFolder(folderName);
Path cachePath = Constants.CACHE_FOLDER.resolve(folderName);

try {
if (!Files.exists(originalPath)) {
Files.createDirectories(originalPath);
continue;
} else if (!Files.isDirectory(originalPath)) {
LOGGER.warn("Path {} is not a directory, skipping!", originalPath);
continue;
}

if (!Files.exists(cachePath)) Files.createDirectories(cachePath);
else FileUtils.emptyFolder(cachePath);

exploreFolder(discoverer, originalPath, cachePath);
} catch (IOException e) {

}
}
}

public static void exploreFolder(ModDiscoverer discoverer, Path in, Path out) throws IOException {
try (Stream<Path> stream = Files.list(in)) {
stream.forEach(item -> {
if (Files.isDirectory(item) && discoverer.acceptDirectories()) {

} else {
try {
if (isInteresting(discoverer, item) && !isFabricMod(item)) handleFile(discoverer, item);
} catch (IOException | URISyntaxException e) {
throw new RuntimeException(e);
}
}
});
}
}

public static boolean isInteresting(ModDiscoverer discoverer, Path item) {
String fileName = item.getFileName().toString();

boolean open = false;

for (String ext : discoverer.getModExtensions()) {
if (fileName.endsWith(ext)) {
open = true;
break;
}
}

return open;
}

public static void handleFile(ModDiscoverer discoverer, Path item) throws IOException, URISyntaxException {
if (discoverer.acceptAnyFile()) {

} else {
List<String> zipEntries = new ArrayList<>();
List<String> mods = new ArrayList<>();

firstRound(item, discoverer, zipEntries, mods);
secondRound(item, discoverer, zipEntries, mods);
}
}

public static boolean isFabricMod(Path item) throws IOException {
AtomicBoolean fabric = new AtomicBoolean(false);

openZip(item, (entry, fullName, shortName) -> {
if (!entry.isDirectory()) {
if (shortName.equals("fabric.mod.json") || shortName.equals("quilt.mod.json")) {
fabric.set(true);
return true;
}
}

return false;
});

return fabric.get();
}

public static void firstRound(Path mod, ModDiscoverer discoverer, List<String> entries, List<String> mods) throws IOException {
openZip(mod, (entry, fullName, shortName) -> {
if (!entry.isDirectory()) {
entries.add(fullName);

if (discoverer.isMod(fullName)) {
mods.add(fullName);
}
}

return false;
});
}

public static void secondRound(Path mod, ModDiscoverer discoverer, List<String> entries, List<String> mods) throws URISyntaxException, IOException {
try (FileSystem fs = getJarFS(mod)) {
mods.removeIf(modEntry -> {
Path modPath = fs.getPath(modEntry);

return !discoverer.isMod(modEntry, modPath);
});

for (String entry : entries) {
Path entryPath = fs.getPath(entry);

if (discoverer.isMod(entry, entryPath)) mods.add(entry);
}
}
}


}
23 changes: 9 additions & 14 deletions src/main/legacyJava/fr/catcore/modremapperapi/utils/Constants.java
Original file line number Diff line number Diff line change
@@ -1,26 +1,21 @@
package fr.catcore.modremapperapi.utils;

import fr.catcore.modremapperapi.impl.LoaderUtils;
import net.fabricmc.loader.api.FabricLoader;
import net.legacyfabric.fabric.api.logger.v1.Logger;

import java.io.File;

public class Constants {
public static final File MAIN_FOLDER = new File(FabricLoader.getInstance().getGameDir().toFile(), "mod-remapping-api");
public static final File VERSIONED_FOLDER = new File(
new File(MAIN_FOLDER,
FabricLoader.getInstance().getModContainer("minecraft").get().getMetadata().getVersion().getFriendlyString()
), FabricLoader.getInstance().getModContainer("mod-remapping-api").get().getMetadata().getVersion().getFriendlyString()
);
@Deprecated
public static final File MAIN_FOLDER = LoaderUtils.getMainFolder().toFile();
@Deprecated
public static final File VERSIONED_FOLDER = fr.catcore.modremapperapi.api.v1.Constants.CACHE_FOLDER.toFile();
public static final File EXTRA_MAPPINGS_FILE = new File(VERSIONED_FOLDER, "extra_mappings.tiny");
public static final File REMAPPED_MAPPINGS_FILE = new File(VERSIONED_FOLDER, "remapped_mappings.tiny");

public static final File LIB_FOLDER = new File(VERSIONED_FOLDER, "libs");
public static final Logger MAIN_LOGGER = Logger.get("ModRemappingAPI");

static {
MAIN_FOLDER.mkdirs();
VERSIONED_FOLDER.mkdirs();
LIB_FOLDER.mkdirs();
}
@Deprecated
public static final File LIB_FOLDER = fr.catcore.modremapperapi.api.v1.Constants.LIB_FOLDER.toFile();
@Deprecated
public static final Logger MAIN_LOGGER = fr.catcore.modremapperapi.api.v1.Constants.MAIN_LOGGER;
}

0 comments on commit 4653c3e

Please sign in to comment.