diff --git a/Makefile b/Makefile index 01f94485..801c16e3 100644 --- a/Makefile +++ b/Makefile @@ -2,13 +2,14 @@ .PHONY: clean clean: - rm -rf build common/build fabric/build forge/build + rm -rf build common/build fabric/build neoforge/build #forge/build .PHONY: jar jar: ./gradlew remapJar ls -1 fabric/build/libs + ls -1 neoforge/build/libs # ls -1 forge/build/libs test: @@ -39,14 +40,18 @@ deps: .PHONY: inst inst: # rm -f ~/minecraft/instances/1.20.1-forge-dev/.minecraft/mods/fastback* + rm -f ~/minecraft/instances/1.20.1-neoforge-dev/.minecraft/mods/fastback* rm -f ~/minecraft/instances/1.20.1-fabric-dev/.minecraft/mods/fasback* cp fabric/build/libs/fastback*-fabric.jar ~/minecraft/instances/1.20.1-fabric-dev/.minecraft/mods/ + cp neoforge/build/libs/fastback*-neoforge.jar ~/minecraft/instances/1.20.1-neoforge-dev/.minecraft/mods/ # cp forge/build/libs/fastback*-forge.jar ~/minecraft/instances/1.20.1-forge-dev/.minecraft/mods/ .PHONY: tvf tvf: + jar -tvf neoforge/build/libs/fastback*-neoforge.jar # jar -tvf forge/build/libs/fastback*-forge.jar .PHONY: tvfs tvfs: + jar -tvf neoforge/build/libs/fastback*-shadow.jar # jar -tvf forge/build/libs/fastback*-shadow.jar diff --git a/README.md b/README.md index c2f1a73d..45ba2934 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ of disk space. ## Features +* **Now with NeoForge support!** * Incrementally backup just the changed files * Faster, smaller backups than zipping * Back up locally @@ -31,7 +32,6 @@ of disk space. * Support for restoring remote snapshots * Better management of remote snapshots * UI for managing backups from the title screen -* ~~Forge support (maybe)~~ ## Acknowledgements diff --git a/build.gradle b/build.gradle index fbde8332..ec7ac4b1 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ plugins { id "architectury-plugin" version "3.4-SNAPSHOT" - id "dev.architectury.loom" version "1.6-SNAPSHOT" apply false + id "dev.architectury.loom" version "1.7-SNAPSHOT" apply false } @@ -19,6 +19,7 @@ subprojects { maven { url 'https://maven.fabricmc.net/' } maven { url 'https://maven.nucleoid.xyz' } maven { url 'https://oss.sonatype.org/content/repositories/snapshots' } + maven { url 'https://maven.neoforged.net/releases/' } } java { diff --git a/common/build.gradle b/common/build.gradle index 79f8757a..637840e5 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -1,6 +1,7 @@ architectury { common("fabric") + common("neoforge") // NOTE: Forge is no longer supported and the build has been disabled // See: https://github.com/pcal43/fastback/issues/333 //common("forge") diff --git a/common/src/main/java/net/pcal/fastback/logging/Log4jLogger.java b/common/src/main/java/net/pcal/fastback/logging/Log4jLogger.java index 68636615..4abcd1b4 100644 --- a/common/src/main/java/net/pcal/fastback/logging/Log4jLogger.java +++ b/common/src/main/java/net/pcal/fastback/logging/Log4jLogger.java @@ -54,6 +54,11 @@ public void warn(String message) { this.log4j.warn(message); } + @Override + public void warn(String message, Throwable t) { + this.log4j.warn(message, t); + } + @Override public void info(String message) { this.log4j.info(message); diff --git a/common/src/main/java/net/pcal/fastback/logging/SystemLogger.java b/common/src/main/java/net/pcal/fastback/logging/SystemLogger.java index 8fcc60c8..4d7266f5 100644 --- a/common/src/main/java/net/pcal/fastback/logging/SystemLogger.java +++ b/common/src/main/java/net/pcal/fastback/logging/SystemLogger.java @@ -44,6 +44,8 @@ default void error(Throwable e) { void warn(String message); + void warn(String message, Throwable t); + void info(String message); void debug(String message); diff --git a/common/src/main/java/net/pcal/fastback/mod/ModImpl.java b/common/src/main/java/net/pcal/fastback/mod/ModImpl.java index 69b6df30..0082ca53 100644 --- a/common/src/main/java/net/pcal/fastback/mod/ModImpl.java +++ b/common/src/main/java/net/pcal/fastback/mod/ModImpl.java @@ -30,6 +30,7 @@ import java.nio.file.Path; import java.util.Collection; import java.util.Map; +import java.util.ServiceConfigurationError; import static java.nio.file.Files.createTempDirectory; import static java.util.Objects.requireNonNull; @@ -162,10 +163,14 @@ public void onInitialize() { syslog().info("git-lfs is installed: " + gitLfsVersion); } } - if (SshSessionFactory.getInstance() == null) { - syslog().warn("An ssh provider was not initialized for jgit. Operations on a remote repo over ssh will fail."); - } else { - syslog().info("SshSessionFactory: " + SshSessionFactory.getInstance().toString()); + try { + if (SshSessionFactory.getInstance() == null) { + syslog().warn("An ssh provider was not initialized for jgit. Operations on a remote repo over ssh will fail."); + } else { + syslog().info("SshSessionFactory: " + SshSessionFactory.getInstance().toString()); + } + } catch (Exception | ServiceConfigurationError e) { + syslog().warn("An ssh provider was not initialized for jgit. Operations on a remote repo over ssh will fail.", e); } syslog().debug("onInitialize complete"); } diff --git a/etc/release.sh b/etc/release.sh index a66e8781..01efb8b8 100755 --- a/etc/release.sh +++ b/etc/release.sh @@ -50,6 +50,7 @@ fi # FABRIC_LIBS_DIR='fabric/build/libs' +NEOFORGE_LIBS_DIR='neoforge/build/libs' # NOTE: Forge is no longer supported and the build has been disabled # See: https://github.com/pcal43/fastback/issues/333 @@ -69,6 +70,7 @@ rm gradle.properties mv gradle.properties.temp gradle.properties rm -rf "${FABRIC_LIBS_DIR}" +rm -rf "${NEOFORGE_LIBS_DIR}" # NOTE: Forge is no longer supported and the build has been disabled # See: https://github.com/pcal43/fastback/issues/333 @@ -84,7 +86,7 @@ git push # Do github release # set -x -gh release create --generate-notes --title "${RELEASE_VERSION}" --notes "release ${RELEASE_VERSION}" ${RELEASE_VERSION} "${FABRIC_LIBS_DIR}"/* # "${FORGE_LIBS_DIR}"/* +gh release create --generate-notes --title "${RELEASE_VERSION}" --notes "release ${RELEASE_VERSION}" ${RELEASE_VERSION} "${FABRIC_LIBS_DIR}"/* "${NEOFORGE_LIBS_DIR}"/* # "${FORGE_LIBS_DIR}"/* set +x diff --git a/fabric/src/main/java/net/pcal/fastback/mod/fabric/BaseFabricProvider.java b/fabric/src/main/java/net/pcal/fastback/mod/fabric/BaseFabricProvider.java index 7e40ca30..dfbb700d 100644 --- a/fabric/src/main/java/net/pcal/fastback/mod/fabric/BaseFabricProvider.java +++ b/fabric/src/main/java/net/pcal/fastback/mod/fabric/BaseFabricProvider.java @@ -27,7 +27,6 @@ import net.minecraft.commands.CommandSourceStack; import net.minecraft.server.MinecraftServer; import net.minecraft.world.level.storage.LevelStorageSource; -import net.minecraft.world.level.storage.LevelSummary; import net.pcal.fastback.logging.Log4jLogger; import net.pcal.fastback.logging.SystemLogger; import net.pcal.fastback.logging.UserMessage; diff --git a/fabric/src/main/java/net/pcal/fastback/mod/fabric/mixins/MinecraftServerMixin.java b/fabric/src/main/java/net/pcal/fastback/mod/fabric/mixins/MinecraftServerMixin.java index 6978bd16..87964a5d 100644 --- a/fabric/src/main/java/net/pcal/fastback/mod/fabric/mixins/MinecraftServerMixin.java +++ b/fabric/src/main/java/net/pcal/fastback/mod/fabric/mixins/MinecraftServerMixin.java @@ -41,7 +41,7 @@ public class MinecraftServerMixin { * Intercept the call to saveAll that triggers on autosave, pass it through and then send out notification that * the autosave is done. */ - @Redirect(method = "tickServer(Ljava/util/function/BooleanSupplier;)V", + @Redirect(method = "autoSave()V", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/MinecraftServer;saveEverything(ZZZ)Z")) public boolean fastback_saveAll(MinecraftServer instance, boolean suppressLogs, boolean flush, boolean force) { boolean result = instance.saveEverything(suppressLogs, flush, force); diff --git a/fabric/src/main/resources/fabric.mod.json b/fabric/src/main/resources/fabric.mod.json index 0a3f151c..37c2e70b 100644 --- a/fabric/src/main/resources/fabric.mod.json +++ b/fabric/src/main/resources/fabric.mod.json @@ -25,7 +25,7 @@ "fastback.mixins.json" ], "depends": { - "fabricloader": ">=0.15.11", + "fabricloader": ">=0.16.4", "fabric": "*", "minecraft": "1.21.x", "java": ">=21" diff --git a/gradle.properties b/gradle.properties index 8b32086b..c40eb9ea 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,7 @@ # # Fastback # -mod_version = 0.19.1+1.21-prerelease +mod_version = 0.19.2+1.21.3-prerelease maven_group = net.pcal maven_name = fastback archives_base_name = fastback @@ -10,9 +10,9 @@ archives_base_name = fastback # # Fabric & Minecraft - https://fabricmc.net/develop # -minecraft_version=1.21 -loader_version=0.15.11 -fabric_version=0.100.6+1.21 +minecraft_version=1.21.3 +loader_version=0.16.4 +fabric_version=0.106.1+1.21.3 # # Forge @@ -22,15 +22,20 @@ fabric_version=0.100.6+1.21 # NOTE: Forge is no longer supported and the build has been disabled # See: https://github.com/pcal43/fastback/issues/333 +# NeoForge +# +# https://projects.neoforged.net/neoforged/neoforge +neo_version = 21.3.31-beta + # # common dependencies # # https://mvnrepository.com/artifact/org.eclipse.jgit/org.eclipse.jgit -jgit_version = 6.8.0.202311291450-r +jgit_version = 6.10.0.202406032230-r # https://mvnrepository.com/artifact/org.apache.sshd/sshd-core -apache_sshd_version = 2.12.1 +apache_sshd_version = 2.14.0 # https://mvnrepository.com/artifact/com.googlecode.javaewah/JavaEWAH JavaEWAH_version = 1.2.3 @@ -39,10 +44,10 @@ JavaEWAH_version = 1.2.3 eddsa_version = 0.3.0 # https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -test_log4j_version = 2.23.1 +test_log4j_version = 2.24.1 # https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-engine -junit_jupiter_version = 5.10.2 +junit_jupiter_version = 5.11.2 # @@ -54,13 +59,13 @@ fabric_permissions_version = 0.3.1 # https://github.com/NucleoidMC/Server-Translations/releases # https://maven.nucleoid.xyz/xyz/nucleoid/server-translations-api/ -server_translations_version = 2.3.1+1.21-pre2 +server_translations_version = 2.4.0+1.21.2-rc1 # # Build settings # -architectury_version = 12.1.2 +architectury_version = 13.0.8 org.gradle.daemon = true org.gradle.parallel = true org.gradle.jvmargs = -Xmx4G diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e6441136..a4b76b95 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 b82aa23a..9355b415 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 1aa94a42..f5feea6d 100755 --- a/gradlew +++ b/gradlew @@ -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/. @@ -84,7 +86,8 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum diff --git a/gradlew.bat b/gradlew.bat index 6689b85b..9b42019c 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,11 +59,11 @@ 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 diff --git a/neoforge/build.gradle b/neoforge/build.gradle new file mode 100644 index 00000000..e4196efd --- /dev/null +++ b/neoforge/build.gradle @@ -0,0 +1,148 @@ +plugins { + id "com.github.johnrengelman.shadow" version "8.1.1" + id "com.modrinth.minotaur" version "2.8.7" + id "com.matthewprenger.cursegradle" version "1.4.0" +} + +architectury { + platformSetupLoomIde() + neoForge() +} + +shadowJar { + //https://stackoverflow.com/questions/73286776/grpc-unsupportedaddresstypeexception-but-only-when-packaged-with-shadowjar + // This does in fact make service discovery work when packaged; still doesn't work in the IDE. see SshHacks. + mergeServiceFiles() +} + +configurations { + common + shadowCommon + compileClasspath.extendsFrom common + runtimeClasspath.extendsFrom common + developmentNeoForge.extendsFrom common +} + +archivesBaseName = "${project.archives_base_name}" +version = "${project.mod_version}-neoforge" +group = project.maven_group + +dependencies { + neoForge("net.neoforged:neoforge:${project.neo_version}") { transitive false } + + // note to self: implementation, NOT include. include does implicit jarjar + + common(project(path: ":common", configuration: "namedElements")) { transitive false } + shadowCommon(project(path: ":common", configuration: "transformProductionNeoForge")) { transitive = false } + + // FIXME? I still don't understand if I need to declare all of these things as forgeRuntimeLibrary. It sort + // of seems like I do. + + forgeRuntimeLibrary implementation("org.eclipse.jgit:org.eclipse.jgit:${project.jgit_version}") { transitive = false } + shadowCommon("org.eclipse.jgit:org.eclipse.jgit:${project.jgit_version}") { transitive = false } + + forgeRuntimeLibrary runtimeOnly("com.googlecode.javaewah:JavaEWAH:${project.JavaEWAH_version}") { transitive = false } + shadowCommon("com.googlecode.javaewah:JavaEWAH:${project.JavaEWAH_version}") { transitive = false } + + // https://mvnrepository.com/artifact/org.eclipse.jgit/org.eclipse.jgit.ssh.apache + forgeRuntimeLibrary runtimeOnly("org.eclipse.jgit:org.eclipse.jgit.ssh.apache:${project.jgit_version}") { transitive = false } + shadowCommon("org.eclipse.jgit:org.eclipse.jgit.ssh.apache:${project.jgit_version}") { transitive = false } + + // https://mvnrepository.com/artifact/org.apache.sshd/sshd-core + forgeRuntimeLibrary runtimeOnly("org.apache.sshd:sshd-core:${project.apache_sshd_version}") { transitive = false } + shadowCommon("org.apache.sshd:sshd-core:${project.apache_sshd_version}") { transitive = false } + + // https://mvnrepository.com/artifact/org.apache.sshd/sshd-common + forgeRuntimeLibrary runtimeOnly("org.apache.sshd:sshd-common:${project.apache_sshd_version}") { transitive = false } + shadowCommon("org.apache.sshd:sshd-common:${project.apache_sshd_version}") { transitive = false } + + // this enables ed25519 support in apache_sshd + // https://github.com/apache/mina-sshd/blob/dfa109b7b535d64e8ee395ddd0419e7696fb24ee/docs/dependencies.md + forgeRuntimeLibrary runtimeOnly("net.i2p.crypto:eddsa:${project.eddsa_version}") { transitive = false } + shadowCommon("net.i2p.crypto:eddsa:${project.eddsa_version}") { transitive = false } +} + +processResources { + inputs.property "version", project.version + + filesMatching("META-INF/mods.toml") { + expand "version": project.version + } +} + +shadowJar { + configurations = [project.configurations.shadowCommon] + exclude('META-INF/maven/**') + + // https://stackoverflow.com/questions/36659980/java-jar-classnotfoundexception-even-though-dependent-library-exists + // Forge has full control over loading the classes of a mod and it specifically checks the package information + // of every class it loads against a set of restricted package paths to protect its own dependencies from + // accidentally being overwritten by loading a different version of a similar dependency. In this case, Forge + // uses a few Apache libs, so it prevents the loading of classes from the org.apache package namespace. + + relocate 'org/eclipse', 'net/pcal/fastback/shaded/org/eclipse' + relocate 'com/jcraft', 'net/pcal/fastback/shaded/com/jcraft' + archiveClassifier = 'dev-shadow' +} + +remapJar { + inputFile.set shadowJar.archiveFile + dependsOn shadowJar + archiveClassifier = null +} + +jar { + + archiveClassifier = 'dev' +} + +sourcesJar { + def commonSources = project(":common").sourcesJar + dependsOn commonSources + from commonSources.archiveFile.map { zipTree(it) } +} + +processResources { + inputs.property "version", project.version + filesMatching("META-INF/neoforge.mods.toml") { + expand "version": project.version + } +} + + +// https://github.com/modrinth/minotaur +modrinth { + token = System.getenv("MODRINTH_TOKEN") ?: 'MODRINTH_TOKEN_NOT_SET' + projectId = "fastback" + versionNumber = "${project.version}" + versionType = "alpha" + uploadFile = remapJar + changelog = "
https://github.com/pcal43/fastback/releases/tag/${project.mod_version}
" + gameVersions = ["${project.minecraft_version}"] + loaders = ["neoforge"] + dependencies {} +} + + +// https://github.com/matthewprenger/CurseGradle +curseforge { + apiKey = System.getenv("CURSEFORGE_TOKEN") ?: 'CURSEFORGE_TOKEN_NOT_SET' + + project { + id = "667417" + releaseType = "alpha" + changelog = "https://github.com/pcal43/fastback/releases/tag/${project.mod_version}" + changelogType = "markdown" + mod_version = "${project.version}" + addGameVersion((String) project.minecraft_version) + addGameVersion "NeoForge" + mainArtifact(remapJar) + afterEvaluate { + uploadTask.dependsOn("remapJar") + } + } + + options { + forgeGradleIntegration = false + } +} diff --git a/neoforge/gradle.properties b/neoforge/gradle.properties new file mode 100644 index 00000000..7da18ea6 --- /dev/null +++ b/neoforge/gradle.properties @@ -0,0 +1 @@ +loom.platform=neoforge diff --git a/neoforge/src/main/java/net/pcal/fastback/mod/neoforge/ForgeClientProvider.java b/neoforge/src/main/java/net/pcal/fastback/mod/neoforge/ForgeClientProvider.java new file mode 100644 index 00000000..3057e4e0 --- /dev/null +++ b/neoforge/src/main/java/net/pcal/fastback/mod/neoforge/ForgeClientProvider.java @@ -0,0 +1,113 @@ +package net.pcal.fastback.mod.neoforge; + +import net.neoforged.fml.ModContainer; +import net.neoforged.neoforge.client.event.CustomizeGuiOverlayEvent; +import net.neoforged.neoforge.client.event.ScreenEvent; +import net.neoforged.neoforge.common.NeoForge; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent; +import net.neoforged.fml.ModLoadingContext; +import net.pcal.fastback.logging.UserMessage; + +import static java.util.Objects.requireNonNull; +import static net.pcal.fastback.logging.SystemLogger.syslog; +import static net.pcal.fastback.mod.MinecraftProvider.messageToText; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.chat.Component; + +/** + * Handles client-specific tasks. + * + * @author pcal + * @since 0.16.0 + */ +final class ForgeClientProvider extends ForgeCommonProvider { + + // ====================================================================== + // Constants + + private static final long TEXT_TIMEOUT = 10 * 1000; + + // ====================================================================== + // Fields + + //private MinecraftClient client = null; + private Component hudText; + private long hudTextTime; + private final Minecraft client; + + public ForgeClientProvider(ModContainer container) { + super(container); + container.getEventBus().addListener(this::onClientStartupEvent); + NeoForge.EVENT_BUS.addListener(this::onGuiOverlayEvent); + NeoForge.EVENT_BUS.addListener(this::onScreenRenderEvent); + this.client = requireNonNull(Minecraft.getInstance(), "MinecraftClient.getInstance() returned null"); + } + + // ====================================================================== + // Forge Event handlers + + private void onClientStartupEvent(FMLClientSetupEvent event) { + this.onInitialize(); + } + + private void onGuiOverlayEvent(CustomizeGuiOverlayEvent.Chat event) { + this.renderOverlayText(event.getGuiGraphics()); + } + + private void onScreenRenderEvent(ScreenEvent.Render.Post event) { + this.renderOverlayText(event.getGuiGraphics()); + } + + // ====================================================================== + // MinecraftProvider implementation + + @Override + public boolean isClient() { + return true; + } + + @Override + public void setHudText(UserMessage userMessage) { + if (userMessage == null) { + clearHudText(); + } else { + this.hudText = messageToText(userMessage); // so the hud renderer can find it + this.hudTextTime = System.currentTimeMillis(); + } + } + + @Override + public void clearHudText() { + this.hudText = null; + // TODO someday it might be nice to bring back the fading text effect. But getting to it properly + // clean up 100% of the time is more than I want to deal with right now. + } + + @Override + public void setMessageScreenText(UserMessage userMessage) { + final Component text = messageToText(userMessage); + this.hudText = text; + final Screen screen = client.screen; + // TODO; fix this + //if (screen != null) screen.title = text; + } + + @Override + void renderOverlayText(final GuiGraphics drawContext) { + if (this.hudText == null) return; + // if (!this.client.options.getShowAutosaveIndicator().getValue()) return; FIXME + if (System.currentTimeMillis() - this.hudTextTime > TEXT_TIMEOUT) { + // Don't leave it sitting up there forever if we fail to call clearHudText() + this.hudText = null; + syslog().debug("hud text timed out. somebody forgot to clean up"); + return; + } + if (client != null) { + drawContext.drawString(this.client.font, this.hudText, 2, 2, 1); + } + } +} \ No newline at end of file diff --git a/neoforge/src/main/java/net/pcal/fastback/mod/neoforge/ForgeCommonProvider.java b/neoforge/src/main/java/net/pcal/fastback/mod/neoforge/ForgeCommonProvider.java new file mode 100644 index 00000000..24c18e16 --- /dev/null +++ b/neoforge/src/main/java/net/pcal/fastback/mod/neoforge/ForgeCommonProvider.java @@ -0,0 +1,217 @@ +package net.pcal.fastback.mod.neoforge; + +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.storage.LevelResource; +import net.neoforged.fml.ModContainer; +import net.neoforged.fml.loading.FMLPaths; +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.ServerStoppingEvent; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.fml.event.lifecycle.FMLDedicatedServerSetupEvent; +import net.neoforged.fml.ModLoadingContext; +import net.pcal.fastback.logging.SystemLogger; +import net.pcal.fastback.logging.UserMessage; +import net.pcal.fastback.mod.LifecycleListener; +import net.pcal.fastback.mod.MinecraftProvider; +import org.slf4j.LoggerFactory; + +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import static java.util.Objects.requireNonNull; +import static net.pcal.fastback.commands.Commands.createBackupCommand; +import static net.pcal.fastback.logging.SystemLogger.syslog; +import static net.pcal.fastback.mod.MinecraftProvider.messageToText; + +/** + * @author pcal + * @since 0.16.0 + */ +class ForgeCommonProvider implements MinecraftProvider, MixinGateway { + + static final String MOD_ID = "fastback"; + private MinecraftServer logicalServer; + private ModContainer container; + private LifecycleListener lifecycleListener = null; + private Runnable autoSaveListener; + private boolean isWorldSaveEnabled = true; + + ForgeCommonProvider(ModContainer container) { + this.container = container; + + container.getEventBus().addListener(this::onDedicatedServerStartupEvent); + NeoForge.EVENT_BUS.addListener(this::onServerStartupEvent); + NeoForge.EVENT_BUS.addListener(this::onServerStoppingEvent); + NeoForge.EVENT_BUS.addListener(this::onRegisterCommandEvent); + } + + + // ====================================================================== + // Forge Event handlers + + private void onDedicatedServerStartupEvent(FMLDedicatedServerSetupEvent event) { + this.onInitialize(); + } + + private void onServerStartupEvent(ServerStartedEvent event) { + this.logicalServer = event.getServer(); + requireNonNull(this.lifecycleListener).onWorldStart(); + } + + private void onServerStoppingEvent(ServerStoppingEvent event) { + requireNonNull(this.lifecycleListener).onWorldStop(); + this.logicalServer = null; + } + + private void onRegisterCommandEvent(RegisterCommandsEvent event) { + final CommandDispatcher