diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..dfd0e30 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,10 @@ +# Set update schedule for GitHub Actions + +version: 2 +updates: + + - package-ecosystem: "github-actions" + directory: "/" + schedule: + # Check for updates to GitHub Actions every week + interval: "weekly" diff --git a/.github/workflows/build_artifacts.yml b/.github/workflows/build_artifacts.yml index 4549d13..f8bb955 100644 --- a/.github/workflows/build_artifacts.yml +++ b/.github/workflows/build_artifacts.yml @@ -11,27 +11,44 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 + with: + submodules: true - - name: Set up JDK 17 - uses: actions/setup-java@v3 + - name: Set up JDK 21 + uses: actions/setup-java@v5 with: - java-version: '17' + java-version: '21' distribution: 'temurin' - - name: Make gradle wrapper executable - if: ${{ runner.os != 'Windows' }} - run: chmod +x ./gradlew + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v5 + with: + cache-read-only: false + + - name: Store short commit hash + run: echo "short_commit_hash=$(git rev-parse --short "$GITHUB_SHA")" >> "$GITHUB_ENV" - name: Build with Gradle - uses: gradle/gradle-build-action@v2 + run: ./gradlew build env: + PRESERVE_PRERELEASE_VERSION: true DISABLE_PROPERTIES_UPDATE: true - with: - arguments: build + DISABLE_MUSIC: true + VERSION_SUFFIX: ${{ env.short_commit_hash }} + + - name: Publish to Maven + run: ./gradlew publishMavenPublicationToOffsetMonkey538Repository + env: + PRESERVE_PRERELEASE_VERSION: true + DISABLE_PROPERTIES_UPDATE: true + DISABLE_MUSIC: true + VERSION_SUFFIX: ${{ env.short_commit_hash }} + MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }} + MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }} - name: Upload build artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: Artifacts - path: build/libs/ + name: Build Artifacts + path: ./loader/*/*/build/libs/ diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 24a393c..eb42348 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -13,38 +13,52 @@ jobs: contents: write steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 + with: + submodules: true - - name: Set up JDK 17 - uses: actions/setup-java@v3 + - name: Set up JDK 21 + uses: actions/setup-java@v5 with: - java-version: '17' + java-version: '21' distribution: 'temurin' - - name: Make gradle wrapper executable - if: ${{ runner.os != 'Windows' }} - run: chmod +x ./gradlew + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v5 + with: + cache-read-only: false - name: Build with Gradle - uses: gradle/gradle-build-action@v2 + run: ./gradlew build env: + IS_RELEASE: true DISABLE_PROPERTIES_UPDATE: true - with: - arguments: build + DISABLE_MUSIC: true + VERSION_SUFFIX: "" - name: Upload to Modrinth - uses: gradle/gradle-build-action@v2 + run: ./gradlew modrinth env: + IS_RELEASE: true + DISABLE_PROPERTIES_UPDATE: true + DISABLE_MUSIC: true + VERSION_SUFFIX: "" MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }} VERSION_NAME: ${{ github.event.release.name }} - with: - arguments: modrinth + VERSION_IS_PRERELEASE: ${{ github.event.release.prerelease }} + VERSION_CHANGELOG: ${{ github.event.release.body }} + + - name: Publish to Maven + run: ./gradlew publishMavenPublicationToOffsetMonkey538Repository + env: + IS_RELEASE: true + DISABLE_PROPERTIES_UPDATE: true + DISABLE_MUSIC: true + VERSION_SUFFIX: "" + MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }} + MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }} - name: Upload to GitHub - uses: svenstaro/upload-release-action@v2 + uses: softprops/action-gh-release@v2 with: - repo_token: ${{ secrets.GITHUB_TOKEN }} - file: build/libs/*.jar - tag: ${{ github.ref }} - overwrite: true - file_glob: true + files: ./loader/*/*/build/libs/*.jar diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..cc7fe46 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "buildSrc"] + path = buildSrc + url = https://github.com/OffsetMods538/multiversion-buildscripts diff --git a/LICENSE b/LICENSE index 299706d..801d9ff 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2023 OffsetMonkey538 +Copyright (c) 2023-2026 OffsetMonkey538 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index ef7d41b..74a1780 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,10 @@ -[![](https://jitpack.io/v/top.offsetmonkey538/monkeylib538.svg)](https://jitpack.io/#top.offsetmonkey538/monkeylib538) - # MonkeyLib538 +[![discord-singular](https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/cozy/social/discord-singular_vector.svg)](https://discord.offsetmonkey538.top/) +[![modrinth](https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/cozy/available/modrinth_vector.svg)](https://modrinth.com/mod/monkeylib538) + Make sure to download the correct version for the Minecraft version you're using! A library mod used by OffsetMonkey538's mods. Required for them to run. -Currently only includes a config library. +Currently includes a config library and abstractions for allowing support of multiple Minecraft versions in one jar. + +###### This mod collects anonymous usage information, read more about what's collected [here](https://github.com/OffsetMods538/MonkeyMetrics-Server). No personal data is collected. This can be disabled by modifying the config at `config/monkeylib538/telemetry.json` or by running the `/monkeylib538 telemetry set isEnabled false` command. diff --git a/build.gradle b/build.gradle index a91431b..b078479 100644 --- a/build.gradle +++ b/build.gradle @@ -1,185 +1,74 @@ plugins { - id 'fabric-loom' version '1.4-SNAPSHOT' - id 'io.github.dexman545.outlet' version '1.6.1' - id 'com.modrinth.minotaur' version '2.+' - id 'maven-publish' + id 'multiloader-root' + id 'java' + id 'java-library' + id 'net.neoforged.moddev' version "${neoforged_moddev}" apply false + id 'fabric-loom' version "${fabric_loom}" apply false + id 'io.papermc.paperweight.userdev' version "${papermc_paperweight_userdev}" apply false + id 'xyz.jpenilla.run-paper' version "${jpenilla_run_task}" apply false + id 'com.gradleup.shadow' version "${gradleup_shadow}" apply false + id 'xyz.jpenilla.resource-factory' version "${jpenilla_resource_factory}" apply false + id 'io.github.dexman545.outlet' version "${dexman_outlet}" apply false + id 'com.modrinth.minotaur' version "${modrinth_minotaur}" apply false + id 'hamburg.janove.elevator-music' version "0.1" } -sourceCompatibility = JavaVersion.VERSION_17 -targetCompatibility = JavaVersion.VERSION_17 - -archivesBaseName = "monkeylib538" -version = "${project.mod_version}+${project.minecraft_version}" - -outlet { - maintainPropertiesFile = System.getenv("DISABLE_PROPERTIES_UPDATE") == null - mcVersionRange = project.supported_minecraft_versions - propertiesData = [ - 'yarn_version': outlet.yarnVersion(project.minecraft_version), - 'loader_version': outlet.loaderVersion() - ] -} - - -loom { - splitEnvironmentSourceSets() - - sourceSets { - testmod { - compileClasspath += main.compileClasspath - runtimeClasspath += main.runtimeClasspath - - compileClasspath += client.compileClasspath - runtimeClasspath += client.runtimeClasspath - } - } - - mods { - monkeyconfig538 { - sourceSet sourceSets.main - sourceSet sourceSets.client - } - - testmod { - sourceSet sourceSets.testmod - } - } - - accessWidenerPath = file("src/main/resources/monkeylib538.accesswidener") - - runs { - server { - runDir "run/server" +//elevatorMusic { +// if (Boolean.parseBoolean(System.getenv("DISABLE_MUSIC"))) return +// waitMusic = file("${rootProject.projectDir}/veryImportant/music.wav") +// successSound = file("${rootProject.projectDir}/veryImportant/done.wav") +//} + +subprojects { + apply plugin: "java-library" + + repositories { + mavenCentral() + mavenLocal() + exclusiveContent { + forRepository { + maven { + name = "OffsetMods538" + url = "https://maven.offsetmonkey538.top/releases" + } + } + filter { + includeGroupAndSubgroups "top.offsetmonkey538" + } } - - testmodClient { - client() - name = "Testmod Client" - runDir "run/testmod" - source sourceSets.testmod - } - } - - createRemapConfigurations(sourceSets.testmod) -} - -// https://gist.github.com/maityyy/3dbcd558d58a6412c3a2a38c72706e8e -afterEvaluate { - loom.runs.configureEach { - vmArg "-javaagent:${configurations.compileClasspath.find{ it.name.contains("sponge-mixin") }}" - } -} - -configurations { - includeModImplementation - - include.extendsFrom includeModImplementation - modImplementation.extendsFrom includeModImplementation - - - includeImplementation - - include.extendsFrom includeImplementation - implementation.extendsFrom includeImplementation - - - includeApi - - include.extendsFrom includeApi - api.extendsFrom includeApi -} - -repositories { - mavenCentral() -} - -dependencies { - minecraft "com.mojang:minecraft:${project.minecraft_version}" - mappings "net.fabricmc:yarn:${project.yarn_version}:v2" - modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" - - includeApi "blue.endless:jankson:${project.jankson_version}" - - - testmodImplementation sourceSets.main.output - testmodImplementation sourceSets.client.output -} - -processResources { - inputs.properties(Map.of( - "modVersion", project.mod_version, - "supportedMinecraftVersions", project.supported_minecraft_versions - )) - - filesMatching("fabric.mod.json") { - expand(Map.of( - "modVersion", project.mod_version, - "supportedMinecraftVersions", project.supported_minecraft_versions - )) - } - - exclude ".cache/**" -} - -tasks.withType(JavaCompile).configureEach { - it.options.release = 17 -} - -java { - withSourcesJar() - withJavadocJar() -} - -jar { - from("LICENSE") { - rename { "${it}_${project.archivesBaseName}" } - } -} - -tasks.register('testmodJar', Jar) { - from sourceSets.testmod.output - destinationDirectory = new File(project.buildDir, "devlibs") - archiveClassifier = "testmod" -} - -import net.fabricmc.loom.task.RemapJarTask - -tasks.register('remapTestmodJar', RemapJarTask) { - dependsOn testmodJar - input = testmodJar.archiveFile - archiveClassifier = "testmod" - addNestedDependencies = false -} - -build.dependsOn remapTestmodJar - -modrinth { - token = System.getenv("MODRINTH_TOKEN") - projectId = "monkeylib538" - def customVersionName = System.getenv("VERSION_NAME") - if (customVersionName != null) versionName = customVersionName - versionNumber = "${project.version}" - versionType = "beta" - uploadFile = remapJar.archiveFile - //additionalFiles = [sourcesJar.archiveFile, javadocJar.archiveFile] - additionalFiles = [sourcesJar.archiveFile] - gameVersions = outlet.mcVersions() - syncBodyFrom = rootProject.file("README.md").text - def changelogFile = rootProject.file("CHANGELOG.md") - if (changelogFile.exists()) { - changelog = changelogFile.text } dependencies { + api "top.offsetmonkey538.offsetutils538:offsetutils538:${rootProject.offsetutils538_version}" + compileOnlyApi "org.jspecify:jspecify:${rootProject.jspecify_version}" } } -tasks.modrinth.dependsOn(tasks.modrinthSyncBody) - -publishing { - publications { - maven(MavenPublication) { - from components.java +configure(subprojects.findAll { it.hasProperty("project_name") }) { + apply plugin: "maven-publish" + + publishing { + repositories { + maven { + name = "OffsetMonkey538" + url = "https://maven.offsetmonkey538.top/releases" + credentials { + username = providers.gradleProperty("OffsetMonkey538Username").getOrElse(System.getenv("MAVEN_USERNAME")) + password = providers.gradleProperty("OffsetMonkey538Password").getOrElse(System.getenv("MAVEN_PASSWORD")) + } + authentication { + basic(BasicAuthentication) + } + } + } + publications { + register("maven", MavenPublication) { + afterEvaluate { + artifactId base.archivesName.get() + } + groupId "top.offsetmonkey538.monkeylib538" + from components.java + } } } -} \ No newline at end of file +} diff --git a/buildSrc b/buildSrc new file mode 160000 index 0000000..31a2373 --- /dev/null +++ b/buildSrc @@ -0,0 +1 @@ +Subproject commit 31a2373f007a4ef7aaaabdcf4d28fd283ef42175 diff --git a/common/build.gradle b/common/build.gradle new file mode 100644 index 0000000..e2e79c9 --- /dev/null +++ b/common/build.gradle @@ -0,0 +1,21 @@ +plugins { + id 'multiloader-base' +} + +repositories { + maven { + name = "Mojang Libraries" + url = "https://libraries.minecraft.net" + content { + includeGroup "com.mojang" + } + } +} + +dependencies { + compileOnly "com.mojang:datafixerupper:${rootProject.datafixerupper_version}" + compileOnly "com.mojang:brigadier:${rootProject.brigadier_version}" + compileOnly "com.google.code.gson:gson:${rootProject.gson_version}" + + compileOnlyApi "net.kyori:adventure-api:${project.adventure_api_version}" +} diff --git a/common/gradle.properties b/common/gradle.properties new file mode 100644 index 0000000..6d3b82c --- /dev/null +++ b/common/gradle.properties @@ -0,0 +1,5 @@ +project_name = common + +# Dependencies +## Adventure +adventure_api_version = 4.26.1 \ No newline at end of file diff --git a/common/src/main/java/top/offsetmonkey538/monkeylib538/common/MonkeyLib538Common.java b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/MonkeyLib538Common.java new file mode 100644 index 0000000..df1e040 --- /dev/null +++ b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/MonkeyLib538Common.java @@ -0,0 +1,22 @@ +package top.offsetmonkey538.monkeylib538.common; + +import top.offsetmonkey538.monkeylib538.common.telemetry.TelemetryHandler; +import top.offsetmonkey538.offsetutils538.api.log.OffsetLogger; + +import java.util.ServiceLoader; + +public final class MonkeyLib538Common { + public static final String MOD_ID = "monkeylib538"; + public static final OffsetLogger LOGGER = OffsetLogger.create(MOD_ID); + + public static void initialize() { + TelemetryHandler.initialize(); + } + + public static T load(Class clazz) { + LOGGER.info("Loading service for: %s", clazz); + return ServiceLoader.load(clazz, MonkeyLib538Common.class.getClassLoader()) + .findFirst() + .orElseThrow(() -> new RuntimeException("Failed to load service for " + clazz.getName())); + } +} diff --git a/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/annotation/MonkeyLibSerializable.java b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/annotation/MonkeyLibSerializable.java new file mode 100644 index 0000000..c39f6ab --- /dev/null +++ b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/annotation/MonkeyLibSerializable.java @@ -0,0 +1,12 @@ +package top.offsetmonkey538.monkeylib538.common.api.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface MonkeyLibSerializable { + String value() default ""; +} diff --git a/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/annotation/package-info.java b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/annotation/package-info.java new file mode 100644 index 0000000..1bb1fea --- /dev/null +++ b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/annotation/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package top.offsetmonkey538.monkeylib538.common.api.annotation; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/command/CommandAbstractionApi.java b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/command/CommandAbstractionApi.java new file mode 100644 index 0000000..719639e --- /dev/null +++ b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/command/CommandAbstractionApi.java @@ -0,0 +1,210 @@ +package top.offsetmonkey538.monkeylib538.common.api.command; + +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.builder.RequiredArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import net.kyori.adventure.text.Component; +import org.jspecify.annotations.Nullable; +import top.offsetmonkey538.offsetutils538.api.annotation.Internal; +import top.offsetmonkey538.offsetutils538.api.text.ArgReplacer; + +import static top.offsetmonkey538.monkeylib538.common.MonkeyLib538Common.load; +import static top.offsetmonkey538.offsetutils538.api.text.ArgReplacer.replaceArgs; + +/** + * Provides some abstractions for dealing with commands. + *
+ * Mostly for internal use for the config command. + * + *

