diff --git a/src/main/java/fr/catcore/modremapperapi/api/v1/Constants.java b/src/main/java/fr/catcore/modremapperapi/api/v1/Constants.java new file mode 100644 index 0000000..fba0f81 --- /dev/null +++ b/src/main/java/fr/catcore/modremapperapi/api/v1/Constants.java @@ -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(); + } +} diff --git a/src/main/java/fr/catcore/modremapperapi/api/v1/ModDiscoverer.java b/src/main/java/fr/catcore/modremapperapi/api/v1/ModDiscoverer.java new file mode 100644 index 0000000..c55eea0 --- /dev/null +++ b/src/main/java/fr/catcore/modremapperapi/api/v1/ModDiscoverer.java @@ -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(); +} diff --git a/src/main/java/fr/catcore/modremapperapi/api/v1/ModInfos.java b/src/main/java/fr/catcore/modremapperapi/api/v1/ModInfos.java new file mode 100644 index 0000000..1083859 --- /dev/null +++ b/src/main/java/fr/catcore/modremapperapi/api/v1/ModInfos.java @@ -0,0 +1,2 @@ +package fr.catcore.modremapperapi.api.v1;public interface ModInfos { +} diff --git a/src/main/java/fr/catcore/modremapperapi/api/v1/ModRemapper.java b/src/main/java/fr/catcore/modremapperapi/api/v1/ModRemapper.java index 696b610..ca8ed93 100644 --- a/src/main/java/fr/catcore/modremapperapi/api/v1/ModRemapper.java +++ b/src/main/java/fr/catcore/modremapperapi/api/v1/ModRemapper.java @@ -1,4 +1,5 @@ package fr.catcore.modremapperapi.api.v1; public interface ModRemapper { + ModDiscoverer[] getModDiscoverers(); } diff --git a/src/main/java/fr/catcore/modremapperapi/api/v1/mapping/Renamed.java b/src/main/java/fr/catcore/modremapperapi/api/v1/mapping/Renamed.java new file mode 100644 index 0000000..f88cc0e --- /dev/null +++ b/src/main/java/fr/catcore/modremapperapi/api/v1/mapping/Renamed.java @@ -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(); +} diff --git a/src/main/java/fr/catcore/modremapperapi/impl/FileUtils.java b/src/main/java/fr/catcore/modremapperapi/impl/FileUtils.java new file mode 100644 index 0000000..1f6efaa --- /dev/null +++ b/src/main/java/fr/catcore/modremapperapi/impl/FileUtils.java @@ -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() { + @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 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); + } +} diff --git a/src/main/java/fr/catcore/modremapperapi/impl/LoaderUtils.java b/src/main/java/fr/catcore/modremapperapi/impl/LoaderUtils.java new file mode 100644 index 0000000..dc0fbca --- /dev/null +++ b/src/main/java/fr/catcore/modremapperapi/impl/LoaderUtils.java @@ -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()); + } +} diff --git a/src/main/java/fr/catcore/modremapperapi/impl/MRAPIImpl.java b/src/main/java/fr/catcore/modremapperapi/impl/MRAPIImpl.java index 55a57ca..34c1dc2 100644 --- a/src/main/java/fr/catcore/modremapperapi/impl/MRAPIImpl.java +++ b/src/main/java/fr/catcore/modremapperapi/impl/MRAPIImpl.java @@ -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 REMAPPERS = new ArrayList<>(); } diff --git a/src/main/java/fr/catcore/modremapperapi/impl/ModExplorer.java b/src/main/java/fr/catcore/modremapperapi/impl/ModExplorer.java new file mode 100644 index 0000000..7069f05 --- /dev/null +++ b/src/main/java/fr/catcore/modremapperapi/impl/ModExplorer.java @@ -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 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 zipEntries = new ArrayList<>(); + List 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 entries, List 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 entries, List 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); + } + } + } + + +} diff --git a/src/main/legacyJava/fr/catcore/modremapperapi/utils/Constants.java b/src/main/legacyJava/fr/catcore/modremapperapi/utils/Constants.java index 0087220..d245328 100644 --- a/src/main/legacyJava/fr/catcore/modremapperapi/utils/Constants.java +++ b/src/main/legacyJava/fr/catcore/modremapperapi/utils/Constants.java @@ -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; }