diff --git a/buildSrc/src/main/groovy/multiloader-common.gradle b/buildSrc/src/main/groovy/multiloader-common.gradle index ae8831ea4..785287d4f 100644 --- a/buildSrc/src/main/groovy/multiloader-common.gradle +++ b/buildSrc/src/main/groovy/multiloader-common.gradle @@ -172,7 +172,7 @@ tasks.named('processTestmodResources', ProcessResources) { filesMatching(['META-INF/mods.toml', 'META-INF/neoforge.mods.toml']) { expand manifestExpandProps } - filesMatching(['pack.mcmeta', 'fabric.mod.json']) { + filesMatching(['pack.mcmeta', 'fabric.mod.json', 'paper-plugin.yml']) { expand manifestJsonExpandProps } inputs.properties(manifestExpandProps) diff --git a/common/src/main/java/journeymap/api/v2/common/waypoint/WaypointFactory.java b/common/src/main/java/journeymap/api/v2/common/waypoint/WaypointFactory.java index 16a3b3446..549f67396 100644 --- a/common/src/main/java/journeymap/api/v2/common/waypoint/WaypointFactory.java +++ b/common/src/main/java/journeymap/api/v2/common/waypoint/WaypointFactory.java @@ -76,25 +76,25 @@ public static Waypoint createWaypoint(String modId, BlockPos pos, @Nullable Stri @Deprecated public static Waypoint createClientWaypoint(String modId, BlockPos pos, @Nullable String name, ResourceKey primaryDimension, boolean persistent) { - return createClientWaypoint(modId, pos, name, primaryDimension.identifier().toString(), persistent); + return createWaypoint(modId, pos, name, primaryDimension.identifier().toString(), persistent); } @Deprecated public static Waypoint createClientWaypoint(String modId, BlockPos pos, ResourceKey primaryDimension, boolean persistent) { - return createClientWaypoint(modId, pos, primaryDimension.identifier().toString(), persistent); + return createWaypoint(modId, pos, primaryDimension.identifier().toString(), persistent); } @Deprecated public static Waypoint createClientWaypoint(String modId, BlockPos pos, String primaryDimension, boolean persistent) { - return createClientWaypoint(modId, pos, null, primaryDimension, persistent); + return createWaypoint(modId, pos, null, primaryDimension, persistent); } @Deprecated public static Waypoint createClientWaypoint(String modId, BlockPos pos, @Nullable String name, String primaryDimension, boolean persistent) { - return getInstance().store.createClientWaypoint(modId, pos, name, primaryDimension, persistent); + return getInstance().store.createWaypoint(modId, pos, name, primaryDimension, persistent); } public static Waypoint fromWaypointJsonString(String waypoint) diff --git a/docs/changelog.md b/docs/changelog.md index 854c7f6ca..1613d1256 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -2,6 +2,8 @@ ====================================================== **API 2.0.0-SNAPSHOT** **Requires Journeymap v6.0.0** +* Added Paper support: `journeymap-api-paper` artifact for writing server-side JourneyMap addons as Paper plugins. +* Added server plugin support and server api and events. * Added Server Properties, so mods can add properties to JourneyMap's Server Admin options tab. * Added LayeredScreen abstraction for layirng screens. * Refactored Waypoint and WaypointGroups to be more concrete. diff --git a/docs/howto.md b/docs/howto.md index 9daaa80be..f13b5e9e2 100644 --- a/docs/howto.md +++ b/docs/howto.md @@ -33,14 +33,15 @@ For example: #!gradle // Version of JourneyMap API to use -`journeymap-api-forge:2.0.0-1.21.1-SNAPSHOT` -`journeymap-api-neoforge:2.0.0-1.21.1-SNAPSHOT` -`journeymap-api-fabric:2.0.0-1.21.1-SNAPSHOT` +`journeymap-api-forge:2.0.0-26.1-SNAPSHOT` +`journeymap-api-neoforge:2.0.0-26.11-SNAPSHOT` +`journeymap-api-fabric:2.0.0-26.1-SNAPSHOT` +`journeymap-api-paper:2.0.0-26.1-SNAPSHOT` // for multiloader setups, common jar -`journeymap-api-common:2.0.0-1.21.1-SNAPSHOT` +`journeymap-api-common:2.0.0-26.1-SNAPSHOT` -journeymap_api_version = 2.0.0-1.21.1-SNAPSHOT +journeymap_api_version = 2.0.0-26.1-SNAPSHOT // Note: None of the blocks below belong in your buildscript block. Put them below it instead. repositories { @@ -87,8 +88,20 @@ dependencies { modCompileOnlyApi group: 'info.journeymap', name: 'journeymap-api-fabric', version: project.journeymap_api_version, changing: true } +// PAPER (server-side addons only) +dependencies { + compileOnly group: 'info.journeymap', name: 'journeymap-api-paper', version: project.journeymap_api_version, changing: true +} + ``` +The Paper API artifact is the server-side counterpart for Paper/Spigot plugins. It is published +with the Minecraft version baked into the version string (e.g. `journeymap-api-paper:2.0.0-26.1-SNAPSHOT`) +rather than the loader-agnostic suffix used by the mod-loader artifacts. The jar bundles the full +API surface (common + server + client) so shared code resolves at compile time; only the +`journeymap.api.v2.common.*` and `journeymap.api.v2.server.*` packages are usable on a Paper server +at runtime. + Example forge: mods.toml entry for a soft dependency. Set `mandatory=true` for a hard dependency if needed. ``` @@ -112,6 +125,19 @@ ordering = "NONE" side = "CLIENT" ``` +Example paper: a Paper addon is itself a Paper plugin, so it declares the dependency in +`paper-plugin.yml`. `join-classpath: true` makes the JourneyMap API classes (bundled inside the +JourneyMap Paper plugin jar) visible to your plugin's classloader at runtime. + +``` +dependencies: + server: + journeymap: + load: BEFORE + required: true + join-classpath: true +``` + *Note that the journeymap-api.jar is built with deobfuscated code so that it can be used at compile time and when stepping through a debugger in your development environment.* @@ -137,11 +163,19 @@ all plugin logic, sample factories, and event subscriptions live in common. - Forge: [forge/src/testmod/java/example/mod/forge/ForgeExampleMod.java](../forge/src/testmod/java/example/mod/forge/ForgeExampleMod.java) - NeoForge: [neoforge/src/testmod/java/example/mod/neoforge/NeoForgeExampleMod.java](../neoforge/src/testmod/java/example/mod/neoforge/NeoForgeExampleMod.java) +* Paper addon example (server-side only, since Paper has no client, so it does not use the shared + `common/src/testmod/` example mod): + - [paper/src/testmod/java/example/paper/ExampleJourneyMapPaperAddon.java](../paper/src/testmod/java/example/paper/ExampleJourneyMapPaperAddon.java) - a single class that is both a Paper plugin (`extends JavaPlugin`) and a JourneyMap addon (`implements IServerPlugin`, annotated `@JourneyMapPlugin`). + - [paper/src/testmod/resources/paper-plugin.yml](../paper/src/testmod/resources/paper-plugin.yml) - the plugin manifest, including the `journeymap` server dependency. + * Running the test mod in dev: - The testmod source set is registered as a runnable mod in each loader's run config. - Use the standard run tasks: `./gradlew :fabric:runClient`, `./gradlew :forge:runClient`, `./gradlew :neoforge:runClient`. - In IntelliJ, the per-loader run configs include the testmod source set automatically. - Drop the JourneyMap jar into `{loader}/run/client/mods/` before launching. + - Paper: `./gradlew :paper:runDevBundleServer` boots a Paper server with the example addon. Without + the JourneyMap Paper plugin present, only `onEnable` fires (this verifies the API classes load on + a real Paper classpath); full addon discovery requires a Paper server that has JourneyMap installed. III. Write your Plugin ============================= @@ -177,6 +211,13 @@ III. Write your Plugin *[journeymap.api.v2.server.IServerPlugin](../common/src/main/java/journeymap/api/v2/server/IServerPlugin.java)* instead of `IClientPlugin`, annotate the same way, and (on Fabric) add the class to the `journeymap_server` entrypoint alongside any client plugin. See [ExampleServerPlugin](../common/src/testmod/java/example/mod/server/plugin/ExampleServerPlugin.java) for a working example. +6. For Paper: a Paper addon is a server-side plugin only. Implement `IServerPlugin` (Paper has no + client, so `IClientPlugin` is not usable at runtime). Annotate the class with `@JourneyMapPlugin`. + The JourneyMap Paper plugin discovers addons by scanning every loaded plugin jar for the + annotation, so there is no entrypoint list to maintain. Your addon must be a normal Paper plugin + (`extends JavaPlugin` with a `paper-plugin.yml`) that declares the `journeymap` server dependency + shown in Section I. See [ExampleJourneyMapPaperAddon](../paper/src/testmod/java/example/paper/ExampleJourneyMapPaperAddon.java) + for a working example. IV. Test your Plugin ============================= diff --git a/gradle.properties b/gradle.properties index 29ca65ec6..71f80777c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -40,6 +40,11 @@ neo_form_version=26.1-1 fabric_api_version=0.144.0+26.1 fabric_loader_version=0.18.4 +# Paper https://papermc.io/ +paper_version=26.1.2.build.+ +paperweight_userdev_version=2.0.0-beta.21 +run_paper_version=2.3.1 + # Journeymap cursemaven version jm_project_id=32274 diff --git a/paper/build.gradle b/paper/build.gradle new file mode 100644 index 000000000..19eab664a --- /dev/null +++ b/paper/build.gradle @@ -0,0 +1,89 @@ +/* + * JourneyMap API (http://journeymap.info) + * http://github.com/TeamJM/journeymap-api + * + * Copyright (c) 2011-2016 Techbrew. All Rights Reserved. + * The following limited rights are granted to you: + * + * You MAY: + * + Write your own code that uses the API source code in journeymap.* packages as a dependency. + * + Write and distribute your own code that uses, modifies, or extends the example source code in example.* packages + * + Fork and modify any source code for the purpose of submitting Pull Requests to the TeamJM/journeymap-api repository. + * Submitting new or modified code to the repository means that you are granting Techbrew all rights to the submitted code. + * + * You MAY NOT: + * - Distribute source code or classes (whether modified or not) from journeymap.* packages. + * - Submit any code to the TeamJM/journeymap-api repository with a different license than this one. + * - Use code or artifacts from the repository in any way not explicitly granted by this license. + * + */ +plugins { + id 'net.neoforged.moddev' + id 'multiloader-loader' + id 'io.papermc.paperweight.userdev' version "${paperweight_userdev_version}" + id 'xyz.jpenilla.run-paper' version "${run_paper_version}" +} + +def baseName = "${project.mod_name}" + "-paper" +base.archivesName = baseName + +// NeoForm provides compile-time access to vanilla Minecraft (including client classes +// like net.minecraft.client.Minecraft, com.mojang.blaze3d.platform.*, and the full +// net.minecraft.* server surface). The published journeymap-api-paper jar therefore +// includes the entire API (common + server + client). Client API classes are inert on +// a Paper server at runtime because no code path instantiates them; their presence in +// the jar is purely for compile-time resolution by consumers (e.g. the JM Paper plugin +// shading this artifact still needs to resolve client-API references in shared code). +neoForge { + neoFormVersion = neo_form_version +} + +// paperweight-userdev still pulls the Paper dev bundle so Paper-specific NMS classes +// resolve when consumers compile against this artifact. +dependencies { + paperweight.paperDevBundle(paper_version) +} + +// Implement mcgradleconventions loader attribute +def loaderAttribute = Attribute.of('io.github.mcgradleconventions.loader', String) +['apiElements', 'runtimeElements', 'sourcesElements', 'javadocElements'].each { variant -> + configurations.matching { it.name == variant }.configureEach { + attributes { + attribute(loaderAttribute, 'paper') + } + } +} +sourceSets.configureEach { + [it.compileClasspathConfigurationName, it.runtimeClasspathConfigurationName].each { variant -> + configurations.named("$variant") { + attributes { + attribute(loaderAttribute, 'paper') + } + } + } +} + +// Override the testmod source set: skip the common testmod (which is a client +// example mod and cannot compile on Paper) and use only paper/src/testmod/. +sourceSets { + testmod { + java.srcDirs = ['src/testmod/java'] + resources.srcDirs = ['src/testmod/resources'] + } +} + +dependencies { + testmodImplementation sourceSets.main.output + testmodImplementation paperweight.paperDevBundle(paper_version) +} + +// Use the paperweight-userdev-bridged `runDevBundleServer` task: it reads the Paper +// version directly from the dev bundle (no run-paper version-table lookup that 2.3.1's +// bundled list doesn't know about 26.1.2). Replace the default pluginJars (which +// includes the library `jar` — has no plugin.yml so Paper errors on it) with just +// the testmod jar, and isolate the run dir + auto-accept EULA for unattended runs. +tasks.named('runDevBundleServer', xyz.jpenilla.runpaper.task.RunServer).configure { + pluginJars.setFrom(tasks.named('testmodJar')) + runDirectory(file('run/testmod-server')) + systemProperty('com.mojang.eula.agree', 'true') +} diff --git a/paper/src/testmod/java/example/paper/ExampleJourneyMapPaperAddon.java b/paper/src/testmod/java/example/paper/ExampleJourneyMapPaperAddon.java new file mode 100644 index 000000000..f222795b8 --- /dev/null +++ b/paper/src/testmod/java/example/paper/ExampleJourneyMapPaperAddon.java @@ -0,0 +1,38 @@ +/* + * JourneyMap API (http://journeymap.info) + * http://github.com/TeamJM/journeymap-api + * + * Copyright (c) 2011-2016 Techbrew. All Rights Reserved. + * See the LICENSE file in this repo for license terms. + */ +package example.paper; + +import org.bukkit.plugin.java.JavaPlugin; + +/** + * Minimal example Paper entry point for a JourneyMap addon. This class is a + * pure Bukkit shim: it is NOT a JourneyMap plugin and does NOT carry + * {@code @JourneyMapPlugin}. + * + * The canonical annotated {@code IServerPlugin} example is + * {@code example.mod.server.plugin.ExampleServerPlugin} in {@code common/src/testmod}. + * JM's Paper plugin scanner discovers annotated classes by classpath annotation + * scan, not by {@code instanceof JavaPlugin}, so the addon's Bukkit entry point + * and its {@code IServerPlugin} should be separate classes. Combining them in + * one class breaks at JM-side instantiation because Bukkit's {@code JavaPlugin} + * no-arg constructor throws when invoked outside a {@code PluginClassLoader}. + * + * When run via {@code :paper:runTestmodServer} (no JM Paper plugin present), + * only onEnable fires, verifying the API classes load on a real Paper classpath. + * Full addon discovery requires running this plugin against a Paper server that + * has JM Paper installed alongside a real annotated {@code IServerPlugin} on + * the same classpath. + */ +public final class ExampleJourneyMapPaperAddon extends JavaPlugin +{ + @Override + public void onEnable() + { + getLogger().info("Example JM Paper shim loaded."); + } +} diff --git a/paper/src/testmod/resources/paper-plugin.yml b/paper/src/testmod/resources/paper-plugin.yml new file mode 100644 index 000000000..33bbbeee9 --- /dev/null +++ b/paper/src/testmod/resources/paper-plugin.yml @@ -0,0 +1,13 @@ +name: ExampleJourneyMapPaperAddon +version: ${version} +main: example.paper.ExampleJourneyMapPaperAddon +api-version: '26.1.2' +author: ${mod_author} +description: Example JourneyMap API addon for Paper. +load: STARTUP +dependencies: + server: + journeymap: + load: BEFORE + required: true + join-classpath: true diff --git a/readme.md b/readme.md index 9b3a1fadc..fd3738ff6 100644 --- a/readme.md +++ b/readme.md @@ -17,6 +17,7 @@ Versions API v2.0.0 - Removed ClientPlugin annotation in favor of JourneyMapPlugin annotation which takes the API version the addon was built against. - API project now uses MultiLoader Template. - Forge version is now a mod that JouneyMap now JarJars in the main mod. +- Added Paper support: `journeymap-api-paper` for server-side addons running as Paper plugins. [How to use the JourneyMap API](docs/howto.md) diff --git a/settings.gradle b/settings.gradle index 6ea163a02..4c59756bb 100644 --- a/settings.gradle +++ b/settings.gradle @@ -50,3 +50,4 @@ include("common") include("fabric") include("neoforge") include("forge") +include("paper")