From 661d340944f433b49b7298343ba39451bf5e78c1 Mon Sep 17 00:00:00 2001 From: ILikePlayingGames <22475143+ILikePlayingGames@users.noreply.github.com> Date: Wed, 10 Jul 2024 22:10:19 -0400 Subject: [PATCH 1/6] Various buildscript improvements - Add DevAuth for logging into online mode servers (disabled by default) - Fill in mod version during build in ForgeModAPI.java - Fix gradle running out of memory during `gradlew setupDecompWorkspace` - Add some development tips to README.md - Change logging to log4j in ForgeModAPI.java --- README.md | 11 ++++++++++- build.gradle | 7 +++++++ gradle.properties | 2 ++ .../java/net/hypixel/modapi/forge/ForgeModAPI.java | 13 +++++++------ 4 files changed, 26 insertions(+), 7 deletions(-) create mode 100644 gradle.properties diff --git a/README.md b/README.md index b309cd8..bf922d2 100644 --- a/README.md +++ b/README.md @@ -5,4 +5,13 @@ This repository contains the implementation of the Hypixel Mod API for the Froge ## Contributing -If you wish to contribute to this implementation of the Mod API to offer improvements or fixes, you can do so by forking the repository and creating a pull request. \ No newline at end of file +If you wish to contribute to this implementation of the Mod API to offer improvements or fixes, you can do so by forking the repository and creating a pull request. + +> [!IMPORTANT] +> Run `gradlew setupDecompWorkspace` after importing the project to generate the files required to build it + +If IntelliJ still shows unknown symbol errors after running the command, you may need to [clear the filesystem cache](https://www.jetbrains.com/help/idea/invalidate-caches.html). + +### Testing Your Changes + +You can enable DevAuth to log in to the Hypixel server with your Minecraft account. Please see the [DevAuth docs](https://github.com/DJtheRedstoner/DevAuth) for more details. \ No newline at end of file diff --git a/build.gradle b/build.gradle index b6ba6fd..e198753 100755 --- a/build.gradle +++ b/build.gradle @@ -22,6 +22,9 @@ repositories { maven { url "https://repo.hypixel.net/repository/Hypixel/" } + maven { + url "https://pkgs.dev.azure.com/djtheredstoner/DevAuth/_packaging/public/maven/v1" + } mavenLocal() } @@ -31,6 +34,9 @@ minecraft { runDir = "run" mappings = "stable_22" + + replace('${version}', project.version) + replaceIn("ForgeModAPI.java") } configurations { @@ -40,6 +46,7 @@ configurations { dependencies { shade "net.hypixel:mod-api:1.0" + runtimeOnly "me.djtheredstoner:DevAuth-forge-legacy:1.2.1" } jar { diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..fbb5570 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,2 @@ +# Ensure Gradle has enough RAM to decompile Minecraft +org.gradle.jvmargs=-Xmx2G \ No newline at end of file diff --git a/src/main/java/net/hypixel/modapi/forge/ForgeModAPI.java b/src/main/java/net/hypixel/modapi/forge/ForgeModAPI.java index c7c31c2..dfbcce8 100644 --- a/src/main/java/net/hypixel/modapi/forge/ForgeModAPI.java +++ b/src/main/java/net/hypixel/modapi/forge/ForgeModAPI.java @@ -20,14 +20,14 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.network.FMLNetworkEvent; -import java.util.logging.Level; -import java.util.logging.Logger; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; @Mod(modid = ForgeModAPI.MODID, version = ForgeModAPI.VERSION, clientSideOnly = true, name = "Hypixel Mod API") public class ForgeModAPI { public static final String MODID = "hypixel_mod_api"; - public static final String VERSION = "1.0.0.1"; - private static final Logger LOGGER = Logger.getLogger("HypixelModAPI"); + public static final String VERSION = "${version}"; + private static final Logger LOGGER = LogManager.getLogger("HypixelModAPI"); // We store a local reference to the net handler, so it's instantly available from the moment we connect private NetHandlerPlayClient netHandler; @@ -36,6 +36,7 @@ public class ForgeModAPI { public void init(FMLPostInitializationEvent event) { MinecraftForge.EVENT_BUS.register(this); HypixelModAPI.getInstance().setPacketSender(this::sendPacket); + LOGGER.debug("Hypixel Mod API initialized"); } @SubscribeEvent(priority = EventPriority.LOWEST) @@ -55,7 +56,7 @@ private boolean sendPacket(HypixelPacket packet) { } if (!netHandler.getNetworkManager().isChannelOpen()) { - LOGGER.warning("Attempted to send packet while channel is closed!"); + LOGGER.warn("Attempted to send packet while channel is closed!"); netHandler = null; return false; } @@ -91,7 +92,7 @@ protected void channelRead0(ChannelHandlerContext ctx, Packet msg) { try { HypixelModAPI.getInstance().handle(identifier, new PacketSerializer(buffer)); } catch (Exception e) { - LOGGER.log(Level.WARNING, "Failed to handle packet " + identifier, e); + LOGGER.warn("Failed to handle packet {}", identifier, e); } finally { buffer.release(); } From 2a556a687a4fbd9298daa6fa00d0b18de6315038 Mon Sep 17 00:00:00 2001 From: ILikePlayingGames <22475143+ILikePlayingGames@users.noreply.github.com> Date: Wed, 10 Jul 2024 22:12:41 -0400 Subject: [PATCH 2/6] Remove test log line --- src/main/java/net/hypixel/modapi/forge/ForgeModAPI.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/net/hypixel/modapi/forge/ForgeModAPI.java b/src/main/java/net/hypixel/modapi/forge/ForgeModAPI.java index dfbcce8..282408c 100644 --- a/src/main/java/net/hypixel/modapi/forge/ForgeModAPI.java +++ b/src/main/java/net/hypixel/modapi/forge/ForgeModAPI.java @@ -36,7 +36,6 @@ public class ForgeModAPI { public void init(FMLPostInitializationEvent event) { MinecraftForge.EVENT_BUS.register(this); HypixelModAPI.getInstance().setPacketSender(this::sendPacket); - LOGGER.debug("Hypixel Mod API initialized"); } @SubscribeEvent(priority = EventPriority.LOWEST) From 6671846319d1fcc5b8b999a77f297b098763535d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linnea=20Gr=C3=A4f?= Date: Fri, 12 Jul 2024 18:23:37 +0200 Subject: [PATCH 3/6] Add tweaker loader --- build.gradle | 22 +- settings.gradle | 1 + tweaker/build.gradle | 22 ++ .../modapi/tweaker/HypixelModAPITweaker.java | 200 ++++++++++++++++++ 4 files changed, 235 insertions(+), 10 deletions(-) create mode 100644 settings.gradle create mode 100644 tweaker/build.gradle create mode 100644 tweaker/src/main/java/net/hypixel/modapi/tweaker/HypixelModAPITweaker.java diff --git a/build.gradle b/build.gradle index b6ba6fd..36577c8 100755 --- a/build.gradle +++ b/build.gradle @@ -11,20 +11,22 @@ buildscript { } } apply plugin: 'net.minecraftforge.gradle.forge' +allprojects { + version = "1.0.0.1" // First 3 numbers should correspond to the version of the API, last number is for the mod itself for any changes/fixes + group = "net.hypixel.modapi" // http://maven.apache.org/guides/mini/guide-naming-conventions.html + archivesBaseName = "HypixelModAPI" -version = "1.0.0.1" // First 3 numbers should correspond to the version of the API, last number is for the mod itself for any changes/fixes -group = "net.hypixel.modapi" // http://maven.apache.org/guides/mini/guide-naming-conventions.html -archivesBaseName = "HypixelModAPI" -sourceCompatibility = 1.8 -targetCompatibility = 1.8 - -repositories { - maven { - url "https://repo.hypixel.net/repository/Hypixel/" + repositories { + maven { + url "https://repo.hypixel.net/repository/Hypixel/" + } + mavenLocal() } - mavenLocal() } +sourceCompatibility = 1.8 +targetCompatibility = 1.8 + minecraft { version = "1.8.9-11.15.1.1722" // version = "1.8.9-11.15.1.2318-1.8.9" diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..54eaa93 --- /dev/null +++ b/settings.gradle @@ -0,0 +1 @@ +include 'tweaker' \ No newline at end of file diff --git a/tweaker/build.gradle b/tweaker/build.gradle new file mode 100644 index 0000000..8962b17 --- /dev/null +++ b/tweaker/build.gradle @@ -0,0 +1,22 @@ +apply plugin: 'net.minecraftforge.gradle.forge' + +minecraft { + version = "1.8.9-11.15.1.1722" +// version = "1.8.9-11.15.1.2318-1.8.9" + runDir = "run" + + mappings = "stable_22" +} + +sourceCompatibility = 1.8 +targetCompatibility = 1.8 + +task generateVersionInfo(type: WriteProperties) { + outputFile(file(new File(buildDir, "/properties/hypixel-mod-api-bundled.properties"))) + property("version", version) +} + +tasks.jar { + from(project(":").jar) + from(generateVersionInfo) +} diff --git a/tweaker/src/main/java/net/hypixel/modapi/tweaker/HypixelModAPITweaker.java b/tweaker/src/main/java/net/hypixel/modapi/tweaker/HypixelModAPITweaker.java new file mode 100644 index 0000000..857433c --- /dev/null +++ b/tweaker/src/main/java/net/hypixel/modapi/tweaker/HypixelModAPITweaker.java @@ -0,0 +1,200 @@ +package net.hypixel.modapi.tweaker; + +import net.minecraft.launchwrapper.ITweaker; +import net.minecraft.launchwrapper.Launch; +import net.minecraft.launchwrapper.LaunchClassLoader; +import net.minecraftforge.fml.relauncher.CoreModManager; +import org.apache.commons.io.IOUtils; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Files; +import java.util.List; +import java.util.Objects; +import java.util.Properties; + +/** + * A tweaker class to automatically load the hypixel mod api while resolving conflicts + * from multiple mods providing a copy. This saves users from having to download the + * mod api separately. + */ +public class HypixelModAPITweaker implements ITweaker { + + public static final String VERSION_NAME; + public static final long VERSION; + + static { + // Load version information from the .properties generated by the gradle task generateVersionInfo + Properties properties = new Properties(); + try { + properties.load(HypixelModAPITweaker.class.getResourceAsStream("/hypixel-mod-api-bundled.properties")); + } catch (IOException e) { + e.printStackTrace(); + } + VERSION_NAME = properties.getProperty("version", "0.0.0.0"); + String[] versionComponents = VERSION_NAME.split("\\."); + assert versionComponents.length == 4; + // We pack each of the four version components into a long. + // To do so we use the biggest number that can fit 4 times into a long: + //noinspection ConstantValue + assert Math.pow(10000, 4) < Long.MAX_VALUE; + long version = 0; + for (int i = 0; i < 4; i++) { + version *= 10000; + version += Long.parseLong(versionComponents[i]); + } + VERSION = version; + } + + public static final String BUNDLED_JAR_NAME = "HypixelModAPI-" + VERSION_NAME + ".jar"; + + /** + * This is the key which is used in the {@link Launch#blackboard} to perform + * version negotiation. + * + * @see #getBlackboardVersion() + * @see #offerVersionToBlackboard() + */ + public static final String VERSION_KEY = "net.hypixel.mod-api.version:1"; + + private boolean hasOfferedVersion = false; + + /** + * Get the current version declared on the blackboard. + * The blackboard allows us to store arbitrary values. We store an int indicating the max version installed. + * + * @see #VERSION_KEY + */ + public static long getBlackboardVersion() { + Object blackboardVersion = Launch.blackboard.get(VERSION_KEY); + // In case nobody has declared a version on the blackboard yet, we return an incredibly outdated past version + if (blackboardVersion == null) return Long.MIN_VALUE; + // In case we later switch to another version format we declare any non-integer as an incredibly advanced future version + if (!(blackboardVersion instanceof Long)) return Long.MAX_VALUE; + return (Long) blackboardVersion; + } + + /** + * Inject our API jar into forge if we are the highest available version. + * + * @see #injectAPI() + */ + private void tryInjectAPI() { + // If the maximum installed version isn't our version return + if (getBlackboardVersion() != VERSION) return; + // If we didn't offer to install this version return + if (!hasOfferedVersion) return; + + injectAPI(); + } + + /** + * Unpacks the actual API file into a temporary folder from where it can be loaded. + * + * @return the location of the extracted API + */ + private File unpackAPI() { + File extractedFile = new File("hypixel-mod-api/" + BUNDLED_JAR_NAME).getAbsoluteFile(); + //noinspection ResultOfMethodCallIgnored + extractedFile.getParentFile().mkdirs(); + try (InputStream bundledJar = Objects.requireNonNull( + getClass().getResourceAsStream("/" + BUNDLED_JAR_NAME), + "Could not find bundled hypixel mod api"); + OutputStream outputStream = Files.newOutputStream(extractedFile.toPath())) { + IOUtils.copy(bundledJar, outputStream); + return extractedFile; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * @return the jar containing this class + */ + private File getThisJar() { + URL thisJarURL = getClass().getProtectionDomain().getCodeSource().getLocation(); + if (thisJarURL == null) return null; + if (!"file".equals(thisJarURL.getProtocol())) return null; + try { + return new File(thisJarURL.toURI()).getAbsoluteFile(); + } catch (URISyntaxException ignored) { + } + return null; + } + + /** + * Inject the API into Forge to be loaded as a mod. This will also extract the JAR. + */ + private void injectAPI() { + CoreModManager.getReparseableCoremods() + .add(unpackAPI().getPath()); + } + + /** + * Instruct Forge to load the current JAR as a mod. + * By default, Forge does not load mods if they contain a tweaker, only loading the tweaker instead. + * This function will remove this JAR from the list of ignored mods and schedule it to be scanned for mods. + */ + private void allowModLoading() { + File file = getThisJar(); + if (file != null) { + CoreModManager.getReparseableCoremods() + .add(file.getPath()); + CoreModManager.getIgnoredMods() + .remove(file.getPath()); + } + } + + /** + * Offers our bundled version to the {@link Launch#blackboard}. If there is already a + * higher version than ours installed then this will not do anything. Otherwise, it + * will set {@link #hasOfferedVersion} and increment the version in the blackboard. + * + * @see #VERSION_KEY + */ + private void offerVersionToBlackboard() { + if (getBlackboardVersion() < VERSION) { + hasOfferedVersion = true; + Launch.blackboard.put(VERSION_KEY, VERSION); + } + } + + /* + Below here are all the ITweaker methods. The tweaker methods are executed in rounds. + + 1. Run class init and init (constructor) for each tweaker + 2. Run acceptOptions for each tweaker + 3. Run injectIntoClassLoader for each tweaker + 4. If any cascading tweakers have been registered, go back to step 1 + 5. After there are no new tweakers after an entire round: + 6. Run getLaunchArguments for each tweaker + 7. Run getLaunchTarget only on the first tweaker found (and execute that class) + + By first offering our version negotiation in acceptOptions or injectIntoClassloader and + then injection our JARs in getLaunchArguments, we can ensure that every tweaker had time + to make their version announcement heard. + */ + @Override + public void acceptOptions(List args, File gameDir, File assetsDir, String profile) { + offerVersionToBlackboard(); + } + + @Override + public void injectIntoClassLoader(LaunchClassLoader classLoader) { + } + + @Override + public String getLaunchTarget() { + return null; + } + + @Override + public String[] getLaunchArguments() { + tryInjectAPI(); + return new String[0]; + } +} From 044900d6c238ba797423e0ad6b52aab0bdbcf3e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linnea=20Gr=C3=A4f?= Date: Fri, 12 Jul 2024 18:45:35 +0200 Subject: [PATCH 4/6] Add logging --- .../modapi/tweaker/HypixelModAPITweaker.java | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/tweaker/src/main/java/net/hypixel/modapi/tweaker/HypixelModAPITweaker.java b/tweaker/src/main/java/net/hypixel/modapi/tweaker/HypixelModAPITweaker.java index 857433c..6195833 100644 --- a/tweaker/src/main/java/net/hypixel/modapi/tweaker/HypixelModAPITweaker.java +++ b/tweaker/src/main/java/net/hypixel/modapi/tweaker/HypixelModAPITweaker.java @@ -5,6 +5,8 @@ import net.minecraft.launchwrapper.LaunchClassLoader; import net.minecraftforge.fml.relauncher.CoreModManager; import org.apache.commons.io.IOUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import java.io.File; import java.io.IOException; @@ -24,6 +26,7 @@ */ public class HypixelModAPITweaker implements ITweaker { + private static Logger LOGGER = LogManager.getLogger(); public static final String VERSION_NAME; public static final long VERSION; @@ -33,9 +36,10 @@ public class HypixelModAPITweaker implements ITweaker { try { properties.load(HypixelModAPITweaker.class.getResourceAsStream("/hypixel-mod-api-bundled.properties")); } catch (IOException e) { - e.printStackTrace(); + LOGGER.error("Could not load version information for bundled hypixel mod API", e); } VERSION_NAME = properties.getProperty("version", "0.0.0.0"); + LOGGER.info("Loaded bundled hypixel mod API version as {}", VERSION_NAME); String[] versionComponents = VERSION_NAME.split("\\."); assert versionComponents.length == 4; // We pack each of the four version components into a long. @@ -48,6 +52,7 @@ public class HypixelModAPITweaker implements ITweaker { version += Long.parseLong(versionComponents[i]); } VERSION = version; + LOGGER.info("Loaded bundled hypixel mod API numeric version as {}", VERSION); } public static final String BUNDLED_JAR_NAME = "HypixelModAPI-" + VERSION_NAME + ".jar"; @@ -85,9 +90,15 @@ public static long getBlackboardVersion() { */ private void tryInjectAPI() { // If the maximum installed version isn't our version return - if (getBlackboardVersion() != VERSION) return; + if (getBlackboardVersion() != VERSION) { + LOGGER.info("Blackboard version newer than our version {}. Skipping injecting API.", VERSION); + return; + } // If we didn't offer to install this version return - if (!hasOfferedVersion) return; + if (!hasOfferedVersion) { + LOGGER.info("Someone else with the same version number {} offered to inject themselves first. Skipping injecting API.", VERSION); + return; + } injectAPI(); } @@ -99,6 +110,7 @@ private void tryInjectAPI() { */ private File unpackAPI() { File extractedFile = new File("hypixel-mod-api/" + BUNDLED_JAR_NAME).getAbsoluteFile(); + LOGGER.info("Unpacking mod API to {}", extractedFile); //noinspection ResultOfMethodCallIgnored extractedFile.getParentFile().mkdirs(); try (InputStream bundledJar = Objects.requireNonNull( @@ -106,8 +118,10 @@ private File unpackAPI() { "Could not find bundled hypixel mod api"); OutputStream outputStream = Files.newOutputStream(extractedFile.toPath())) { IOUtils.copy(bundledJar, outputStream); + LOGGER.info("Successfully extracted mod API file"); return extractedFile; } catch (IOException e) { + LOGGER.error("Could not extract mod API file", e); throw new RuntimeException(e); } } @@ -130,6 +144,7 @@ private File getThisJar() { * Inject the API into Forge to be loaded as a mod. This will also extract the JAR. */ private void injectAPI() { + LOGGER.info("Injecting mod API of version {}", VERSION_NAME); CoreModManager.getReparseableCoremods() .add(unpackAPI().getPath()); } @@ -146,6 +161,9 @@ private void allowModLoading() { .add(file.getPath()); CoreModManager.getIgnoredMods() .remove(file.getPath()); + LOGGER.info("Re-added mod {} to the mod candidate list.", file); + } else { + LOGGER.warn("Did not find JAR including this tweaker, cannot re-add mod."); } } @@ -158,6 +176,7 @@ private void allowModLoading() { */ private void offerVersionToBlackboard() { if (getBlackboardVersion() < VERSION) { + LOGGER.info("Offering newer version {} > {}", VERSION, getBlackboardVersion()); hasOfferedVersion = true; Launch.blackboard.put(VERSION_KEY, VERSION); } From ebbe3df91ffc7194cd533b409db8b125aa09b686 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linnea=20Gr=C3=A4f?= Date: Fri, 12 Jul 2024 21:38:29 +0200 Subject: [PATCH 5/6] Fix depending on not reobfJar --- build.gradle | 16 ++++++++++++++-- tweaker/build.gradle | 4 ++++ .../modapi/tweaker/HypixelModAPITweaker.java | 10 ++++++++-- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index 36577c8..63a7dca 100755 --- a/build.gradle +++ b/build.gradle @@ -12,8 +12,9 @@ buildscript { } apply plugin: 'net.minecraftforge.gradle.forge' allprojects { - version = "1.0.0.1" // First 3 numbers should correspond to the version of the API, last number is for the mod itself for any changes/fixes - group = "net.hypixel.modapi" // http://maven.apache.org/guides/mini/guide-naming-conventions.html + apply plugin: 'maven-publish' + version = "1.0.0.2" // First 3 numbers should correspond to the version of the API, last number is for the mod itself for any changes/fixes + group = "net.hypixel" // http://maven.apache.org/guides/mini/guide-naming-conventions.html archivesBaseName = "HypixelModAPI" repositories { @@ -22,6 +23,17 @@ allprojects { } mavenLocal() } + + publishing { + publications { + maven(MavenPublication) { + groupId = project.group + artifactId = project == rootProject ? 'mod-api-forge' : ('mod-api-forge-' + project.name) + version = project.version + from components.java + } + } + } } sourceCompatibility = 1.8 diff --git a/tweaker/build.gradle b/tweaker/build.gradle index 8962b17..e8eada8 100644 --- a/tweaker/build.gradle +++ b/tweaker/build.gradle @@ -17,6 +17,10 @@ task generateVersionInfo(type: WriteProperties) { } tasks.jar { + dependsOn(project(":").reobfJar) from(project(":").jar) from(generateVersionInfo) + manifest { + attributes("TweakClass": "net.hypixel.modapi.tweaker.HypixelModAPITweaker") + } } diff --git a/tweaker/src/main/java/net/hypixel/modapi/tweaker/HypixelModAPITweaker.java b/tweaker/src/main/java/net/hypixel/modapi/tweaker/HypixelModAPITweaker.java index 6195833..4464cd7 100644 --- a/tweaker/src/main/java/net/hypixel/modapi/tweaker/HypixelModAPITweaker.java +++ b/tweaker/src/main/java/net/hypixel/modapi/tweaker/HypixelModAPITweaker.java @@ -12,6 +12,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.net.MalformedURLException; import java.net.URISyntaxException; import java.net.URL; import java.nio.file.Files; @@ -145,8 +146,12 @@ private File getThisJar() { */ private void injectAPI() { LOGGER.info("Injecting mod API of version {}", VERSION_NAME); - CoreModManager.getReparseableCoremods() - .add(unpackAPI().getPath()); + try { + Launch.classLoader.addURL(unpackAPI().toURI().toURL()); + LOGGER.info("Added mod API to classpath"); + } catch (MalformedURLException e) { + LOGGER.error("Could not add mod API to classpath", e); + } } /** @@ -200,6 +205,7 @@ private void offerVersionToBlackboard() { @Override public void acceptOptions(List args, File gameDir, File assetsDir, String profile) { offerVersionToBlackboard(); + allowModLoading(); } @Override From 694a2e1fbf6eedeffcd3faff92ea2e4a9362e731 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linnea=20Gr=C3=A4f?= Date: Fri, 12 Jul 2024 22:56:16 +0200 Subject: [PATCH 6/6] Add docs --- README.md | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index bf922d2..b8e8608 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,69 @@ # Forge Mod API -This repository contains the implementation of the Hypixel Mod API for the Froge Mod Loader in 1.8.9 for end-users. If you are a developer, and are looking to utilise the API you should look at the core [Hypixel Mod API](https://github.com/HypixelDev/ModAPI) repository. +This repository contains the implementation of the Hypixel Mod API for the Forge Mod Loader in 1.8.9 for end-users. If you are a developer, and are looking to utilise the API you should look at the core [Hypixel Mod API](https://github.com/HypixelDev/ModAPI) repository. + +## Usage + +Add the HyPixel Maven repository to your build: + +```kotlin +repositories { + maven("https://repo.hypixel.net/repository/Hypixel/") +} +``` + +Then depend on the Forge Mod API. This will automatically pull in dependencies too. + +```kotlin +val version = "1.0.0.2" +dependencies { + modImplementation("net.hypixel:mod-api-forge:$version") + // If you use ForgeGradle 2 you might need to use fg.deobf or deobfCompile instead. Consult your MDK for tips on how + // to depend on an obfuscated dependency +} +``` + +From here on out you can use the [HyPixel Mod API](https://github.com/HypixelDev/ModAPI#example-usage) directly. + +### Bundling the HyPixel Mod API + +When using the HyPixel Mod API you need to instruct your users to +[download](https://modrinth.com/mod/hypixel-mod-api/versions?l=forge) the mod api and put it in their mods folders. + +Alternatively you can bundle a loading tweaker instead. This involves a bit more setup, but will result in your mod +containing a copy of the mod api and at runtime selecting the newest available version of the mod api. + +First you need to have a shadow plugin in your gradle setup. Note that normal `fileTree` based JAR copying does not +work, since we will need to relocate some files. Instead, use the [shadow plugin](https://github.com/johnrengelman/shadow) +or make use of a [template](https://github.com/nea89o/Forge1.8.9Template) with the plugin already set up. + +Once you have your shadow plugin set up you will need to include a new dependency: +```kotlin +dependencies { + modImplementation("net.hypixel:mod-api-forge:$version") // You should already have this dependency from earlier + shadowImpl("net.hypixel:mod-api-forge-tweaker:$version") // You need to add this dependency +} +``` + +Make sure to relocate the `net.hypixel.modapi.tweaker` package to a unique location such as `my.modid.modapitweaker`. + +Finally, add a manifest entry to your JAR pointing the `TweakClass` to `my.modid.modapitweaker.HypixelModAPITweaker` +(or otherwise load the tweaker using delegation). + +```kotlin +tasks.shadowJar { + configurations = listOf(shadowImpl) + relocate("net.hypixel.modapi.tweaker", "my.modid.modapitweaker.HypixelModAPITweaker") +} + +tasks.withType(org.gradle.jvm.tasks.Jar::class) { + manifest.attributes.run { + this["TweakClass"] = "my.modid.modapitweaker.HypixelModAPITweaker" + } +} +``` + +Now your users will automatically use the bundled version of the mod api. ## Contributing