diff --git a/fabric/1.21.7/README.md b/fabric/1.21.7/README.md new file mode 100644 index 00000000..f224a06b --- /dev/null +++ b/fabric/1.21.7/README.md @@ -0,0 +1,4 @@ +# Fabric - 1.21.7 + +This is the branch specifically for fabric 1.21.7. +Any differences will be listed below. For full documentation, see the `core` branch. diff --git a/fabric/1.21.7/build.gradle b/fabric/1.21.7/build.gradle new file mode 100644 index 00000000..815c2e67 --- /dev/null +++ b/fabric/1.21.7/build.gradle @@ -0,0 +1,102 @@ +plugins { + id 'fabric-loom' version '1.11-SNAPSHOT' + id 'maven-publish' +} + +apply from: '../../global.properties' + +group = project.maven_group +archivesBaseName = 'AdvancedBackups-' + modloaderName + "-" + minecraftVersion + +loom { + accessWidenerPath = file("src/main/resources/advancedbackups.accesswidener") +} + + +repositories { + // Add repositories to retrieve artifacts from in here. + // You should only use this when depending on other mods because + // Loom adds the essential maven repositories to download Minecraft and libraries from automatically. + // See https://docs.gradle.org/current/userguide/declaring_repositories.html + // for more information about repositories. +} + +configurations { + // configuration that holds jars to include in the jar + extraLibs +} + +dependencies { + // To change the versions see the gradle.properties file + minecraft "com.mojang:minecraft:${project.minecraft_version}" + mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" + modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" + + // Fabric API. This is technically optional, but you probably want it anyway. + modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" + + // Uncomment the following line to enable the deprecated Fabric API modules. + // These are included in the Fabric API production distribution and allow you to update your mod to the latest modules at a later more convenient time. + + // modImplementation "net.fabricmc.fabric-api:fabric-api-deprecated:${project.fabric_version}" + + implementation files(abCoreLibPath) + extraLibs files(abCoreLibPath) +} + +processResources { + inputs.property "version", project.version + + filesMatching("fabric.mod.json") { + expand "version": project.version + } +} + +tasks.withType(JavaCompile).configureEach { + it.options.release = 21 +} + +java { + // Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task + // if it is present. + // If you remove this line, sources will not be generated. + withSourcesJar() + + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 +} + +jar { + manifest { + attributes([ + "Main-Class" : "computer.heather.advancedbackups.cli.AdvancedBackupsCLI", + "Specification-Title" : "advancedbackups", + "Specification-Vendor" : "Heather White", + "Specification-Version" : "1", // We are version 1 of ourselves + "Implementation-Title" : project.name, + "Implementation-Version" : project.jar.archiveVersion, + "Implementation-Vendor" : "Heather White", + "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ") + ]) + } + from { + configurations.extraLibs.collect { it.isDirectory() ? it : zipTree(it) } + } +} + +// configure the maven publication +publishing { + publications { + mavenJava(MavenPublication) { + from components.java + } + } + + // See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing. + repositories { + // Add repositories to publish to here. + // Notice: This block does NOT have the same function as the block in the top level. + // The repositories here will be used for publishing your artifact, not for + // retrieving dependencies. + } +} diff --git a/fabric/1.21.7/gradle.properties b/fabric/1.21.7/gradle.properties new file mode 100644 index 00000000..010d9d34 --- /dev/null +++ b/fabric/1.21.7/gradle.properties @@ -0,0 +1,22 @@ +# Done to increase the memory available to gradle. +org.gradle.jvmargs=-Xmx1G +org.gradle.parallel=true + +# Fabric Properties +# check these on https://fabricmc.net/develop +minecraft_version=1.21.7 +yarn_mappings=1.21.7+build.6 +loader_version=0.16.14 +loom_version=1.11-SNAPSHOT + +# Mod Properties +version=2.0 +mod_version=2.0 +maven_group=computer.heather.advancedbackups +archives_base_name=advancedbackups +modloaderName =fabric + +minecraftVersion =1.21.7 + +# Dependencies +fabric_version=0.128.2+1.21.7 diff --git a/fabric/1.21.7/gradle/wrapper/gradle-wrapper.jar b/fabric/1.21.7/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000..a4b76b95 Binary files /dev/null and b/fabric/1.21.7/gradle/wrapper/gradle-wrapper.jar differ diff --git a/fabric/1.21.7/gradle/wrapper/gradle-wrapper.properties b/fabric/1.21.7/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..ca025c83 --- /dev/null +++ b/fabric/1.21.7/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/fabric/1.21.7/gradlew b/fabric/1.21.7/gradlew new file mode 100644 index 00000000..f5feea6d --- /dev/null +++ b/fabric/1.21.7/gradlew @@ -0,0 +1,252 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 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. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# 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/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# 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 -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 + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + 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. +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=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# 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" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +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, 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 \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/fabric/1.21.7/gradlew.bat b/fabric/1.21.7/gradlew.bat new file mode 100644 index 00000000..9d21a218 --- /dev/null +++ b/fabric/1.21.7/gradlew.bat @@ -0,0 +1,94 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@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 ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +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 + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +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 %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/fabric/1.21.7/settings.gradle b/fabric/1.21.7/settings.gradle new file mode 100644 index 00000000..bb8fa375 --- /dev/null +++ b/fabric/1.21.7/settings.gradle @@ -0,0 +1,12 @@ +pluginManagement { + repositories { + maven { + name = 'Fabric' + url = 'https://maven.fabricmc.net/' + } + mavenCentral() + gradlePluginPortal() + } +} + +rootProject.name = 'fabric-1.21.7' diff --git a/fabric/1.21.7/src/main/java/computer/heather/advancedbackups/AdvancedBackups.java b/fabric/1.21.7/src/main/java/computer/heather/advancedbackups/AdvancedBackups.java new file mode 100644 index 00000000..5710d4e8 --- /dev/null +++ b/fabric/1.21.7/src/main/java/computer/heather/advancedbackups/AdvancedBackups.java @@ -0,0 +1,130 @@ +package computer.heather.advancedbackups; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import computer.heather.advancedbackups.client.ClientContactor; +import computer.heather.advancedbackups.core.ABCore; +import computer.heather.advancedbackups.core.backups.BackupTimer; +import computer.heather.advancedbackups.core.backups.BackupWrapper; +import computer.heather.advancedbackups.core.config.ConfigManager; +import computer.heather.advancedbackups.network.PacketBackupStatus; +import computer.heather.advancedbackups.network.PacketToastSubscribe; +import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; +import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; +import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; +import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; +import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; +import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; +import net.fabricmc.loader.impl.FabricLoaderImpl; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.WorldSavePath; + +public class AdvancedBackups implements ModInitializer { + // This logger is used to write text to the console and the log file. + // It is considered best practice to use your mod id as the logger's name. + // That way, it's clear which mod wrote info, warnings, and errors. + + public static final Logger LOGGER = LoggerFactory.getLogger("advanced-backups"); + + public static final Consumer infoLogger = LOGGER::info; + public static final Consumer warningLogger = LOGGER::warn; + public static final Consumer errorLogger = LOGGER::error; + + public static final ArrayList players = new ArrayList<>(); + + public static MinecraftServer server; + + @Override + public void onInitialize() { + + ServerLifecycleEvents.SERVER_STARTING.register((server) -> { + AdvancedBackups.server = server; + ABCore.worldName = server.getSaveProperties().getLevelName(); + ABCore.worldDir = server.getSavePath(WorldSavePath.ROOT); + + ABCore.disableSaving = AdvancedBackups::disableSaving; + ABCore.enableSaving = AdvancedBackups::enableSaving; + ABCore.saveOnce = AdvancedBackups::saveOnce; + + ABCore.infoLogger = infoLogger; + ABCore.warningLogger = warningLogger; + ABCore.errorLogger = errorLogger; + + ABCore.resetActivity = AdvancedBackups::resetActivity; + + ABCore.clientContactor = new ClientContactor(); + ABCore.modJar = new File(FabricLoaderImpl.INSTANCE.getModContainer("advancedbackups").get().getOrigin().getPaths().get(0).toAbsolutePath().toString()); + + + ConfigManager.loadOrCreateConfig(); + LOGGER.info("Config loaded!!"); + }); + + ServerLifecycleEvents.SERVER_STARTED.register((server) -> { + BackupWrapper.checkStartupBackups(); + }); + ServerLifecycleEvents.SERVER_STOPPING.register((server) -> { + BackupWrapper.checkShutdownBackups(); + }); + + ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> { + ABCore.setActivity(true); + }); + + CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> { + AdvancedBackupsCommand.register(dispatcher); + }); + + + ServerTickEvents.END_SERVER_TICK.register((server) -> { + BackupTimer.check(); + }); + + PayloadTypeRegistry.playS2C().register(PacketBackupStatus.ID, PacketBackupStatus.CODEC); + PayloadTypeRegistry.playC2S().register(PacketToastSubscribe.ID, PacketToastSubscribe.CODEC); + + ServerPlayNetworking.registerGlobalReceiver(PacketToastSubscribe.ID, PacketToastSubscribe::handle); + + + } + + + + + public static void disableSaving() { + MinecraftServer server = AdvancedBackups.server; + for (ServerWorld level : server.getWorlds()) { + if (level != null && !level.savingDisabled) { + level.savingDisabled = true; + } + } + } + + public static void enableSaving() { + MinecraftServer server = AdvancedBackups.server; + for (ServerWorld level : server.getWorlds()) { + if (level != null && level.savingDisabled) { + level.savingDisabled = false; + } + } + } + + public static void saveOnce(boolean flush) { + MinecraftServer server = AdvancedBackups.server; + server.saveAll(true, flush, true); + } + + public static void resetActivity() { + List players = server.getPlayerManager().getPlayerList(); + ABCore.setActivity(!players.isEmpty()); + } +} diff --git a/fabric/1.21.7/src/main/java/computer/heather/advancedbackups/AdvancedBackupsCommand.java b/fabric/1.21.7/src/main/java/computer/heather/advancedbackups/AdvancedBackupsCommand.java new file mode 100644 index 00000000..31f75a23 --- /dev/null +++ b/fabric/1.21.7/src/main/java/computer/heather/advancedbackups/AdvancedBackupsCommand.java @@ -0,0 +1,68 @@ +package computer.heather.advancedbackups; + +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.ParseResults; +import com.mojang.brigadier.arguments.StringArgumentType; + +import computer.heather.advancedbackups.core.CoreCommandSystem; +import net.minecraft.server.command.CommandManager; +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.text.Text; + +public class AdvancedBackupsCommand { + public static void register(CommandDispatcher stack) { + stack.register(CommandManager.literal("backup").requires((runner) -> { + return !AdvancedBackups.server.isDedicated() || runner.hasPermissionLevel(2); + }).then(CommandManager.literal("start").executes((runner) -> { + CoreCommandSystem.startBackup((response) -> { + runner.getSource().sendFeedback(() -> Text.of(response), true); + }); + return 1; + })) + + .then(CommandManager.literal("reload-config").executes((runner) -> { + CoreCommandSystem.reloadConfig((response) -> { + runner.getSource().sendFeedback(() -> Text.of(response), true); + }); + return 1; + })) + + .then(CommandManager.literal("reset-chain").executes((runner) -> { + CoreCommandSystem.resetChainLength((response) -> { + runner.getSource().sendFeedback(() -> Text.of(response), true); + }); + return 1; + })) + + .then(CommandManager.literal("snapshot").executes((runner) -> { + CoreCommandSystem.snapshot((response) -> { + runner.getSource().sendFeedback(() -> Text.of(response), true); + }, "snapshot"); + return 1; + }) + .then(CommandManager.argument("name", StringArgumentType.greedyString()).executes((runner) -> { + ParseResults parseResults = stack.parse(StringArgumentType.getString(runner, "name"), runner.getSource()); + String snapshotName = parseResults.getReader().getString(); + CoreCommandSystem.snapshot((response) -> { + runner.getSource().sendFeedback(() -> Text.of(response), true); + }, snapshotName); + return 1; + }))) + + .then(CommandManager.literal("cancel").executes((runner) -> { + CoreCommandSystem.cancelBackup((response) -> { + runner.getSource().sendFeedback(() -> Text.of(response), true); + }); + return 1; + })) + + .then(CommandManager.literal("reload-client-config").executes((runner) -> { + runner.getSource().sendFeedback(() -> Text.of("This command can only be ran on the client!"), true); + return 1; + })) + + ); + } + + +} diff --git a/fabric/1.21.7/src/main/java/computer/heather/advancedbackups/client/AdvancedBackupsClientCommand.java b/fabric/1.21.7/src/main/java/computer/heather/advancedbackups/client/AdvancedBackupsClientCommand.java new file mode 100644 index 00000000..67478c3a --- /dev/null +++ b/fabric/1.21.7/src/main/java/computer/heather/advancedbackups/client/AdvancedBackupsClientCommand.java @@ -0,0 +1,62 @@ +package computer.heather.advancedbackups.client; + + +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.ParseResults; +import com.mojang.brigadier.arguments.StringArgumentType; + +import computer.heather.advancedbackups.core.CoreCommandSystem; +import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager; +import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; +import net.minecraft.client.MinecraftClient; +import net.minecraft.network.packet.c2s.play.CommandExecutionC2SPacket; +import net.minecraft.text.Text; + +public class AdvancedBackupsClientCommand { + public static void register(CommandDispatcher dispatcher) { + dispatcher.register(ClientCommandManager.literal("backup").requires((runner) -> { + return true; + }).then(ClientCommandManager.literal("start").executes((runner) -> { + MinecraftClient.getInstance().player.networkHandler.sendPacket(new CommandExecutionC2SPacket("backup start")); + return 1; + })) + + .then(ClientCommandManager.literal("reload-config").executes((runner) -> { + MinecraftClient.getInstance().player.networkHandler.sendPacket(new CommandExecutionC2SPacket("backup reload-config")); + return 1; + })) + + .then(ClientCommandManager.literal("reset-chain").executes((runner) -> { + MinecraftClient.getInstance().player.networkHandler.sendPacket(new CommandExecutionC2SPacket("backup reset-chain")); + return 1; + })) + + .then(ClientCommandManager.literal("snapshot").executes((runner) -> { + MinecraftClient.getInstance().player.networkHandler.sendPacket(new CommandExecutionC2SPacket("backup snapshot")); + return 1; + }) + + .then(ClientCommandManager.argument("name", StringArgumentType.greedyString()).executes((runner) -> { + ParseResults parseResults = dispatcher.parse(StringArgumentType.getString(runner, "name"), runner.getSource()); + String snapshotName = parseResults.getReader().getString(); + MinecraftClient.getInstance().player.networkHandler.sendPacket(new CommandExecutionC2SPacket("backup snapshot " + snapshotName)); + return 1; + }))) + + .then(ClientCommandManager.literal("cancel").executes((runner) -> { + MinecraftClient.getInstance().player.networkHandler.sendPacket(new CommandExecutionC2SPacket("backup cancel")); + return 1; + })) + + .then(ClientCommandManager.literal("reload-client-config").executes((runner) -> { + CoreCommandSystem.reloadClientConfig((response) -> { + runner.getSource().sendFeedback(Text.of(response)); + }); + return 1; + })) + + ); + } + + +} \ No newline at end of file diff --git a/fabric/1.21.7/src/main/java/computer/heather/advancedbackups/client/BackupToast.java b/fabric/1.21.7/src/main/java/computer/heather/advancedbackups/client/BackupToast.java new file mode 100644 index 00000000..2fa026dc --- /dev/null +++ b/fabric/1.21.7/src/main/java/computer/heather/advancedbackups/client/BackupToast.java @@ -0,0 +1,144 @@ +package computer.heather.advancedbackups.client; + + +import computer.heather.advancedbackups.core.config.ClientConfigManager; +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gl.RenderPipelines; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.render.RenderLayer; +import net.minecraft.client.resource.language.I18n; +import net.minecraft.client.toast.Toast; +import net.minecraft.client.toast.ToastManager; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.util.Identifier; + +public class BackupToast implements Toast { + + public static boolean starting; + public static boolean started; + public static boolean failed; + public static boolean finished; + public static boolean cancelled; + + public static int progress; + public static int max; + + public static boolean exists = false; + + private static long time; + private static boolean timeSet = false; + + public static final ItemStack stack = new ItemStack(Items.PAPER); + private static final Identifier TEXTURE = Identifier.of("toast/advancement"); + + public static String title = "You shouldn't see this!"; + public static int textColour = 0; + + private Visibility visibility = Visibility.SHOW; + + @Override + public void draw(DrawContext context, TextRenderer renderer, long startTime) { + context.drawGuiTexture(RenderPipelines.GUI_TEXTURED, TEXTURE, 0, ClientConfigManager.darkMode.get() ? 0 : this.getHeight(), this.getWidth(), this.getHeight()); + + context.drawItemWithoutEntity(stack, 8, 8);; + + float percent = finished ? 100 : (float) progress / (float) max; + + context.fill(4, 28, 156, 29, ColourHelper.colour + (255, (int) ClientConfigManager.progressBackgroundRed.get(), (int) ClientConfigManager.progressBackgroundGreen.get(), (int) ClientConfigManager.progressBackgroundBlue.get())); + + float f = Math.min(156, ( + 156 * percent + )); + + if (!exists) { + if (title.equals(I18n.translate("advancedbackups.backup_finished"))){ + textColour = ColourHelper.colour(255, (int) ClientConfigManager.progressTextRed.get(), (int) ClientConfigManager.progressTextGreen.get(), (int) ClientConfigManager.progressTextBlue.get()); + context.drawText(renderer, I18n.translate(title), 25, 11, textColour, false); + context.fill(4, 28, 156, 29, ColourHelper.colour + (255, (int) ClientConfigManager.progressBarRed.get(), (int) ClientConfigManager.progressBarGreen.get(), (int) ClientConfigManager.progressBarBlue.get())); + } + else { + textColour = ColourHelper.colour(255, (int) ClientConfigManager.errorTextRed.get(), (int) ClientConfigManager.errorTextGreen.get(), (int) ClientConfigManager.errorTextBlue.get()); + context.drawText(renderer, I18n.translate(title), 25, 11, textColour, false); + } + visibility = Visibility.HIDE; + return; + } + + title = "You shouldn't see this!"; + + + if (starting) { + textColour = ColourHelper.colour(255, (int) ClientConfigManager.progressTextRed.get(), (int) ClientConfigManager.progressTextGreen.get(), (int) ClientConfigManager.progressTextBlue.get()); + title = I18n.translate("advancedbackups.backup_starting"); + } + else if (started) { + textColour = ColourHelper.colour(255, (int) ClientConfigManager.progressTextRed.get(), (int) ClientConfigManager.progressTextGreen.get(), (int) ClientConfigManager.progressTextBlue.get()); + title = I18n.translate("advancedbackups.progress", round(percent * 100)); + } + else if (failed) { + textColour = ColourHelper.colour(255, (int) ClientConfigManager.errorTextRed.get(), (int) ClientConfigManager.errorTextGreen.get(), (int) ClientConfigManager.errorTextBlue.get()); + title = I18n.translate("advancedbackups.backup_failed"); + if (!timeSet) { + time = System.currentTimeMillis(); + timeSet = true; + } + } + else if (finished) { + textColour = ColourHelper.colour(255, (int) ClientConfigManager.progressTextRed.get(), (int) ClientConfigManager.progressTextGreen.get(), (int) ClientConfigManager.progressTextBlue.get()); + title = I18n.translate("advancedbackups.backup_finished"); + if (!timeSet) { + time = System.currentTimeMillis(); + timeSet = true; + } + } + else if (cancelled) { + textColour = ColourHelper.colour(255, (int) ClientConfigManager.errorTextRed.get(), (int) ClientConfigManager.errorTextGreen.get(), (int) ClientConfigManager.errorTextBlue.get()); + title = I18n.translate("advancedbackups.backup_cancelled"); + if (!timeSet) { + time = System.currentTimeMillis(); + timeSet = true; + } + } + + context.drawText(renderer, title, 25, 11, textColour, false); + + if (timeSet && System.currentTimeMillis() >= time + 5000) { + starting = false; + started = false; + failed = false; + finished = false; + progress = 0; + max = 0; + timeSet = false; + exists = false; + visibility = Visibility.HIDE; + return; + } + + context.fill(4, 28, Math.max(4, (int) f), 29, ColourHelper.colour + (255, (int) ClientConfigManager.progressBarRed.get(), (int) ClientConfigManager.progressBarGreen.get(), (int) ClientConfigManager.progressBarBlue.get())); + + visibility = Visibility.SHOW; + } + + + private static String round (float value) { + return String.format("%.1f", value); + } + + + @Override + public Visibility getVisibility() { + return visibility; + } + + + @Override + public void update(ToastManager manager, long time) { + // does this need to do anything? + } + +} diff --git a/fabric/1.21.7/src/main/java/computer/heather/advancedbackups/client/ClientContactor.java b/fabric/1.21.7/src/main/java/computer/heather/advancedbackups/client/ClientContactor.java new file mode 100644 index 00000000..0592d66d --- /dev/null +++ b/fabric/1.21.7/src/main/java/computer/heather/advancedbackups/client/ClientContactor.java @@ -0,0 +1,78 @@ +package computer.heather.advancedbackups.client; + +import java.util.List; + +import computer.heather.advancedbackups.AdvancedBackups; +import computer.heather.advancedbackups.interfaces.IClientContactor; +import computer.heather.advancedbackups.network.NetworkHandler; +import computer.heather.advancedbackups.network.PacketBackupStatus; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.ServerPlayerEntity; + +public class ClientContactor implements IClientContactor { + + @Override + public void backupComplete(boolean all) { + MinecraftServer server = AdvancedBackups.server; + List players = server.getPlayerManager().getPlayerList(); + PacketBackupStatus packet = new PacketBackupStatus(false, false, false, true, false, 0, 0); + for (ServerPlayerEntity player : players) { + if (!AdvancedBackups.players.contains(player.getUuidAsString())) continue; + if (!server.isDedicated() || player.hasPermissionLevel(3) || all) { + NetworkHandler.sendToClient(player, packet); + } + } + } + + @Override + public void backupFailed(boolean all) { + MinecraftServer server = AdvancedBackups.server; + List players = server.getPlayerManager().getPlayerList(); + PacketBackupStatus packet = new PacketBackupStatus(false, false, true, false, false, 0, 0); + for (ServerPlayerEntity player : players) { + if (!AdvancedBackups.players.contains(player.getUuidAsString())) continue; + if (!server.isDedicated() || player.hasPermissionLevel(3) || all) { + NetworkHandler.sendToClient(player, packet); + } + } + } + + @Override + public void backupProgress(int progress, int max, boolean all) { + MinecraftServer server = AdvancedBackups.server; + List players = server.getPlayerManager().getPlayerList(); + PacketBackupStatus packet = new PacketBackupStatus(false, true, false, false, false, progress, max); + for (ServerPlayerEntity player : players) { + if (!AdvancedBackups.players.contains(player.getUuidAsString())) continue; + if (!server.isDedicated() || player.hasPermissionLevel(3) || all) { + NetworkHandler.sendToClient(player, packet); + } + } + } + + @Override + public void backupStarting(boolean all) { + MinecraftServer server = AdvancedBackups.server; + List players = server.getPlayerManager().getPlayerList(); + PacketBackupStatus packet = new PacketBackupStatus(true, false, false, false, false, 0, 0); + for (ServerPlayerEntity player : players) { + if (!AdvancedBackups.players.contains(player.getUuidAsString())) continue; + if (!server.isDedicated() || player.hasPermissionLevel(3) || all) { + NetworkHandler.sendToClient(player, packet); + } + } + } + + @Override + public void backupCancelled(boolean all) { + MinecraftServer server = AdvancedBackups.server; + List players = server.getPlayerManager().getPlayerList(); + PacketBackupStatus packet = new PacketBackupStatus(false, false, false, false, true, 0, 0); + for (ServerPlayerEntity player : players) { + if (!AdvancedBackups.players.contains(player.getUuidAsString())) continue; + if (!server.isDedicated() || player.hasPermissionLevel(3) || all) { + NetworkHandler.sendToClient(player, packet); + } + } + } +} diff --git a/fabric/1.21.7/src/main/java/computer/heather/advancedbackups/client/ClientWrapper.java b/fabric/1.21.7/src/main/java/computer/heather/advancedbackups/client/ClientWrapper.java new file mode 100644 index 00000000..b137a58a --- /dev/null +++ b/fabric/1.21.7/src/main/java/computer/heather/advancedbackups/client/ClientWrapper.java @@ -0,0 +1,76 @@ +package computer.heather.advancedbackups.client; + +import computer.heather.advancedbackups.AdvancedBackups; +import computer.heather.advancedbackups.core.ABCore; +import computer.heather.advancedbackups.core.config.ClientConfigManager; +import computer.heather.advancedbackups.network.PacketBackupStatus; +import computer.heather.advancedbackups.network.PacketToastSubscribe; +import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; +import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents; +import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; +import net.minecraft.client.MinecraftClient; + +public class ClientWrapper implements ClientModInitializer { + + @Override + public void onInitializeClient() { + + ABCore.infoLogger = AdvancedBackups.infoLogger; + ABCore.warningLogger = AdvancedBackups.warningLogger; + ABCore.errorLogger = AdvancedBackups.errorLogger; + + ClientLifecycleEvents.CLIENT_STARTED.register((client) -> { + ClientConfigManager.loadOrCreateConfig(); + }); + + ClientPlayConnectionEvents.JOIN.register((handler, sender, client) -> { + PacketToastSubscribe packet = new PacketToastSubscribe(ClientConfigManager.showProgress.get()); + if (ClientPlayNetworking.canSend(packet.getId())) { + //Make sure a server can receive the packet before trying to send! + ClientPlayNetworking.send(packet); + } + else { + ABCore.warningLogger.accept("Refusing to send packet " + packet + " as the server cannot accept it!"); + } + }); + + ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> { + AdvancedBackupsClientCommand.register(dispatcher); + + }); + + + ClientPlayNetworking.registerGlobalReceiver(PacketBackupStatus.ID, ClientWrapper::handle); + + + } + + + + public static void handle(PacketBackupStatus message, ClientPlayNetworking.Context context) { + + + + MinecraftClient.getInstance().execute(() -> { + BackupToast.starting = message.starting(); + BackupToast.started = message.started(); + BackupToast.failed = message.failed(); + BackupToast.finished = message.finished(); + BackupToast.cancelled = message.cancelled(); + + BackupToast.progress = message.progress(); + BackupToast.max = message.max(); + + if (!BackupToast.exists) { + BackupToast.exists = true; + MinecraftClient.getInstance().getToastManager().add(new BackupToast()); + } + + }); + + + } + +} diff --git a/fabric/1.21.7/src/main/java/computer/heather/advancedbackups/client/ColourHelper.java b/fabric/1.21.7/src/main/java/computer/heather/advancedbackups/client/ColourHelper.java new file mode 100644 index 00000000..5619961d --- /dev/null +++ b/fabric/1.21.7/src/main/java/computer/heather/advancedbackups/client/ColourHelper.java @@ -0,0 +1,31 @@ +package computer.heather.advancedbackups.client; + +//A colour helper, loosely based on that of vanilla 1.16. +//What is the modern equivalent..? +public class ColourHelper { + + public static int alpha(int in) { + return in >>> 24; + } + + public static int red(int in) { + return in >> 16 & 255; + } + + public static int green(int in) { + return in >> 8 & 255; + } + + public static int blue(int in) { + return in & 255; + } + + public static int colour(int a, int r, int g, int b) { + return a << 24 | r << 16 | g << 8 | b; + } + + public static int colour(int a, long r, long g, long b) { + return colour(a, (int) r, (int) g, (int) b); + } + +} \ No newline at end of file diff --git a/fabric/1.21.7/src/main/java/computer/heather/advancedbackups/network/NetworkHandler.java b/fabric/1.21.7/src/main/java/computer/heather/advancedbackups/network/NetworkHandler.java new file mode 100644 index 00000000..bbc45301 --- /dev/null +++ b/fabric/1.21.7/src/main/java/computer/heather/advancedbackups/network/NetworkHandler.java @@ -0,0 +1,16 @@ +package computer.heather.advancedbackups.network; + +import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; +import net.minecraft.server.network.ServerPlayerEntity; + +public class NetworkHandler { + + public static void sendToClient(ServerPlayerEntity player, PacketBackupStatus packet) { + + ServerPlayNetworking.send(player, packet); + + } + + + +} diff --git a/fabric/1.21.7/src/main/java/computer/heather/advancedbackups/network/PacketBackupStatus.java b/fabric/1.21.7/src/main/java/computer/heather/advancedbackups/network/PacketBackupStatus.java new file mode 100644 index 00000000..fb0ccf93 --- /dev/null +++ b/fabric/1.21.7/src/main/java/computer/heather/advancedbackups/network/PacketBackupStatus.java @@ -0,0 +1,39 @@ +package computer.heather.advancedbackups.network; + +import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.codec.PacketCodec; +import net.minecraft.network.packet.CustomPayload; +import net.minecraft.util.Identifier; + +public record PacketBackupStatus(boolean starting, boolean started, boolean failed, boolean finished, boolean cancelled, int progress, int max) implements CustomPayload { + + public static final Id ID = new CustomPayload.Id(Identifier.of("advancedbackups:backup_status")); + + public static final PacketCodec CODEC = PacketCodec.of((packet, buf) -> { + buf.writeBoolean(packet.starting); + buf.writeBoolean(packet.started); + buf.writeBoolean(packet.failed); + buf.writeBoolean(packet.finished); + buf.writeBoolean(packet.cancelled); + buf.writeInt(packet.progress); + buf.writeInt(packet.max); + }, + + buf -> new PacketBackupStatus( + buf.readBoolean(), + buf.readBoolean(), + buf.readBoolean(), + buf.readBoolean(), + buf.readBoolean(), + buf.readInt(), + buf.readInt() + )); + + + @Override + public Id getId() { + return ID; + } + + +} diff --git a/fabric/1.21.7/src/main/java/computer/heather/advancedbackups/network/PacketToastSubscribe.java b/fabric/1.21.7/src/main/java/computer/heather/advancedbackups/network/PacketToastSubscribe.java new file mode 100644 index 00000000..ccde0af8 --- /dev/null +++ b/fabric/1.21.7/src/main/java/computer/heather/advancedbackups/network/PacketToastSubscribe.java @@ -0,0 +1,45 @@ +package computer.heather.advancedbackups.network; + +import computer.heather.advancedbackups.AdvancedBackups; +import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.codec.PacketCodec; +import net.minecraft.network.codec.PacketCodecs; +import net.minecraft.network.packet.CustomPayload; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.Identifier; + +public record PacketToastSubscribe(boolean enable) implements CustomPayload { + + public static final Id ID = new CustomPayload.Id(Identifier.of("advancedbackups:toast_subscribe")); + + public PacketToastSubscribe(boolean enable) { + this.enable = enable; + } + + public static final PacketCodec CODEC = PacketCodec.tuple(PacketCodecs.BOOLEAN, PacketToastSubscribe::enable, PacketToastSubscribe::new); + + + public static void handle(PacketToastSubscribe message, ServerPlayNetworking.Context context) { + + ServerPlayerEntity player = context.player(); + + if (message.enable() && !AdvancedBackups.players.contains(player.getUuidAsString())) { + AdvancedBackups.players.add(player.getUuidAsString()); + } + else if (!message.enable()) { + AdvancedBackups.players.remove(player.getUuidAsString()); + } + + } + + + + @Override + public Id getId() { + return ID; + } + + + +} diff --git a/fabric/1.21.7/src/main/resources/advancedbackups.accesswidener b/fabric/1.21.7/src/main/resources/advancedbackups.accesswidener new file mode 100644 index 00000000..7ed2cc67 --- /dev/null +++ b/fabric/1.21.7/src/main/resources/advancedbackups.accesswidener @@ -0,0 +1,4 @@ +accessWidener v2 named + +#Required for commands for now, should rework this at some point +accessible field net/minecraft/client/network/ClientPlayNetworkHandler lastSeenMessagesCollector Lnet/minecraft/network/message/LastSeenMessagesCollector; \ No newline at end of file diff --git a/fabric/1.21.7/src/main/resources/fabric.mod.json b/fabric/1.21.7/src/main/resources/fabric.mod.json new file mode 100644 index 00000000..bd8fa5d1 --- /dev/null +++ b/fabric/1.21.7/src/main/resources/fabric.mod.json @@ -0,0 +1,31 @@ +{ + "schemaVersion": 1, + "id": "advancedbackups", + "version": "${version}", + "accessWidener" : "advancedbackups.accesswidener", + "name": "Advanced Backups", + "description": "An extremely advanced backup mod.\n\nSupports many backup types.\n\nConfig file and github contain documentation.", + "authors": [ + "Mommy Heather" + ], + "contact": { + "homepage": "https://github.com/HeatherComputer/advancedbackups" + }, + "license": "BSD", + "icon": "assets/advanced-backups/icon.png", + "environment": "*", + "entrypoints": { + "main": [ + "computer.heather.advancedbackups.AdvancedBackups" + ], + "client": [ + "computer.heather.advancedbackups.client.ClientWrapper" + ] + }, + "depends": { + "fabricloader": ">=0.16.14", + "minecraft": ">=1.21.7", + "java": ">=21", + "fabric-api": "*" + } +} diff --git a/fabric/1.21.7/src/main/resources/pack.mcmeta b/fabric/1.21.7/src/main/resources/pack.mcmeta new file mode 100644 index 00000000..877382f4 --- /dev/null +++ b/fabric/1.21.7/src/main/resources/pack.mcmeta @@ -0,0 +1,8 @@ +{ + "pack": { + "description": "advancedbackups resources", + "pack_format": 9, + "forge:resource_pack_format": 8, + "forge:data_pack_format": 9 + } +}