Adrenix hace 4 años
commit
fe8d49b60a

+ 5 - 0
.gitattributes

@@ -0,0 +1,5 @@
+# Disable autocrlf on generated files, they always generate with LF
+# Add any extra files or paths here to make git stop saying they
+# are changed when only line endings change.
+src/generated/**/.cache/cache text eol=lf
+src/generated/**/*.json text eol=lf

+ 26 - 0
.gitignore

@@ -0,0 +1,26 @@
+# eclipse
+bin
+*.launch
+.settings
+.metadata
+.classpath
+.project
+
+# idea
+out
+*.ipr
+*.iws
+*.iml
+.idea
+
+# gradle
+build
+.gradle
+
+# other
+eclipse
+run
+logs
+
+# Files from Forge MDK
+forge*changelog.txt

+ 65 - 0
CREDITS.txt

@@ -0,0 +1,65 @@
+Minecraft Forge: Credits/Thank You
+
+Forge is a set of tools and modifications to the Minecraft base game code to assist 
+mod developers in creating new and exciting content. It has been in development for 
+several years now, but I would like to take this time thank a few people who have 
+helped it along it's way.
+
+First, the people who originally created the Forge projects way back in Minecraft 
+alpha. Eloraam of RedPower, and SpaceToad of Buildcraft, without their acceptiance 
+of me taking over the project, who knows what Minecraft modding would be today.
+
+Secondly, someone who has worked with me, and developed some of the core features
+that allow modding to be as functional, and as simple as it is, cpw. For developing
+FML, which stabelized the client and server modding ecosystem. As well as the base
+loading system that allows us to modify Minecraft's code as elegently as possible.
+
+Mezz, who has stepped up as the issue and pull request manager. Helping to keep me
+sane as well as guiding the community into creating better additions to Forge.
+
+Searge, Bspks, Fesh0r, ProfMobious, and all the rest over on the MCP team {of which 
+I am a part}. For creating some of the core tools needed to make Minecraft modding 
+both possible, and as stable as can be.
+  On that note, here is some specific information of the MCP data we use:
+    * Minecraft Coder Pack (MCP) *
+      Forge Mod Loader and Minecraft Forge have permission to distribute and automatically 
+      download components of MCP and distribute MCP data files. This permission is not 
+      transitive and others wishing to redistribute the Minecraft Forge source independently
+      should seek permission of MCP or remove the MCP data files and request their users 
+      to download MCP separately.
+      
+And lastly, the countless community members who have spent time submitting bug reports, 
+pull requests, and just helping out the community in general. Thank you.
+
+--LexManos
+
+=========================================================================
+
+This is Forge Mod Loader.
+
+You can find the source code at all times at https://github.com/MinecraftForge/MinecraftForge/tree/1.12.x/src/main/java/net/minecraftforge/fml
+
+This minecraft mod is a clean open source implementation of a mod loader for minecraft servers
+and minecraft clients.
+
+The code is authored by cpw.
+
+It began by partially implementing an API defined by the client side ModLoader, authored by Risugami.
+http://www.minecraftforum.net/topic/75440-
+This support has been dropped as of Minecraft release 1.7, as Risugami no longer maintains ModLoader.
+
+It also contains suggestions and hints and generous helpings of code from LexManos, author of MinecraftForge.
+http://www.minecraftforge.net/
+
+Additionally, it contains an implementation of topological sort based on that 
+published at http://keithschwarz.com/interesting/code/?dir=topological-sort
+
+It also contains code from the Maven project for performing versioned dependency
+resolution. http://maven.apache.org/
+
+It also contains a partial repackaging of the javaxdelta library from http://sourceforge.net/projects/javaxdelta/
+with credit to it's authors.
+
+Forge Mod Loader downloads components from the Minecraft Coder Pack
+(http://mcp.ocean-labs.de/index.php/Main_Page) with kind permission from the MCP team.
+

+ 135 - 0
LICENSE.txt

@@ -0,0 +1,135 @@
+Minecraft Mod Public License
+============================
+
+Version 2.0.3
+
+0. Definitions
+--------------
+
+**Game**: Computer software which provides diversion or amusement. Often a form of play. 
+
+**Mod**: Software which modifies the Game, in any form (source, compiled binary, etc).
+
+**Asset**: Graphic, audio, data file, or other medium used by the Mod.
+
+**User**: Anyone who that interacts with the Game or the Mod in any way.
+
+**Dependency**: Software required for the Mod to execute, compile, or otherwise "work" correctly.
+
+**API**: Software intermediary for interaction with the Mod.
+
+**Derivative**: Software which includes any portion of the Mod other than the API, with modifications, additions, or subtractions.
+
+**Addon**: Software that extends the Mod, but is not a derivative.
+
+**Modpack**: A collection of mods and configuration files pre-tested to work when installed together.
+
+**Modpack Creator**: An individual who creates modpacks.
+
+**Author(s)**: Original programmer or programmers responsible for writing the Mod.
+
+**Contributor**: Programmer or programmers who contribute code to the Mod, but are not the Author.
+
+**Codebase**: The Mod source code, complete with source history and Contributor records.
+
+**Distributor**: Anyone who distributes the compiled mod.
+
+1. Scope
+--------
+
+The present license is granted to any User of the Mod.
+
+The User is expected to comply with any Game End User License Agreement (EULA) and/or Terms of Service (ToS) as it exists at the time the Mod is initially distributed.
+
+This license is separate from the license of any Mod it depends on and does not invalidate any license requirement of the dependency.
+
+2. Liability
+--------
+
+The User accepts the following liability:
+ - The Mod is provided 'as is' with no warranties, implied or otherwise.
+ - The Author is not responsible for dragon, troll, pirate, or ninja attacks.
+ - Slaying any and all mythological creatures is the sole responsibility of the User.
+ - The Author takes no responsibility for any damages incurred from the use or misuse of the Mod.
+ - The Mod may alter fundamental parts of the Game.
+ - The User is liable for any and all damages resulting from the use or misuse of the Mod.
+ - The Author may not be held responsible for the incompetency or sadism of a Modpack Creator.
+
+3. Right to use
+--------
+
+The User is allowed to install the Mod and play without restriction.  
+The User may not limit access to the Mod in any way, except as provided by the Game.  
+
+4. Right to examine
+--------
+
+The User may decompile compiled binaries of the Mod.  
+The User may examine the Mod's source code.
+
+5. Right to distribute
+--------
+
+The Author reserves the right to distribute the Mod.  
+The Author may designate a person or organization as a Distributor.  
+A Distributor is granted the right to distribute the Mod.  
+The Author may require that a Distributor provides a direct link to the Codebase.  
+The User may not distribute the Mod without being granted distribution rights from the Author.  
+The Author may revoke distribution rights from any Distributor.  
+
+6. Right to contribute
+--------
+
+The User may "fork" the Codebase.  
+The User may compile the Codebase.  
+The User may submit contributions to the Author for inclusion in the Mod.  
+The User grants the Author all rights to any contribution.  
+The User renounces all rights to their contribution except as specified under this license.  
+The User retains the right to re-use code they've written.  
+The Author may specify a Contributor License Agreement allowing a Contributor to retain some or all rights.  
+
+7. Right to derive
+--------
+
+The User may create Derivative(s) based on the Mod.  
+A Derivative must contain changes which a reasonably informed person would consider significant.  
+
+The User may distribute a Derivative if the following conditions are met:
+ - The Derivative does not generate revenue.
+ - The Derivative provides credit to the Author.
+ - The Derivative complies with the Mod license.
+
+8. Right to Assets
+--------
+Unless otherwise specified, Assets are considered a part of the Mod.  
+Unless otherwise specified, Assets are governed by the same rights as the Mod.  
+The Author may specify categorical exceptions to Asset licensing.  
+The Author may specify exact or Codebase path exceptions to Asset licensing.  
+The Author may include Assets licensed under different licenses.  
+
+9. Right to distribute addons
+--------
+
+The User may develop non-Derivative Addons.  
+An Addon may include the Mod API without being considered a Derivative.  
+The Addon may be distributed under a different license.  
+
+10. Right to create Modpack(s)
+--------
+
+The User may create Modpack(s) which include the Mod.  
+A Modpack Creator is granted the right to distribute the Mod as part of a Modpack.  
+
+Modpacks containing the Mod may not be used to generate revenue unless specifically granted this right by the Author.  
+
+11. Author responsibilities
+--------
+
+The Author must make the Mod source freely and publicly available.  
+
+12. Author rights
+--------
+
+The Author may grant a User the status of Contributor or Author.  
+The Author retains the right to the Mod name.  
+The Author may change the Mod license, but cannot do so retroactively.

+ 63 - 0
README.md

@@ -0,0 +1,63 @@
+# OldSwing Mod
+[
+![CurseForge Downloads](http://cf.way2muchnoise.eu/old-swing.svg)
+![CurseForge Versions](http://cf.way2muchnoise.eu/versions/old-swing.svg)
+](https://www.curseforge.com/minecraft/mc-mods/old-swing)
+[
+![Discord](https://img.shields.io/discord/452988045252100107?label=Discord)
+](https://discordapp.com/invite/jWdfVh3)  
+
+This mod brings back the old swinging animations before Minecraft Beta 1.8. This is an "eye candy" mod targeted towards nostalgic enthusiasts. As a bonus, this mod is also very configurable. All animation changes can be toggled. Moreover, you can customize the swing speeds of swords, tools, items, and everything in-between!
+
+## Version 2.0.0
+Old swing has been updated to 1.16! Hooray!
+- Every change in the game is now configurable.
+- Since Forge does not have an in-game config GUI yet, you can change these values with the `/oldswing` command.
+  - You can also use the config file. After you save your changes, the game will automatically update without a restart.
+- More old-school animations have been implemented.
+
+## What Changes?
+Only the animations will change. The goal of this mod is to provide a swinging animation that has not been seen since Minecraft Beta 1.7.
+- The arm sway animation has been disabled. (Configurable)
+- The cooldown animation that plays after every swing or change in hotbar slot has been disabled. (Configurable)
+- The re-equip animation no longer plays when an item damage value changes. (Configurable)
+- The swinging animation has been slowed down. (Configurable)
+
+### Note
+None of these animation modifications impacts block breaking speed or combat. Moreover, these changes are only visible to the client. Meaning only you can see the changes in animation. Potion effects that impacted the animation before still do.
+
+## Configuration
+As an added feature, you can configure how fast - or slow - the swing speed animation is for any item in the game. That means if you prefer your sword swinging speeds to be fast and tool swinging speeds to be slow, you can do that. Even the placing speed animation for blocks can be changed if needed. Additionally, if motion sickness is of concern for you - or for an audience - I recommend setting the animation speed to 10 or higher. This will result in a slower and smoother swinging animation.
+
+You can modify all configuration options in-game with the `/oldswing` command. Unfortunately, this command will not be available in online multiplayer. However, you can still edit these configuration options within the config file. After you save the file, the new changes will automatically be applied in-game without a restart. Nifty!
+
+## Commands
+These commands come equipped with auto-completion.
+- `/oldswing set` Used to change a config value.
+- `/oldswing get` Used to get current values saved in the config.
+
+## Demo Video
+Watch the following video to see what this mod changes. https://www.youtube.com/watch?v=nbUPpU4r49o
+[![YouTube Thumbnail](https://cdn.discordapp.com/attachments/800426030996389929/812830411969265684/yt_thumbdesign.png)](https://www.youtube.com/watch?v=nbUPpU4r49o "Old Swing Mod Ver. 2 (Demo)")
+
+## Compatibility
+If you come across a compatibility issue, please let me know! It is best to create an issue if you come across one. You might also experience animation issues when using modded items that utilize the re-equip animation. If this is the case, you can turn off the oldswing reequip animation in the config or through the /oldswing command.
+
+## FAQ
+### Can I include Old Swing in my pack?
+Sure!
+
+### Is this mod server safe?
+Yes. This mod only changes visual animations and is client-side only.
+
+### I ran into an issue running this mod.
+Please submit an issue.
+
+### Will there be a backport to 1.15?
+If there is a bit of demand for this, I will look into it since 1.15 is a LTS version for Forge.
+
+### What about a backport of version 2 to 1.12?
+There needs to be a lot of demand for this before I would consider it.
+
+## CurseForge Link
+https://www.curseforge.com/minecraft/mc-mods/old-swing

+ 147 - 0
build.gradle

@@ -0,0 +1,147 @@
+buildscript {
+    repositories {
+        maven { url = 'https://files.minecraftforge.net/maven' }
+        jcenter()
+        mavenCentral()
+    }
+    dependencies {
+        classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '3.+', changing: true
+    }
+}
+apply plugin: 'net.minecraftforge.gradle'
+// Only edit below this line, the above code adds and enables the necessary things for Forge to be setup.
+apply plugin: 'eclipse'
+apply plugin: 'maven-publish'
+
+version = '2.0.0'
+group = 'mod.adrenix.oldswing' // http://maven.apache.org/guides/mini/guide-naming-conventions.html
+archivesBaseName = 'oldswing'
+
+sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = '1.8' // Need this here so eclipse task generates correctly.
+
+println('Java: ' + System.getProperty('java.version') + ' JVM: ' + System.getProperty('java.vm.version') + '(' + System.getProperty('java.vendor') + ') Arch: ' + System.getProperty('os.arch'))
+minecraft {
+    // The mappings can be changed at any time, and must be in the following format.
+    // snapshot_YYYYMMDD   Snapshot are built nightly.
+    // stable_#            Stables are built at the discretion of the MCP team.
+    // Use non-default mappings at your own risk. they may not always work.
+    // Simply re-run your setup task after changing the mappings to update your workspace.
+    mappings channel: 'snapshot', version: '20200514-1.16'
+    // makeObfSourceJar = false // an Srg named sources jar is made by default. uncomment this to disable.
+    
+    // accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg')
+
+    // Default run configurations.
+    // These can be tweaked, removed, or duplicated as needed.
+    runs {
+        client {
+            workingDirectory project.file('run')
+
+            // Recommended logging data for a userdev environment
+            property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP'
+
+            // Recommended logging level for the console
+            property 'forge.logging.console.level', 'debug'
+
+            mods {
+                oldswing {
+                    source sourceSets.main
+                }
+            }
+        }
+
+        server {
+            workingDirectory project.file('run')
+
+            // Recommended logging data for a userdev environment
+            property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP'
+
+            // Recommended logging level for the console
+            property 'forge.logging.console.level', 'debug'
+
+            mods {
+                oldswing {
+                    source sourceSets.main
+                }
+            }
+        }
+
+        data {
+            workingDirectory project.file('run')
+
+            // Recommended logging data for a userdev environment
+            property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP'
+
+            // Recommended logging level for the console
+            property 'forge.logging.console.level', 'debug'
+
+            args '--mod', 'oldswing', '--all', '--output', file('src/generated/resources/')
+
+            mods {
+                oldswing {
+                    source sourceSets.main
+                }
+            }
+        }
+    }
+}
+
+dependencies {
+    // Specify the version of Minecraft to use, If this is any group other then 'net.minecraft' it is assumed
+    // that the dep is a ForgeGradle 'patcher' dependency. And it's patches will be applied.
+    // The userdev artifact is a special name and will get all sorts of transformations applied to it.
+    minecraft 'net.minecraftforge:forge:1.16.3-34.1.0'
+
+    // You may put jars on which you depend on in ./libs or you may define them like so..
+    // compile "some.group:artifact:version:classifier"
+    // compile "some.group:artifact:version"
+
+    // Real examples
+    // compile 'com.mod-buildcraft:buildcraft:6.0.8:dev'  // adds buildcraft to the dev env
+    // compile 'com.googlecode.efficient-java-matrix-library:ejml:0.24' // adds ejml to the dev env
+
+    // The 'provided' configuration is for optional dependencies that exist at compile-time but might not at runtime.
+    // provided 'com.mod-buildcraft:buildcraft:6.0.8:dev'
+
+    // These dependencies get remapped to your current MCP mappings
+    // deobf 'com.mod-buildcraft:buildcraft:6.0.8:dev'
+
+    // For more info...
+    // http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html
+    // http://www.gradle.org/docs/current/userguide/dependency_management.html
+
+}
+
+// Example for how to get properties into the manifest for reading by the runtime..
+jar {
+    manifest {
+        attributes([
+            "Specification-Title": "oldswing",
+            "Specification-Vendor": "mod.adrenix.oldswing",
+            "Specification-Version": "2.0.0", // We are version 1 of ourselves
+            "Implementation-Title": project.name,
+            "Implementation-Version": "${version}",
+            "Implementation-Vendor" :"mod.adrenix.oldswing",
+            "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ")
+        ])
+    }
+}
+
+// Example configuration to allow publishing using the maven-publish task
+// This is the preferred method to reobfuscate your jar file
+jar.finalizedBy('reobfJar') 
+// However if you are in a multi-project build, dev time needs unobfed jar files, so you can delay the obfuscation until publishing by doing
+//publish.dependsOn('reobfJar')
+
+publishing {
+    publications {
+        mavenJava(MavenPublication) {
+            artifact jar
+        }
+    }
+    repositories {
+        maven {
+            url "file:///${project.projectDir}/mcmodsrepo"
+        }
+    }
+}

+ 4 - 0
gradle.properties

@@ -0,0 +1,4 @@
+# Sets default memory used for gradle commands. Can be overridden by user or command line properties.
+# This is required to provide enough memory for the Minecraft decompilation process.
+org.gradle.jvmargs=-Xmx3G
+org.gradle.daemon=false

BIN
gradle/wrapper/gradle-wrapper.jar


+ 5 - 0
gradle/wrapper/gradle-wrapper.properties

@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.3-bin.zip

+ 172 - 0
gradlew

@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+    echo "$*"
+}
+
+die () {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# 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
+    ;;
+  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"
+    which java >/dev/null 2>&1 || 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
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+    JAVACMD=`cygpath --unix "$JAVACMD"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Escape application args
+save () {
+    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+    echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+  cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"

+ 84 - 0
gradlew.bat

@@ -0,0 +1,84 @@
+@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=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@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=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+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.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+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.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+: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 %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="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!
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega

+ 45 - 0
src/main/java/mod/adrenix/oldswing/OldSwingMod.java

@@ -0,0 +1,45 @@
+package mod.adrenix.oldswing;
+
+import mod.adrenix.oldswing.command.CommandRegistry;
+import mod.adrenix.oldswing.config.ClientConfig;
+import mod.adrenix.oldswing.config.ConfigHandler;
+import net.minecraftforge.common.MinecraftForge;
+import net.minecraftforge.eventbus.api.SubscribeEvent;
+import net.minecraftforge.fml.ExtensionPoint;
+import net.minecraftforge.fml.ModLoadingContext;
+import net.minecraftforge.fml.common.Mod;
+import net.minecraftforge.fml.config.ModConfig;
+import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
+import net.minecraftforge.fml.event.server.FMLServerStartingEvent;
+import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
+import net.minecraftforge.fml.loading.FMLLoader;
+import net.minecraftforge.fml.network.FMLNetworkConstants;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+@Mod(OldSwingMod.MOD_ID)
+public class OldSwingMod {
+    public static final String MOD_ID = "oldswing";
+    public static final Logger LOGGER = LogManager.getLogger();
+
+    public OldSwingMod() {
+        ModLoadingContext.get().registerExtensionPoint(ExtensionPoint.DISPLAYTEST, () -> Pair.of(() -> FMLNetworkConstants.IGNORESERVERONLY, (a, b) -> true));
+        if (FMLLoader.getDist().isDedicatedServer())
+            return;
+
+        ModLoadingContext.get().registerConfig(ModConfig.Type.CLIENT, ConfigHandler.CLIENT_SPEC);
+        FMLJavaModLoadingContext.get().getModEventBus().addListener(this::configSetup);
+
+        MinecraftForge.EVENT_BUS.register(this);
+    }
+
+    public void configSetup(final FMLClientSetupEvent event) {
+        ClientConfig.loadCustomItems();
+    }
+
+    @SubscribeEvent
+    public void serverStarting(FMLServerStartingEvent event) {
+        CommandRegistry.register(event.getServer().getCommandManager().getDispatcher());
+    }
+}

+ 17 - 0
src/main/java/mod/adrenix/oldswing/command/ColorUtil.java

@@ -0,0 +1,17 @@
+package mod.adrenix.oldswing.command;
+
+import net.minecraft.util.text.TextFormatting;
+
+public class ColorUtil {
+    public static String value(String value) {
+        if (value.equals("true"))
+            return format("true", TextFormatting.GREEN);
+        else if (value.equals("false"))
+            return format("false", TextFormatting.RED);
+        return format(value, TextFormatting.YELLOW);
+    }
+
+    public static String format(String in, TextFormatting color) {
+        return TextFormatting.fromColorIndex(color.getColorIndex()) + in + TextFormatting.fromColorIndex(TextFormatting.RESET.getColorIndex());
+    }
+}

+ 31 - 0
src/main/java/mod/adrenix/oldswing/command/CommandRegistry.java

@@ -0,0 +1,31 @@
+package mod.adrenix.oldswing.command;
+
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import mod.adrenix.oldswing.OldSwingMod;
+import mod.adrenix.oldswing.command.executors.Animations;
+import mod.adrenix.oldswing.command.executors.Paths;
+import mod.adrenix.oldswing.command.executors.State;
+import mod.adrenix.oldswing.command.executors.Swings;
+import net.minecraft.command.CommandSource;
+import net.minecraft.command.Commands;
+
+public class CommandRegistry {
+    public static void register(CommandDispatcher<CommandSource> dispatcher) {
+        final LiteralArgumentBuilder<CommandSource> builder = Commands.literal(OldSwingMod.MOD_ID);
+
+        builder
+                .then(
+                        Commands.literal("set")
+                                .then(Swings.register())
+                                .then(Animations.register())
+                                .then(State.register())
+                )
+                .then(
+                        Commands.literal("get")
+                                .then(Paths.register())
+                );
+
+        dispatcher.register(builder);
+    }
+}

+ 82 - 0
src/main/java/mod/adrenix/oldswing/command/executors/Animations.java

@@ -0,0 +1,82 @@
+package mod.adrenix.oldswing.command.executors;
+
+import com.mojang.brigadier.arguments.BoolArgumentType;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.suggestion.SuggestionProvider;
+import mod.adrenix.oldswing.config.ClientConfig;
+import mod.adrenix.oldswing.config.ConfigHandler;
+import net.minecraft.command.CommandSource;
+import net.minecraft.command.Commands;
+import net.minecraft.command.ISuggestionProvider;
+import net.minecraft.util.text.ITextComponent;
+
+public class Animations {
+    private static final SuggestionProvider<CommandSource> FLAG_SUGGESTION = (context, builder) ->
+            ISuggestionProvider.suggest(new String[]{"true", "false"}, builder);
+
+    public static LiteralArgumentBuilder<CommandSource> register() {
+        return Commands.literal("animation")
+                .then(Commands.literal("disableReequip")
+                        .then(Commands.argument("flag", BoolArgumentType.bool())
+                                .suggests(FLAG_SUGGESTION)
+                                .executes(context -> toggleReequipAnimation(
+                                        context.getSource(), BoolArgumentType.getBool(context, "flag")
+                                ))
+                        )
+                )
+
+                .then(Commands.literal("disableCooldown")
+                        .then(Commands.argument("flag", BoolArgumentType.bool())
+                                .suggests(FLAG_SUGGESTION)
+                                .executes(context -> toggleCooldown(
+                                        context.getSource(), BoolArgumentType.getBool(context, "flag")
+                                ))
+                        )
+                )
+
+                .then(Commands.literal("disableArmSway")
+                        .then(Commands.argument("flag", BoolArgumentType.bool())
+                                .suggests(FLAG_SUGGESTION)
+                                .executes(context -> toggleSwayAnimation(
+                                        context.getSource(), BoolArgumentType.getBool(context, "flag")
+                                ))
+                        )
+                );
+    }
+
+    private static int toggleCooldown(CommandSource source, boolean flag) {
+        ClientConfig.prevent_cooldown.set(flag);
+        ConfigHandler.bake();
+
+        final String state = flag ?
+                "The cooldown animation that plays after a swing or change in slot will now be prevented. This will not modify combat." :
+                "A cooldown animation will now play after every swing or change in slot. This will not modify combat.";
+        source.sendFeedback(ITextComponent.func_244388_a(state), true);
+
+        return 1;
+    }
+
+    private static int toggleReequipAnimation(CommandSource source, boolean flag) {
+        ClientConfig.prevent_reequip.set(flag);
+        ConfigHandler.bake();
+
+        final String state = flag ?
+                "Reequip animation will no longer play when an item's durability changes." :
+                "Reequip animation will now play when an item's durability changes.";
+        source.sendFeedback(ITextComponent.func_244388_a(state), true);
+
+        return 1;
+    }
+
+    private static int toggleSwayAnimation(CommandSource source, boolean flag) {
+        ClientConfig.prevent_sway.set(flag);
+        ConfigHandler.bake();
+
+        final String state = flag ?
+                "The subtle arm sway animation that happens when you look around will now be prevented." :
+                "You will now see a subtle arm sway animation occur as you look around.";
+        source.sendFeedback(ITextComponent.func_244388_a(state), true);
+
+        return 1;
+    }
+}

+ 86 - 0
src/main/java/mod/adrenix/oldswing/command/executors/Paths.java

@@ -0,0 +1,86 @@
+package mod.adrenix.oldswing.command.executors;
+
+import com.electronwill.nightconfig.core.Config;
+import com.mojang.brigadier.arguments.StringArgumentType;
+import com.mojang.brigadier.builder.RequiredArgumentBuilder;
+import com.mojang.brigadier.suggestion.SuggestionProvider;
+import mod.adrenix.oldswing.command.ColorUtil;
+import mod.adrenix.oldswing.config.ClientConfig;
+import mod.adrenix.oldswing.config.ConfigHandler;
+import net.minecraft.command.CommandSource;
+import net.minecraft.command.Commands;
+import net.minecraft.command.ISuggestionProvider;
+import net.minecraft.util.text.ITextComponent;
+import net.minecraft.util.text.TextFormatting;
+import net.minecraftforge.common.ForgeConfigSpec;
+
+import java.util.Map;
+
+public class Paths {
+    private static final SuggestionProvider<CommandSource> CONFIG_SUGGESTION = (context, builder) ->
+            ISuggestionProvider.suggest(new String[]{"animations", "swings", "items"}, builder);
+
+    public static RequiredArgumentBuilder<CommandSource, String> register() {
+         return Commands.argument("path", StringArgumentType.string())
+                .suggests(CONFIG_SUGGESTION)
+                .executes(context -> getConfigurationStates(
+                        context.getSource(), StringArgumentType.getString(context, "path"))
+                );
+    }
+
+    private static int getConfigurationStates(CommandSource source, String path) {
+        if (!ConfigHandler.mod_enabled) {
+            source.sendErrorMessage(ITextComponent.func_244388_a("The mod must be enabled to see config values."));
+            return 0;
+        }
+
+        switch (path) {
+            case "animations":
+                for (Map.Entry<String, ForgeConfigSpec.ConfigValue<?>> entry : ClientConfig.ANIMATIONS.entrySet()) {
+                    ForgeConfigSpec.ConfigValue<?> value = entry.getValue();
+
+                    final String out = String.format("Config option %s has value of: %s",
+                            ColorUtil.format(String.valueOf(value.getPath()), TextFormatting.LIGHT_PURPLE), ColorUtil.value(value.get().toString()));
+                    source.sendFeedback(ITextComponent.func_244388_a(out), true);
+                }
+
+                return 1;
+            case "swings":
+                for (Map.Entry<String, ForgeConfigSpec.IntValue> entry : ClientConfig.SPEEDS.entrySet()) {
+                    ForgeConfigSpec.IntValue value = entry.getValue();
+
+                    final String out = String.format("Swing speeds for %s has a swing speed of: %s",
+                            ColorUtil.format(String.valueOf(entry.getKey()), TextFormatting.LIGHT_PURPLE),
+                            ColorUtil.format(String.valueOf(value.get()), TextFormatting.YELLOW));
+                    source.sendFeedback(ITextComponent.func_244388_a(out), true);
+                }
+
+                return 1;
+            case "items":
+                int counter = 0;
+                for (Config.Entry entry : ConfigHandler.custom_speeds.entrySet()) {
+                    counter++; if (counter == 15) {
+                        source.sendFeedback(ITextComponent.func_244388_a(
+                                ColorUtil.format("...remaining items can be found in config file.", TextFormatting.ITALIC)), true);
+                        break;
+                    }
+
+                    final String out = String.format("Item [%s] has swing speed of: %s",
+                            ColorUtil.format(String.valueOf(entry.getKey()), TextFormatting.LIGHT_PURPLE),
+                            ColorUtil.format(entry.getValue().toString(), TextFormatting.YELLOW));
+                    source.sendFeedback(ITextComponent.func_244388_a(out), true);
+                }
+
+                if (counter == 0) {
+                    source.sendErrorMessage(ITextComponent.func_244388_a("There are no items with custom swing speeds."));
+                    return 0;
+                }
+
+                return 1;
+        }
+
+        source.sendErrorMessage(ITextComponent.func_244388_a("Unknown configuration path."));
+
+        return 0;
+    }
+}

+ 33 - 0
src/main/java/mod/adrenix/oldswing/command/executors/State.java

@@ -0,0 +1,33 @@
+package mod.adrenix.oldswing.command.executors;
+
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import mod.adrenix.oldswing.command.ColorUtil;
+import mod.adrenix.oldswing.config.ClientConfig;
+import mod.adrenix.oldswing.config.ConfigHandler;
+import net.minecraft.command.CommandSource;
+import net.minecraft.command.Commands;
+import net.minecraft.util.text.ITextComponent;
+
+public class State {
+    public static LiteralArgumentBuilder<CommandSource> register() {
+        return Commands.literal("mod")
+                .then(Commands.literal("enable")
+                        .executes(context -> modState(context.getSource(), true))
+                )
+
+                .then(Commands.literal("disable")
+                        .executes(context -> modState(context.getSource(), false))
+                );
+    }
+
+    private static int modState(CommandSource source, boolean flag) {
+        ClientConfig.mod_enabled.set(flag);
+        ConfigHandler.bake();
+
+        final String out = String.format("OldSwing enabled: %s",
+                ColorUtil.value(String.valueOf(flag)));
+        source.sendFeedback(ITextComponent.func_244388_a(out), true);
+
+        return 1;
+    }
+}

+ 143 - 0
src/main/java/mod/adrenix/oldswing/command/executors/Swings.java

@@ -0,0 +1,143 @@
+package mod.adrenix.oldswing.command.executors;
+
+import com.mojang.brigadier.arguments.IntegerArgumentType;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.suggestion.SuggestionProvider;
+import mod.adrenix.oldswing.command.ColorUtil;
+import mod.adrenix.oldswing.config.ClientConfig;
+import mod.adrenix.oldswing.config.ConfigHandler;
+import mod.adrenix.oldswing.config.CustomSwing;
+import net.minecraft.command.CommandSource;
+import net.minecraft.command.Commands;
+import net.minecraft.command.ISuggestionProvider;
+import net.minecraft.command.arguments.ItemArgument;
+import net.minecraft.command.arguments.ItemInput;
+import net.minecraft.item.Item;
+import net.minecraft.util.ResourceLocation;
+import net.minecraft.util.text.ITextComponent;
+import net.minecraft.util.text.TextFormatting;
+import net.minecraftforge.registries.ForgeRegistries;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+
+public class Swings {
+    private static final ArrayList<String> VALID_SPEEDS = new ArrayList<>();
+    private static final int MIN = ConfigHandler.MIN;
+    private static final int MAX = ConfigHandler.MAX;
+
+    static {
+        for (int i = MIN; i <= MAX; i++) {
+            VALID_SPEEDS.add(Integer.toString(i));
+        }
+    }
+
+    private static final SuggestionProvider<CommandSource> SPEED_SUGGESTION = (context, builder) ->
+            ISuggestionProvider.suggest(VALID_SPEEDS, builder);
+
+    public static LiteralArgumentBuilder<CommandSource> register() {
+        return Commands.literal("swing")
+                .then(Commands.literal("items")
+                        .then(Commands.argument("speed", IntegerArgumentType.integer())
+                                .suggests(SPEED_SUGGESTION)
+                                .executes(context -> changeSwingSpeed(
+                                        context.getSource(), IntegerArgumentType.getInteger(context, "speed"), "items"
+                                ))
+                        )
+                )
+
+                .then(Commands.literal("swords")
+                        .then(Commands.argument("speed", IntegerArgumentType.integer())
+                                .suggests(SPEED_SUGGESTION)
+                                .executes(context -> changeSwingSpeed(
+                                        context.getSource(), IntegerArgumentType.getInteger(context, "speed"), "swords"
+                                ))
+                        )
+                )
+
+                .then(Commands.literal("tools")
+                        .then(Commands.argument("speed", IntegerArgumentType.integer())
+                                .suggests(SPEED_SUGGESTION)
+                                .executes(context -> changeSwingSpeed(
+                                        context.getSource(), IntegerArgumentType.getInteger(context, "speed"), "tools"
+                                ))
+                        )
+                )
+
+                .then(Commands.literal("custom")
+                        .then(Commands.argument("item", ItemArgument.item())
+                                .then(Commands.argument("speed", IntegerArgumentType.integer())
+                                        .suggests(SPEED_SUGGESTION)
+                                        .executes(context -> addCustomSwing(
+                                                context.getSource(),
+                                                ItemArgument.getItem(context, "item"),
+                                                IntegerArgumentType.getInteger(context, "speed")
+                                        ))
+                                )
+                        )
+                );
+    }
+
+    private static int rangeError(@NotNull CommandSource source) {
+        source.sendErrorMessage(ITextComponent.func_244388_a(String.format("Swing speed out of range! [Range: %d ~ %d]", MIN, MAX)));
+        return 0;
+    }
+
+    private static int changeSwingSpeed(CommandSource source, int speed, String on) {
+        if (speed < MIN || speed > MAX) {
+            return rangeError(source);
+        }
+
+        switch (on) {
+            case "items":
+                ClientConfig.swing_speed.set(speed);
+                break;
+            case "swords":
+                ClientConfig.sword_speed.set(speed);
+                break;
+            case "tools":
+                ClientConfig.tool_speed.set(speed);
+                break;
+        }
+
+        ConfigHandler.bake();
+
+        final String oldSwing = String.format("%s: %s",
+                ColorUtil.format("Alpha/Beta Minecraft", TextFormatting.LIGHT_PURPLE),
+                ColorUtil.format("8", TextFormatting.YELLOW)
+        );
+
+        final String newSwing = String.format("%s: %s",
+                ColorUtil.format("Modern Minecraft", TextFormatting.LIGHT_PURPLE),
+                ColorUtil.format("6", TextFormatting.YELLOW)
+        );
+
+        final String info = String.format("%s\n%s\nSuccessfully changed %s swing speed to: %s.",
+                oldSwing, newSwing, ColorUtil.format(on, TextFormatting.GOLD), ColorUtil.format(Integer.toString(speed), TextFormatting.AQUA));
+        source.sendFeedback(ITextComponent.func_244388_a(info), true);
+
+        return 1;
+    }
+
+    private static int addCustomSwing(CommandSource source, ItemInput itemIn, int speed) {
+        Item item = itemIn.getItem();
+        ResourceLocation resource = ForgeRegistries.ITEMS.getKey(item);
+
+        if (resource == null) {
+            source.sendErrorMessage(ITextComponent.func_244388_a("Item [" + itemIn.toString() + "] does not exist in the forge item registry."));
+            return 0;
+        } else if (speed < MIN || speed > MAX) {
+            return rangeError(source);
+        }
+
+        CustomSwing.add(resource.toString(), speed);
+        ConfigHandler.bake();
+
+        final String out = String.format("Successfully added [%s] with speed: %s",
+                ColorUtil.format(resource.toString(), TextFormatting.GREEN),
+                ColorUtil.format(String.valueOf(speed), TextFormatting.YELLOW));
+        source.sendFeedback(ITextComponent.func_244388_a(out), true);
+
+        return 1;
+    }
+}

+ 93 - 0
src/main/java/mod/adrenix/oldswing/config/ClientConfig.java

@@ -0,0 +1,93 @@
+package mod.adrenix.oldswing.config;
+
+import com.electronwill.nightconfig.core.Config;
+import net.minecraftforge.common.ForgeConfigSpec;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+public class ClientConfig {
+    /* Mod State */
+    public static ForgeConfigSpec.BooleanValue mod_enabled;
+
+    /* Animation Options */
+    public static ForgeConfigSpec.BooleanValue prevent_cooldown;
+    public static ForgeConfigSpec.BooleanValue prevent_reequip;
+    public static ForgeConfigSpec.BooleanValue prevent_sway;
+    public static final Map<String, ForgeConfigSpec.ConfigValue<?>> ANIMATIONS = new HashMap<>();
+
+    /* Swing Speeds */
+    public static ForgeConfigSpec.IntValue swing_speed;
+    public static ForgeConfigSpec.IntValue sword_speed;
+    public static ForgeConfigSpec.IntValue tool_speed;
+    public static ForgeConfigSpec.ConfigValue<Config> custom;
+    public static final Map<String, ForgeConfigSpec.IntValue> SPEEDS = new HashMap<>();
+
+    public ClientConfig(ForgeConfigSpec.Builder builder) {
+        /* Mod State */
+        mod_enabled = builder
+                .comment(" Use this option to enable or disable the mod.")
+                .define("mod.enabled", true);
+
+        /* Standard Animations */
+        prevent_cooldown = builder
+                .comment(" Enabling this option will prevent the cooldown animation that plays after every swing or change in slot.",
+                         " This does not disable or modify the cooldown attack system, this only disables the animation.")
+                .define("animation.prevent_cooldown", true);
+
+        prevent_reequip = builder
+                .comment(" Enabling this option will prevent the reequip animation from playing when an item takes damage.",
+                         " The purpose of this is to prevent the animation from playing after every block break.",
+                         " Disable this option if you are experiencing issues with other mods.")
+                .define("animation.prevent_reequip", true);
+
+        prevent_sway = builder
+                .comment(" Enabling this option will prevent the subtle arm sway when looking in different directions.")
+                .define("animation.prevent_sway", true);
+
+
+        /* Swing Speeds */
+        builder.comment(
+                " The higher the swing number is the slower the swinging animation will be.",
+                " Alpha/Beta Minecraft: 8",
+                " Modern Minecraft: 6");
+        builder.push("swings");
+
+        swing_speed = builder
+                .comment(" Use this option to assign a swing speed to anything that isn't a sword or tool.")
+                .defineInRange("item_speed", ConfigHandler.OLD_SPEED, ConfigHandler.MIN, ConfigHandler.MAX);
+
+        sword_speed = builder
+                .comment(" Give a custom swing speed for swords.")
+                .defineInRange("sword_speed", ConfigHandler.OLD_SPEED, ConfigHandler.MIN, ConfigHandler.MAX);
+
+        tool_speed = builder
+                .comment(" Give a custom swing speed for tools.",
+                         " Like shovels, pickaxes, and axes.")
+                .defineInRange("tool_speed", ConfigHandler.OLD_SPEED, ConfigHandler.MIN, ConfigHandler.MAX);
+
+        custom = builder
+                .comment(" Add a custom swing speed for any item in the game.")
+                .defineInList("items", Config.inMemory(), Collections.emptyList());
+
+        /* Command References */
+        ANIMATIONS.put("reequipAnimation", prevent_reequip);
+        ANIMATIONS.put("cooldownAnimation", prevent_cooldown);
+        ANIMATIONS.put("armSway", prevent_sway);
+
+        SPEEDS.put("tools", tool_speed);
+        SPEEDS.put("swords", sword_speed);
+        SPEEDS.put("everything else", swing_speed);
+    }
+
+    public static void loadCustomItems() {
+        custom.get().entrySet().forEach(entry -> custom.get().add(entry.getKey(), entry.getValue()));
+
+        // Ensure user has a couple of examples that shows how to add custom swing speeds.
+        if (custom.get().size() == 0) {
+            CustomSwing.add("minecraft:wooden_sword", ConfigHandler.OLD_SPEED);
+            CustomSwing.add("minecraft:wooden_axe", ConfigHandler.OLD_SPEED);
+        }
+    }
+}

+ 53 - 0
src/main/java/mod/adrenix/oldswing/config/ConfigHandler.java

@@ -0,0 +1,53 @@
+package mod.adrenix.oldswing.config;
+
+import com.electronwill.nightconfig.core.Config;
+import mod.adrenix.oldswing.OldSwingMod;
+import net.minecraftforge.api.distmarker.Dist;
+import net.minecraftforge.common.ForgeConfigSpec;
+import net.minecraftforge.eventbus.api.SubscribeEvent;
+import net.minecraftforge.fml.common.Mod;
+import net.minecraftforge.fml.config.ModConfig;
+import org.apache.commons.lang3.tuple.Pair;
+
+@Mod.EventBusSubscriber(modid = OldSwingMod.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT)
+public class ConfigHandler {
+    public static final ClientConfig CLIENT;
+    public static final ForgeConfigSpec CLIENT_SPEC;
+    public static final int OLD_SPEED = 8;
+    public static final int NEW_SPEED = 6;
+    public static final int MIN = 4;
+    public static final int MAX = 16;
+
+    public static Config custom_speeds;
+    public static int swing_speed = OLD_SPEED;
+    public static int sword_speed = OLD_SPEED;
+    public static int tool_speed = OLD_SPEED;
+    public static boolean prevent_cooldown = true;
+    public static boolean prevent_reequip = true;
+    public static boolean prevent_sway = true;
+    public static boolean mod_enabled = true;
+
+    static {
+        final Pair<ClientConfig, ForgeConfigSpec> pair = new ForgeConfigSpec.Builder().configure(ClientConfig::new);
+        CLIENT_SPEC = pair.getRight();
+        CLIENT = pair.getLeft();
+    }
+
+    @SubscribeEvent
+    public static void onModConfigEvent(final ModConfig.ModConfigEvent configEvent) {
+        if (configEvent.getConfig().getSpec() == ConfigHandler.CLIENT_SPEC) {
+            bake();
+        }
+    }
+
+    public static void bake() {
+        custom_speeds = ClientConfig.custom.get();
+        swing_speed = ClientConfig.swing_speed.get();
+        sword_speed = ClientConfig.sword_speed.get();
+        tool_speed = ClientConfig.tool_speed.get();
+        prevent_cooldown = ClientConfig.prevent_cooldown.get();
+        prevent_reequip = ClientConfig.prevent_reequip.get();
+        prevent_sway = ClientConfig.prevent_sway.get();
+        mod_enabled = ClientConfig.mod_enabled.get();
+    }
+}

+ 38 - 0
src/main/java/mod/adrenix/oldswing/config/CustomSwing.java

@@ -0,0 +1,38 @@
+package mod.adrenix.oldswing.config;
+
+import mod.adrenix.oldswing.OldSwingMod;
+import net.minecraft.util.ResourceLocation;
+import net.minecraftforge.registries.ForgeRegistries;
+
+public class CustomSwing {
+    public static void add(String item, int speed) {
+        if (ForgeRegistries.ITEMS.containsKey(ResourceLocation.tryCreate(item))) {
+            try {
+                if (speed >= ConfigHandler.MIN && speed <= ConfigHandler.MAX) {
+                    if (ClientConfig.custom.get().contains(item)) {
+                        ClientConfig.custom.get().set(item, speed);
+                        ClientConfig.custom.set(ClientConfig.custom.get());
+
+                        OldSwingMod.LOGGER.info(String.format("Replacing %s with new swing speed of %d.", item, speed));
+                        return;
+                    }
+
+                    ClientConfig.custom.get().add(item, speed);
+                    ClientConfig.custom.set(ClientConfig.custom.get());
+
+                    OldSwingMod.LOGGER.info(String.format("Adding %s with custom swing speed of %d.", item, speed));
+                    return;
+                }
+
+                final String issue = String.format("%s will will not receive a custom speed since the number was out of range (%d ~ %d)",
+                        item, ConfigHandler.MIN, ConfigHandler.MAX);
+
+                OldSwingMod.LOGGER.error(issue);
+            } catch (NumberFormatException e) {
+                OldSwingMod.LOGGER.error(item + " will not receive a custom speed since the speed provided was not a number.");
+            }
+        } else {
+            OldSwingMod.LOGGER.warn(item + " will not receive a custom speed since it was not found in the forge item registry.");
+        }
+    }
+}

+ 77 - 0
src/main/java/mod/adrenix/oldswing/config/TransformerHelper.java

@@ -0,0 +1,77 @@
+package mod.adrenix.oldswing.config;
+
+import com.electronwill.nightconfig.core.Config;
+import com.mojang.blaze3d.matrix.MatrixStack;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.entity.player.ClientPlayerEntity;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemStack;
+import net.minecraft.item.SwordItem;
+import net.minecraft.item.ToolItem;
+import net.minecraft.util.ResourceLocation;
+import net.minecraft.util.math.vector.Quaternion;
+import net.minecraftforge.client.ForgeHooksClient;
+import net.minecraftforge.fml.loading.FMLLoader;
+import net.minecraftforge.registries.ForgeRegistries;
+
+import javax.annotation.Nonnull;
+
+/* Transformer Helpers - Suppressed unused since these are called with ASM */
+@SuppressWarnings("unused")
+public class TransformerHelper {
+    @SuppressWarnings("unused")
+    public static int swingSpeed() {
+        if (FMLLoader.getDist().isDedicatedServer() || !ConfigHandler.mod_enabled)
+            return ConfigHandler.NEW_SPEED;
+
+        ClientPlayerEntity player = Minecraft.getInstance().player;
+        if (player == null) {
+            return ConfigHandler.swing_speed;
+        }
+
+        Item item = player.getHeldItemMainhand().getItem();
+        ResourceLocation source = ForgeRegistries.ITEMS.getKey(item);
+
+        for (Config.Entry entry : ConfigHandler.custom_speeds.entrySet()) {
+            if (source != null && source.toString().equals(entry.getKey())) {
+                return entry.getValue();
+            }
+        }
+
+        if (item instanceof SwordItem) {
+            return ConfigHandler.sword_speed;
+        } else if (item instanceof ToolItem) {
+            return ConfigHandler.tool_speed;
+        }
+
+        return ConfigHandler.swing_speed;
+    }
+
+    @SuppressWarnings("unused")
+    public static float getCooldownAnimationFloat(ClientPlayerEntity player, float adjustTicks) {
+        return ConfigHandler.prevent_cooldown && ConfigHandler.mod_enabled ? 1.0F : player.getCooledAttackStrength(adjustTicks);
+    }
+
+    @SuppressWarnings("unused")
+    public static boolean shouldCauseReequipAnimation(@Nonnull ItemStack from, @Nonnull ItemStack to, int slot) {
+        if (!ConfigHandler.prevent_reequip || !ConfigHandler.mod_enabled) {
+            return ForgeHooksClient.shouldCauseReequipAnimation(from, to, slot);
+        }
+
+        boolean fromInvalid = from.isEmpty();
+        boolean toInvalid = to.isEmpty();
+
+        if (fromInvalid && toInvalid) return false;
+        if (fromInvalid || toInvalid) return true;
+
+        return !ItemStack.areItemsEqualIgnoreDurability(from, to);
+    }
+
+    @SuppressWarnings("unused")
+    public static void armSway(MatrixStack matrixStackIn, Quaternion quaternion) {
+        if (!ConfigHandler.prevent_sway || !ConfigHandler.mod_enabled) {
+            matrixStackIn.rotate(quaternion);
+            matrixStackIn.rotate(quaternion);
+        }
+    }
+}

+ 3 - 0
src/main/resources/META-INF/coremods.json

@@ -0,0 +1,3 @@
+{
+  "OldSwing Transformer": "oldswing-transformer.js"
+}

+ 31 - 0
src/main/resources/META-INF/mods.toml

@@ -0,0 +1,31 @@
+# The name of the mod loader type to load - for regular FML @Mod mods it should be javafml
+modLoader="javafml" #mandatory
+# A version range to match for said mod loader - for regular FML @Mod it will be the forge version
+loaderVersion="[34,)" #mandatory This is typically bumped every Minecraft version by Forge. See our download page for lists of versions.
+# The license for you mod. This is mandatory metadata and allows for easier comprehension of your redistributive properties.
+# Review your options at https://choosealicense.com/. All rights reserved is the default copyright stance, and is thus the default here.
+license="LGPLv3"
+# A URL to refer people to when problems occur with this mod
+issueTrackerURL="https://github.com/Adrenix/OldSwing/issues" #optional
+# A list of mods - how many allowed here is determined by the individual mod loader
+[[mods]] #mandatory
+# The modid of the mod
+modId="oldswing" #mandatory
+# The version number of the mod - there's a few well known ${} variables useable here or just hardcode it
+version="${file.jarVersion}" #mandatory
+ # A display name for the mod
+displayName="Old Swing Mod" #mandatory
+# A URL to query for updates for this mod. See the JSON update specification <here>
+# updateJSONURL="http://myurl.me/" #optional
+# A URL for the "homepage" for this mod, displayed in the mod UI
+displayURL="https://github.com/Adrenix/OldSwing" #optional
+# A file name (in the root of the mod JAR) containing a logo for display
+logoFile="oldswing-logo.png" #optional
+# A text field displayed in the mod UI
+#credits="Thanks for this example mod goes to Java" #optional
+# A text field displayed in the mod UI
+authors="Adrenix" #optional
+# The description text for the mod (multi line!) (#mandatory)
+description='''
+Brings back the old swinging animations before Minecraft Beta 1.8.
+'''

BIN
src/main/resources/oldswing-logo.png


+ 144 - 0
src/main/resources/oldswing-transformer.js

@@ -0,0 +1,144 @@
+function initializeCoreMod() {
+    function debug(msg) {
+        Java.type('net.minecraftforge.coremod.api.ASMAPI').log("DEBUG", "[oldswing] " + msg);
+    }
+
+    /*Class/Interface*/ Opcodes = Java.type("org.objectweb.asm.Opcodes");
+    /*Class*/ ASM_API = Java.type("net.minecraftforge.coremod.api.ASMAPI");
+    /*Class*/ MethodInsnNode = Java.type("org.objectweb.asm.tree.MethodInsnNode");
+
+    return {
+        "LivingEntity#getArmSwingAnimationEnd": {
+            "target": {
+                "type": "METHOD",
+                "class": "net.minecraft.entity.LivingEntity",
+                "methodName": "func_82166_i",
+                "methodDesc": "()I"
+            },
+            "transformer": function(method) {
+                debug("Running LivingEntity#getArmSwingAnimationEnd transformer...");
+
+                for (var i = 0; i < method.instructions.size(); i++) {
+                    var instruction = method.instructions.get(i);
+
+                    if (instruction.getOpcode() == Opcodes.BIPUSH) {
+                        if (instruction.operand == 6) {
+                            method.instructions.set(instruction, new MethodInsnNode(
+                                Opcodes.INVOKESTATIC,
+                                "mod/adrenix/oldswing/config/TransformerHelper",
+                                "swingSpeed",
+                                "()I"
+                            ));
+
+                            debug("Swapped an operand from 6 to TransformerHelper.swingSpeed method");
+                        }
+                    }
+                }
+
+                return method;
+            }
+        },
+
+        "FirstPersonRenderer#renderItemInFirstPerson": {
+            "target": {
+                "type": "METHOD",
+                "class": "net.minecraft.client.renderer.FirstPersonRenderer",
+                "methodName": "func_228396_a_",
+                "methodDesc": "(FLcom/mojang/blaze3d/matrix/MatrixStack;Lnet/minecraft/client/renderer/IRenderTypeBuffer$Impl;Lnet/minecraft/client/entity/player/ClientPlayerEntity;I)V"
+            },
+            "transformer": function(method) {
+                debug("Running FirstPersonRenderer#renderItemInFirstPerson transformer...");
+
+                var isArmPitchHooked = false;
+                var isArmYawHooked = false;
+
+                for (var i = 0; i < method.instructions.size(); i++) {
+                    if (isArmPitchHooked && isArmYawHooked) { break; }
+
+                    var instruction = method.instructions.get(i);
+                    if (instruction.getOpcode() == Opcodes.FMUL && instruction.getNext().getOpcode() == Opcodes.INVOKEVIRTUAL) {
+                        // matrixStackIn.rotate(Vector3f.XP.rotationDegrees((playerEntityIn.getPitch(partialTicks) - f3) * 0.1F));
+                        // matrixStackIn.rotate(Vector3f.YP.rotationDegrees((playerEntityIn.getYaw(partialTicks) - f4) * 0.1F));
+
+                        method.instructions.set(instruction.getNext().getNext(), new MethodInsnNode(
+                            Opcodes.INVOKESTATIC,
+                            "mod/adrenix/oldswing/config/TransformerHelper",
+                            "armSway",
+                            "(Lcom/mojang/blaze3d/matrix/MatrixStack;Lnet/minecraft/util/math/vector/Quaternion;)V",
+                            false
+                        ));
+
+                        if (!isArmPitchHooked && !isArmYawHooked) {
+                            isArmPitchHooked = true;
+                            debug("Successfully hooked arm pitch");
+                        } else if (!isArmYawHooked) {
+                            isArmYawHooked = true;
+                            debug("Successfully hooked arm yaw");
+                        }
+                    }
+                }
+
+                return method;
+            }
+        },
+
+        "FirstPersonRenderer#tick": {
+            "target": {
+                "type": "METHOD",
+                "class": "net.minecraft.client.renderer.FirstPersonRenderer",
+                "methodName": "func_78441_a",
+                "methodDesc": "()V"
+            },
+            "transformer": function(method) {
+                debug("Running FirstPersonRenderer#tick transformer...");
+
+                var isFloatChanged = false;
+                var isReequipChangedMain = false;
+                var isReequipChangedOff = false;
+
+                for (var i = 0; i < method.instructions.size(); i++) {
+                    if (isFloatChanged && isReequipChangedMain && isReequipChangedOff) { break; }
+
+                    var instruction = method.instructions.get(i);
+                    if (!isFloatChanged && instruction.getOpcode() == Opcodes.ALOAD && instruction.var == 1) {
+                        if (instruction.getNext().getOpcode() == Opcodes.FCONST_1) {
+                            var instruction = instruction.getNext().getNext();
+                            if (instruction.getOpcode() == Opcodes.INVOKEVIRTUAL) {
+                                method.instructions.set(instruction, new MethodInsnNode(
+                                    Opcodes.INVOKESTATIC,
+                                    "mod/adrenix/oldswing/config/TransformerHelper",
+                                    "getCooldownAnimationFloat",
+                                    "(Lnet/minecraft/client/entity/player/ClientPlayerEntity;F)F",
+                                    false
+                                ));
+
+                                isFloatChanged = true;
+                                debug("Successfully reassigned getCooledAttackStrength to TransformerHelper getCooldownAnimationFloat");
+                            }
+                        }
+                    } else if (isFloatChanged && (instruction.getOpcode() == Opcodes.GETFIELD || instruction.getOpcode() == Opcodes.ICONST_M1)) {
+                        if (instruction.getNext().getOpcode() == Opcodes.INVOKESTATIC) {
+                            method.instructions.set(instruction.getNext(), new MethodInsnNode(
+                                Opcodes.INVOKESTATIC,
+                                "mod/adrenix/oldswing/config/TransformerHelper",
+                                "shouldCauseReequipAnimation",
+                                "(Lnet/minecraft/item/ItemStack;Lnet/minecraft/item/ItemStack;I)Z",
+                                false
+                            ));
+
+                            if (!isReequipChangedMain && !isReequipChangedOff) {
+                                isReequipChangedMain = true;
+                                debug("Successfully reassigned shouldCauseReequipAnimation to TransformerHelper for Main");
+                            } else if (!isReequipChangedOff) {
+                                isReequipChangedOff = true;
+                                debug("Successfully reassigned shouldCauseReequipAnimation to TransformerHelper for Off");
+                            }
+                        }
+                    }
+                }
+
+                return method;
+            }
+        }
+    };
+}

+ 7 - 0
src/main/resources/pack.mcmeta

@@ -0,0 +1,7 @@
+{
+    "pack": {
+        "description": "Old swing mod resources",
+        "pack_format": 6,
+        "_comment": "A pack_format of 6 requires json lang files and some texture changes from 1.16.2. Note: we require v6 pack meta for all mods."
+    }
+}