An {@link Object} is used as the generic type for the argument builders, but the implementations ({@link #literalImpl(String)} and {@link #argumentImpl(String, ArgumentType)}) will create them with platform-specific command sources. + *
+ * This way, the methods here can be called with a {@link CommandContext context} containing with the generic {@link Object} and implementations will cast that to the platform-specific command sources for implementing the methods. + *

+ */ +public interface CommandAbstractionApi { + @Internal + CommandAbstractionApi INSTANCE = load(CommandAbstractionApi.class); + + /** + * Creates a {@link LiteralArgumentBuilder} for the current platform specific command source. + * + * @param name the name of the {@link LiteralArgumentBuilder} + * @return a {@link LiteralArgumentBuilder} for the current platform specific command source. + */ + @SuppressWarnings("unchecked") + static LiteralArgumentBuilder literal(final String name) { + return (LiteralArgumentBuilder) INSTANCE.literalImpl(name); + } + + /** + * Creates a {@link RequiredArgumentBuilder} for the current platform specific command source and provided {@link ArgumentType}. + * + * @param name the name of the {@link RequiredArgumentBuilder} + * @param type the {@link ArgumentType} to use. + * @param the type for the {@link ArgumentType} + * @return a {@link RequiredArgumentBuilder} for the current platform specific command source and provided {@link ArgumentType}. + */ + @SuppressWarnings("unchecked") + static RequiredArgumentBuilder argument(final String name, final ArgumentType type) { + return (RequiredArgumentBuilder) INSTANCE.argumentImpl(name, type); + } + + /** + * Sends a message to the command source. + * + * @param ctx the {@link CommandContext} to get the current-platform-specific command source from. + * @param message the message to send, will be formatted using {@link ArgReplacer#replaceArgs(String, Object)} + * @param arg the arg for replacing in the message + */ + static void sendMessage(final CommandContext ctx, final String message, final Object arg) { + sendMessage(ctx, replaceArgs(message, arg)); + } + + /** + * Sends a message to the command source. + * + * @param ctx the {@link CommandContext} to get the current-platform-specific command source from. + * @param message the message to send, will be formatted using {@link ArgReplacer#replaceArgs(String, Object, Object)} + * @param arg1 the first arg for replacing in the message + * @param arg2 the second arg for replacing in the message + */ + static void sendMessage(final CommandContext ctx, final String message, @Nullable final Object arg1, @Nullable final Object arg2) { + sendMessage(ctx, replaceArgs(message, arg1, arg2)); + } + + /** + * Sends a message to the command source. + * + * @param ctx the {@link CommandContext} to get the current-platform-specific command source from. + * @param message the message to send, will be formatted using {@link ArgReplacer#replaceArgs(String, Object...)} + * @param args the args for replacing in the message + */ + static void sendMessage(final CommandContext ctx, final String message, @Nullable final Object... args) { + sendMessage(ctx, replaceArgs(message, args)); + } + + /** + * Sends a message to the command source. + * + * @param ctx the {@link CommandContext} to get the current-platform-specific command source from. + * @param message the message to send + */ + static void sendMessage(final CommandContext ctx, final String message) { + INSTANCE.sendMessageImpl(ctx, message); + } + + /** + * Sends an error message to the command source. + * + * @param ctx the {@link CommandContext} to get the current-platform-specific command source from. + * @param message the error message to send, will be formatted using {@link ArgReplacer#replaceArgs(String, Object...)} + * @param arg the args for replacing in the error message + */ + static void sendError(final CommandContext ctx, final String message, @Nullable final Object arg) { + sendError(ctx, replaceArgs(message, arg)); + } + + /** + * Sends an error message to the command source. + * + * @param ctx the {@link CommandContext} to get the current-platform-specific command source from. + * @param message the error message to send, will be formatted using {@link ArgReplacer#replaceArgs(String, Object...)} + * @param arg1 the first arg for replacing in the error message + * @param arg2 the second arg for replacing in the error message + */ + static void sendError(final CommandContext ctx, final String message, @Nullable final Object arg1, @Nullable final Object arg2) { + sendError(ctx, replaceArgs(message, arg1, arg2)); + } + + /** + * Sends an error message to the command source. + * + * @param ctx the {@link CommandContext} to get the current-platform-specific command source from. + * @param message the error message to send, will be formatted using {@link ArgReplacer#replaceArgs(String, Object...)} + * @param args the args for replacing in the error message + */ + static void sendError(final CommandContext ctx, final String message, @Nullable final Object... args) { + sendError(ctx, replaceArgs(message, args)); + } + + /** + * Sends an error message to the command source. + * + * @param ctx the {@link CommandContext} to get the current-platform-specific command source from. + * @param message the error message to send + */ + static void sendError(final CommandContext ctx, final String message) { + INSTANCE.sendErrorImpl(ctx, message); + } + + /** + * Sends a {@link Component} to the command source. + * + * @param ctx the {@link CommandContext} to get the current-platform-specific command source from. + * @param text the {@link Component} to send + */ + static void sendText(final CommandContext ctx, final Component text) { + INSTANCE.sendTextImpl(ctx, text); + } + + /** + * Checks whether the provided command source is executed by a player. + * + * @param source the current-platform-specific command source. + * @return whether the provided command source is executed by a player. + */ + static boolean executedByPlayer(final Object source) { + return INSTANCE.executedByPlayerImpl(source); + } + + /** + * Checks whether the provided command source has operator permissions or is the host of a singleplayer server. + *
+ * This returns true for singleplayer hosts even when cheats are disabled. + * + * @param source the current-platform-specific command source. + * @return whether the provided command source has operator permissions or is the host of a singleplayer server + * @see #isOp(Object) + * @see #isHost(Object) + */ + static boolean isAdmin(final Object source) { + return isOp(source) || isHost(source); + } + + /** + * Checks whether the provided command source has operator permissions. + * + * @param source the current-platform-specific command source. + * @return whether the provided command source has operator permissions + * @see #isAdmin(Object) + * @see #isHost(Object) + */ + static boolean isOp(final Object source) { + return INSTANCE.isOpImpl(source); + } + + /** + * Checks whether the provided command source is the host of a singleplayer server. + *
+ * Unlike {@link #isOp(Object)}, this method returns true even when cheats aren't enabled. + * + * @param source the current-platform-specific command source. + * @return whether the provided command source is the host of a singleplayer server + * @see #isAdmin(Object) + * @see #isOp(Object) + */ + static boolean isHost(final Object source) { + return INSTANCE.isHostImpl(source); + } + + + @Internal LiteralArgumentBuilder literalImpl(final String name); + @Internal RequiredArgumentBuilder argumentImpl(final String name, final ArgumentType type); + @Internal void sendMessageImpl(final CommandContext ctx, final String message); + @Internal void sendErrorImpl(final CommandContext ctx, final String message); + @Internal void sendTextImpl(final CommandContext ctx, final Component text); + @Internal boolean executedByPlayerImpl(final Object source); + @Internal boolean isOpImpl(final Object source); + @Internal boolean isHostImpl(final Object source); +} diff --git a/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/command/CommandRegistrationApi.java b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/command/CommandRegistrationApi.java new file mode 100644 index 0000000..b5e73d4 --- /dev/null +++ b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/command/CommandRegistrationApi.java @@ -0,0 +1,43 @@ +package top.offsetmonkey538.monkeylib538.common.api.command; + +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.tree.CommandNode; +import top.offsetmonkey538.offsetutils538.api.annotation.Internal; + +import java.util.Collection; + +import static top.offsetmonkey538.monkeylib538.common.MonkeyLib538Common.load; + +/** + * Provides a method to register a {@link LiteralArgumentBuilder command} at startup. + */ +public interface CommandRegistrationApi { + @Internal + CommandRegistrationApi INSTANCE = load(CommandRegistrationApi.class); + + /** + * Adds the provided command to the list of commands to be registered at startup. + * + * @param command the command to register + */ + static void registerCommand(final LiteralArgumentBuilder command) { + registerCommand(command.build()); + } + + /** + * Adds the provided command to the list of commands to be registered at startup. + * + * @param command the command to register + */ + static void registerCommand(final CommandNode command) { + INSTANCE.registerCommandImpl(command); + } + + static Collection> getCommands() { + return INSTANCE.getCommandsImpl(); + } + + + @Internal void registerCommandImpl(final CommandNode command); + @Internal Collection> getCommandsImpl(); +} diff --git a/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/command/ConfigCommandApi.java b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/command/ConfigCommandApi.java new file mode 100644 index 0000000..107b90a --- /dev/null +++ b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/command/ConfigCommandApi.java @@ -0,0 +1,117 @@ +package top.offsetmonkey538.monkeylib538.common.api.command; + +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import org.jspecify.annotations.Nullable; +import top.offsetmonkey538.offsetutils538.api.annotation.Internal; +import top.offsetmonkey538.offsetutils538.api.config.ConfigHolder; + +import static top.offsetmonkey538.monkeylib538.common.MonkeyLib538Common.load; + +/** + * Provides methods for creating and registering config commands using {@link ConfigHolder}s. + * + *

A generated config command will have the following subcommands: + *

+ *     reset:
+ *         Resets the config to default values
+ *     reload:
+ *         Reloads the config from disk
+ *     location:
+ *         Prints the absolute path to the config file with a click event to copy it.
+ *     get:
+ *         option:
+ *             Gets the given config options value.
+ *     set:
+ *         option:
+ *             If there's no way to represent the config option in a command,
+ *             this will tell the user to modify it manually.
+ *             newValue:
+ *                 Sets the given config option to the given new value.
+ * 
+ */ +public interface ConfigCommandApi { + @Internal + ConfigCommandApi INSTANCE = load(ConfigCommandApi.class); + + /** + * Creates and registers a config command using the provided command tree and {@link ConfigHolder}. + * + *

The command tree could for example be {@code "modid", "config"} for the command to look like {@code /modid config reset/reload/get/set}

+ * + * @param configHolder your {@link ConfigHolder} instance. + * @param commandTree the command tree. + */ + static void registerConfigCommand(final ConfigHolder configHolder, final String... commandTree) { + registerConfigCommand(configHolder, null, commandTree); + } + /** + * Creates and registers a config command using the provided command tree and {@link ConfigHolder}. + *
+ * The {@code configReloadCallback} is executed after the {@code reload} command is run, and can be used for reinitializing stuff based on the new values. + *

The command tree could for example be {@code "modid", "config"} for the command to look like {@code /modid config reset/reload/get/set}

+ * + * @param configHolder your {@link ConfigHolder} instance. + * @param configReloadCallback executed when config is reloaded by the {@code reload} command. + * @param commandTree the command tree. + */ + static void registerConfigCommand(final ConfigHolder configHolder, final @Nullable Runnable configReloadCallback, final String... commandTree) { + registerConfigCommand(configHolder, configReloadCallback, null, commandTree); + } + /** + * Creates and registers a config command using the provided command tree and {@link ConfigHolder}. + *
+ * The {@code configReloadCallback} is executed after the {@code reload} command is run, and can be used for reinitializing stuff based on the new values. + * + *

The command tree could for example be {@code "modid", "config"} for the command to look like {@code /modid config reset/reload/get/set}

+ * + * @param configHolder your {@link ConfigHolder} instance. + * @param configReloadCallback executed when config is reloaded by the {@code reload} command. + * @param configValueSetCallback executed when a config value is changed by the {@code set} command. + * @param commandTree the command tree. + */ + static void registerConfigCommand(final ConfigHolder configHolder, final @Nullable Runnable configReloadCallback, final @Nullable Runnable configValueSetCallback, final String... commandTree) { + INSTANCE.registerConfigCommandImpl(configHolder, configReloadCallback, configValueSetCallback, commandTree); + } + + /** + * Creates a config command using the provided name and {@link ConfigHolder}. + * + * @param commandName the name of the command. + * @param configHolder your {@link ConfigHolder} instance. + * @return a config command using the provided name and {@link ConfigHolder}. + */ + static LiteralArgumentBuilder createConfigCommand(final String commandName, final ConfigHolder configHolder) { + return createConfigCommand(commandName, configHolder, null); + } + /** + * Creates a config command using the provided name and {@link ConfigHolder}. + *
+ * The {@code configReloadCallback} is executed after the {@code reload} command is run, and can be used for reinitializing stuff based on the new values. + * + * @param commandName the name of the command. + * @param configReloadCallback executed when config is reloaded by the {@code reload} command. + * @param configHolder your {@link ConfigHolder} instance. + * @return a config command using the provided name and {@link ConfigHolder}. + */ + static LiteralArgumentBuilder createConfigCommand(final String commandName, final ConfigHolder configHolder, final @Nullable Runnable configReloadCallback) { + return createConfigCommand(commandName, configHolder, configReloadCallback, null); + } + /** + * Creates a config command using the provided name and {@link ConfigHolder}. + *
+ * The {@code configReloadCallback} is executed after the {@code reload} command is run, and can be used for reinitializing stuff based on the new values. + * + * @param commandName the name of the command. + * @param configReloadCallback executed when config is reloaded by the {@code reload} command. + * @param configValueSetCallback executed when a config value is changed by the {@code set} command. + * @param configHolder your {@link ConfigHolder} instance. + * @return a config command using the provided name and {@link ConfigHolder}. + */ + static LiteralArgumentBuilder createConfigCommand(final String commandName, final ConfigHolder configHolder, final @Nullable Runnable configReloadCallback, final @Nullable Runnable configValueSetCallback) { + return INSTANCE.createConfigCommandImpl(commandName, configHolder, configReloadCallback, configValueSetCallback); + } + + + @Internal void registerConfigCommandImpl(final ConfigHolder configHolder, final @Nullable Runnable configReloadCallback, final @Nullable Runnable configValueSetCallback, final String... commandTree); + @Internal LiteralArgumentBuilder createConfigCommandImpl(final String commandName, final ConfigHolder configHolder, final @Nullable Runnable configReloadCallback, final @Nullable Runnable configValueSetCallback); +} diff --git a/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/command/package-info.java b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/command/package-info.java new file mode 100644 index 0000000..66d80b7 --- /dev/null +++ b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/command/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package top.offsetmonkey538.monkeylib538.common.api.command; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/lifecycle/ClientLifecycleApi.java b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/lifecycle/ClientLifecycleApi.java new file mode 100644 index 0000000..8d912f5 --- /dev/null +++ b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/lifecycle/ClientLifecycleApi.java @@ -0,0 +1,14 @@ +package top.offsetmonkey538.monkeylib538.common.api.lifecycle; + +import top.offsetmonkey538.offsetutils538.api.event.Event; + +public final class ClientLifecycleApi { + private ClientLifecycleApi() {} + + /** + * Runs the provided work when client finishes loading (right before loading screen fades to title screen) + */ + public static final Event LOAD_FINISHED = Event.createEvent(Runnable.class, handlers -> () -> { + for (final Runnable work : handlers) work.run(); + }); +} diff --git a/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/lifecycle/ServerLifecycleApi.java b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/lifecycle/ServerLifecycleApi.java new file mode 100644 index 0000000..4796eb8 --- /dev/null +++ b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/lifecycle/ServerLifecycleApi.java @@ -0,0 +1,20 @@ +package top.offsetmonkey538.monkeylib538.common.api.lifecycle; + +import top.offsetmonkey538.offsetutils538.api.event.Event; + +public final class ServerLifecycleApi { + private ServerLifecycleApi() {} + + public static final Event STARTING = Event.createEvent(Runnable.class, handlers -> () -> { + for (final Runnable work : handlers) work.run(); + }); + public static final Event STARTED = Event.createEvent(Runnable.class, handlers -> () -> { + for (final Runnable work : handlers) work.run(); + }); + public static final Event STOPPING = Event.createEvent(Runnable.class, handlers -> () -> { + for (final Runnable work : handlers) work.run(); + }); + public static final Event STOPPED = Event.createEvent(Runnable.class, handlers -> () -> { + for (final Runnable work : handlers) work.run(); + }); +} diff --git a/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/lifecycle/package-info.java b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/lifecycle/package-info.java new file mode 100644 index 0000000..45c6964 --- /dev/null +++ b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/lifecycle/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package top.offsetmonkey538.monkeylib538.common.api.lifecycle; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/platform/LoaderUtil.java b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/platform/LoaderUtil.java new file mode 100644 index 0000000..0fc8bc4 --- /dev/null +++ b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/platform/LoaderUtil.java @@ -0,0 +1,134 @@ +package top.offsetmonkey538.monkeylib538.common.api.platform; + +import net.kyori.adventure.text.Component; +import org.jspecify.annotations.Nullable; +import top.offsetmonkey538.offsetutils538.api.annotation.Internal; + +import java.nio.file.Path; +import java.util.function.Supplier; + +import static top.offsetmonkey538.monkeylib538.common.MonkeyLib538Common.load; + +/** + * Utilities methods for working with different loaders + */ +public interface LoaderUtil { + @Internal + LoaderUtil INSTANCE = load(LoaderUtil.class); + + /** + * Returns the current Minecraft version used. + * + * @return the current Minecraft version used + */ + static String getMinecraftVersion() { + return INSTANCE.getMinecraftVersionImpl(); + } + + /** + * Provides the current mod loader's name/branding. + * + *

When running on client, it's fine to call this whenever. + *
+ * When running on server, calling this before the SERVER_STARTING event has been invoked will return an empty string.

+ * + * @return the current mod loader's name/branding or an empty string when called on a dedicated server before it has started starting. + */ + static @Nullable String getLoaderName() { + return BrandGetter.INSTANCE.getBrand(); + } + + /** + * Returns the path to the config directory. + * + * @return the path to the config directory + */ + static Path getConfigDir() { + return INSTANCE.getConfigDirImpl(); + } + /** + * Returns the path to the mods directory. + * + * @return the path to the mods directory + */ + static Path getModsDir() { + return INSTANCE.getModsDirImpl(); + } + + /** + * Returns true when the game is launched in a development environment (IDE). + *
+ * On paper, this is only true when the system property {@code xyz.jpenilla.run-task} is true. + * + * @return true when the game is launched in a development environment (IDE). + */ + static boolean isDevelopmentEnvironment() { + return INSTANCE.isDevelopmentEnvironmentImpl(); + } + + /** + * Returns true when the game is launched as a dedicated server. + * + * @return true when the game is launched as a dedicated server + */ + static boolean isDedicatedServer() { + return INSTANCE.isDedicatedServerImpl(); + } + + /** + * Returns true when the game is launched as a dedicated server, and it's allowed to use the epoll channel type. + *

Calling before {@link top.offsetmonkey538.monkeylib538.common.api.lifecycle.ServerLifecycleApi#STARTING ServerLifecycleApi#STARTING} has been invoked will throw an {@link IllegalStateException}.

+ * + * @return true when the game is launched as a dedicated server it's allowed to use the epoll channel type. + */ + static boolean isEpollEnabled() { + return INSTANCE.isEpollEnabledImpl(); + } + + /** + * Returns the port that the Minecraft dedicated server binds to. + *

Calling before {@link top.offsetmonkey538.monkeylib538.common.api.lifecycle.ServerLifecycleApi#STARTING ServerLifecycleApi#STARTING} has been invoked will throw an {@link IllegalStateException}.

+ *

Calling when the game isn't running as a dedicated server will throw an {@link IllegalStateException}.

+ * + * @return the port that the Minecraft dedicated server binds to. + */ + static int getVanillaServerPort() { + return INSTANCE.getVanillaServerPortImpl(); + } + + /** + * Sends the messages supplied by the provided supplier to admins when they join. + *
+ * Also sends the message(s) on singleplayer start + * + * @param messageSupplier called to get the messages to send + */ + static void sendMessagesToAdminsOnJoin(final Supplier messageSupplier) { + INSTANCE.sendMessagesToAdminsOnJoinImpl(messageSupplier); + } + + @Internal String getMinecraftVersionImpl(); + @Internal Path getConfigDirImpl(); + @Internal Path getModsDirImpl(); + @Internal boolean isDevelopmentEnvironmentImpl(); + @Internal boolean isDedicatedServerImpl(); + @Internal boolean isEpollEnabledImpl(); + @Internal int getVanillaServerPortImpl(); + @Internal void sendMessagesToAdminsOnJoinImpl(final Supplier messageSupplier); + + @Internal + interface BrandGetter { + BrandGetter INSTANCE = isDedicatedServer() ? load(ServerBrandGetter.class) : load(ClientBrandGetter.class); + + @Nullable String getBrand(); + } + + @Internal + interface ClientBrandGetter extends BrandGetter { + + } + @Internal + interface ServerBrandGetter extends BrandGetter { + + } +} diff --git a/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/platform/package-info.java b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/platform/package-info.java new file mode 100644 index 0000000..e8ce00a --- /dev/null +++ b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/platform/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package top.offsetmonkey538.monkeylib538.common.api.platform; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/telemetry/TelemetryRegistry.java b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/telemetry/TelemetryRegistry.java new file mode 100644 index 0000000..b9de39c --- /dev/null +++ b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/telemetry/TelemetryRegistry.java @@ -0,0 +1,17 @@ +package top.offsetmonkey538.monkeylib538.common.api.telemetry; + +import top.offsetmonkey538.offsetutils538.api.annotation.Internal; + +import static top.offsetmonkey538.monkeylib538.common.MonkeyLib538Common.load; + +public interface TelemetryRegistry { + @Internal + TelemetryRegistry INSTANCE = load(TelemetryRegistry.class); + + static void register(final String modId) { + INSTANCE.registerImpl(modId); + } + + @Internal + void registerImpl(final String modId); +} diff --git a/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/telemetry/package-info.java b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/telemetry/package-info.java new file mode 100644 index 0000000..dc283d9 --- /dev/null +++ b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/telemetry/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package top.offsetmonkey538.monkeylib538.common.api.telemetry; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/text/TextFormattingApi.java b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/text/TextFormattingApi.java new file mode 100644 index 0000000..8c564a4 --- /dev/null +++ b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/text/TextFormattingApi.java @@ -0,0 +1,23 @@ +package top.offsetmonkey538.monkeylib538.common.api.text; + +import net.kyori.adventure.text.Component; +import top.offsetmonkey538.monkeylib538.common.impl.text.TextFormattingImpl; +import top.offsetmonkey538.offsetutils538.api.annotation.Internal; + +/** + * Parses my stupid custom format into a {@link Component}. + * @deprecated Not deprecated for removal, but this format is ass and shouldn't be used except for converting existing strings in configs and then serializing them with something more sensible like MiniMessage. + */ +@SuppressWarnings("DeprecatedIsStillUsed") +@Deprecated +public interface TextFormattingApi { + @Internal + TextFormattingApi INSTANCE = new TextFormattingImpl(); + + static Component styleText(final String text) throws Exception { + return INSTANCE.styleTextImpl(text); + } + + @Internal + Component styleTextImpl(final String text) throws Exception; +} diff --git a/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/text/package-info.java b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/text/package-info.java new file mode 100644 index 0000000..ed22205 --- /dev/null +++ b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/text/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package top.offsetmonkey538.monkeylib538.common.api.text; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/wrapper/Identifier.java b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/wrapper/Identifier.java new file mode 100644 index 0000000..2a5b1c6 --- /dev/null +++ b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/wrapper/Identifier.java @@ -0,0 +1,68 @@ +package top.offsetmonkey538.monkeylib538.common.api.wrapper; + +import com.mojang.serialization.Codec; +import top.offsetmonkey538.offsetutils538.api.annotation.Internal; + +import static top.offsetmonkey538.monkeylib538.common.MonkeyLib538Common.load; + +/** + * Wrapper around a vanilla Identifier/ResourceLocation. + */ +public interface Identifier { + /** + * Codec for this class + */ + Codec CODEC = load(CodecProvider.class).get(); + + /** + * Returns the namespace of this Identifier. + *
+ * Examples: {@code minecraft}, {@code monkeylib538}. + * + * @return the namespace of this Identifier + */ + String getNamespace(); + /** + * Returns the path of this Identifier. + * + * @return the path of this Identifier + */ + String getPath(); + + /** + * Creates an identifier from the provided location. + *

The location must separate the namespace and path with a colon like so {@code "namespace:path"}

+ * + * @param location the location to parse + * @return an identifier from the provided location + */ + static Identifier of(String location) { + return Instantiator.INSTANCE.of(location); + } + + /** + * Creates an identifier from the provided namespace and path. + * + * @param namespace the namespace of the identifier + * @param path the path of the identifier + * @return an identifier from the provided namespace and path + */ + static Identifier of(String namespace, String path) { + return Instantiator.INSTANCE.of(namespace, path); + } + + @Internal + interface Instantiator { + Instantiator INSTANCE = load(Instantiator.class); + + Identifier of(String location); + Identifier of(String namespace, String path); + } + + @Internal + interface CodecProvider { + CodecProvider INSTANCE = load(CodecProvider.class); + + Codec get(); + } +} diff --git a/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/wrapper/package-info.java b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/wrapper/package-info.java new file mode 100644 index 0000000..4cc0b22 --- /dev/null +++ b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/api/wrapper/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package top.offsetmonkey538.monkeylib538.common.api.wrapper; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/common/src/main/java/top/offsetmonkey538/monkeylib538/common/impl/command/CommandRegistrationApiImpl.java b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/impl/command/CommandRegistrationApiImpl.java new file mode 100644 index 0000000..3d96fde --- /dev/null +++ b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/impl/command/CommandRegistrationApiImpl.java @@ -0,0 +1,34 @@ +package top.offsetmonkey538.monkeylib538.common.impl.command; + +import com.mojang.brigadier.tree.CommandNode; +import top.offsetmonkey538.monkeylib538.common.api.command.CommandRegistrationApi; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +public final class CommandRegistrationApiImpl implements CommandRegistrationApi { + private static final Map> commands = new HashMap<>(); + + @Override + public void registerCommandImpl(CommandNode command) { + registerCommand(command); + } + + private static void registerCommand(final CommandNode command) { + @SuppressWarnings("unchecked") // I'm sure it'll be fineeee + final CommandNode existingCommand = (CommandNode) commands.get(command.getName()); + if (existingCommand == null) { + commands.put(command.getName(), command); + return; + } + for (final CommandNode child : command.getChildren()) { + existingCommand.addChild(child); + } + } + + @Override + public Collection> getCommandsImpl() { + return commands.values(); + } +} diff --git a/common/src/main/java/top/offsetmonkey538/monkeylib538/common/impl/command/ConfigCommandImpl.java b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/impl/command/ConfigCommandImpl.java new file mode 100644 index 0000000..3e55153 --- /dev/null +++ b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/impl/command/ConfigCommandImpl.java @@ -0,0 +1,228 @@ +package top.offsetmonkey538.monkeylib538.common.impl.command; + +import com.mojang.brigadier.Command; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.arguments.BoolArgumentType; +import com.mojang.brigadier.arguments.DoubleArgumentType; +import com.mojang.brigadier.arguments.FloatArgumentType; +import com.mojang.brigadier.arguments.IntegerArgumentType; +import com.mojang.brigadier.arguments.LongArgumentType; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.event.ClickEvent; +import net.kyori.adventure.text.event.HoverEvent; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; +import org.jspecify.annotations.Nullable; +import top.offsetmonkey538.monkeylib538.common.api.command.CommandAbstractionApi; +import top.offsetmonkey538.monkeylib538.common.api.command.CommandRegistrationApi; +import top.offsetmonkey538.monkeylib538.common.api.command.ConfigCommandApi; +import top.offsetmonkey538.monkeylib538.common.api.platform.LoaderUtil; +import top.offsetmonkey538.offsetutils538.api.config.Config; +import top.offsetmonkey538.offsetutils538.api.config.ConfigHolder; +import top.offsetmonkey538.offsetutils538.api.config.ConfigManager; +import top.offsetmonkey538.offsetutils538.api.log.ErrorHandler; + +import java.lang.reflect.Field; + +import static top.offsetmonkey538.monkeylib538.common.MonkeyLib538Common.LOGGER; +import static top.offsetmonkey538.monkeylib538.common.api.command.CommandAbstractionApi.argument; +import static top.offsetmonkey538.monkeylib538.common.api.command.CommandAbstractionApi.literal; +import static top.offsetmonkey538.offsetutils538.api.text.ArgReplacer.replaceArgs; + +public final class ConfigCommandImpl implements ConfigCommandApi { + public ConfigCommandImpl() { + + } + + @Override + public void registerConfigCommandImpl(ConfigHolder configHolder, @Nullable Runnable configReloadCallback, @Nullable Runnable configValueSetCallback, String... commandTree) { + @SuppressWarnings("unchecked") + LiteralArgumentBuilder command = (LiteralArgumentBuilder) ConfigCommandApi.createConfigCommand(commandTree[commandTree.length - 1], configHolder, configReloadCallback, configValueSetCallback); + for (int i = commandTree.length - 2; i >= 0; i--) { + final LiteralArgumentBuilder parent = literal(commandTree[i]); + parent.then(command); + command = parent; + } + + CommandRegistrationApi.registerCommand(command); + } + + @Override + public LiteralArgumentBuilder createConfigCommandImpl(String commandName, ConfigHolder configHolder, @Nullable Runnable configReloadCallback, @Nullable Runnable configValueSetCallback) { + final LiteralArgumentBuilder rootCommand = literal(commandName).requires(CommandAbstractionApi::isAdmin); + final String configName = configHolder.toString(); + + // Reset command + rootCommand.then(literal("reset").executes(ctx -> { + // Resets the config to default + configHolder.set(null); + + boolean[] failed = new boolean[]{false}; + ConfigManager.save(configHolder, createErrorHandler(ctx, configHolder, failed)); + if (failed[0]) return 0; + + CommandAbstractionApi.sendMessage(ctx, "Reset config '%s'.", configName); + return Command.SINGLE_SUCCESS; + })); + + // Reload command + rootCommand.then(literal("reload").executes(ctx -> { + boolean[] failed = new boolean[]{false}; + ConfigManager.init(configHolder, createErrorHandler(ctx, configHolder, failed)); + if (failed[0]) return 0; + + if (configReloadCallback != null) configReloadCallback.run(); + CommandAbstractionApi.sendMessage(ctx, "Reloaded config '%s'.", configName); + return Command.SINGLE_SUCCESS; + })); + + // Location command + rootCommand.then(literal("location").executes(ctx -> { + final String filePath = configHolder.get().getFilePath().toAbsolutePath().toString(); + CommandAbstractionApi.sendText(ctx, Component + .text(replaceArgs("Config '%s' is located at ", configHolder)) + .append(Component + .text(filePath) + .style(style -> style + .decorate(TextDecoration.UNDERLINED) + .hoverEvent(HoverEvent.showText(Component.text("Click to copy"))) + .clickEvent(ClickEvent.copyToClipboard(filePath)) + ) + ) + ); + return Command.SINGLE_SUCCESS; + })); + + // Config fields + final LiteralArgumentBuilder getCommand = literal("get"); + final LiteralArgumentBuilder setCommand = literal("set"); + + addGetSetCommandsForClass(getCommand, setCommand, configHolder.getConfigClass(), configHolder, configValueSetCallback); + + rootCommand.then(getCommand); + rootCommand.then(setCommand); + + return rootCommand; + } + + private static void addGetSetCommandsForClass(final LiteralArgumentBuilder getCommand, final LiteralArgumentBuilder setCommand, final Class fieldsHolder, final ConfigHolder configHolder, final @Nullable Runnable configValueSetCallback) { + addGetSetCommandsForClass(getCommand, setCommand, fieldsHolder, configHolder, configValueSetCallback, configHolder::get, null); + } + + private static void addGetSetCommandsForClass(final LiteralArgumentBuilder getCommand, final LiteralArgumentBuilder setCommand, final Class fieldsHolder, final ConfigHolder configHolder, final @Nullable Runnable configValueSetCallback, final FieldParentGetter fieldParentGetter, final @Nullable String fieldNamePrefix) { + if (fieldsHolder.getFields().length == 0) { + LOGGER.warn("Can't unpack class '%s' in config '%s' from tree '%s' as it doesn't contain any fields, ignoring!", fieldsHolder.getName(), configHolder, fieldNamePrefix); + if (fieldNamePrefix == null) { + LOGGER.error("The above error happened at the root of the config? Something is...... wrong"); + return; + } + + final LiteralArgumentBuilder command = literal(fieldNamePrefix).executes(context -> { + CommandAbstractionApi.sendText(context, Component + .text("The value of '%s' in config '%s' is too complex for the command. Please see the config manually at ").append(Component + .text(replaceArgs("[%s]", configHolder.get().getFilePath().toAbsolutePath().toString())).style(style -> style + .decorate(TextDecoration.UNDERLINED) + .hoverEvent(HoverEvent.showText(Component.text("Click to copy"))) + .clickEvent(ClickEvent.copyToClipboard(configHolder.get().getFilePath().toAbsolutePath().toString())) + ) + ).style(style -> style + .color(NamedTextColor.RED) + ) + ); + return 0; + }); + getCommand.then(command); + setCommand.then(command); + return; + } + + for (final Field field : fieldsHolder.getFields()) { + final String fieldName = fieldNamePrefix == null ? field.getName() : fieldNamePrefix + field.getName(); + final ArgumentType fieldValueType = getType(configHolder.toString(), field.getType()); + + if (fieldValueType == null) { + addGetSetCommandsForClass(getCommand, setCommand, field.getType(), configHolder, configValueSetCallback, fieldParentGetter.adopt(field), fieldName + "."); + continue; + } + + // This field can be used normally in a command + getCommand.then(createGetCommandForField(fieldName, field, fieldParentGetter, configHolder)); + setCommand.then(createSetCommandForField(fieldName, field, fieldValueType, fieldParentGetter, configHolder, configValueSetCallback)); + } + } + + private static LiteralArgumentBuilder createGetCommandForField(final String fieldName, final Field field, final FieldParentGetter fieldParentGetter, final ConfigHolder configHolder) { + return literal(fieldName).executes(ctx -> { + final Object value; + try { + value = field.get(fieldParentGetter.get()); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + CommandAbstractionApi.sendMessage(ctx, "The value of '%s' in config '%s' is '%s'", fieldName, configHolder, value); + return Command.SINGLE_SUCCESS; + }); + } + + private static LiteralArgumentBuilder createSetCommandForField(final String fieldName, final Field field, final ArgumentType fieldValueType, final FieldParentGetter fieldParentGetter, final ConfigHolder configHolder, final @Nullable Runnable configValueSetCallback) { + return literal(fieldName).then(argument("value", fieldValueType).executes(ctx -> { + final Object originalValue; + final Object newValue; + try { + originalValue = field.get(fieldParentGetter.get()); + newValue = ctx.getArgument("value", field.getType()); + + field.set(fieldParentGetter.get(), newValue); + + // Try saving + boolean[] failed = new boolean[]{false}; + ConfigManager.save(configHolder, createErrorHandler(ctx, configHolder, failed)); + if (failed[0]) return 0; + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + CommandAbstractionApi.sendMessage(ctx, "The value of '%s' in config '%s' has been changed from '%s' to '%s'!", fieldName, configHolder, originalValue, newValue); + if (configValueSetCallback != null) configValueSetCallback.run(); + return Command.SINGLE_SUCCESS; + })); + } + + private static ErrorHandler createErrorHandler(final CommandContext ctx, final ConfigHolder configHolder, final boolean[] failed) { + return configHolder.getErrorHandler().andThen((error, throwable) -> { + failed[0] = true; + + CommandAbstractionApi.sendError(ctx, "Error:\n%s", error); + + if (throwable != null) CommandAbstractionApi.sendError(ctx, "\nCause:\n%s", throwable); + }); + } + + private static @Nullable ArgumentType getType(final String configName, final Class value) { + // TODO: I think items and entities and vectors and stuff have their own argument type so add them as well + if (value.isAssignableFrom(Byte.class) || value.isAssignableFrom(byte.class)) return IntegerArgumentType.integer(Byte.MIN_VALUE, Byte.MAX_VALUE); + if (value.isAssignableFrom(Short.class) || value.isAssignableFrom(short.class)) return IntegerArgumentType.integer(Short.MIN_VALUE, Short.MAX_VALUE); + if (value.isAssignableFrom(Integer.class) || value.isAssignableFrom(int.class)) return IntegerArgumentType.integer(); + if (value.isAssignableFrom(Long.class) || value.isAssignableFrom(long.class)) return LongArgumentType.longArg(); + if (value.isAssignableFrom(Float.class) || value.isAssignableFrom(float.class)) return FloatArgumentType.floatArg(); + if (value.isAssignableFrom(Double.class) || value.isAssignableFrom(double.class)) return DoubleArgumentType.doubleArg(); + if (value.isAssignableFrom(Boolean.class) || value.isAssignableFrom(boolean.class)) return BoolArgumentType.bool(); + + if (value.isAssignableFrom(String.class)) return StringArgumentType.string(); + + if (LoaderUtil.isDevelopmentEnvironment()) LOGGER.info("Couldn't find suitable argument type for class '%s' in config '%s'! Unpacking from fields...", value.getName(), configName); + + return null; + } + + @FunctionalInterface + private interface FieldParentGetter { + Object get() throws IllegalAccessException; + + default FieldParentGetter adopt(Field newField) { + return () -> newField.get(this.get()); + } + } +} diff --git a/common/src/main/java/top/offsetmonkey538/monkeylib538/common/impl/command/package-info.java b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/impl/command/package-info.java new file mode 100644 index 0000000..73b8679 --- /dev/null +++ b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/impl/command/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package top.offsetmonkey538.monkeylib538.common.impl.command; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/common/src/main/java/top/offsetmonkey538/monkeylib538/common/impl/telemetry/TelemetryRegistryImpl.java b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/impl/telemetry/TelemetryRegistryImpl.java new file mode 100644 index 0000000..56cccb7 --- /dev/null +++ b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/impl/telemetry/TelemetryRegistryImpl.java @@ -0,0 +1,17 @@ +package top.offsetmonkey538.monkeylib538.common.impl.telemetry; + +import com.google.gson.JsonArray; +import top.offsetmonkey538.monkeylib538.common.api.telemetry.TelemetryRegistry; + +public final class TelemetryRegistryImpl implements TelemetryRegistry { + public final JsonArray registry = new JsonArray(); + + public TelemetryRegistryImpl() { + + } + + @Override + public void registerImpl(String modId) { + registry.add(modId); + } +} diff --git a/common/src/main/java/top/offsetmonkey538/monkeylib538/common/impl/telemetry/package-info.java b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/impl/telemetry/package-info.java new file mode 100644 index 0000000..34074c6 --- /dev/null +++ b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/impl/telemetry/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package top.offsetmonkey538.monkeylib538.common.impl.telemetry; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/common/src/main/java/top/offsetmonkey538/monkeylib538/common/impl/text/MonkeyLibStyle.java b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/impl/text/MonkeyLibStyle.java new file mode 100644 index 0000000..6fe14ae --- /dev/null +++ b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/impl/text/MonkeyLibStyle.java @@ -0,0 +1,121 @@ +package top.offsetmonkey538.monkeylib538.common.impl.text; + +import net.kyori.adventure.text.event.ClickEvent; +import net.kyori.adventure.text.event.HoverEvent; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.Style; +import net.kyori.adventure.text.format.TextColor; +import net.kyori.adventure.text.format.TextDecoration; +import org.jspecify.annotations.Nullable; + +import java.net.URI; +import java.nio.file.Path; +import java.util.Map; +import java.util.function.Function; + +record MonkeyLibStyle(Style style) { + private static final Map> FORMATTING_CODES = Map.ofEntries( + Map.entry('0', style -> style.withColor(NamedTextColor.BLACK.value())), + Map.entry('1', style -> style.withColor(NamedTextColor.DARK_BLUE.value())), + Map.entry('2', style -> style.withColor(NamedTextColor.DARK_GREEN.value())), + Map.entry('3', style -> style.withColor(NamedTextColor.DARK_AQUA.value())), + Map.entry('4', style -> style.withColor(NamedTextColor.DARK_RED.value())), + Map.entry('5', style -> style.withColor(NamedTextColor.DARK_PURPLE.value())), + Map.entry('6', style -> style.withColor(NamedTextColor.GOLD.value())), + Map.entry('7', style -> style.withColor(NamedTextColor.GRAY.value())), + Map.entry('8', style -> style.withColor(NamedTextColor.DARK_GRAY.value())), + Map.entry('9', style -> style.withColor(NamedTextColor.BLUE.value())), + Map.entry('a', style -> style.withColor(NamedTextColor.GREEN.value())), + Map.entry('b', style -> style.withColor(NamedTextColor.AQUA.value())), + Map.entry('c', style -> style.withColor(NamedTextColor.RED.value())), + Map.entry('d', style -> style.withColor(NamedTextColor.LIGHT_PURPLE.value())), + Map.entry('e', style -> style.withColor(NamedTextColor.YELLOW.value())), + Map.entry('f', style -> style.withColor(NamedTextColor.WHITE.value())), + Map.entry('k', style -> style.withObfuscated(true)), + Map.entry('l', style -> style.withBold(true)), + Map.entry('m', style -> style.withStrikethrough(true)), + Map.entry('n', style -> style.withUnderline(true)), + Map.entry('o', style -> style.withItalic(true)), + Map.entry('r', style -> MonkeyLibStyle.empty()) + ); + + public Style get() { + return style; + } + + public MonkeyLibStyle withShowText(MonkeyLibText value) { + return new top.offsetmonkey538.monkeylib538.common.impl.text.MonkeyLibStyle(style.hoverEvent(HoverEvent.showText(value.get()))); + } + + public MonkeyLibStyle withOpenUrl(URI value) { + return new top.offsetmonkey538.monkeylib538.common.impl.text.MonkeyLibStyle(style.clickEvent(ClickEvent.openUrl(value.toString()))); + } + + public MonkeyLibStyle withOpenFile(Path value) { + return new top.offsetmonkey538.monkeylib538.common.impl.text.MonkeyLibStyle(style.clickEvent(ClickEvent.openFile(value.toString()))); + } + + public MonkeyLibStyle withRunCommand(String value) { + return new top.offsetmonkey538.monkeylib538.common.impl.text.MonkeyLibStyle(style.clickEvent(ClickEvent.runCommand(value))); + } + + public MonkeyLibStyle withSuggestCommand(String value) { + return new top.offsetmonkey538.monkeylib538.common.impl.text.MonkeyLibStyle(style.clickEvent(ClickEvent.suggestCommand(value))); + } + + public MonkeyLibStyle withCopyToClipboard(String value) { + return new top.offsetmonkey538.monkeylib538.common.impl.text.MonkeyLibStyle(style.clickEvent(ClickEvent.copyToClipboard(value))); + } + + public MonkeyLibStyle copyEventsFrom(MonkeyLibStyle from) { + final Style fromStyle = from.get(); + return new top.offsetmonkey538.monkeylib538.common.impl.text.MonkeyLibStyle(style + .hoverEvent(fromStyle.hoverEvent()) + .clickEvent(fromStyle.clickEvent()) + ); + } + + public MonkeyLibStyle withObfuscated(boolean obfuscated) { + return withDecoration(TextDecoration.OBFUSCATED, obfuscated); + } + + public MonkeyLibStyle withBold(boolean bold) { + return withDecoration(TextDecoration.BOLD, bold); + } + + public MonkeyLibStyle withStrikethrough(boolean strikethrough) { + return withDecoration(TextDecoration.STRIKETHROUGH, strikethrough); + } + + public MonkeyLibStyle withUnderline(boolean underline) { + return withDecoration(TextDecoration.UNDERLINED, underline); + } + + public MonkeyLibStyle withItalic(final boolean italic) { + return withDecoration(TextDecoration.ITALIC, italic); + } + + private MonkeyLibStyle withDecoration(final TextDecoration decoration, final boolean value) { + return value == style.hasDecoration(decoration) ? this : new top.offsetmonkey538.monkeylib538.common.impl.text.MonkeyLibStyle(style.decoration(decoration, TextDecoration.State.byBoolean(value))); + } + + public MonkeyLibStyle withColor(final int rgbColor) { + //noinspection DataFlowIssue: IDE doesn't understand that VVV down there, style.color() can't be null because it's an OR after the null check + return style.color() == null || rgbColor != style.color().value() ? new top.offsetmonkey538.monkeylib538.common.impl.text.MonkeyLibStyle(style.color(TextColor.color(rgbColor))) : this; + } + + public @Nullable MonkeyLibStyle withFormattingCode(final char code) { + final Function action = FORMATTING_CODES.get(code); + + if (action == null) return null; + return action.apply(this); + } + + public boolean equals(final MonkeyLibStyle other) { + return this.style.equals(other.get()); + } + + static MonkeyLibStyle empty() { + return new MonkeyLibStyle(Style.empty()); + } +} diff --git a/common/src/main/java/top/offsetmonkey538/monkeylib538/common/impl/text/MonkeyLibText.java b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/impl/text/MonkeyLibText.java new file mode 100644 index 0000000..2f7ac17 --- /dev/null +++ b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/impl/text/MonkeyLibText.java @@ -0,0 +1,53 @@ +package top.offsetmonkey538.monkeylib538.common.impl.text; + +import net.kyori.adventure.text.Component; +import org.jspecify.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +final class MonkeyLibText { + private final Component text; + + private MonkeyLibText(final Component text) { + this.text = text.compact(); + } + + public Component get() { + return text; + } + + public @Nullable MonkeyLibText getLastSibling() { + return text.children() == null ? null : text.children().isEmpty() ? null : new MonkeyLibText(text.children().getLast()); + } + + public MonkeyLibText setLastSibling(MonkeyLibText newSibling) { + final List siblings = new ArrayList<>(text.children()); + siblings.set(siblings.size() - 1, newSibling.get()); + return new MonkeyLibText(text.children(siblings)); + } + + public MonkeyLibText append(final MonkeyLibText other) { + return new MonkeyLibText(text.append(other.get())); + } + + public MonkeyLibStyle getStyle() { + return new MonkeyLibStyle(text.style()); + } + + public MonkeyLibText setStyle(MonkeyLibStyle style) { + return new MonkeyLibText(text.style(style.get())); + } + + public String getString() { + return text.toString(); + } + + public static MonkeyLibText of(final String text) { + return new MonkeyLibText(Component.text(text)); + } + + public static MonkeyLibText empty() { + return new MonkeyLibText(Component.empty()); + } +} diff --git a/common/src/main/java/top/offsetmonkey538/monkeylib538/common/impl/text/TextFormattingImpl.java b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/impl/text/TextFormattingImpl.java new file mode 100644 index 0000000..de46cec --- /dev/null +++ b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/impl/text/TextFormattingImpl.java @@ -0,0 +1,249 @@ +package top.offsetmonkey538.monkeylib538.common.impl.text; + +import com.google.common.base.Suppliers; +import net.kyori.adventure.text.Component; +import top.offsetmonkey538.monkeylib538.common.api.text.TextFormattingApi; + +import java.net.URI; +import java.nio.file.Path; +import java.util.function.BiFunction; +import java.util.function.Supplier; + +import static top.offsetmonkey538.offsetutils538.api.text.ArgReplacer.replaceArgs; + +@SuppressWarnings("deprecation") +public final class TextFormattingImpl implements TextFormattingApi { + private static final Supplier DEFAULT_STYLE = Suppliers.memoize(() -> MonkeyLibStyle.empty().withItalic(false).withColor(0xFFFFFF)); + + @Override + public Component styleTextImpl(final String text) throws Exception { + MonkeyLibText result = MonkeyLibText.empty(); + + final Context context = new Context( + false, + false, + DEFAULT_STYLE.get(), + text.toCharArray(), + 0 + ); + + for (; context.characterIndex < context.characters.length; context.characterIndex++) { + context.currentChar = context.characters[context.characterIndex]; + result = handleChar(result, context); + } + + return result.get().compact(); + } + + private static MonkeyLibText handleChar(final MonkeyLibText result, final Context context) throws Exception { + // Previous character specified this one as a formatting code + if (context.isFormattingCode) switch (context.currentChar) { + case '#': + context.isFormattingCode = false; + handleHexCode(context); + return result; + case '{': + context.isFormattingCode = false; + return handleAction(result, context); + default: + context.isFormattingCode = false; + handleNormalFormattingCode(context); + return result; + } + + // When this character hasn't been escaped, check if it is a formatting code or escapes the next one. + if (!context.isEscaped) switch (context.currentChar) { + case '&': + context.isFormattingCode = true; + return result; + case '\\': + context.isEscaped = true; + return result; + } + context.isEscaped = false; + + + // Handle adding this character to the result + final MonkeyLibText lastSibling = result.getLastSibling(); + if (lastSibling != null && lastSibling.getStyle().equals(context.style)) { + return result.setLastSibling(MonkeyLibText.of(lastSibling.getString() + context.currentChar).setStyle(context.style)); + } else { + return result.append(MonkeyLibText.of(String.valueOf(context.currentChar)).setStyle(context.style)); + } + } + + private static void handleHexCode(final Context context) throws Exception { + final String hexCodeString = readChars(context, 6, "Unfinished hex code starting at character nr %s!"); + + final int hexCode; + try { + hexCode = Integer.parseInt(hexCodeString, 16); + } catch (NumberFormatException e) { + throw new Exception(replaceArgs("Invalid hex color '#%s' starting at character nr %s", hexCodeString, context.characterIndex), e); + } + + context.style = context.style.withColor(hexCode); + } + + private static MonkeyLibText handleAction(MonkeyLibText result, final Context context) throws Exception { + final int startIndex = context.characterIndex; + final String actionNameBoxed = readUntil(context, ','); // This has the current { char and the ending , char. So "{hoverText," + final String actionName = actionNameBoxed.substring(1, actionNameBoxed.length() - 1); // Only action name itself, without the { and ,. So "hoverText" + final Action action; + try { + action = Action.valueOf(actionName); + } catch (IllegalArgumentException e) { + throw new Exception(replaceArgs("Unknown action name '%s' starting at character nr %s!", actionName, startIndex)); + } + + context.readNext(); + if (context.currentChar != '\'') throw new Exception(replaceArgs("Expected character nr %s to be ' (single quote). Got %s", context.characterIndex, context.currentChar)); + + Object arg; + final MonkeyLibStyle originalStyle = context.style; + if (action.isArgStyled) { + arg = MonkeyLibText.empty(); + for (context.readNext(); context.characterIndex < context.characters.length; context.characterIndex++) { + context.currentChar = context.characters[context.characterIndex]; + + if (context.currentChar == '\'' && !context.isEscaped) break; + + arg = handleChar((MonkeyLibText) arg, context); + } + } else { + final StringBuilder builder = new StringBuilder(); + + for (context.readNext(); context.characterIndex < context.characters.length; context.characterIndex++) { + context.currentChar = context.characters[context.characterIndex]; + + if (context.isEscaped) { + context.isEscaped = false; + builder.append(context.currentChar); + continue; + } + if (context.currentChar == '\'') break; + if (context.currentChar == '\\') context.isEscaped = true; + + builder.append(context.currentChar); + } + + arg = builder.toString(); + } + + context.style = action.modifier.apply(originalStyle, arg); + + + context.readNext(); + if (context.currentChar != ',') throw new Exception(replaceArgs("Expected character nr %s to be , (coma). Got %s", context.characterIndex, context.currentChar)); + context.readNext(); + if (context.currentChar != '\'') throw new Exception(replaceArgs("Expected character nr %s to be ' (single quote). Got %s", context.characterIndex, context.currentChar)); + + for (context.readNext(); context.characterIndex < context.characters.length; context.characterIndex++) { + context.currentChar = context.characters[context.characterIndex]; + + if (context.currentChar == '\'' && !context.isEscaped) break; + + result = handleChar(result, context); + } + context.style = originalStyle; + + context.readNext(); + if (context.currentChar != '}') throw new Exception(replaceArgs("Expected character nr %s to be } (closed curly bracket). Got %s", context.characterIndex, context.currentChar)); + return result; + } + private static void handleNormalFormattingCode(final Context context) throws Exception { + if (context.currentChar == 'r') { + context.style = DEFAULT_STYLE.get().copyEventsFrom(context.style); + return; + } + + final MonkeyLibStyle newStyle = context.style.withFormattingCode(context.currentChar); + if (newStyle == null) throw new Exception(replaceArgs("Invalid formatting code '%s' at character nr %s'!", context.currentChar, context.characterIndex)); + context.style = newStyle; + } + + @SuppressWarnings("SameParameterValue") + private static String readChars(final Context context, final int numChars, final String error) throws Exception { + final int endIndex = context.characterIndex + numChars; + if (endIndex >= context.characters.length) throw new Exception(replaceArgs(error, context.characterIndex)); + + final StringBuilder builder = new StringBuilder(numChars); + for (context.characterIndex++; context.characterIndex <= endIndex; context.characterIndex++) { + context.currentChar = context.characters[context.characterIndex]; + builder.append(context.currentChar); + } + context.characterIndex--; + return builder.toString(); + } + + @SuppressWarnings("SameParameterValue") + private static String readUntil(final Context context, final char expectedChar) throws Exception { + final StringBuilder builder = new StringBuilder(); + final int startIndex = context.characterIndex; + final char startChar = context.currentChar; + + while (context.currentChar != expectedChar) { + builder.append(context.currentChar); + + context.characterIndex++; + if (context.characterIndex >= context.characters.length) throw new Exception(replaceArgs("Expected character '%s' at some point after character nr %s ('%s')!", expectedChar, startIndex, startChar)); + + context.currentChar = context.characters[context.characterIndex]; + } + builder.append(context.currentChar); + + return builder.toString(); + } + + private static final class Context { + private boolean isFormattingCode; + private boolean isEscaped; + private MonkeyLibStyle style; + private final char[] characters; + private int characterIndex; + private char currentChar; + + + private Context( + final boolean isFormattingCode, + final boolean isEscaped, + final MonkeyLibStyle style, + final char[] characters, + int characterIndex + ) { + this.isFormattingCode = isFormattingCode; + this.isEscaped = isEscaped; + this.style = style; + this.characters = characters; + this.characterIndex = characterIndex; + } + + private void readNext() { + this.characterIndex++; + this.currentChar = this.characters[this.characterIndex]; + } + } + + private enum Action { + hoverText(true, MonkeyLibStyle::withShowText), + + openUrl((style, arg) -> style.withOpenUrl(URI.create(arg))), + openFile((style, arg) -> style.withOpenFile(Path.of(arg))), + runCommand(MonkeyLibStyle::withRunCommand), + suggestCommand(MonkeyLibStyle::withSuggestCommand), + copyToClipboard(MonkeyLibStyle::withCopyToClipboard); + + + public final boolean isArgStyled; + public final BiFunction modifier; + + Action(@SuppressWarnings("unused") final boolean isArgStyled, final BiFunction modifier) { + this.isArgStyled = true; + this.modifier = (style, arg) -> modifier.apply(style, (MonkeyLibText) arg); + } + Action(final BiFunction modifier) { + this.isArgStyled = false; + this.modifier = (style, arg) -> modifier.apply(style, (String) arg); + } + } +} diff --git a/common/src/main/java/top/offsetmonkey538/monkeylib538/common/impl/text/package-info.java b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/impl/text/package-info.java new file mode 100644 index 0000000..e9025c8 --- /dev/null +++ b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/impl/text/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package top.offsetmonkey538.monkeylib538.common.impl.text; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/common/src/main/java/top/offsetmonkey538/monkeylib538/common/package-info.java b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/package-info.java new file mode 100644 index 0000000..6b97f9f --- /dev/null +++ b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package top.offsetmonkey538.monkeylib538.common; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/common/src/main/java/top/offsetmonkey538/monkeylib538/common/telemetry/TelemetryConfig.java b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/telemetry/TelemetryConfig.java new file mode 100644 index 0000000..c657e70 --- /dev/null +++ b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/telemetry/TelemetryConfig.java @@ -0,0 +1,26 @@ +package top.offsetmonkey538.monkeylib538.common.telemetry; + +import blue.endless.jankson.Comment; +import top.offsetmonkey538.monkeylib538.common.api.platform.LoaderUtil; +import top.offsetmonkey538.offsetutils538.api.config.Config; + +import java.nio.file.Path; + +import static top.offsetmonkey538.monkeylib538.common.MonkeyLib538Common.MOD_ID; + +public final class TelemetryConfig implements Config { + @Comment("Boolean for enabling/disabling telemetry, either true or false. Defaults to true") + public boolean isEnabled = !LoaderUtil.isDevelopmentEnvironment(); + @Comment("Used for making sure the first launch won't send any telemetry data to give time to modify the config after it's been generated. Defaults to true, but is set to false after launching") + public boolean isFirstLaunch = true; + + @Override + public Path getConfigDirPath() { + return LoaderUtil.getConfigDir(); + } + + @Override + public String getId() { + return MOD_ID + "/telemetry"; + } +} diff --git a/common/src/main/java/top/offsetmonkey538/monkeylib538/common/telemetry/TelemetryHandler.java b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/telemetry/TelemetryHandler.java new file mode 100644 index 0000000..878eeff --- /dev/null +++ b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/telemetry/TelemetryHandler.java @@ -0,0 +1,91 @@ +package top.offsetmonkey538.monkeylib538.common.telemetry; + +import com.google.gson.JsonObject; +import top.offsetmonkey538.monkeylib538.common.api.command.ConfigCommandApi; +import top.offsetmonkey538.monkeylib538.common.api.lifecycle.ClientLifecycleApi; +import top.offsetmonkey538.monkeylib538.common.api.lifecycle.ServerLifecycleApi; +import top.offsetmonkey538.monkeylib538.common.api.platform.LoaderUtil; +import top.offsetmonkey538.monkeylib538.common.api.telemetry.TelemetryRegistry; +import top.offsetmonkey538.monkeylib538.common.impl.telemetry.TelemetryRegistryImpl; +import top.offsetmonkey538.offsetutils538.api.config.ConfigHolder; +import top.offsetmonkey538.offsetutils538.api.config.ConfigManager; + +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; + +import static top.offsetmonkey538.monkeylib538.common.MonkeyLib538Common.LOGGER; +import static top.offsetmonkey538.monkeylib538.common.MonkeyLib538Common.MOD_ID; + +public final class TelemetryHandler { + private TelemetryHandler() { + + } + + private static boolean hasSent = false; + + private static final ConfigHolder telemetryConfig = ConfigManager.init(ConfigHolder.create(TelemetryConfig::new, LOGGER)); + + public static void initialize() { + TelemetryRegistry.register(MOD_ID); + ConfigCommandApi.registerConfigCommand(telemetryConfig, null, TelemetryHandler::sendOnNewThread, MOD_ID, "telemetry"); + + if (telemetryConfig.get().isFirstLaunch) { + LOGGER.info("Not sending telemetry on first launch to allow for disabling it after config creation."); + telemetryConfig.get().isFirstLaunch = false; + ConfigManager.save(telemetryConfig); + return; + } + + // Other mods have probably registered themselves for telemetry before either of the two following points. They should just be able to use their default initializers afaik + // For dedicated servers, I need to use ServerStarted as LoaderUtil$ServerBrandGetter only starts working after ServerStarting happens. + if (LoaderUtil.isDedicatedServer()) ServerLifecycleApi.STARTING.listen(TelemetryHandler::sendOnNewThread); + // For clients, running once loading finishes is probably fine. + else ClientLifecycleApi.LOAD_FINISHED.listen(TelemetryHandler::sendOnNewThread); + } + + public static void sendOnNewThread() { + // TODO: maybe should have some better way of creating the thread? + new Thread(() -> { + if (telemetryConfig.get().isEnabled && !hasSent) try { + TelemetryHandler.send(); + hasSent = true; + } catch (Exception e) { + LOGGER.error("Failed to send telemetry data :(", e); + } + }).start(); + } + + private static void send() throws IOException, InterruptedException { + final String jsonData = collectAnalytics(); + byte[] data = jsonData.getBytes(StandardCharsets.UTF_8); + + final HttpRequest.Builder request = HttpRequest.newBuilder(URI.create("https://analytics.offsetmonkey538.top/ingest")); + request.POST(HttpRequest.BodyPublishers.ofByteArray(data)); + request.version(HttpClient.Version.HTTP_1_1); + request.header("User-Agent", "MonkeyLib538/1"); + request.header("Content-Type", "application/json"); + + try (final HttpClient client = HttpClient.newBuilder().build()) { + final HttpResponse response = client.send(request.build(), HttpResponse.BodyHandlers.ofString()); + + if (response.statusCode() >= 200 && response.statusCode() <= 299) return; + + LOGGER.error("Received non-2xx response when trying to send the following telemetry data: %s", jsonData); + LOGGER.error("Full response:\n%s", response.body()); + } + } + + private static String collectAnalytics() { + final JsonObject jsobData = new JsonObject(); + jsobData.addProperty("mc", LoaderUtil.getMinecraftVersion()); + jsobData.addProperty("e", LoaderUtil.isDedicatedServer() ? "s" : "c"); + jsobData.addProperty("l", LoaderUtil.getLoaderName() == null ? "unknown" : LoaderUtil.getLoaderName()); + jsobData.add("m", ((TelemetryRegistryImpl) TelemetryRegistry.INSTANCE).registry); + + return jsobData.toString(); + } +} diff --git a/common/src/main/java/top/offsetmonkey538/monkeylib538/common/telemetry/package-info.java b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/telemetry/package-info.java new file mode 100644 index 0000000..17a82fc --- /dev/null +++ b/common/src/main/java/top/offsetmonkey538/monkeylib538/common/telemetry/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package top.offsetmonkey538.monkeylib538.common.telemetry; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/common/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.command.CommandRegistrationApi b/common/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.command.CommandRegistrationApi new file mode 100644 index 0000000..958cb3e --- /dev/null +++ b/common/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.command.CommandRegistrationApi @@ -0,0 +1 @@ +top.offsetmonkey538.monkeylib538.common.impl.command.CommandRegistrationApiImpl \ No newline at end of file diff --git a/common/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.command.ConfigCommandApi b/common/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.command.ConfigCommandApi new file mode 100644 index 0000000..1e14b9e --- /dev/null +++ b/common/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.command.ConfigCommandApi @@ -0,0 +1 @@ +top.offsetmonkey538.monkeylib538.common.impl.command.ConfigCommandImpl \ No newline at end of file diff --git a/common/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.telemetry.TelemetryRegistry b/common/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.telemetry.TelemetryRegistry new file mode 100644 index 0000000..cff3404 --- /dev/null +++ b/common/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.telemetry.TelemetryRegistry @@ -0,0 +1 @@ +top.offsetmonkey538.monkeylib538.common.impl.telemetry.TelemetryRegistryImpl \ No newline at end of file diff --git a/common/src/main/resources/assets/monkeylib538/icon.png b/common/src/main/resources/assets/monkeylib538/icon.png new file mode 100644 index 0000000..ab96e21 Binary files /dev/null and b/common/src/main/resources/assets/monkeylib538/icon.png differ diff --git a/gradle.properties b/gradle.properties index cfb8a50..eec0bfa 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,20 +1,38 @@ # Increase memory and *parallel* -org.gradle.jvmargs = -Xmx6G +org.gradle.jvmargs = -Xmx8G org.gradle.parallel = true -# Fabric -# Check at https://fabricmc.net/develop -minecraft_version = 1.20.4 - -# These should be automatically updated, unless the environment -# variable "DISABLE_PROPERTIES_UPDATE" is set. -yarn_version = 1.20.4+build.3 -loader_version = 0.15.3 - # Dependencies -# Jankson, check at https://github.com/falkreon/Jankson +## OffsetUtils538, check at https://github.com/OffsetMods538/OffsetUtils538 +offsetutils538_version = 1.0.0-beta.0.1769521362208+909721c +## DataFixerUpper, check at https://github.com/Mojang/DataFixerUpper +datafixerupper_version = 8.0.16 +## GSON, idk +gson_version = 2.11.0 +## Brigadier, check at https://github.com/Mojang/brigadier +brigadier_version = 1.0.18 +## JSpecify, check at https://mvnrepository.com/artifact/org.jspecify/jspecify +jspecify_version = 1.0.0 +## Jankson, check at https://github.com/falkreon/Jankson jankson_version = 1.2.3 +## DevAuth, check at https://github.com/DJtheRedstoner/DevAuth +devauth_version = 1.2.2 + +## Gradle plugins +neoforged_moddev = 2.0.+ +fabric_loom = 1.15-SNAPSHOT +papermc_paperweight_userdev = 2.0.0-beta.19 +jpenilla_run_task = 3.0.2 +gradleup_shadow = 9.3.1 +jpenilla_resource_factory = 1.3.1 +dexman_outlet = 1.6.1 +modrinth_minotaur = 2.+ # Mod Properties -mod_version = 1.0.2 -supported_minecraft_versions = >=1.19.2 +mod_version = 3.0.0-beta.2 +mod_name = MonkeyLib538 +mod_id = monkeylib538 +mod_description = A library for OffsetMonkey538's mods that allows for multiversion and -loader coolness +mod_website = https://modrinth.com/mod/monkeylib538 +mod_issues = https://github.com/OffsetMods538/MonkeyLib538/issues +mod_sources = https://github.com/OffsetMods538/MonkeyLib538 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index c1962a7..61285a6 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ac7cb7a..44ae953 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,8 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=9d926787066a081739e8200858338b4a69e837c3a821a33aca9db09dd4a41026 -distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip +distributionSha256Sum=0d585f69da091fc5b2beced877feab55a3064d43b8a1d46aeb07996b0915e0e0 +distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.0-bin.zip networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index aeb74cb..adff685 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015-2021 the original authors. +# Copyright © 2015 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -83,7 +85,8 @@ done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -111,7 +114,6 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -130,10 +132,13 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. @@ -141,7 +146,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac @@ -149,7 +154,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -166,7 +171,6 @@ fi # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) @@ -198,16 +202,15 @@ fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" # Stop when "xargs" is not available. diff --git a/gradlew.bat b/gradlew.bat index 93e3f59..c4bdd3a 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @@ -43,11 +45,11 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -57,22 +59,21 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail :execute @rem Setup the command line -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* :end @rem End local scope for the variables with windows NT shell diff --git a/javadoc-stylesheet.css b/javadoc-stylesheet.css new file mode 100644 index 0000000..3d30c98 --- /dev/null +++ b/javadoc-stylesheet.css @@ -0,0 +1,34 @@ +:root { + --body-text-color: #e0e0e3; + --block-text-color: #e6e7ef; + --body-background-color: #404040; + --section-background-color: #484848; + --detail-background-color: #404040; + --navbar-text-color: #ffffff; + --subnav-background-color: #303030; + --selected-background-color: #f8981d; + --selected-text-color: #253441; + --selected-link-color: #1f389c; + --even-row-color: #484848; + --odd-row-color: #383838; + --title-color: #ffffff; + --link-color: #a0c0f8; + --link-color-active: #ffb863; + --snippet-background-color: #383838; + --snippet-text-color: var(--block-text-color); + --snippet-highlight-color: #f7c590; + --border-color: #383838; + --table-border-color: #000000; + --search-input-background-color: #000000; + --search-input-text-color: #ffffff; + --search-input-placeholder-color: #909090; + --search-tag-highlight-color: #ffff00; + --copy-icon-brightness: 250%; + --copy-button-background-color-active: rgba(168, 168, 176, 0.3); + --invalid-tag-background-color: #ffe6e6; + --invalid-tag-text-color: #000000; +} + +.top-nav { + background: linear-gradient(to right, #ff005b, #ff146a, #ff2980, #e93f80, #d45480, #be6980, #a97f80, #7e7f80); +} diff --git a/jitpack.yml b/jitpack.yml deleted file mode 100644 index 11927c4..0000000 --- a/jitpack.yml +++ /dev/null @@ -1,4 +0,0 @@ -jdk: - - openjdk17 -env: - DISABLE_PROPERTIES_UPDATE: true \ No newline at end of file diff --git a/loader/fabric/1.21.1/gradle.properties b/loader/fabric/1.21.1/gradle.properties new file mode 100644 index 0000000..46cbce5 --- /dev/null +++ b/loader/fabric/1.21.1/gradle.properties @@ -0,0 +1,15 @@ +project_name = fabric-1.21.1 +commonModdedVersion = 1.21.1 + +# Dependencies +## Adventure +adventure_version = 5.14.2 + +# Minecraft version +minecraft_version = 1.21.1 +supported_minecraft_versions = >=1.21.1 <=1.21.8 + +# These should be automatically updated, unless the environment +# variable "DISABLE_PROPERTIES_UPDATE" is set. +loader_version = 0.18.4 +fapi_version = 0.116.8+1.21.1 diff --git a/loader/fabric/1.21.1/src/main/java/top/offsetmonkey538/monkeylib538/fabric/v1211/.gitkeep b/loader/fabric/1.21.1/src/main/java/top/offsetmonkey538/monkeylib538/fabric/v1211/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/loader/fabric/1.21.11/gradle.properties b/loader/fabric/1.21.11/gradle.properties new file mode 100644 index 0000000..20b4591 --- /dev/null +++ b/loader/fabric/1.21.11/gradle.properties @@ -0,0 +1,15 @@ +project_name = fabric-1.21.11 +commonModdedVersion = 1.21.11 + +# Dependencies +## Adventure +adventure_version = 6.8.0 + +# Minecraft version +minecraft_version = 1.21.11 +supported_minecraft_versions = >=1.21.11 + +# These should be automatically updated, unless the environment +# variable "DISABLE_PROPERTIES_UPDATE" is set. +loader_version = 0.18.4 +fapi_version = 0.141.3+1.21.11 diff --git a/loader/fabric/1.21.11/src/main/java/top/offsetmonkey538/monkeylib538/fabric/v12111/.gitkeep b/loader/fabric/1.21.11/src/main/java/top/offsetmonkey538/monkeylib538/fabric/v12111/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/loader/fabric/1.21.9/gradle.properties b/loader/fabric/1.21.9/gradle.properties new file mode 100644 index 0000000..31f3702 --- /dev/null +++ b/loader/fabric/1.21.9/gradle.properties @@ -0,0 +1,15 @@ +project_name = fabric-1.21.9 +commonModdedVersion = 1.21.9 + +# Dependencies +## Adventure +adventure_version = 6.7.0 + +# Minecraft version +minecraft_version = 1.21.9 +supported_minecraft_versions = >=1.21.9 <=1.21.10 + +# These should be automatically updated, unless the environment +# variable "DISABLE_PROPERTIES_UPDATE" is set. +loader_version = 0.18.4 +fapi_version = 0.134.1+1.21.9 diff --git a/loader/fabric/1.21.9/src/main/java/top/offsetmonkey538/monkeylib538/fabric/v1219/.gitkeep b/loader/fabric/1.21.9/src/main/java/top/offsetmonkey538/monkeylib538/fabric/v1219/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/loader/fabric/build.gradle b/loader/fabric/build.gradle new file mode 100644 index 0000000..99f65f5 --- /dev/null +++ b/loader/fabric/build.gradle @@ -0,0 +1,53 @@ +import dex.plugins.outlet.v2.util.ReleaseType +import xyz.jpenilla.resourcefactory.fabric.Environment + +plugins { + id 'multiloader-fabric' +} + +allprojects { + fabricModJson { + mitLicense() + author("OffsetMonkey538") + contact { + extra = ["discord": "https://discord.offsetmonkey538.top"] + } + environment = Environment.ANY + mainEntrypoint("top.offsetmonkey538.monkeylib538.fabric.MonkeyLib538Initializer") + mixin("monkeylib538.modded.mixins.json") + + depends("fabric-api", "*") + depends("adventure-platform-fabric", "*") + + breaks("cog", "<=2.1.1") + breaks("bettermultishot", "<=2.5.0") + breaks("withered-bone-meal", "<=2.2.0") + breaks("github-resourcepack-manager", "<=4.0.1") + breaks("better-fire-aspect", "<=1.1.0") + breaks("easy-item-despawn", "<=1.1.0") + } + + // Gotta have this here cause I can't import it in buildSrc + outlet.allowedReleaseTypes = Set.of(ReleaseType.RELEASE) + + dependencies { + modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fapi_version}" + modImplementation("net.kyori:adventure-platform-fabric:${project.adventure_version}") { + exclude(group: "net.fabricmc.fabric-api") + } + } +} + +subprojects { + dependencies { + includeRuntime "top.offsetmonkey538.offsetutils538:offsetutils538:${rootProject.offsetutils538_version}" + includeRuntime "blue.endless:jankson:${rootProject.jankson_version}" + } + + modrinth { + dependencies { + required.project "fabric-api" + required.project "adventure-platform-mod" + } + } +} diff --git a/loader/fabric/gradle.properties b/loader/fabric/gradle.properties new file mode 100644 index 0000000..e02b9fb --- /dev/null +++ b/loader/fabric/gradle.properties @@ -0,0 +1,14 @@ +project_name = fabric + +# Dependencies +## Adventure +adventure_version = 6.8.0 + +# Minecraft version +minecraft_version = 1.21.10 +supported_minecraft_versions = * + +# These should be automatically updated, unless the environment +# variable "DISABLE_PROPERTIES_UPDATE" is set. +loader_version = 0.18.4 +fapi_version = 0.138.4+1.21.10 diff --git a/loader/fabric/src/main/java/top/offsetmonkey538/monkeylib538/fabric/MonkeyLib538Initializer.java b/loader/fabric/src/main/java/top/offsetmonkey538/monkeylib538/fabric/MonkeyLib538Initializer.java new file mode 100644 index 0000000..13f0e7c --- /dev/null +++ b/loader/fabric/src/main/java/top/offsetmonkey538/monkeylib538/fabric/MonkeyLib538Initializer.java @@ -0,0 +1,45 @@ +package top.offsetmonkey538.monkeylib538.fabric; + +import com.mojang.brigadier.tree.CommandNode; +import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; +import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.server.dedicated.DedicatedServer; +import org.jspecify.annotations.Nullable; +import top.offsetmonkey538.monkeylib538.common.MonkeyLib538Common; +import top.offsetmonkey538.monkeylib538.common.api.command.CommandRegistrationApi; +import top.offsetmonkey538.monkeylib538.common.api.lifecycle.ServerLifecycleApi; + +public class MonkeyLib538Initializer implements ModInitializer { + private static @Nullable DedicatedServer minecraftServer = null; + + /** + * Public no-args constructor for fabric to do it's magic with + */ + public MonkeyLib538Initializer() { + + } + + @Override + public void onInitialize() { + MonkeyLib538Common.initialize(); + + CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> { + //noinspection unchecked + CommandRegistrationApi.getCommands().forEach(command -> dispatcher.getRoot().addChild((CommandNode) command)); + }); + + ServerLifecycleEvents.SERVER_STARTING.register(minecraftServer1 -> { + minecraftServer = (minecraftServer1 instanceof DedicatedServer server ? server : null); + ServerLifecycleApi.STARTING.getInvoker().run(); + }); + ServerLifecycleEvents.SERVER_STARTED.register(minecraftServer -> ServerLifecycleApi.STARTED.getInvoker().run()); + ServerLifecycleEvents.SERVER_STOPPING.register(minecraftServer -> ServerLifecycleApi.STOPPING.getInvoker().run()); + ServerLifecycleEvents.SERVER_STOPPED.register(minecraftServer -> ServerLifecycleApi.STOPPED.getInvoker().run()); + } + + public static @Nullable DedicatedServer getServer() { + return minecraftServer; + } +} diff --git a/loader/fabric/src/main/java/top/offsetmonkey538/monkeylib538/fabric/impl/platform/LoaderUtilImpl.java b/loader/fabric/src/main/java/top/offsetmonkey538/monkeylib538/fabric/impl/platform/LoaderUtilImpl.java new file mode 100644 index 0000000..5e4c666 --- /dev/null +++ b/loader/fabric/src/main/java/top/offsetmonkey538/monkeylib538/fabric/impl/platform/LoaderUtilImpl.java @@ -0,0 +1,65 @@ +package top.offsetmonkey538.monkeylib538.fabric.impl.platform; + +import net.fabricmc.api.EnvType; +import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; +import net.fabricmc.loader.api.FabricLoader; +import net.fabricmc.loader.impl.util.SystemProperties; +import net.kyori.adventure.text.Component; +import top.offsetmonkey538.monkeylib538.common.api.platform.LoaderUtil; +import top.offsetmonkey538.monkeylib538.fabric.MonkeyLib538Initializer; +import top.offsetmonkey538.monkeylib538.modded.api.player.ModdedPlayerApi; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.function.Supplier; + +public final class LoaderUtilImpl implements LoaderUtil { + @Override + public String getMinecraftVersionImpl() { + return FabricLoader.getInstance().getRawGameVersion(); + } + + @Override + public Path getConfigDirImpl() { + return FabricLoader.getInstance().getConfigDir(); + } + + @Override + public Path getModsDirImpl() { + final String directory = System.getProperty(SystemProperties.MODS_FOLDER); + return directory == null ? FabricLoader.getInstance().getGameDir().resolve("mods") : Paths.get(directory); + } + + @Override + public boolean isDevelopmentEnvironmentImpl() { + return FabricLoader.getInstance().isDevelopmentEnvironment(); + } + + @Override + public boolean isDedicatedServerImpl() { + return FabricLoader.getInstance().getEnvironmentType() == EnvType.SERVER; + } + + @Override + public boolean isEpollEnabledImpl() { + if (!isDedicatedServerImpl()) return false; + if (MonkeyLib538Initializer.getServer() == null) throw new IllegalStateException("Tried calling 'isEpollEnabledImpl' before server STARTING event was invoked!"); + return MonkeyLib538Initializer.getServer().getProperties().useNativeTransport; + } + + @Override + public int getVanillaServerPortImpl() { + if (!isDedicatedServerImpl()) throw new IllegalStateException("Tried calling 'getVanillaServerPortImpl' when game isn't a dedicated server!"); + if (MonkeyLib538Initializer.getServer() == null) throw new IllegalStateException("Tried calling 'getVanillaServerPortImpl' before server STARTING event was invoked!"); + return MonkeyLib538Initializer.getServer().getServerPort(); + } + + @Override + public void sendMessagesToAdminsOnJoinImpl(Supplier messageSupplier) { + ServerPlayConnectionEvents.JOIN.register(((serverPlayNetworkHandler, packetSender, minecraftServer) -> { + if (!ModdedPlayerApi.isPlayerOp(minecraftServer.getPlayerList(), serverPlayNetworkHandler.player) && !ModdedPlayerApi.isPlayerHost(minecraftServer, serverPlayNetworkHandler.player)) return; + + for (Component text : messageSupplier.get()) serverPlayNetworkHandler.player.sendMessage(text); + })); + } +} diff --git a/loader/fabric/src/main/java/top/offsetmonkey538/monkeylib538/fabric/impl/platform/package-info.java b/loader/fabric/src/main/java/top/offsetmonkey538/monkeylib538/fabric/impl/platform/package-info.java new file mode 100644 index 0000000..0b61fa0 --- /dev/null +++ b/loader/fabric/src/main/java/top/offsetmonkey538/monkeylib538/fabric/impl/platform/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package top.offsetmonkey538.monkeylib538.fabric.impl.platform; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/loader/fabric/src/main/java/top/offsetmonkey538/monkeylib538/fabric/impl/server/ServerProviderImpl.java b/loader/fabric/src/main/java/top/offsetmonkey538/monkeylib538/fabric/impl/server/ServerProviderImpl.java new file mode 100644 index 0000000..d56c4cd --- /dev/null +++ b/loader/fabric/src/main/java/top/offsetmonkey538/monkeylib538/fabric/impl/server/ServerProviderImpl.java @@ -0,0 +1,14 @@ +package top.offsetmonkey538.monkeylib538.fabric.impl.server; + +import net.minecraft.server.dedicated.DedicatedServer; +import org.jspecify.annotations.Nullable; +import top.offsetmonkey538.monkeylib538.fabric.MonkeyLib538Initializer; +import top.offsetmonkey538.monkeylib538.modded.api.server.ServerProvider; + +public final class ServerProviderImpl implements ServerProvider { + + @Override + public @Nullable DedicatedServer getServerImpl() { + return MonkeyLib538Initializer.getServer(); + } +} diff --git a/loader/fabric/src/main/java/top/offsetmonkey538/monkeylib538/fabric/impl/server/package-info.java b/loader/fabric/src/main/java/top/offsetmonkey538/monkeylib538/fabric/impl/server/package-info.java new file mode 100644 index 0000000..238dd6e --- /dev/null +++ b/loader/fabric/src/main/java/top/offsetmonkey538/monkeylib538/fabric/impl/server/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package top.offsetmonkey538.monkeylib538.fabric.impl.server; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/loader/fabric/src/main/java/top/offsetmonkey538/monkeylib538/fabric/package-info.java b/loader/fabric/src/main/java/top/offsetmonkey538/monkeylib538/fabric/package-info.java new file mode 100644 index 0000000..8d0ef35 --- /dev/null +++ b/loader/fabric/src/main/java/top/offsetmonkey538/monkeylib538/fabric/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package top.offsetmonkey538.monkeylib538.fabric; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/loader/fabric/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.platform.LoaderUtil b/loader/fabric/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.platform.LoaderUtil new file mode 100644 index 0000000..ce3148b --- /dev/null +++ b/loader/fabric/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.platform.LoaderUtil @@ -0,0 +1 @@ +top.offsetmonkey538.monkeylib538.fabric.impl.platform.LoaderUtilImpl \ No newline at end of file diff --git a/loader/fabric/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.modded.api.server.ServerProvider b/loader/fabric/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.modded.api.server.ServerProvider new file mode 100644 index 0000000..f760846 --- /dev/null +++ b/loader/fabric/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.modded.api.server.ServerProvider @@ -0,0 +1 @@ +top.offsetmonkey538.monkeylib538.fabric.impl.server.ServerProviderImpl \ No newline at end of file diff --git a/loader/neoforge/1.21.1/gradle.properties b/loader/neoforge/1.21.1/gradle.properties new file mode 100644 index 0000000..3360959 --- /dev/null +++ b/loader/neoforge/1.21.1/gradle.properties @@ -0,0 +1,15 @@ +project_name = neoforge-1.21.1 +commonModdedVersion = 1.21.1 + +# Dependencies +## Adventure +adventure_version = 6.0.0 + +# Minecraft version +minecraft_version = 1.21.1 +supported_minecraft_versions = >=1.21.1 <=1.21.8 +minecraft_version_range = [1.21.1,1.21.8] + +neoforge_version = 21.1.219 +parchment_minecraft_version = 1.21.1 +parchment_mappings_version = 2024.11.17 diff --git a/loader/neoforge/1.21.1/src/main/java/top/offsetmonkey538/monkeylib538/neoforge/v1211/impl/platform/VersionSpecificLoaderUtilImpl.java b/loader/neoforge/1.21.1/src/main/java/top/offsetmonkey538/monkeylib538/neoforge/v1211/impl/platform/VersionSpecificLoaderUtilImpl.java new file mode 100644 index 0000000..2057a39 --- /dev/null +++ b/loader/neoforge/1.21.1/src/main/java/top/offsetmonkey538/monkeylib538/neoforge/v1211/impl/platform/VersionSpecificLoaderUtilImpl.java @@ -0,0 +1,24 @@ +package top.offsetmonkey538.monkeylib538.neoforge.v1211.impl.platform; + +import net.neoforged.api.distmarker.Dist; +import net.neoforged.fml.loading.FMLEnvironment; +import net.neoforged.fml.loading.FMLLoader; +import net.neoforged.fml.loading.VersionInfo; +import top.offsetmonkey538.monkeylib538.neoforge.impl.platform.LoaderUtilImpl; + +public final class VersionSpecificLoaderUtilImpl implements LoaderUtilImpl.VersionSpecific { + @Override + public VersionInfo getVersionInfo() { + return FMLLoader.versionInfo(); + } + + @Override + public boolean isProduction() { + return FMLEnvironment.production; + } + + @Override + public Dist getDist() { + return FMLEnvironment.dist; + } +} diff --git a/loader/neoforge/1.21.1/src/main/java/top/offsetmonkey538/monkeylib538/neoforge/v1211/impl/platform/package-info.java b/loader/neoforge/1.21.1/src/main/java/top/offsetmonkey538/monkeylib538/neoforge/v1211/impl/platform/package-info.java new file mode 100644 index 0000000..d28aeaf --- /dev/null +++ b/loader/neoforge/1.21.1/src/main/java/top/offsetmonkey538/monkeylib538/neoforge/v1211/impl/platform/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package top.offsetmonkey538.monkeylib538.neoforge.v1211.impl.platform; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/loader/neoforge/1.21.1/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.neoforge.impl.platform.LoaderUtilImpl$VersionSpecific b/loader/neoforge/1.21.1/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.neoforge.impl.platform.LoaderUtilImpl$VersionSpecific new file mode 100644 index 0000000..7ec41be --- /dev/null +++ b/loader/neoforge/1.21.1/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.neoforge.impl.platform.LoaderUtilImpl$VersionSpecific @@ -0,0 +1 @@ +top.offsetmonkey538.monkeylib538.neoforge.v1211.impl.platform.VersionSpecificLoaderUtilImpl \ No newline at end of file diff --git a/loader/neoforge/1.21.11/gradle.properties b/loader/neoforge/1.21.11/gradle.properties new file mode 100644 index 0000000..d8785b0 --- /dev/null +++ b/loader/neoforge/1.21.11/gradle.properties @@ -0,0 +1,15 @@ +project_name = neoforge-1.21.11 +commonModdedVersion = 1.21.11 + +# Dependencies +## Adventure +adventure_version = 6.8.0 + +# Minecraft version +minecraft_version = 1.21.11 +supported_minecraft_versions = >=1.21.11 +minecraft_version_range = [1.21.11,) + +neoforge_version = 21.11.17-beta +parchment_minecraft_version = 1.21.10 +parchment_mappings_version = 2025.10.12 diff --git a/loader/neoforge/1.21.11/src/main/java/top/offsetmonkey538/monkeylib538/neoforge/v12111/impl/platform/VersionSpecificLoaderUtilImpl.java b/loader/neoforge/1.21.11/src/main/java/top/offsetmonkey538/monkeylib538/neoforge/v12111/impl/platform/VersionSpecificLoaderUtilImpl.java new file mode 100644 index 0000000..3a5d411 --- /dev/null +++ b/loader/neoforge/1.21.11/src/main/java/top/offsetmonkey538/monkeylib538/neoforge/v12111/impl/platform/VersionSpecificLoaderUtilImpl.java @@ -0,0 +1,24 @@ +package top.offsetmonkey538.monkeylib538.neoforge.v12111.impl.platform; + +import net.neoforged.api.distmarker.Dist; +import net.neoforged.fml.loading.FMLEnvironment; +import net.neoforged.fml.loading.FMLLoader; +import net.neoforged.fml.loading.VersionInfo; +import top.offsetmonkey538.monkeylib538.neoforge.impl.platform.LoaderUtilImpl; + +public final class VersionSpecificLoaderUtilImpl implements LoaderUtilImpl.VersionSpecific { + @Override + public VersionInfo getVersionInfo() { + return FMLLoader.getCurrent().getVersionInfo(); + } + + @Override + public boolean isProduction() { + return FMLEnvironment.isProduction(); + } + + @Override + public Dist getDist() { + return FMLEnvironment.getDist(); + } +} diff --git a/loader/neoforge/1.21.11/src/main/java/top/offsetmonkey538/monkeylib538/neoforge/v12111/impl/platform/package-info.java b/loader/neoforge/1.21.11/src/main/java/top/offsetmonkey538/monkeylib538/neoforge/v12111/impl/platform/package-info.java new file mode 100644 index 0000000..2281bd7 --- /dev/null +++ b/loader/neoforge/1.21.11/src/main/java/top/offsetmonkey538/monkeylib538/neoforge/v12111/impl/platform/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package top.offsetmonkey538.monkeylib538.neoforge.v12111.impl.platform; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/loader/neoforge/1.21.11/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.neoforge.impl.platform.LoaderUtilImpl$VersionSpecific b/loader/neoforge/1.21.11/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.neoforge.impl.platform.LoaderUtilImpl$VersionSpecific new file mode 100644 index 0000000..57bc628 --- /dev/null +++ b/loader/neoforge/1.21.11/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.neoforge.impl.platform.LoaderUtilImpl$VersionSpecific @@ -0,0 +1 @@ +top.offsetmonkey538.monkeylib538.neoforge.v12111.impl.platform.VersionSpecificLoaderUtilImpl \ No newline at end of file diff --git a/loader/neoforge/1.21.9/gradle.properties b/loader/neoforge/1.21.9/gradle.properties new file mode 100644 index 0000000..5876f04 --- /dev/null +++ b/loader/neoforge/1.21.9/gradle.properties @@ -0,0 +1,15 @@ +project_name = neoforge-1.21.9 +commonModdedVersion = 1.21.9 + +# Dependencies +## Adventure +adventure_version = 6.7.0 + +# Minecraft version +minecraft_version = 1.21.9 +supported_minecraft_versions = >=1.21.9 <=1.21.10 +minecraft_version_range = [1.21.9,1.21.10] + +neoforge_version = 21.9.16-beta +parchment_minecraft_version = 1.21.9 +parchment_mappings_version = 2025.10.05 diff --git a/loader/neoforge/1.21.9/src/main/java/top/offsetmonkey538/monkeylib538/neoforge/v1219/impl/platform/VersionSpecificLoaderUtilImpl.java b/loader/neoforge/1.21.9/src/main/java/top/offsetmonkey538/monkeylib538/neoforge/v1219/impl/platform/VersionSpecificLoaderUtilImpl.java new file mode 100644 index 0000000..2ced111 --- /dev/null +++ b/loader/neoforge/1.21.9/src/main/java/top/offsetmonkey538/monkeylib538/neoforge/v1219/impl/platform/VersionSpecificLoaderUtilImpl.java @@ -0,0 +1,24 @@ +package top.offsetmonkey538.monkeylib538.neoforge.v1219.impl.platform; + +import net.neoforged.api.distmarker.Dist; +import net.neoforged.fml.loading.FMLEnvironment; +import net.neoforged.fml.loading.FMLLoader; +import net.neoforged.fml.loading.VersionInfo; +import top.offsetmonkey538.monkeylib538.neoforge.impl.platform.LoaderUtilImpl; + +public final class VersionSpecificLoaderUtilImpl implements LoaderUtilImpl.VersionSpecific { + @Override + public VersionInfo getVersionInfo() { + return FMLLoader.getCurrent().getVersionInfo(); + } + + @Override + public boolean isProduction() { + return FMLEnvironment.isProduction(); + } + + @Override + public Dist getDist() { + return FMLEnvironment.getDist(); + } +} diff --git a/loader/neoforge/1.21.9/src/main/java/top/offsetmonkey538/monkeylib538/neoforge/v1219/impl/platform/package-info.java b/loader/neoforge/1.21.9/src/main/java/top/offsetmonkey538/monkeylib538/neoforge/v1219/impl/platform/package-info.java new file mode 100644 index 0000000..591db19 --- /dev/null +++ b/loader/neoforge/1.21.9/src/main/java/top/offsetmonkey538/monkeylib538/neoforge/v1219/impl/platform/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package top.offsetmonkey538.monkeylib538.neoforge.v1219.impl.platform; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/loader/neoforge/1.21.9/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.neoforge.impl.platform.LoaderUtilImpl$VersionSpecific b/loader/neoforge/1.21.9/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.neoforge.impl.platform.LoaderUtilImpl$VersionSpecific new file mode 100644 index 0000000..1f4ff9d --- /dev/null +++ b/loader/neoforge/1.21.9/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.neoforge.impl.platform.LoaderUtilImpl$VersionSpecific @@ -0,0 +1 @@ +top.offsetmonkey538.monkeylib538.neoforge.v1219.impl.platform.VersionSpecificLoaderUtilImpl \ No newline at end of file diff --git a/loader/neoforge/build.gradle b/loader/neoforge/build.gradle new file mode 100644 index 0000000..043864c --- /dev/null +++ b/loader/neoforge/build.gradle @@ -0,0 +1,38 @@ +import dex.plugins.outlet.v2.util.ReleaseType + +plugins { + id 'multiloader-neoforge' +} + +allprojects { + neoForgeModsToml { + mitLicense() + mod(rootProject.neo_mod_id) { + authors = "OffsetMonkey538" + dependencies { + required("adventure_platform_neoforge") + } + } + mixin("monkeylib538.modded.mixins.json") + } + + dependencies { + implementation "net.kyori:adventure-platform-neoforge:${project.adventure_version}" + } +} + +subprojects { + // Gotta have this here cause I can't import it in buildSrc + outlet.allowedReleaseTypes = Set.of(ReleaseType.RELEASE) + + dependencies { + includeRuntime "top.offsetmonkey538.offsetutils538:offsetutils538:${rootProject.offsetutils538_version}" + includeRuntime "blue.endless:jankson:${rootProject.jankson_version}" + } + + modrinth { + dependencies { + required.project "adventure-platform-mod" + } + } +} diff --git a/loader/neoforge/gradle.properties b/loader/neoforge/gradle.properties new file mode 100644 index 0000000..6f07614 --- /dev/null +++ b/loader/neoforge/gradle.properties @@ -0,0 +1,12 @@ +project_name = neoforge + +# Dependencies +## Adventure +adventure_version = 6.8.0 + +# Minecraft version +minecraft_version = 1.21.11 + +neoforge_version = 21.11.17-beta +parchment_minecraft_version = 1.21.10 +parchment_mappings_version = 2025.10.12 diff --git a/loader/neoforge/src/main/java/top/offsetmonkey538/monkeylib538/neoforge/MonkeyLib538Initializer.java b/loader/neoforge/src/main/java/top/offsetmonkey538/monkeylib538/neoforge/MonkeyLib538Initializer.java new file mode 100644 index 0000000..4313096 --- /dev/null +++ b/loader/neoforge/src/main/java/top/offsetmonkey538/monkeylib538/neoforge/MonkeyLib538Initializer.java @@ -0,0 +1,47 @@ +package top.offsetmonkey538.monkeylib538.neoforge; + +import com.mojang.brigadier.tree.CommandNode; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.server.dedicated.DedicatedServer; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.fml.ModContainer; +import net.neoforged.fml.common.Mod; +import net.neoforged.neoforge.common.NeoForge; +import net.neoforged.neoforge.event.RegisterCommandsEvent; +import net.neoforged.neoforge.event.server.ServerStartedEvent; +import net.neoforged.neoforge.event.server.ServerStartingEvent; +import net.neoforged.neoforge.event.server.ServerStoppedEvent; +import net.neoforged.neoforge.event.server.ServerStoppingEvent; +import org.jspecify.annotations.Nullable; +import top.offsetmonkey538.monkeylib538.common.MonkeyLib538Common; +import top.offsetmonkey538.monkeylib538.common.api.command.CommandRegistrationApi; +import top.offsetmonkey538.monkeylib538.common.api.lifecycle.ServerLifecycleApi; + +@Mod("monkeylib538") +public class MonkeyLib538Initializer { + private static @Nullable DedicatedServer minecraftServer = null; + + /** + * Constructor that neo magic calls + */ + public MonkeyLib538Initializer(IEventBus modEventBus, ModContainer modContainer) { + MonkeyLib538Common.initialize(); + + NeoForge.EVENT_BUS.addListener(RegisterCommandsEvent.class, registerCommandsEvent -> { + //noinspection unchecked + CommandRegistrationApi.getCommands().forEach(command -> registerCommandsEvent.getDispatcher().getRoot().addChild((CommandNode) command)); + }); + + NeoForge.EVENT_BUS.addListener(ServerStartingEvent.class, serverStartingEvent -> { + minecraftServer = (serverStartingEvent.getServer() instanceof DedicatedServer server ? server : null); + ServerLifecycleApi.STARTING.getInvoker().run(); + }); + NeoForge.EVENT_BUS.addListener(ServerStartedEvent.class, event -> ServerLifecycleApi.STARTED.getInvoker().run()); + NeoForge.EVENT_BUS.addListener(ServerStoppingEvent.class, event -> ServerLifecycleApi.STOPPING.getInvoker().run()); + NeoForge.EVENT_BUS.addListener(ServerStoppedEvent.class, event -> ServerLifecycleApi.STOPPED.getInvoker().run()); + } + + public static @Nullable DedicatedServer getServer() { + return minecraftServer; + } +} diff --git a/loader/neoforge/src/main/java/top/offsetmonkey538/monkeylib538/neoforge/impl/platform/LoaderUtilImpl.java b/loader/neoforge/src/main/java/top/offsetmonkey538/monkeylib538/neoforge/impl/platform/LoaderUtilImpl.java new file mode 100644 index 0000000..e22061f --- /dev/null +++ b/loader/neoforge/src/main/java/top/offsetmonkey538/monkeylib538/neoforge/impl/platform/LoaderUtilImpl.java @@ -0,0 +1,82 @@ +package top.offsetmonkey538.monkeylib538.neoforge.impl.platform; + +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.text.Component; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.player.Player; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.fml.loading.FMLPaths; +import net.neoforged.fml.loading.VersionInfo; +import net.neoforged.neoforge.common.NeoForge; +import net.neoforged.neoforge.event.entity.player.PlayerEvent; +import top.offsetmonkey538.monkeylib538.common.api.platform.LoaderUtil; +import top.offsetmonkey538.monkeylib538.modded.api.player.ModdedPlayerApi; +import top.offsetmonkey538.monkeylib538.neoforge.MonkeyLib538Initializer; + +import java.nio.file.Path; +import java.util.function.Supplier; + +import static top.offsetmonkey538.monkeylib538.common.MonkeyLib538Common.load; + +public final class LoaderUtilImpl implements LoaderUtil { + @Override + public String getMinecraftVersionImpl() { + return VersionSpecific.INSTANCE.getVersionInfo().mcVersion(); + } + + @Override + public Path getConfigDirImpl() { + return FMLPaths.CONFIGDIR.get(); + } + + @Override + public Path getModsDirImpl() { + return FMLPaths.MODSDIR.get(); + } + + @Override + public boolean isDevelopmentEnvironmentImpl() { + return !VersionSpecific.INSTANCE.isProduction(); + } + + @Override + public boolean isDedicatedServerImpl() { + return VersionSpecific.INSTANCE.getDist() == Dist.DEDICATED_SERVER; + } + + @Override + public boolean isEpollEnabledImpl() { + if (!isDedicatedServerImpl()) return false; + if (MonkeyLib538Initializer.getServer() == null) throw new IllegalStateException("Tried calling 'isEpollEnabledImpl' before server STARTING event was invoked!"); + return MonkeyLib538Initializer.getServer().getProperties().useNativeTransport; + } + + @Override + public int getVanillaServerPortImpl() { + if (!isDedicatedServerImpl()) throw new IllegalStateException("Tried calling 'getVanillaServerPortImpl' when game isn't a dedicated server!"); + if (MonkeyLib538Initializer.getServer() == null) throw new IllegalStateException("Tried calling 'getVanillaServerPortImpl' before server STARTING event was invoked!"); + return MonkeyLib538Initializer.getServer().getServerPort(); + } + + @Override + public void sendMessagesToAdminsOnJoinImpl(Supplier messageSupplier) { + NeoForge.EVENT_BUS.addListener(PlayerEvent.PlayerLoggedInEvent.class, playerLoggedInEvent -> { + final Player player = playerLoggedInEvent.getEntity(); + final MinecraftServer server = player.level().getServer(); + if (server == null || !(player instanceof ServerPlayer serverPlayer)) return; // Don't send messages from logical client side. Still should be sending from integrated server though afaik + + if (!ModdedPlayerApi.isPlayerOp(server.getPlayerList(), player) && !ModdedPlayerApi.isPlayerHost(server, player)) return; + + for (Component text : messageSupplier.get()) ((Audience) serverPlayer).sendMessage(text); + }); + } + + public interface VersionSpecific { + VersionSpecific INSTANCE = load(VersionSpecific.class); + + VersionInfo getVersionInfo(); + boolean isProduction(); + Dist getDist(); + } +} diff --git a/loader/neoforge/src/main/java/top/offsetmonkey538/monkeylib538/neoforge/impl/platform/package-info.java b/loader/neoforge/src/main/java/top/offsetmonkey538/monkeylib538/neoforge/impl/platform/package-info.java new file mode 100644 index 0000000..b33e4db --- /dev/null +++ b/loader/neoforge/src/main/java/top/offsetmonkey538/monkeylib538/neoforge/impl/platform/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package top.offsetmonkey538.monkeylib538.neoforge.impl.platform; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/loader/neoforge/src/main/java/top/offsetmonkey538/monkeylib538/neoforge/impl/server/ServerProviderImpl.java b/loader/neoforge/src/main/java/top/offsetmonkey538/monkeylib538/neoforge/impl/server/ServerProviderImpl.java new file mode 100644 index 0000000..ebf9087 --- /dev/null +++ b/loader/neoforge/src/main/java/top/offsetmonkey538/monkeylib538/neoforge/impl/server/ServerProviderImpl.java @@ -0,0 +1,14 @@ +package top.offsetmonkey538.monkeylib538.neoforge.impl.server; + +import net.minecraft.server.dedicated.DedicatedServer; +import org.jspecify.annotations.Nullable; +import top.offsetmonkey538.monkeylib538.modded.api.server.ServerProvider; +import top.offsetmonkey538.monkeylib538.neoforge.MonkeyLib538Initializer; + +public final class ServerProviderImpl implements ServerProvider { + + @Override + public @Nullable DedicatedServer getServerImpl() { + return MonkeyLib538Initializer.getServer(); + } +} diff --git a/loader/neoforge/src/main/java/top/offsetmonkey538/monkeylib538/neoforge/impl/server/package-info.java b/loader/neoforge/src/main/java/top/offsetmonkey538/monkeylib538/neoforge/impl/server/package-info.java new file mode 100644 index 0000000..ae4ba6d --- /dev/null +++ b/loader/neoforge/src/main/java/top/offsetmonkey538/monkeylib538/neoforge/impl/server/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package top.offsetmonkey538.monkeylib538.neoforge.impl.server; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/loader/neoforge/src/main/java/top/offsetmonkey538/monkeylib538/neoforge/package-info.java b/loader/neoforge/src/main/java/top/offsetmonkey538/monkeylib538/neoforge/package-info.java new file mode 100644 index 0000000..20dc9b9 --- /dev/null +++ b/loader/neoforge/src/main/java/top/offsetmonkey538/monkeylib538/neoforge/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package top.offsetmonkey538.monkeylib538.neoforge; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/loader/neoforge/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.platform.LoaderUtil b/loader/neoforge/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.platform.LoaderUtil new file mode 100644 index 0000000..e4fbd26 --- /dev/null +++ b/loader/neoforge/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.platform.LoaderUtil @@ -0,0 +1 @@ +top.offsetmonkey538.monkeylib538.neoforge.impl.platform.LoaderUtilImpl \ No newline at end of file diff --git a/loader/neoforge/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.modded.api.server.ServerProvider b/loader/neoforge/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.modded.api.server.ServerProvider new file mode 100644 index 0000000..781a912 --- /dev/null +++ b/loader/neoforge/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.modded.api.server.ServerProvider @@ -0,0 +1 @@ +top.offsetmonkey538.monkeylib538.neoforge.impl.server.ServerProviderImpl \ No newline at end of file diff --git a/loader/paper/1.21.1/gradle.properties b/loader/paper/1.21.1/gradle.properties new file mode 100644 index 0000000..87de08b --- /dev/null +++ b/loader/paper/1.21.1/gradle.properties @@ -0,0 +1,10 @@ +project_name = paper-1.21.1 + + +## "Common" fabric one should depend on the latest version just so it can access Minecraft and Fabric. +## It MUST NOT include version-specific code + +# huioiuk +minecraft_version = 1.21.1 +supported_minecraft_versions = >=1.21.1 +paper_version = 1.21.1-R0.1-SNAPSHOT diff --git a/loader/paper/build.gradle b/loader/paper/build.gradle new file mode 100644 index 0000000..8293994 --- /dev/null +++ b/loader/paper/build.gradle @@ -0,0 +1,23 @@ +import dex.plugins.outlet.v2.util.ReleaseType + +plugins { + id 'multiloader-paper' +} + +allprojects { + // Gotta have this here cause I can't import it in buildSrc + outlet.allowedReleaseTypes = Set.of(ReleaseType.RELEASE) + + paperPluginYaml { + main = "top.offsetmonkey538.monkeylib538.paper.impl.platform.LoaderUtilImpl\$MonkeyLib538Initializer" + authors.add("OffsetMonkey538") + load = "STARTUP" + } +} + +subprojects { + dependencies { + include runtimeOnly("top.offsetmonkey538.offsetutils538:offsetutils538:${rootProject.offsetutils538_version}") + include runtimeOnly("blue.endless:jankson:${rootProject.jankson_version}") + } +} diff --git a/loader/paper/gradle.properties b/loader/paper/gradle.properties new file mode 100644 index 0000000..eb4b5b2 --- /dev/null +++ b/loader/paper/gradle.properties @@ -0,0 +1,10 @@ +project_name = paper + + +## "Common" fabric one should depend on the latest version just so it can access Minecraft and Fabric. +## It MUST NOT include version-specific code + +# huioiuk +minecraft_version = 1.21.10 +supported_minecraft_versions = * +paper_version = 1.21.10-R0.1-SNAPSHOT diff --git a/loader/paper/src/main/java/top/offsetmonkey538/monkeylib538/paper/api/command/PaperCommandAbstractionApi.java b/loader/paper/src/main/java/top/offsetmonkey538/monkeylib538/paper/api/command/PaperCommandAbstractionApi.java new file mode 100644 index 0000000..71b50cf --- /dev/null +++ b/loader/paper/src/main/java/top/offsetmonkey538/monkeylib538/paper/api/command/PaperCommandAbstractionApi.java @@ -0,0 +1,19 @@ +package top.offsetmonkey538.monkeylib538.paper.api.command; + +import com.mojang.brigadier.context.CommandContext; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import top.offsetmonkey538.monkeylib538.common.api.command.CommandAbstractionApi; +import top.offsetmonkey538.offsetutils538.api.annotation.Internal; + +public interface PaperCommandAbstractionApi extends CommandAbstractionApi { + static CommandSourceStack get(CommandContext ctx) { + return ((PaperCommandAbstractionApi) INSTANCE).getImpl(ctx); + } + static CommandSourceStack get(Object commandSource) { + return ((PaperCommandAbstractionApi) INSTANCE).getImpl(commandSource); + } + + @Internal + CommandSourceStack getImpl(CommandContext ctx); + @Internal CommandSourceStack getImpl(Object commandSource); +} diff --git a/loader/paper/src/main/java/top/offsetmonkey538/monkeylib538/paper/api/command/package-info.java b/loader/paper/src/main/java/top/offsetmonkey538/monkeylib538/paper/api/command/package-info.java new file mode 100644 index 0000000..abbdae0 --- /dev/null +++ b/loader/paper/src/main/java/top/offsetmonkey538/monkeylib538/paper/api/command/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package top.offsetmonkey538.monkeylib538.paper.api.command; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/loader/paper/src/main/java/top/offsetmonkey538/monkeylib538/paper/impl/command/CommandAbstractionImpl.java b/loader/paper/src/main/java/top/offsetmonkey538/monkeylib538/paper/impl/command/CommandAbstractionImpl.java new file mode 100644 index 0000000..267c8dc --- /dev/null +++ b/loader/paper/src/main/java/top/offsetmonkey538/monkeylib538/paper/impl/command/CommandAbstractionImpl.java @@ -0,0 +1,69 @@ +package top.offsetmonkey538.monkeylib538.paper.impl.command; + +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.builder.RequiredArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import io.papermc.paper.command.brigadier.Commands; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.entity.Player; +import top.offsetmonkey538.monkeylib538.paper.api.command.PaperCommandAbstractionApi; + +import static top.offsetmonkey538.monkeylib538.paper.api.command.PaperCommandAbstractionApi.get; +import static top.offsetmonkey538.offsetutils538.api.text.ArgReplacer.replaceArgs; + +public final class CommandAbstractionImpl implements PaperCommandAbstractionApi { + + @Override + public LiteralArgumentBuilder literalImpl(String name) { + return Commands.literal(name); + } + + @Override + public RequiredArgumentBuilder argumentImpl(String name, ArgumentType type) { + return Commands.argument(name, type); + } + + @Override + public void sendMessageImpl(CommandContext ctx, String message) { + get(ctx).getSender().sendMessage(message); + } + + @Override + public void sendErrorImpl(CommandContext ctx, String message) { + get(ctx).getSender().sendMessage(Component.text(message).style(style -> style.color(NamedTextColor.RED))); + } + + @Override + public void sendTextImpl(CommandContext ctx, Component text) { + get(ctx).getSender().sendMessage(text); + } + + @Override + public boolean executedByPlayerImpl(Object source) { + return get(source).getExecutor() instanceof Player; + } + + @Override + public boolean isOpImpl(Object source) { + return get(source).getSender().isOp(); + } + + @Override + public boolean isHostImpl(Object source) { + return false; // No host on dedicated server + } + + @Override + public CommandSourceStack getImpl(CommandContext ctx) { + return getImpl(ctx.getSource()); + } + + @Override + public CommandSourceStack getImpl(Object commandSource) { + if (commandSource instanceof CommandSourceStack serverCommandSource) return serverCommandSource; + throw new IllegalStateException(replaceArgs("Expected command source to be of type '%s', got '%s' instead. Something is very very wrong if you're seeing this error :concern:", CommandSourceStack.class, commandSource.getClass())); + } +} diff --git a/loader/paper/src/main/java/top/offsetmonkey538/monkeylib538/paper/impl/command/package-info.java b/loader/paper/src/main/java/top/offsetmonkey538/monkeylib538/paper/impl/command/package-info.java new file mode 100644 index 0000000..36182a7 --- /dev/null +++ b/loader/paper/src/main/java/top/offsetmonkey538/monkeylib538/paper/impl/command/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package top.offsetmonkey538.monkeylib538.paper.impl.command; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/loader/paper/src/main/java/top/offsetmonkey538/monkeylib538/paper/impl/platform/LoaderUtilImpl.java b/loader/paper/src/main/java/top/offsetmonkey538/monkeylib538/paper/impl/platform/LoaderUtilImpl.java new file mode 100644 index 0000000..581e662 --- /dev/null +++ b/loader/paper/src/main/java/top/offsetmonkey538/monkeylib538/paper/impl/platform/LoaderUtilImpl.java @@ -0,0 +1,122 @@ +package top.offsetmonkey538.monkeylib538.paper.impl.platform; + +import com.mojang.brigadier.tree.CommandNode; +import com.mojang.brigadier.tree.LiteralCommandNode; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents; +import net.kyori.adventure.text.Component; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.dedicated.DedicatedServer; +import org.bukkit.Bukkit; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.server.ServerLoadEvent; +import org.bukkit.plugin.java.JavaPlugin; +import org.jspecify.annotations.Nullable; +import top.offsetmonkey538.monkeylib538.common.MonkeyLib538Common; +import top.offsetmonkey538.monkeylib538.common.api.command.CommandRegistrationApi; +import top.offsetmonkey538.monkeylib538.common.api.lifecycle.ServerLifecycleApi; +import top.offsetmonkey538.monkeylib538.common.api.platform.LoaderUtil; + +import java.nio.file.Path; +import java.util.function.Supplier; + +public final class LoaderUtilImpl implements LoaderUtil { + private static @Nullable MonkeyLib538Initializer plugin; + + @Override + public String getMinecraftVersionImpl() { + return Bukkit.getMinecraftVersion(); + } + + @Override + public Path getConfigDirImpl() { + return getPlugin().getDataPath().getParent(); + } + + @Override + public Path getModsDirImpl() { + return Bukkit.getPluginsFolder().toPath(); + } + + @Override + public boolean isDevelopmentEnvironmentImpl() { + return Boolean.getBoolean("xyz.jpenilla.run-task"); + } + + @Override + public boolean isDedicatedServerImpl() { + return true; + } + + @Override + public boolean isEpollEnabledImpl() { + if (!isDedicatedServerImpl()) return false; + if (plugin == null) throw new IllegalStateException("Tried calling 'isEpollEnabledImpl' before server STARTING event was invoked!"); + return ((DedicatedServer) MinecraftServer.getServer()).getProperties().useNativeTransport; + } + + @Override + public int getVanillaServerPortImpl() { + if (!isDedicatedServerImpl()) throw new IllegalStateException("Tried calling 'getVanillaServerPortImpl' when game isn't a dedicated server!"); + if (plugin == null) throw new IllegalStateException("Tried calling 'getVanillaServerPortImpl' before server STARTING event was invoked!"); + return plugin.getServer().getPort(); + } + + @Override + public void sendMessagesToAdminsOnJoinImpl(Supplier messageSupplier) { + Bukkit.getPluginManager().registerEvents(new AdminMessageSenderEventHandler(messageSupplier), getPlugin()); + } + + private record AdminMessageSenderEventHandler(Supplier messageSupplier) implements Listener { + @EventHandler(priority = EventPriority.MONITOR) + public void onPlayerJoin(final PlayerJoinEvent event) { + if (!event.getPlayer().isOp()) return; + + for (Component text : messageSupplier.get()) event.getPlayer().sendMessage(text); + } + } + + private static void setPlugin(MonkeyLib538Initializer plugin) { + LoaderUtilImpl.plugin = plugin; + } + + public static JavaPlugin getPlugin() { + if (plugin == null) throw new IllegalStateException("Tried accessing plugin before monkeylib538 was initialized"); + return plugin; + } + + + + public static final class MonkeyLib538Initializer extends JavaPlugin implements Listener { + @Override + public void onEnable() { + setPlugin(this); + MonkeyLib538Common.initialize(); + + this.getLifecycleManager().registerEventHandler(LifecycleEvents.COMMANDS, commands -> { + for (CommandNode command : CommandRegistrationApi.getCommands()) { + //noinspection unchecked + commands.registrar().register((LiteralCommandNode) command); + } + }); + + Bukkit.getPluginManager().registerEvents(this, this); + } + + @Override + public void onDisable() { + ServerLifecycleApi.STOPPING.getInvoker().run(); + ServerLifecycleApi.STOPPED.getInvoker().run(); + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onServerLoad(final ServerLoadEvent event) { + if (event.getType() != ServerLoadEvent.LoadType.STARTUP) return; + ServerLifecycleApi.STARTING.getInvoker().run(); + ServerLifecycleApi.STARTED.getInvoker().run(); + } + } +} diff --git a/loader/paper/src/main/java/top/offsetmonkey538/monkeylib538/paper/impl/platform/ServerBrandGetterImpl.java b/loader/paper/src/main/java/top/offsetmonkey538/monkeylib538/paper/impl/platform/ServerBrandGetterImpl.java new file mode 100644 index 0000000..358677b --- /dev/null +++ b/loader/paper/src/main/java/top/offsetmonkey538/monkeylib538/paper/impl/platform/ServerBrandGetterImpl.java @@ -0,0 +1,11 @@ +package top.offsetmonkey538.monkeylib538.paper.impl.platform; + +import org.bukkit.Bukkit; +import top.offsetmonkey538.monkeylib538.common.api.platform.LoaderUtil; + +public final class ServerBrandGetterImpl implements LoaderUtil.ServerBrandGetter { + @Override + public String getBrand() { + return Bukkit.getServer().getName(); + } +} diff --git a/loader/paper/src/main/java/top/offsetmonkey538/monkeylib538/paper/impl/platform/package-info.java b/loader/paper/src/main/java/top/offsetmonkey538/monkeylib538/paper/impl/platform/package-info.java new file mode 100644 index 0000000..76f6c3c --- /dev/null +++ b/loader/paper/src/main/java/top/offsetmonkey538/monkeylib538/paper/impl/platform/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package top.offsetmonkey538.monkeylib538.paper.impl.platform; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/loader/paper/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.command.CommandAbstractionApi b/loader/paper/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.command.CommandAbstractionApi new file mode 100644 index 0000000..f8a517e --- /dev/null +++ b/loader/paper/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.command.CommandAbstractionApi @@ -0,0 +1 @@ +top.offsetmonkey538.monkeylib538.paper.impl.command.CommandAbstractionImpl \ No newline at end of file diff --git a/loader/paper/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.platform.LoaderUtil b/loader/paper/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.platform.LoaderUtil new file mode 100644 index 0000000..6ff8ff4 --- /dev/null +++ b/loader/paper/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.platform.LoaderUtil @@ -0,0 +1 @@ +top.offsetmonkey538.monkeylib538.paper.impl.platform.LoaderUtilImpl \ No newline at end of file diff --git a/loader/paper/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.platform.LoaderUtil$ServerBrandGetter b/loader/paper/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.platform.LoaderUtil$ServerBrandGetter new file mode 100644 index 0000000..04bab16 --- /dev/null +++ b/loader/paper/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.platform.LoaderUtil$ServerBrandGetter @@ -0,0 +1 @@ +top.offsetmonkey538.monkeylib538.paper.impl.platform.ServerBrandGetterImpl \ No newline at end of file diff --git a/modded/1.21.1/gradle.properties b/modded/1.21.1/gradle.properties new file mode 100644 index 0000000..3cd81e5 --- /dev/null +++ b/modded/1.21.1/gradle.properties @@ -0,0 +1,8 @@ +project_name = modded-1.21.1 + +# Dependencies +## Adventure +adventure_version = 6.0.1 + +# Minecraft version +minecraft_version = 1.21.1 diff --git a/modded/1.21.1/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1211/api/wrapper/ModdedVersionIdentifier.java b/modded/1.21.1/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1211/api/wrapper/ModdedVersionIdentifier.java new file mode 100644 index 0000000..cb6a96b --- /dev/null +++ b/modded/1.21.1/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1211/api/wrapper/ModdedVersionIdentifier.java @@ -0,0 +1,17 @@ +package top.offsetmonkey538.monkeylib538.modded.v1211.api.wrapper; + +import net.minecraft.resources.ResourceLocation; +import top.offsetmonkey538.monkeylib538.common.api.wrapper.Identifier; +import top.offsetmonkey538.monkeylib538.modded.api.wrapper.ModdedIdentifier; + +public interface ModdedVersionIdentifier extends ModdedIdentifier { + static Identifier of(ResourceLocation identifier) { + return ModdedInstantiator.INSTANCE.of(identifier); + } + + static ResourceLocation get(Identifier identifier) { + return ((ModdedVersionIdentifier) identifier).get(); + } + + ResourceLocation get(); +} diff --git a/modded/1.21.1/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1211/api/wrapper/package-info.java b/modded/1.21.1/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1211/api/wrapper/package-info.java new file mode 100644 index 0000000..7f779ea --- /dev/null +++ b/modded/1.21.1/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1211/api/wrapper/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package top.offsetmonkey538.monkeylib538.modded.v1211.api.wrapper; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/modded/1.21.1/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1211/impl/command/ModdedCommandAbstractionApiVersionSpecificImpl.java b/modded/1.21.1/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1211/impl/command/ModdedCommandAbstractionApiVersionSpecificImpl.java new file mode 100644 index 0000000..0712dd5 --- /dev/null +++ b/modded/1.21.1/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1211/impl/command/ModdedCommandAbstractionApiVersionSpecificImpl.java @@ -0,0 +1,11 @@ +package top.offsetmonkey538.monkeylib538.modded.v1211.impl.command; + +import net.minecraft.commands.CommandSourceStack; +import top.offsetmonkey538.monkeylib538.modded.api.command.ModdedCommandAbstractionApi; + +public final class ModdedCommandAbstractionApiVersionSpecificImpl implements ModdedCommandAbstractionApi.VersionSpecific { + @Override + public boolean isOp(CommandSourceStack source) { + return source.hasPermission(source.getServer().getOperatorUserPermissionLevel()); + } +} diff --git a/modded/1.21.1/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1211/impl/command/package-info.java b/modded/1.21.1/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1211/impl/command/package-info.java new file mode 100644 index 0000000..ba824c7 --- /dev/null +++ b/modded/1.21.1/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1211/impl/command/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package top.offsetmonkey538.monkeylib538.modded.v1211.impl.command; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/modded/1.21.1/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1211/impl/player/ModdedPlayerApiImpl.java b/modded/1.21.1/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1211/impl/player/ModdedPlayerApiImpl.java new file mode 100644 index 0000000..7a2f822 --- /dev/null +++ b/modded/1.21.1/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1211/impl/player/ModdedPlayerApiImpl.java @@ -0,0 +1,18 @@ +package top.offsetmonkey538.monkeylib538.modded.v1211.impl.player; + +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.players.PlayerList; +import net.minecraft.world.entity.player.Player; +import top.offsetmonkey538.monkeylib538.modded.api.player.ModdedPlayerApi; + +public final class ModdedPlayerApiImpl implements ModdedPlayerApi { + @Override + public boolean isPlayerOpImpl(PlayerList playerManager, Player player) { + return playerManager.isOp(player.getGameProfile()); + } + + @Override + public boolean isPlayerHostImpl(MinecraftServer server, Player player) { + return server.isSingleplayerOwner(player.getGameProfile()); + } +} diff --git a/modded/1.21.1/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1211/impl/player/package-info.java b/modded/1.21.1/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1211/impl/player/package-info.java new file mode 100644 index 0000000..2695faf --- /dev/null +++ b/modded/1.21.1/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1211/impl/player/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package top.offsetmonkey538.monkeylib538.modded.v1211.impl.player; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/modded/1.21.1/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1211/impl/resource/ResourceKeyApiImpl.java b/modded/1.21.1/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1211/impl/resource/ResourceKeyApiImpl.java new file mode 100644 index 0000000..4370d15 --- /dev/null +++ b/modded/1.21.1/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1211/impl/resource/ResourceKeyApiImpl.java @@ -0,0 +1,24 @@ +package top.offsetmonkey538.monkeylib538.modded.v1211.impl.resource; + +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceKey; +import top.offsetmonkey538.monkeylib538.common.api.wrapper.Identifier; +import top.offsetmonkey538.monkeylib538.modded.api.resource.ResourceKeyApi; +import top.offsetmonkey538.monkeylib538.modded.v1211.api.wrapper.ModdedVersionIdentifier; + +public final class ResourceKeyApiImpl implements ResourceKeyApi { + @Override + public ResourceKey createImpl(ResourceKey> resourceKey, Identifier id) { + return ResourceKey.create(resourceKey, ModdedVersionIdentifier.get(id)); + } + + @Override + public ResourceKey> createRegistryImpl(Identifier id) { + return ResourceKey.createRegistryKey(ModdedVersionIdentifier.get(id)); + } + + @Override + public Identifier getLocationImpl(ResourceKey resourceKey) { + return ModdedVersionIdentifier.of(resourceKey.location()); + } +} diff --git a/modded/1.21.1/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1211/impl/resource/package-info.java b/modded/1.21.1/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1211/impl/resource/package-info.java new file mode 100644 index 0000000..f0b1ea7 --- /dev/null +++ b/modded/1.21.1/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1211/impl/resource/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package top.offsetmonkey538.monkeylib538.modded.v1211.impl.resource; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/modded/1.21.1/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1211/impl/wrapper/IdentifierWrapper.java b/modded/1.21.1/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1211/impl/wrapper/IdentifierWrapper.java new file mode 100644 index 0000000..3b4ba38 --- /dev/null +++ b/modded/1.21.1/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1211/impl/wrapper/IdentifierWrapper.java @@ -0,0 +1,52 @@ +package top.offsetmonkey538.monkeylib538.modded.v1211.impl.wrapper; + +import com.mojang.serialization.Codec; +import net.minecraft.resources.ResourceLocation; +import top.offsetmonkey538.monkeylib538.common.api.wrapper.Identifier; +import top.offsetmonkey538.monkeylib538.modded.v1211.api.wrapper.ModdedVersionIdentifier; + +public record IdentifierWrapper(ResourceLocation vanillaIdentifier) implements ModdedVersionIdentifier { + @Override + public String getNamespace() { + return vanillaIdentifier.getNamespace(); + } + + @Override + public String getPath() { + return vanillaIdentifier.getPath(); + } + + @Override + public String toString() { + return vanillaIdentifier.toString(); + } + + @Override + public ResourceLocation get() { + return vanillaIdentifier; + } + + public static final class CodecProviderImpl implements CodecProvider { + @Override + public Codec get() { + return ResourceLocation.CODEC.xmap(IdentifierWrapper::new, ModdedVersionIdentifier::get); + } + } + + public static final class InstantiatorImpl implements ModdedInstantiator { + @Override + public ModdedVersionIdentifier of(String location) { + return new IdentifierWrapper(ResourceLocation.parse(location)); + } + + @Override + public ModdedVersionIdentifier of(String namespace, String path) { + return new IdentifierWrapper(ResourceLocation.fromNamespaceAndPath(namespace, path)); + } + + @Override + public Identifier of(Object identifier) { + return new IdentifierWrapper((ResourceLocation) identifier); + } + } +} diff --git a/modded/1.21.1/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1211/impl/wrapper/package-info.java b/modded/1.21.1/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1211/impl/wrapper/package-info.java new file mode 100644 index 0000000..e196dd7 --- /dev/null +++ b/modded/1.21.1/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1211/impl/wrapper/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package top.offsetmonkey538.monkeylib538.modded.v1211.impl.wrapper; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/modded/1.21.1/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.wrapper.Identifier$CodecProvider b/modded/1.21.1/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.wrapper.Identifier$CodecProvider new file mode 100644 index 0000000..f7962da --- /dev/null +++ b/modded/1.21.1/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.wrapper.Identifier$CodecProvider @@ -0,0 +1 @@ +top.offsetmonkey538.monkeylib538.modded.v1211.impl.wrapper.IdentifierWrapper$CodecProviderImpl \ No newline at end of file diff --git a/modded/1.21.1/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.wrapper.Identifier$Instantiator b/modded/1.21.1/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.wrapper.Identifier$Instantiator new file mode 100644 index 0000000..af6dbb0 --- /dev/null +++ b/modded/1.21.1/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.wrapper.Identifier$Instantiator @@ -0,0 +1 @@ +top.offsetmonkey538.monkeylib538.modded.v1211.impl.wrapper.IdentifierWrapper$InstantiatorImpl \ No newline at end of file diff --git a/modded/1.21.1/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.modded.api.command.ModdedCommandAbstractionApi$VersionSpecific b/modded/1.21.1/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.modded.api.command.ModdedCommandAbstractionApi$VersionSpecific new file mode 100644 index 0000000..9c13796 --- /dev/null +++ b/modded/1.21.1/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.modded.api.command.ModdedCommandAbstractionApi$VersionSpecific @@ -0,0 +1 @@ +top.offsetmonkey538.monkeylib538.modded.v1211.impl.command.ModdedCommandAbstractionApiVersionSpecificImpl \ No newline at end of file diff --git a/modded/1.21.1/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.modded.api.player.ModdedPlayerApi b/modded/1.21.1/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.modded.api.player.ModdedPlayerApi new file mode 100644 index 0000000..d370bb1 --- /dev/null +++ b/modded/1.21.1/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.modded.api.player.ModdedPlayerApi @@ -0,0 +1 @@ +top.offsetmonkey538.monkeylib538.modded.v1211.impl.player.ModdedPlayerApiImpl \ No newline at end of file diff --git a/modded/1.21.1/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.modded.api.resource.ResourceKeyApi b/modded/1.21.1/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.modded.api.resource.ResourceKeyApi new file mode 100644 index 0000000..07ce20a --- /dev/null +++ b/modded/1.21.1/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.modded.api.resource.ResourceKeyApi @@ -0,0 +1 @@ +top.offsetmonkey538.monkeylib538.modded.v1211.impl.resource.ResourceKeyApiImpl \ No newline at end of file diff --git a/modded/1.21.11/gradle.properties b/modded/1.21.11/gradle.properties new file mode 100644 index 0000000..0daaf46 --- /dev/null +++ b/modded/1.21.11/gradle.properties @@ -0,0 +1,8 @@ +project_name = modded-1.21.11 + +# Dependencies +## Adventure +adventure_version = 6.8.0 + +# Minecraft version +minecraft_version = 1.21.11 diff --git a/modded/1.21.11/src/main/java/top/offsetmonkey538/monkeylib538/modded/v12111/api/wrapper/ModdedVersionIdentifier.java b/modded/1.21.11/src/main/java/top/offsetmonkey538/monkeylib538/modded/v12111/api/wrapper/ModdedVersionIdentifier.java new file mode 100644 index 0000000..98f8427 --- /dev/null +++ b/modded/1.21.11/src/main/java/top/offsetmonkey538/monkeylib538/modded/v12111/api/wrapper/ModdedVersionIdentifier.java @@ -0,0 +1,16 @@ +package top.offsetmonkey538.monkeylib538.modded.v12111.api.wrapper; + +import top.offsetmonkey538.monkeylib538.common.api.wrapper.Identifier; +import top.offsetmonkey538.monkeylib538.modded.api.wrapper.ModdedIdentifier; + +public interface ModdedVersionIdentifier extends ModdedIdentifier { + static Identifier of(net.minecraft.resources.Identifier identifier) { + return ModdedInstantiator.INSTANCE.of(identifier); + } + + static net.minecraft.resources.Identifier get(Identifier identifier) { + return ((ModdedVersionIdentifier) identifier).get(); + } + + net.minecraft.resources.Identifier get(); +} diff --git a/modded/1.21.11/src/main/java/top/offsetmonkey538/monkeylib538/modded/v12111/api/wrapper/package-info.java b/modded/1.21.11/src/main/java/top/offsetmonkey538/monkeylib538/modded/v12111/api/wrapper/package-info.java new file mode 100644 index 0000000..fd72b81 --- /dev/null +++ b/modded/1.21.11/src/main/java/top/offsetmonkey538/monkeylib538/modded/v12111/api/wrapper/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package top.offsetmonkey538.monkeylib538.modded.v12111.api.wrapper; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/modded/1.21.11/src/main/java/top/offsetmonkey538/monkeylib538/modded/v12111/impl/command/ModdedCommandAbstractionApiVersionSpecificImpl.java b/modded/1.21.11/src/main/java/top/offsetmonkey538/monkeylib538/modded/v12111/impl/command/ModdedCommandAbstractionApiVersionSpecificImpl.java new file mode 100644 index 0000000..df0b16c --- /dev/null +++ b/modded/1.21.11/src/main/java/top/offsetmonkey538/monkeylib538/modded/v12111/impl/command/ModdedCommandAbstractionApiVersionSpecificImpl.java @@ -0,0 +1,12 @@ +package top.offsetmonkey538.monkeylib538.modded.v12111.impl.command; + +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.server.permissions.Permissions; +import top.offsetmonkey538.monkeylib538.modded.api.command.ModdedCommandAbstractionApi; + +public final class ModdedCommandAbstractionApiVersionSpecificImpl implements ModdedCommandAbstractionApi.VersionSpecific { + @Override + public boolean isOp(CommandSourceStack source) { + return source.permissions().hasPermission(Permissions.COMMANDS_ADMIN); + } +} diff --git a/modded/1.21.11/src/main/java/top/offsetmonkey538/monkeylib538/modded/v12111/impl/command/package-info.java b/modded/1.21.11/src/main/java/top/offsetmonkey538/monkeylib538/modded/v12111/impl/command/package-info.java new file mode 100644 index 0000000..9121134 --- /dev/null +++ b/modded/1.21.11/src/main/java/top/offsetmonkey538/monkeylib538/modded/v12111/impl/command/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package top.offsetmonkey538.monkeylib538.modded.v12111.impl.command; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/modded/1.21.11/src/main/java/top/offsetmonkey538/monkeylib538/modded/v12111/impl/player/ModdedPlayerApiImpl.java b/modded/1.21.11/src/main/java/top/offsetmonkey538/monkeylib538/modded/v12111/impl/player/ModdedPlayerApiImpl.java new file mode 100644 index 0000000..b6b922d --- /dev/null +++ b/modded/1.21.11/src/main/java/top/offsetmonkey538/monkeylib538/modded/v12111/impl/player/ModdedPlayerApiImpl.java @@ -0,0 +1,18 @@ +package top.offsetmonkey538.monkeylib538.modded.v12111.impl.player; + +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.players.PlayerList; +import net.minecraft.world.entity.player.Player; +import top.offsetmonkey538.monkeylib538.modded.api.player.ModdedPlayerApi; + +public final class ModdedPlayerApiImpl implements ModdedPlayerApi { + @Override + public boolean isPlayerOpImpl(PlayerList playerManager, Player player) { + return playerManager.isOp(player.nameAndId()); + } + + @Override + public boolean isPlayerHostImpl(MinecraftServer server, Player player) { + return server.isSingleplayerOwner(player.nameAndId()); + } +} diff --git a/modded/1.21.11/src/main/java/top/offsetmonkey538/monkeylib538/modded/v12111/impl/player/package-info.java b/modded/1.21.11/src/main/java/top/offsetmonkey538/monkeylib538/modded/v12111/impl/player/package-info.java new file mode 100644 index 0000000..f4e1fe2 --- /dev/null +++ b/modded/1.21.11/src/main/java/top/offsetmonkey538/monkeylib538/modded/v12111/impl/player/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package top.offsetmonkey538.monkeylib538.modded.v12111.impl.player; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/modded/1.21.11/src/main/java/top/offsetmonkey538/monkeylib538/modded/v12111/impl/resource/ResourceKeyApiImpl.java b/modded/1.21.11/src/main/java/top/offsetmonkey538/monkeylib538/modded/v12111/impl/resource/ResourceKeyApiImpl.java new file mode 100644 index 0000000..fb025a7 --- /dev/null +++ b/modded/1.21.11/src/main/java/top/offsetmonkey538/monkeylib538/modded/v12111/impl/resource/ResourceKeyApiImpl.java @@ -0,0 +1,24 @@ +package top.offsetmonkey538.monkeylib538.modded.v12111.impl.resource; + +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceKey; +import top.offsetmonkey538.monkeylib538.common.api.wrapper.Identifier; +import top.offsetmonkey538.monkeylib538.modded.api.resource.ResourceKeyApi; +import top.offsetmonkey538.monkeylib538.modded.v12111.api.wrapper.ModdedVersionIdentifier; + +public final class ResourceKeyApiImpl implements ResourceKeyApi { + @Override + public ResourceKey createImpl(ResourceKey> resourceKey, Identifier id) { + return ResourceKey.create(resourceKey, ModdedVersionIdentifier.get(id)); + } + + @Override + public ResourceKey> createRegistryImpl(Identifier id) { + return ResourceKey.createRegistryKey(ModdedVersionIdentifier.get(id)); + } + + @Override + public Identifier getLocationImpl(ResourceKey resourceKey) { + return ModdedVersionIdentifier.of(resourceKey.identifier()); + } +} diff --git a/modded/1.21.11/src/main/java/top/offsetmonkey538/monkeylib538/modded/v12111/impl/resource/package-info.java b/modded/1.21.11/src/main/java/top/offsetmonkey538/monkeylib538/modded/v12111/impl/resource/package-info.java new file mode 100644 index 0000000..b0d0317 --- /dev/null +++ b/modded/1.21.11/src/main/java/top/offsetmonkey538/monkeylib538/modded/v12111/impl/resource/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package top.offsetmonkey538.monkeylib538.modded.v12111.impl.resource; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/modded/1.21.11/src/main/java/top/offsetmonkey538/monkeylib538/modded/v12111/impl/wrapper/IdentifierWrapper.java b/modded/1.21.11/src/main/java/top/offsetmonkey538/monkeylib538/modded/v12111/impl/wrapper/IdentifierWrapper.java new file mode 100644 index 0000000..b912630 --- /dev/null +++ b/modded/1.21.11/src/main/java/top/offsetmonkey538/monkeylib538/modded/v12111/impl/wrapper/IdentifierWrapper.java @@ -0,0 +1,51 @@ +package top.offsetmonkey538.monkeylib538.modded.v12111.impl.wrapper; + +import com.mojang.serialization.Codec; +import net.minecraft.resources.Identifier; +import top.offsetmonkey538.monkeylib538.modded.v12111.api.wrapper.ModdedVersionIdentifier; + +public record IdentifierWrapper(Identifier vanillaIdentifier) implements ModdedVersionIdentifier { + @Override + public String getNamespace() { + return vanillaIdentifier.getNamespace(); + } + + @Override + public String getPath() { + return vanillaIdentifier.getPath(); + } + + @Override + public String toString() { + return vanillaIdentifier.toString(); + } + + @Override + public Identifier get() { + return vanillaIdentifier; + } + + public static final class CodecProviderImpl implements CodecProvider { + @Override + public Codec get() { + return Identifier.CODEC.xmap(IdentifierWrapper::new, ModdedVersionIdentifier::get); + } + } + + public static final class InstantiatorImpl implements ModdedInstantiator { + @Override + public ModdedVersionIdentifier of(String location) { + return new IdentifierWrapper(Identifier.parse(location)); + } + + @Override + public ModdedVersionIdentifier of(String namespace, String path) { + return new IdentifierWrapper(Identifier.fromNamespaceAndPath(namespace, path)); + } + + @Override + public top.offsetmonkey538.monkeylib538.common.api.wrapper.Identifier of(Object identifier) { + return new IdentifierWrapper((net.minecraft.resources.Identifier) identifier); + } + } +} diff --git a/modded/1.21.11/src/main/java/top/offsetmonkey538/monkeylib538/modded/v12111/impl/wrapper/package-info.java b/modded/1.21.11/src/main/java/top/offsetmonkey538/monkeylib538/modded/v12111/impl/wrapper/package-info.java new file mode 100644 index 0000000..2458212 --- /dev/null +++ b/modded/1.21.11/src/main/java/top/offsetmonkey538/monkeylib538/modded/v12111/impl/wrapper/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package top.offsetmonkey538.monkeylib538.modded.v12111.impl.wrapper; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/modded/1.21.11/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.wrapper.Identifier$CodecProvider b/modded/1.21.11/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.wrapper.Identifier$CodecProvider new file mode 100644 index 0000000..1cbbb48 --- /dev/null +++ b/modded/1.21.11/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.wrapper.Identifier$CodecProvider @@ -0,0 +1 @@ +top.offsetmonkey538.monkeylib538.modded.v12111.impl.wrapper.IdentifierWrapper$CodecProviderImpl \ No newline at end of file diff --git a/modded/1.21.11/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.wrapper.Identifier$Instantiator b/modded/1.21.11/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.wrapper.Identifier$Instantiator new file mode 100644 index 0000000..b49bc27 --- /dev/null +++ b/modded/1.21.11/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.wrapper.Identifier$Instantiator @@ -0,0 +1 @@ +top.offsetmonkey538.monkeylib538.modded.v12111.impl.wrapper.IdentifierWrapper$InstantiatorImpl \ No newline at end of file diff --git a/modded/1.21.11/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.modded.api.command.ModdedCommandAbstractionApi$VersionSpecific b/modded/1.21.11/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.modded.api.command.ModdedCommandAbstractionApi$VersionSpecific new file mode 100644 index 0000000..202535f --- /dev/null +++ b/modded/1.21.11/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.modded.api.command.ModdedCommandAbstractionApi$VersionSpecific @@ -0,0 +1 @@ +top.offsetmonkey538.monkeylib538.modded.v12111.impl.command.ModdedCommandAbstractionApiVersionSpecificImpl \ No newline at end of file diff --git a/modded/1.21.11/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.modded.api.player.ModdedPlayerApi b/modded/1.21.11/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.modded.api.player.ModdedPlayerApi new file mode 100644 index 0000000..95bbf33 --- /dev/null +++ b/modded/1.21.11/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.modded.api.player.ModdedPlayerApi @@ -0,0 +1 @@ +top.offsetmonkey538.monkeylib538.modded.v12111.impl.player.ModdedPlayerApiImpl \ No newline at end of file diff --git a/modded/1.21.11/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.modded.api.resource.ResourceKeyApi b/modded/1.21.11/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.modded.api.resource.ResourceKeyApi new file mode 100644 index 0000000..5703397 --- /dev/null +++ b/modded/1.21.11/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.modded.api.resource.ResourceKeyApi @@ -0,0 +1 @@ +top.offsetmonkey538.monkeylib538.modded.v12111.impl.resource.ResourceKeyApiImpl \ No newline at end of file diff --git a/modded/1.21.9/gradle.properties b/modded/1.21.9/gradle.properties new file mode 100644 index 0000000..b23568f --- /dev/null +++ b/modded/1.21.9/gradle.properties @@ -0,0 +1,8 @@ +project_name = modded-1.21.9 + +# Dependencies +## Adventure +adventure_version = 6.7.0 + +# Minecraft version +minecraft_version = 1.21.9 diff --git a/modded/1.21.9/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1219/api/wrapper/ModdedVersionIdentifier.java b/modded/1.21.9/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1219/api/wrapper/ModdedVersionIdentifier.java new file mode 100644 index 0000000..23d62e4 --- /dev/null +++ b/modded/1.21.9/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1219/api/wrapper/ModdedVersionIdentifier.java @@ -0,0 +1,17 @@ +package top.offsetmonkey538.monkeylib538.modded.v1219.api.wrapper; + +import net.minecraft.resources.ResourceLocation; +import top.offsetmonkey538.monkeylib538.common.api.wrapper.Identifier; +import top.offsetmonkey538.monkeylib538.modded.api.wrapper.ModdedIdentifier; + +public interface ModdedVersionIdentifier extends ModdedIdentifier { + static Identifier of(ResourceLocation identifier) { + return ModdedInstantiator.INSTANCE.of(identifier); + } + + static ResourceLocation get(Identifier identifier) { + return ((ModdedVersionIdentifier) identifier).get(); + } + + ResourceLocation get(); +} diff --git a/modded/1.21.9/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1219/api/wrapper/package-info.java b/modded/1.21.9/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1219/api/wrapper/package-info.java new file mode 100644 index 0000000..cabc9e2 --- /dev/null +++ b/modded/1.21.9/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1219/api/wrapper/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package top.offsetmonkey538.monkeylib538.modded.v1219.api.wrapper; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/modded/1.21.9/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1219/impl/command/ModdedCommandAbstractionApiVersionSpecificImpl.java b/modded/1.21.9/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1219/impl/command/ModdedCommandAbstractionApiVersionSpecificImpl.java new file mode 100644 index 0000000..8d42219 --- /dev/null +++ b/modded/1.21.9/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1219/impl/command/ModdedCommandAbstractionApiVersionSpecificImpl.java @@ -0,0 +1,11 @@ +package top.offsetmonkey538.monkeylib538.modded.v1219.impl.command; + +import net.minecraft.commands.CommandSourceStack; +import top.offsetmonkey538.monkeylib538.modded.api.command.ModdedCommandAbstractionApi; + +public final class ModdedCommandAbstractionApiVersionSpecificImpl implements ModdedCommandAbstractionApi.VersionSpecific { + @Override + public boolean isOp(CommandSourceStack source) { + return source.hasPermission(source.getServer().operatorUserPermissionLevel()); + } +} diff --git a/modded/1.21.9/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1219/impl/command/package-info.java b/modded/1.21.9/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1219/impl/command/package-info.java new file mode 100644 index 0000000..8849d1c --- /dev/null +++ b/modded/1.21.9/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1219/impl/command/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package top.offsetmonkey538.monkeylib538.modded.v1219.impl.command; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/modded/1.21.9/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1219/impl/player/ModdedPlayerApiImpl.java b/modded/1.21.9/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1219/impl/player/ModdedPlayerApiImpl.java new file mode 100644 index 0000000..34cf34c --- /dev/null +++ b/modded/1.21.9/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1219/impl/player/ModdedPlayerApiImpl.java @@ -0,0 +1,18 @@ +package top.offsetmonkey538.monkeylib538.modded.v1219.impl.player; + +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.players.PlayerList; +import net.minecraft.world.entity.player.Player; +import top.offsetmonkey538.monkeylib538.modded.api.player.ModdedPlayerApi; + +public final class ModdedPlayerApiImpl implements ModdedPlayerApi { + @Override + public boolean isPlayerOpImpl(PlayerList playerManager, Player player) { + return playerManager.isOp(player.nameAndId()); + } + + @Override + public boolean isPlayerHostImpl(MinecraftServer server, Player player) { + return server.isSingleplayerOwner(player.nameAndId()); + } +} diff --git a/modded/1.21.9/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1219/impl/player/package-info.java b/modded/1.21.9/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1219/impl/player/package-info.java new file mode 100644 index 0000000..2d1840c --- /dev/null +++ b/modded/1.21.9/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1219/impl/player/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package top.offsetmonkey538.monkeylib538.modded.v1219.impl.player; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/modded/1.21.9/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1219/impl/resource/ResourceKeyApiImpl.java b/modded/1.21.9/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1219/impl/resource/ResourceKeyApiImpl.java new file mode 100644 index 0000000..77bca90 --- /dev/null +++ b/modded/1.21.9/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1219/impl/resource/ResourceKeyApiImpl.java @@ -0,0 +1,24 @@ +package top.offsetmonkey538.monkeylib538.modded.v1219.impl.resource; + +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceKey; +import top.offsetmonkey538.monkeylib538.common.api.wrapper.Identifier; +import top.offsetmonkey538.monkeylib538.modded.api.resource.ResourceKeyApi; +import top.offsetmonkey538.monkeylib538.modded.v1219.api.wrapper.ModdedVersionIdentifier; + +public final class ResourceKeyApiImpl implements ResourceKeyApi { + @Override + public ResourceKey createImpl(ResourceKey> resourceKey, Identifier id) { + return ResourceKey.create(resourceKey, ModdedVersionIdentifier.get(id)); + } + + @Override + public ResourceKey> createRegistryImpl(Identifier id) { + return ResourceKey.createRegistryKey(ModdedVersionIdentifier.get(id)); + } + + @Override + public Identifier getLocationImpl(ResourceKey resourceKey) { + return ModdedVersionIdentifier.of(resourceKey.location()); + } +} diff --git a/modded/1.21.9/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1219/impl/resource/package-info.java b/modded/1.21.9/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1219/impl/resource/package-info.java new file mode 100644 index 0000000..22313df --- /dev/null +++ b/modded/1.21.9/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1219/impl/resource/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package top.offsetmonkey538.monkeylib538.modded.v1219.impl.resource; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/modded/1.21.9/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1219/impl/wrapper/IdentifierWrapper.java b/modded/1.21.9/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1219/impl/wrapper/IdentifierWrapper.java new file mode 100644 index 0000000..d9c8c9e --- /dev/null +++ b/modded/1.21.9/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1219/impl/wrapper/IdentifierWrapper.java @@ -0,0 +1,52 @@ +package top.offsetmonkey538.monkeylib538.modded.v1219.impl.wrapper; + +import com.mojang.serialization.Codec; +import net.minecraft.resources.ResourceLocation; +import top.offsetmonkey538.monkeylib538.common.api.wrapper.Identifier; +import top.offsetmonkey538.monkeylib538.modded.v1219.api.wrapper.ModdedVersionIdentifier; + +public record IdentifierWrapper(ResourceLocation vanillaIdentifier) implements ModdedVersionIdentifier { + @Override + public String getNamespace() { + return vanillaIdentifier.getNamespace(); + } + + @Override + public String getPath() { + return vanillaIdentifier.getPath(); + } + + @Override + public String toString() { + return vanillaIdentifier.toString(); + } + + @Override + public ResourceLocation get() { + return vanillaIdentifier; + } + + public static final class CodecProviderImpl implements CodecProvider { + @Override + public Codec get() { + return ResourceLocation.CODEC.xmap(IdentifierWrapper::new, ModdedVersionIdentifier::get); + } + } + + public static final class InstantiatorImpl implements ModdedInstantiator { + @Override + public ModdedVersionIdentifier of(String location) { + return new IdentifierWrapper(ResourceLocation.parse(location)); + } + + @Override + public ModdedVersionIdentifier of(String namespace, String path) { + return new IdentifierWrapper(ResourceLocation.fromNamespaceAndPath(namespace, path)); + } + + @Override + public Identifier of(Object identifier) { + return new IdentifierWrapper((ResourceLocation) identifier); + } + } +} diff --git a/modded/1.21.9/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1219/impl/wrapper/package-info.java b/modded/1.21.9/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1219/impl/wrapper/package-info.java new file mode 100644 index 0000000..f6de2e0 --- /dev/null +++ b/modded/1.21.9/src/main/java/top/offsetmonkey538/monkeylib538/modded/v1219/impl/wrapper/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package top.offsetmonkey538.monkeylib538.modded.v1219.impl.wrapper; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/modded/1.21.9/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.wrapper.Identifier$CodecProvider b/modded/1.21.9/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.wrapper.Identifier$CodecProvider new file mode 100644 index 0000000..98cb509 --- /dev/null +++ b/modded/1.21.9/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.wrapper.Identifier$CodecProvider @@ -0,0 +1 @@ +top.offsetmonkey538.monkeylib538.modded.v1219.impl.wrapper.IdentifierWrapper$CodecProviderImpl \ No newline at end of file diff --git a/modded/1.21.9/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.wrapper.Identifier$Instantiator b/modded/1.21.9/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.wrapper.Identifier$Instantiator new file mode 100644 index 0000000..a4d9cd0 --- /dev/null +++ b/modded/1.21.9/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.wrapper.Identifier$Instantiator @@ -0,0 +1 @@ +top.offsetmonkey538.monkeylib538.modded.v1219.impl.wrapper.IdentifierWrapper$InstantiatorImpl \ No newline at end of file diff --git a/modded/1.21.9/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.modded.api.command.ModdedCommandAbstractionApi$VersionSpecific b/modded/1.21.9/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.modded.api.command.ModdedCommandAbstractionApi$VersionSpecific new file mode 100644 index 0000000..fe3704d --- /dev/null +++ b/modded/1.21.9/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.modded.api.command.ModdedCommandAbstractionApi$VersionSpecific @@ -0,0 +1 @@ +top.offsetmonkey538.monkeylib538.modded.v1219.impl.command.ModdedCommandAbstractionApiVersionSpecificImpl \ No newline at end of file diff --git a/modded/1.21.9/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.modded.api.player.ModdedPlayerApi b/modded/1.21.9/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.modded.api.player.ModdedPlayerApi new file mode 100644 index 0000000..23564b2 --- /dev/null +++ b/modded/1.21.9/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.modded.api.player.ModdedPlayerApi @@ -0,0 +1 @@ +top.offsetmonkey538.monkeylib538.modded.v1219.impl.player.ModdedPlayerApiImpl \ No newline at end of file diff --git a/modded/1.21.9/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.modded.api.resource.ResourceKeyApi b/modded/1.21.9/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.modded.api.resource.ResourceKeyApi new file mode 100644 index 0000000..07a61d1 --- /dev/null +++ b/modded/1.21.9/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.modded.api.resource.ResourceKeyApi @@ -0,0 +1 @@ +top.offsetmonkey538.monkeylib538.modded.v1219.impl.resource.ResourceKeyApiImpl \ No newline at end of file diff --git a/modded/build.gradle b/modded/build.gradle new file mode 100644 index 0000000..c740502 --- /dev/null +++ b/modded/build.gradle @@ -0,0 +1,9 @@ +plugins { + id 'multiloader-modded' +} + +allprojects { + dependencies { + modCompileOnly "net.kyori:adventure-platform-mod-shared-fabric-repack:${project.adventure_version}" + } +} diff --git a/modded/gradle.properties b/modded/gradle.properties new file mode 100644 index 0000000..e6ea150 --- /dev/null +++ b/modded/gradle.properties @@ -0,0 +1,8 @@ +project_name = modded + +# Dependencies +## Adventure +adventure_version = 6.8.0 + +# Minecraft version +minecraft_version = 1.21.11 diff --git a/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/api/command/ModdedCommandAbstractionApi.java b/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/api/command/ModdedCommandAbstractionApi.java new file mode 100644 index 0000000..32872e4 --- /dev/null +++ b/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/api/command/ModdedCommandAbstractionApi.java @@ -0,0 +1,33 @@ +package top.offsetmonkey538.monkeylib538.modded.api.command; + +import com.mojang.brigadier.context.CommandContext; +import net.minecraft.commands.CommandSourceStack; +import top.offsetmonkey538.monkeylib538.common.api.command.CommandAbstractionApi; +import top.offsetmonkey538.offsetutils538.api.annotation.Internal; + +import static top.offsetmonkey538.monkeylib538.common.MonkeyLib538Common.load; + +public interface ModdedCommandAbstractionApi extends CommandAbstractionApi { + static CommandSourceStack get(CommandContext ctx) { + return ((ModdedCommandAbstractionApi) INSTANCE).getImpl(ctx); + } + static CommandSourceStack get(Object commandSource) { + return ((ModdedCommandAbstractionApi) INSTANCE).getImpl(commandSource); + } + + @Override + default boolean isOpImpl(final Object source) { + return VersionSpecific.INSTANCE.isOp(get(source)); + } + + @Internal + CommandSourceStack getImpl(CommandContext ctx); + @Internal CommandSourceStack getImpl(Object commandSource); + + @Internal + interface VersionSpecific { + VersionSpecific INSTANCE = load(VersionSpecific.class); + + boolean isOp(final CommandSourceStack source); + } +} diff --git a/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/api/command/package-info.java b/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/api/command/package-info.java new file mode 100644 index 0000000..647a0a4 --- /dev/null +++ b/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/api/command/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package top.offsetmonkey538.monkeylib538.modded.api.command; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/api/player/ModdedPlayerApi.java b/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/api/player/ModdedPlayerApi.java new file mode 100644 index 0000000..88f198c --- /dev/null +++ b/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/api/player/ModdedPlayerApi.java @@ -0,0 +1,24 @@ +package top.offsetmonkey538.monkeylib538.modded.api.player; + +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.players.PlayerList; +import net.minecraft.world.entity.player.Player; +import top.offsetmonkey538.offsetutils538.api.annotation.Internal; + +import static top.offsetmonkey538.monkeylib538.common.MonkeyLib538Common.load; + +public interface ModdedPlayerApi { + @Internal + ModdedPlayerApi INSTANCE = load(ModdedPlayerApi.class); + + static boolean isPlayerOp(final PlayerList playerManager, final Player player) { + return INSTANCE.isPlayerOpImpl(playerManager, player); + } + static boolean isPlayerHost(final MinecraftServer server, final Player player) { + return INSTANCE.isPlayerHostImpl(server, player); + } + + + @Internal boolean isPlayerOpImpl(final PlayerList playerManager, final Player player); + @Internal boolean isPlayerHostImpl(final MinecraftServer server, final Player player); +} diff --git a/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/api/player/package-info.java b/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/api/player/package-info.java new file mode 100644 index 0000000..23b5faa --- /dev/null +++ b/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/api/player/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package top.offsetmonkey538.monkeylib538.modded.api.player; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/api/resource/ResourceKeyApi.java b/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/api/resource/ResourceKeyApi.java new file mode 100644 index 0000000..bb6bbef --- /dev/null +++ b/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/api/resource/ResourceKeyApi.java @@ -0,0 +1,29 @@ +package top.offsetmonkey538.monkeylib538.modded.api.resource; + +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceKey; +import top.offsetmonkey538.monkeylib538.common.api.wrapper.Identifier; +import top.offsetmonkey538.offsetutils538.api.annotation.Internal; + +import static top.offsetmonkey538.monkeylib538.common.MonkeyLib538Common.load; + +public interface ResourceKeyApi { + @Internal + ResourceKeyApi INSTANCE = load(ResourceKeyApi.class); + + static ResourceKey create(ResourceKey> resourceKey, Identifier id) { + return INSTANCE.createImpl(resourceKey, id); + } + static ResourceKey> createRegistry(Identifier id) { + return INSTANCE.createRegistryImpl(id); + } + + static Identifier getLocation(ResourceKey resourceKey) { + return INSTANCE.getLocationImpl(resourceKey); + } + + + @Internal ResourceKey createImpl(ResourceKey> resourceKey, Identifier id); + @Internal ResourceKey> createRegistryImpl(Identifier id); + @Internal Identifier getLocationImpl(ResourceKey resourceKey); +} diff --git a/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/api/resource/package-info.java b/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/api/resource/package-info.java new file mode 100644 index 0000000..dbd9a89 --- /dev/null +++ b/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/api/resource/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package top.offsetmonkey538.monkeylib538.modded.api.resource; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/api/server/ServerProvider.java b/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/api/server/ServerProvider.java new file mode 100644 index 0000000..a49ae77 --- /dev/null +++ b/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/api/server/ServerProvider.java @@ -0,0 +1,22 @@ +package top.offsetmonkey538.monkeylib538.modded.api.server; + +import net.minecraft.server.dedicated.DedicatedServer; +import org.jspecify.annotations.Nullable; +import top.offsetmonkey538.offsetutils538.api.annotation.Internal; + +import static top.offsetmonkey538.monkeylib538.common.MonkeyLib538Common.load; + +public interface ServerProvider { + @Internal + ServerProvider INSTANCE = load(ServerProvider.class); + + /** + * Server will only exist after server starting event! + * @return the current minecraft dedicated server. + */ + static @Nullable DedicatedServer getServer() { + return INSTANCE.getServerImpl(); + } + + @Internal @Nullable DedicatedServer getServerImpl(); +} diff --git a/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/api/server/package-info.java b/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/api/server/package-info.java new file mode 100644 index 0000000..d778092 --- /dev/null +++ b/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/api/server/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package top.offsetmonkey538.monkeylib538.modded.api.server; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/api/wrapper/ModdedIdentifier.java b/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/api/wrapper/ModdedIdentifier.java new file mode 100644 index 0000000..8a6ee01 --- /dev/null +++ b/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/api/wrapper/ModdedIdentifier.java @@ -0,0 +1,17 @@ +package top.offsetmonkey538.monkeylib538.modded.api.wrapper; + +import top.offsetmonkey538.monkeylib538.common.api.wrapper.Identifier; +import top.offsetmonkey538.offsetutils538.api.annotation.Internal; + +public interface ModdedIdentifier extends Identifier { + static Identifier of(Object identifier) { + return ModdedInstantiator.INSTANCE.of(identifier); + } + + @Internal + interface ModdedInstantiator extends Instantiator { + ModdedInstantiator INSTANCE = (ModdedInstantiator) Instantiator.INSTANCE; + + Identifier of(Object identifier); + } +} diff --git a/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/impl/client/platform/ClientBrandGetterImpl.java b/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/impl/client/platform/ClientBrandGetterImpl.java new file mode 100644 index 0000000..87c6731 --- /dev/null +++ b/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/impl/client/platform/ClientBrandGetterImpl.java @@ -0,0 +1,11 @@ +package top.offsetmonkey538.monkeylib538.modded.impl.client.platform; + +import net.minecraft.client.ClientBrandRetriever; +import top.offsetmonkey538.monkeylib538.common.api.platform.LoaderUtil; + +public final class ClientBrandGetterImpl implements LoaderUtil.ClientBrandGetter { + @Override + public String getBrand() { + return ClientBrandRetriever.getClientModName(); + } +} diff --git a/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/impl/client/platform/package-info.java b/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/impl/client/platform/package-info.java new file mode 100644 index 0000000..d00a66b --- /dev/null +++ b/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/impl/client/platform/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package top.offsetmonkey538.monkeylib538.modded.impl.client.platform; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/impl/command/CommandAbstractionImpl.java b/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/impl/command/CommandAbstractionImpl.java new file mode 100644 index 0000000..0b64584 --- /dev/null +++ b/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/impl/command/CommandAbstractionImpl.java @@ -0,0 +1,65 @@ +package top.offsetmonkey538.monkeylib538.modded.impl.command; + +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.builder.RequiredArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import net.kyori.adventure.audience.Audience; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.player.Player; +import top.offsetmonkey538.monkeylib538.modded.api.command.ModdedCommandAbstractionApi; +import top.offsetmonkey538.monkeylib538.modded.api.player.ModdedPlayerApi; + +import static top.offsetmonkey538.monkeylib538.modded.api.command.ModdedCommandAbstractionApi.get; +import static top.offsetmonkey538.offsetutils538.api.text.ArgReplacer.replaceArgs; + +public final class CommandAbstractionImpl implements ModdedCommandAbstractionApi { + + @Override + public LiteralArgumentBuilder literalImpl(String name) { + return LiteralArgumentBuilder.literal(name); + } + + @Override + public RequiredArgumentBuilder argumentImpl(String name, ArgumentType type) { + return RequiredArgumentBuilder.argument(name, type); + } + + @Override + public void sendMessageImpl(CommandContext ctx, String message) { + get(ctx).sendSuccess(() -> Component.nullToEmpty(message), true); + } + + @Override + public void sendErrorImpl(CommandContext ctx, String message) { + get(ctx).sendFailure(Component.nullToEmpty(message)); + } + + @Override + public void sendTextImpl(CommandContext ctx, net.kyori.adventure.text.Component text) { + ((Audience) get(ctx)).sendMessage(text); + } + + @Override + public boolean executedByPlayerImpl(Object source) { + return get(source).isPlayer(); + } + + @Override + public boolean isHostImpl(Object source) { + // Using instanceof as a null check and variable assign + return get(source).getPlayer() instanceof Player player && ModdedPlayerApi.isPlayerHost(get(source).getServer(), player); + } + + @Override + public CommandSourceStack getImpl(CommandContext ctx) { + return getImpl(ctx.getSource()); + } + + @Override + public CommandSourceStack getImpl(Object commandSource) { + if (commandSource instanceof CommandSourceStack serverCommandSource) return serverCommandSource; + throw new IllegalStateException(replaceArgs("Expected command source to be of type '%s', got '%s' instead. Something is very very wrong if you're seeing this error :concern:", CommandSourceStack.class, commandSource.getClass())); + } +} diff --git a/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/impl/command/package-info.java b/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/impl/command/package-info.java new file mode 100644 index 0000000..3af6d2b --- /dev/null +++ b/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/impl/command/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package top.offsetmonkey538.monkeylib538.modded.impl.command; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/impl/platform/ServerBrandGetterImpl.java b/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/impl/platform/ServerBrandGetterImpl.java new file mode 100644 index 0000000..3cfdd3e --- /dev/null +++ b/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/impl/platform/ServerBrandGetterImpl.java @@ -0,0 +1,13 @@ +package top.offsetmonkey538.monkeylib538.modded.impl.platform; + +import org.jspecify.annotations.Nullable; +import top.offsetmonkey538.monkeylib538.common.api.platform.LoaderUtil; + +import static top.offsetmonkey538.monkeylib538.modded.api.server.ServerProvider.getServer; + +public final class ServerBrandGetterImpl implements LoaderUtil.ServerBrandGetter { + @Override + public @Nullable String getBrand() { + return getServer() == null ? null : getServer().getServerModName(); + } +} diff --git a/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/impl/platform/package-info.java b/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/impl/platform/package-info.java new file mode 100644 index 0000000..2a48a54 --- /dev/null +++ b/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/impl/platform/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package top.offsetmonkey538.monkeylib538.modded.impl.platform; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/mixin/client/MinecraftClientMixin.java b/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/mixin/client/MinecraftClientMixin.java new file mode 100644 index 0000000..80b8741 --- /dev/null +++ b/modded/src/main/java/top/offsetmonkey538/monkeylib538/modded/mixin/client/MinecraftClientMixin.java @@ -0,0 +1,20 @@ +package top.offsetmonkey538.monkeylib538.modded.mixin.client; + +import net.minecraft.client.Minecraft; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import top.offsetmonkey538.monkeylib538.common.api.lifecycle.ClientLifecycleApi; + +@Mixin(Minecraft.class) +public abstract class MinecraftClientMixin { + + @Inject( + method = "onGameLoadFinished", + at = @At("TAIL") + ) + private void monkeylib538$runClientLoadFinishEvent(CallbackInfo ci) { + ClientLifecycleApi.LOAD_FINISHED.getInvoker().run(); + } +} diff --git a/modded/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.command.CommandAbstractionApi b/modded/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.command.CommandAbstractionApi new file mode 100644 index 0000000..5edcdda --- /dev/null +++ b/modded/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.command.CommandAbstractionApi @@ -0,0 +1 @@ +top.offsetmonkey538.monkeylib538.modded.impl.command.CommandAbstractionImpl \ No newline at end of file diff --git a/modded/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.platform.LoaderUtil$ClientBrandGetter b/modded/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.platform.LoaderUtil$ClientBrandGetter new file mode 100644 index 0000000..9d3fad4 --- /dev/null +++ b/modded/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.platform.LoaderUtil$ClientBrandGetter @@ -0,0 +1 @@ +top.offsetmonkey538.monkeylib538.modded.impl.client.platform.ClientBrandGetterImpl \ No newline at end of file diff --git a/modded/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.platform.LoaderUtil$ServerBrandGetter b/modded/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.platform.LoaderUtil$ServerBrandGetter new file mode 100644 index 0000000..1ae8865 --- /dev/null +++ b/modded/src/main/resources/META-INF/services/top.offsetmonkey538.monkeylib538.common.api.platform.LoaderUtil$ServerBrandGetter @@ -0,0 +1 @@ +top.offsetmonkey538.monkeylib538.modded.impl.platform.ServerBrandGetterImpl \ No newline at end of file diff --git a/modded/src/main/resources/monkeylib538.modded.mixins.json b/modded/src/main/resources/monkeylib538.modded.mixins.json new file mode 100644 index 0000000..0e99957 --- /dev/null +++ b/modded/src/main/resources/monkeylib538.modded.mixins.json @@ -0,0 +1,11 @@ +{ + "required": true, + "package": "top.offsetmonkey538.monkeylib538.modded.mixin", + "compatibilityLevel": "JAVA_21", + "client": [ + "client.MinecraftClientMixin" + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/settings.gradle b/settings.gradle index 0fdae2f..2a1cebf 100644 --- a/settings.gradle +++ b/settings.gradle @@ -8,3 +8,26 @@ pluginManagement { gradlePluginPortal() } } + +rootProject.name = "monkeylib538" + + +include "common" + +include "modded" +include "modded:1.21.1" +include "modded:1.21.9" +include "modded:1.21.11" + +include "loader:fabric" +include "loader:fabric:1.21.1" +include "loader:fabric:1.21.9" +include "loader:fabric:1.21.11" + +include "loader:neoforge" +include "loader:neoforge:1.21.1" +include "loader:neoforge:1.21.9" +include "loader:neoforge:1.21.11" + +include "loader:paper" +include "loader:paper:1.21.1" diff --git a/src/client/java/top/offsetmonkey538/monkeylib538/MonkeyLib538Client.java b/src/client/java/top/offsetmonkey538/monkeylib538/MonkeyLib538Client.java deleted file mode 100644 index 642c7bb..0000000 --- a/src/client/java/top/offsetmonkey538/monkeylib538/MonkeyLib538Client.java +++ /dev/null @@ -1,11 +0,0 @@ -package top.offsetmonkey538.monkeylib538; - -import net.fabricmc.api.ClientModInitializer; - -public class MonkeyLib538Client implements ClientModInitializer { - - @Override - public void onInitializeClient() { - // Do stuff - } -} diff --git a/src/client/resources/monkeylib538.client.mixins.json b/src/client/resources/monkeylib538.client.mixins.json deleted file mode 100644 index 6704b1a..0000000 --- a/src/client/resources/monkeylib538.client.mixins.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "required": true, - "package": "top.offsetmonkey538.monkeylib538.mixin.client", - "compatibilityLevel": "JAVA_17", - "client": [ - - ], - "injectors": { - "defaultRequire": 1 - } -} diff --git a/src/main/java/top/offsetmonkey538/monkeylib538/MonkeyLib538.java b/src/main/java/top/offsetmonkey538/monkeylib538/MonkeyLib538.java deleted file mode 100644 index 16677b5..0000000 --- a/src/main/java/top/offsetmonkey538/monkeylib538/MonkeyLib538.java +++ /dev/null @@ -1,20 +0,0 @@ -package top.offsetmonkey538.monkeylib538; - -import net.fabricmc.api.ModInitializer; -import net.minecraft.util.Identifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class MonkeyLib538 implements ModInitializer { - public static final String MOD_ID = "monkeylib538"; - public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); - - @Override - public void onInitialize() { - // Do stuff - } - - public static Identifier id(String path) { - return new Identifier(MOD_ID, path); - } -} diff --git a/src/main/java/top/offsetmonkey538/monkeylib538/config/Config.java b/src/main/java/top/offsetmonkey538/monkeylib538/config/Config.java deleted file mode 100644 index f77167b..0000000 --- a/src/main/java/top/offsetmonkey538/monkeylib538/config/Config.java +++ /dev/null @@ -1,39 +0,0 @@ -package top.offsetmonkey538.monkeylib538.config; - -import blue.endless.jankson.Jankson; -import java.nio.file.Path; -import net.fabricmc.loader.api.FabricLoader; - -/** - * Extend this in your config class. - */ -public abstract class Config { - - /** - * Configure the provided {@link Jankson.Builder}. - * May be overridden if needed. - * - * @param builder The builder to configure. - * @return the configured {@link Jankson.Builder}. - */ - protected Jankson.Builder configureJankson(Jankson.Builder builder) { - // TODO: Default serializers - return builder; - } - - /** - * May be overridden if needed. - * - * @return the path the config should be stored at, including the file extension. - */ - public Path getFilePath() { - return FabricLoader.getInstance().getConfigDir().resolve(getName() + ".json"); - } - - /** - * The name of the config. Used for creating the file path. - * - * @return the name of the config. Used for creating the file path. - */ - protected abstract String getName(); -} diff --git a/src/main/java/top/offsetmonkey538/monkeylib538/config/ConfigManager.java b/src/main/java/top/offsetmonkey538/monkeylib538/config/ConfigManager.java deleted file mode 100644 index 80a293f..0000000 --- a/src/main/java/top/offsetmonkey538/monkeylib538/config/ConfigManager.java +++ /dev/null @@ -1,90 +0,0 @@ -package top.offsetmonkey538.monkeylib538.config; - -import blue.endless.jankson.Jankson; -import blue.endless.jankson.api.SyntaxError; -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.util.function.BiConsumer; - -/** - * Provides methods for loading and saving {@link Config} classes. - */ -public final class ConfigManager { - - /** - * Private constructor - */ - private ConfigManager() { - - } - - /** - * Loads the {@link Config} file if and only if the config file exists. - *
- * Otherwise, it saves the default values to disk. - * - * @see #load(Config, BiConsumer) - * @see #save(Config, BiConsumer) - * @param config An instance of the {@link Config} containing the default values, usually {@code new MyConfig()}. - * @param errorHandler A method to handle errors. For example {@code LOGGER::error}. - * @return either an instance of {@link Config} loaded from disk or the provided default {@link Config}. - */ - public static T init(T config, BiConsumer errorHandler) { - if (config.getFilePath().toFile().exists()) return load(config, errorHandler); - - save(config, errorHandler); - return config; - } - - /** - * Used for loading a {@link Config} class - *
- * Logs an error and returns the provided default {@link Config} when the config file could not be read or is formatted incorrectly. - * - * @see #init(Config, BiConsumer) - * @see #save(Config, BiConsumer) - * @param config An instance of the {@link Config} containing the default values, usually {@code new MyConfig()}. - * @param errorHandler A method to handle errors. For example {@code LOGGER::error}. - * @return an instance of the provided {@link Config} class populated from the config file or the provided default {@link Config} when the config file could not be read or is formatted incorrectly. - */ - @SuppressWarnings("unchecked") - public static T load(T config, BiConsumer errorHandler) { - final Jankson jankson = config.configureJankson(Jankson.builder()).build(); - final File configFile = config.getFilePath().toFile(); - - try { - return (T) jankson.fromJson(jankson.load(configFile), config.getClass()); - } catch (IOException e) { - errorHandler.accept("Config file '" + config.getFilePath() + "' could not be read!", e); - } catch (SyntaxError e) { - errorHandler.accept("Config file '" + config.getFilePath() + "' is formatted incorrectly!", e); - } - - return config; - } - - /** - * Saves the provided instance of {@link Config} onto disk. - *
- * Errors if it couldn't write to the file. - * - * @see #init(Config, BiConsumer) - * @see #load(Config, BiConsumer) - * @param config the instance of {@link Config} to save. - * @param errorHandler A method to handle errors. For example {@code LOGGER::error}. - */ - public static void save(Config config, BiConsumer errorHandler) { - final Jankson jankson = config.configureJankson(Jankson.builder()).build(); - - final String result = jankson - .toJson(config) - .toJson(true, true); - - try { - Files.writeString(config.getFilePath(), result); - } catch (IOException e) { - errorHandler.accept("Config file '" + config.getFilePath() + "' could not be written to!", e); - } - } -} diff --git a/src/main/resources/assets/monkeylib538/icon.png b/src/main/resources/assets/monkeylib538/icon.png deleted file mode 100644 index 858893b..0000000 Binary files a/src/main/resources/assets/monkeylib538/icon.png and /dev/null differ diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json deleted file mode 100644 index 65a74db..0000000 --- a/src/main/resources/fabric.mod.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "schemaVersion": 1, - "id": "monkeylib538", - "version": "${modVersion}", - "name": "MonkeyLib538", - "description": "A library mod for OffsetMonkey538s mods", - "authors": [ - "OffsetMonkey538" - ], - "contact": { - "sources": "https://github.com/OffsetMods538/MonkeyLib538", - "issues": "https://github.com/OffsetMods538/MonkeyLib538/issues", - "homepage": "https://modrinth.com/mod/monkeylib538" - }, - "license": "MIT", - "icon": "assets/monkeylib538/icon.png", - "environment": "*", - "entrypoints": { - "main": [ - "top.offsetmonkey538.monkeylib538.MonkeyLib538" - ], - "client": [ - "top.offsetmonkey538.monkeylib538.MonkeyLib538Client" - ] - }, - "mixins": [ - "monkeylib538.mixins.json", - { - "config": "monkeylib538.client.mixins.json", - "environment": "client" - } - ], - "accessWidener": "monkeylib538.accesswidener", - "depends": { - "minecraft": "${supportedMinecraftVersions}" - } -} diff --git a/src/main/resources/monkeylib538.accesswidener b/src/main/resources/monkeylib538.accesswidener deleted file mode 100644 index b9bc9cb..0000000 --- a/src/main/resources/monkeylib538.accesswidener +++ /dev/null @@ -1 +0,0 @@ -accessWidener v1 named diff --git a/src/main/resources/monkeylib538.mixins.json b/src/main/resources/monkeylib538.mixins.json deleted file mode 100644 index 10697a3..0000000 --- a/src/main/resources/monkeylib538.mixins.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "required": true, - "package": "top.offsetmonkey538.monkeylib538.mixin", - "compatibilityLevel": "JAVA_17", - "mixins": [ - - ], - "injectors": { - "defaultRequire": 1 - } -} diff --git a/src/testmod/java/testmod/Testmod.java b/src/testmod/java/testmod/Testmod.java deleted file mode 100644 index 8c8c75f..0000000 --- a/src/testmod/java/testmod/Testmod.java +++ /dev/null @@ -1,16 +0,0 @@ -package testmod; - -import net.fabricmc.api.ModInitializer; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import testmod.config.ConfigTestmod; - -public class Testmod implements ModInitializer { - public static final String MOD_ID = "testmod"; - public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); - - @Override - public void onInitialize() { - new ConfigTestmod().onInitialize(); - } -} diff --git a/src/testmod/java/testmod/TestmodClient.java b/src/testmod/java/testmod/TestmodClient.java deleted file mode 100644 index e8429c0..0000000 --- a/src/testmod/java/testmod/TestmodClient.java +++ /dev/null @@ -1,11 +0,0 @@ -package testmod; - -import net.fabricmc.api.ClientModInitializer; - -public class TestmodClient implements ClientModInitializer { - - @Override - public void onInitializeClient() { - - } -} diff --git a/src/testmod/java/testmod/config/ConfigTestmod.java b/src/testmod/java/testmod/config/ConfigTestmod.java deleted file mode 100644 index a787786..0000000 --- a/src/testmod/java/testmod/config/ConfigTestmod.java +++ /dev/null @@ -1,15 +0,0 @@ -package testmod.config; - -import top.offsetmonkey538.monkeylib538.config.ConfigManager; - -import static testmod.Testmod.*; - -public class ConfigTestmod { - - public void onInitialize() { - final ModConfig config = ConfigManager.init(new ModConfig(), LOGGER::error); - - LOGGER.info("hello: " + config.hello); - LOGGER.info("Number: " + config.Number); - } -} diff --git a/src/testmod/java/testmod/config/ModConfig.java b/src/testmod/java/testmod/config/ModConfig.java deleted file mode 100644 index d15ed90..0000000 --- a/src/testmod/java/testmod/config/ModConfig.java +++ /dev/null @@ -1,20 +0,0 @@ -package testmod.config; - -import blue.endless.jankson.Comment; -import top.offsetmonkey538.monkeylib538.config.Config; - -import static testmod.Testmod.*; - -public class ModConfig extends Config { - - public String hello = "Hello!"; - - @Comment("Now that's nice!") - public int Number = 69; - - - @Override - protected String getName() { - return MOD_ID; - } -} diff --git a/src/testmod/resources/fabric.mod.json b/src/testmod/resources/fabric.mod.json deleted file mode 100644 index 464cf20..0000000 --- a/src/testmod/resources/fabric.mod.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "schemaVersion": 1, - "id": "testmod", - "version": "testmod-${modVersion}", - "name": "testmod", - "description": "testmod", - "authors": [ - "OffsetMonkey538" - ], - "license": "MIT", - "environment": "*", - "entrypoints": { - "main": [ - "testmod.Testmod" - ], - "client": [ - "testmod.TestmodClient" - ] - } -} diff --git a/veryImportant/done.wav b/veryImportant/done.wav new file mode 100644 index 0000000..9dfad8c Binary files /dev/null and b/veryImportant/done.wav differ diff --git a/veryImportant/music.wav b/veryImportant/music.wav new file mode 100644 index 0000000..397f3ec Binary files /dev/null and b/veryImportant/music.wav differ