diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml
new file mode 100644
index 0000000..ce5d912
--- /dev/null
+++ b/.github/workflows/gradle.yml
@@ -0,0 +1,29 @@
+name: Build
+
+on:
+ push:
+ branches:
+ - master
+ pull_request:
+ branches:
+ - master
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v2
+ - name: Set up JDK 1.8
+ uses: actions/setup-java@v1
+ with:
+ java-version: 1.8
+ - name: Grant execute permission for gradlew
+ run: chmod +x gradlew
+ - name: Build with Gradle
+ run: ./gradlew build
+ - name: Upload jar
+ uses: actions/upload-artifact@v1
+ with:
+ name: Artifacts
+ path: build/libs/
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ead6b55
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,24 @@
+# eclipse
+bin
+*.launch
+.settings
+.metadata
+.classpath
+.project
+
+# idea
+out
+*.ipr
+*.iws
+*.iml
+.idea
+
+# gradle
+build
+.gradle
+
+# other
+eclipse
+run
+*.psd
+*.bat
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..a8ca584
--- /dev/null
+++ b/README.md
@@ -0,0 +1,36 @@
+# **Toolbreak Warning**
+> With this plugin you can prevent breaking your expensive tools, especially when you're mining with high efficiency enchantments and/or haste.
+
+### You can customize these Settings:
+- If the addon is enabled or not
+- The message that pops up, when your tool's durability is low
+- At what percentage of durability the warning should come (customizable for each tooltype)
+
+### Installation
+1. Press `Win` + `R`
+2. Paste this into the window that popped up: `%appdata%/.minecraft/LabyMod/addons-1.12` and press enter
+3. It should open your Labymod addon directory; Paste the [Toolbreak_Warning.jar](https://github.com/RappyTV/Toolbreak-Warning/releases/download/1.0.0/Toolbreak_Warning.jar) in there.
+4. Launch your Labymod client.
+
+If you have any problems with the addon/have update ideas, feel free to
+- Open an Issue [here](https://github.com/RappyTV/Toolbreak-Warning/issues/new/choose)
+ or
+- Open a ticket on my [Discord Server](https://rappytv.com/server) in [this](https://discord.com/channels/815912035124248587/840285653946204181) channel
+
+---
+
+### Social Networks
+
+[][website]
+[][youtube]
+[][instagram]
+[][dcServer]
+[][tiktok]
+
+[website]: https://rappytv.com/
+[youtube]: https://youtube.com/c/RappyTVTutorials
+[instagram]: https://instagram.com/rappyytv
+[dcbotplaylist]: https://youtube.com/playlist?list=PL-NddfqjbJVZ2-CGquW0I42J9IGUkXq12
+[dcServer]: https://rappytv.com/server
+[dcBot]: https://rappytv.com/bot
+[tiktok]: https://tiktok.com/@rappytv
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..7dbf167
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,83 @@
+buildscript {
+ repositories {
+ jcenter()
+ maven { url = "http://files.minecraftforge.net/maven" }
+ }
+ dependencies {
+ classpath 'net.minecraftforge.gradle:ForgeGradle:2.3-SNAPSHOT'
+ }
+}
+apply plugin: 'net.minecraftforge.gradle.forge'
+//Only edit below this line, the above code adds and enables the necessary things for Forge to be setup.
+
+
+version = "1.0"
+group = "com.yourname.modid" // http://maven.apache.org/guides/mini/guide-naming-conventions.html
+archivesBaseName = "modid"
+
+sourceCompatibility = targetCompatibility = '1.8' // Need this here so eclipse task generates correctly.
+compileJava {
+ sourceCompatibility = targetCompatibility = '1.8'
+}
+
+minecraft {
+ version = "1.12.2-14.23.5.2768"
+ runDir = "run"
+
+ // 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 = "snapshot_20171003"
+ // makeObfSourceJar = false // an Srg named sources jar is made by default. uncomment this to disable.
+}
+
+dependencies {
+ // 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'
+
+ // the deobf configurations: 'deobfCompile' and 'deobfProvided' are the same as the normal compile and provided,
+ // except that these dependencies get remapped to your current MCP mappings
+ //deobfCompile 'com.mod-buildcraft:buildcraft:6.0.8:dev'
+ //deobfProvided '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
+
+}
+
+processResources {
+ // this will ensure that this task is redone when the versions change.
+ inputs.property "version", project.version
+ inputs.property "mcversion", project.minecraft.version
+
+ // replace stuff in mcmod.info, nothing else
+ from(sourceSets.main.resources.srcDirs) {
+ include 'mcmod.info'
+
+ // replace version and mcversion
+ expand 'version':project.version, 'mcversion':project.minecraft.version
+ }
+
+ // copy everything else except the mcmod.info
+ from(sourceSets.main.resources.srcDirs) {
+ exclude 'mcmod.info'
+ }
+}
+
+reobf {
+ jar {
+ useNotchSrg()
+ }
+}
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000..e9b9fd5
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,3 @@
+# 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
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..30d399d
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..e18cba7
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Mon Sep 14 12:28:28 PDT 2015
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.14-bin.zip
diff --git a/gradlew b/gradlew
new file mode 100644
index 0000000..91a7e26
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,164 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# 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
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+ [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+# 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\"`/" >&-
+APP_HOME="`pwd -P`"
+cd "$SAVED" >&-
+
+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" ] ; 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"`
+
+ # 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
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/libs/labymod-1.12.2.jar b/libs/labymod-1.12.2.jar
new file mode 100644
index 0000000..4e8e162
Binary files /dev/null and b/libs/labymod-1.12.2.jar differ
diff --git a/src/main/java/com/rappytv/prevtb/events/ToolUse.java b/src/main/java/com/rappytv/prevtb/events/ToolUse.java
new file mode 100644
index 0000000..91d7491
--- /dev/null
+++ b/src/main/java/com/rappytv/prevtb/events/ToolUse.java
@@ -0,0 +1,32 @@
+package com.rappytv.prevtb.events;
+
+import com.rappytv.prevtb.main.Main;
+import com.rappytv.prevtb.util.Util;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.item.ItemStack;
+import net.minecraftforge.event.world.BlockEvent;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+
+public class ToolUse {
+
+ @SubscribeEvent
+ public void onUse(BlockEvent.BreakEvent e) {
+ if(!Main.enabled) return;
+ EntityPlayer p = e.getPlayer();
+ ItemStack i = p.getHeldItemMainhand();
+
+ if(i == null) return;
+ if(!i.isItemStackDamageable()) return;
+ if(p.isCreative()) return;
+
+ if(Util.isPickaxe(i)) {
+ Util.pickaxeUsed(i);
+ }
+ else if(Util.isAxe(i)) {
+ Util.axeUsed(i);
+ }
+ else if(Util.isShovel(i)) {
+ Util.shovelUsed(i);
+ }
+ }
+}
diff --git a/src/main/java/com/rappytv/prevtb/main/Main.java b/src/main/java/com/rappytv/prevtb/main/Main.java
new file mode 100644
index 0000000..bd0127f
--- /dev/null
+++ b/src/main/java/com/rappytv/prevtb/main/Main.java
@@ -0,0 +1,140 @@
+package com.rappytv.prevtb.main;
+
+import com.rappytv.prevtb.events.ToolUse;
+import net.labymod.api.LabyModAddon;
+import net.labymod.settings.elements.*;
+import net.labymod.utils.Consumer;
+import net.labymod.utils.Material;
+
+import java.util.List;
+
+public class Main extends LabyModAddon {
+
+ public static boolean enabled = true;
+ public static String warnMsg = "\u00A7cDo you really want to continue using this tool? Its durability is {durability}%!";
+ public static int warnPercentagePickaxe = 5;
+ public static int warnPercentageAxe = 5;
+ public static int warnPercentageShovel = 5;
+ public static Main instance;
+
+ @Override
+ public void onEnable() {
+ // Sets the instance
+ instance = this;
+
+ getApi().registerForgeListener(new ToolUse());
+ }
+
+ @Override
+ public void loadConfig() {
+ enabled = !getConfig().has("warn.enabled") || getConfig().get("warn.enabled").getAsBoolean();
+ warnMsg = getConfig().has("warn.warnmsg") ? getConfig().get("warn.warnmsg").getAsString() : warnMsg;
+
+ warnPercentagePickaxe = getConfig().has("warn.pick") ? getConfig().get("warn.pick").getAsInt() : warnPercentagePickaxe;
+ warnPercentageAxe = getConfig().has("warn.axe") ? getConfig().get("warn.axe").getAsInt() : warnPercentageAxe;
+ warnPercentageShovel = getConfig().has("warn.shovel") ? getConfig().get("warn.shovel").getAsInt() : warnPercentageShovel;
+ }
+
+ @Override
+ protected void fillSettings(List list) {
+ BooleanElement enabledBool = new BooleanElement("Enabled", new ControlElement.IconData(Material.LEVER), new Consumer() {
+
+ @Override
+ public void accept(Boolean accepted) {
+ enabled = accepted;
+
+ getConfig().addProperty("warn.enabled", enabled);
+ saveConfig();
+ }
+ }, enabled);
+
+ StringElement warnmsg = new StringElement("Warn Message", new ControlElement.IconData(Material.REDSTONE_TORCH_ON), warnMsg, new Consumer() {
+
+ @Override
+ public void accept(String accepted) {
+ warnMsg = accepted;
+
+ getConfig().addProperty("warn.msg", warnMsg);
+ saveConfig();
+ }
+ });
+
+ SliderElement pickSlider = new SliderElement("Pickaxe Warn Percentage",
+ new ControlElement.IconData(Material.IRON_PICKAXE), warnPercentagePickaxe);
+ SliderElement axeSlider = new SliderElement( "Axe Warn Percentage",
+ new ControlElement.IconData(Material.IRON_AXE), warnPercentageAxe);
+ SliderElement spadeSlider = new SliderElement( "Shovel Warn Percentage",
+ new ControlElement.IconData(Material.IRON_SPADE), warnPercentageShovel);
+
+ {
+ // Setting the slider's min & max values
+ pickSlider.setRange(1, 25);
+
+ // Setting slider steps
+ pickSlider.setSteps(1);
+
+ // Adding change listener
+ pickSlider.addCallback(new Consumer() {
+
+ @Override
+ public void accept(Integer accepted) {
+ warnPercentagePickaxe = accepted;
+
+ getConfig().addProperty("warn.pick", warnPercentagePickaxe);
+ saveConfig();
+ }
+ });
+ }
+
+ {
+ // Setting the slider's min & max values
+ axeSlider.setRange(1, 25);
+
+ // Setting slider steps
+ axeSlider.setSteps(1);
+
+ // Adding change listener
+ axeSlider.addCallback(new Consumer() {
+
+ @Override
+ public void accept(Integer accepted) {
+ warnPercentageAxe = accepted;
+
+ getConfig().addProperty("warn.axe", warnPercentageAxe);
+ saveConfig();
+ }
+ });
+ }
+
+ {
+ // Setting the slider's min & max values
+ spadeSlider.setRange(1, 25);
+
+ // Setting slider steps
+ spadeSlider.setSteps(1);
+
+ // Adding change listener
+ spadeSlider.addCallback(new Consumer() {
+
+ @Override
+ public void accept(Integer accepted) {
+ warnPercentageShovel = accepted;
+
+ getConfig().addProperty("warn.shovel", warnPercentageShovel);
+ saveConfig();
+ }
+ });
+ }
+
+ // Adding setting
+ list.add(enabledBool);
+ list.add(warnmsg);
+ list.add(pickSlider);
+ list.add(axeSlider);
+ list.add(spadeSlider);
+ }
+
+ public static Main getMain() {
+ return instance;
+ }
+}
diff --git a/src/main/java/com/rappytv/prevtb/util/Util.java b/src/main/java/com/rappytv/prevtb/util/Util.java
new file mode 100644
index 0000000..b15dac6
--- /dev/null
+++ b/src/main/java/com/rappytv/prevtb/util/Util.java
@@ -0,0 +1,61 @@
+package com.rappytv.prevtb.util;
+
+import com.rappytv.prevtb.main.Main;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiChat;
+import net.minecraft.item.*;
+
+public class Util {
+
+ public static void msg(String text) {
+ Main.getMain().getApi().displayMessageInChat(text);
+ }
+
+ public static boolean isAxe(ItemStack i) {
+ return i.getItem() instanceof ItemAxe;
+ }
+
+ public static boolean isPickaxe(ItemStack i) {
+ return i.getItem() instanceof ItemPickaxe;
+ }
+
+ public static boolean isShovel(ItemStack i) {
+ return i.getItem() instanceof ItemSpade;
+ }
+
+ public static void pickaxeUsed(ItemStack itemStack) {
+ Item i = itemStack.getItem();
+
+ int itemWarnInt = (Main.warnPercentagePickaxe * i.getMaxDamage(itemStack)) / 100;
+ int itemUsedInt = i.getMaxDamage(itemStack) - i.getDamage(itemStack);
+
+ if(itemUsedInt == itemWarnInt) {
+ msg(Main.warnMsg.replace("{durability}", Main.warnPercentagePickaxe + ""));
+ Minecraft.getMinecraft().displayGuiScreen(new GuiChat());
+ }
+ }
+
+ public static void axeUsed(ItemStack itemStack) {
+ Item i = itemStack.getItem();
+
+ int itemWarnInt = (Main.warnPercentageAxe * i.getMaxDamage(itemStack)) / 100;
+ int itemUsedInt = i.getMaxDamage(itemStack) - i.getDamage(itemStack);
+
+ if(itemUsedInt == itemWarnInt) {
+ msg(Main.warnMsg.replace("{durability}", Main.warnPercentageAxe + ""));
+ Minecraft.getMinecraft().displayGuiScreen(new GuiChat());
+ }
+ }
+
+ public static void shovelUsed(ItemStack itemStack) {
+ Item i = itemStack.getItem();
+
+ int itemWarnInt = (Main.warnPercentageShovel * i.getMaxDamage(itemStack)) / 100;
+ int itemUsedInt = i.getMaxDamage(itemStack) - i.getDamage(itemStack);
+
+ if(itemUsedInt == itemWarnInt) {
+ msg(Main.warnMsg.replace("{durability}", Main.warnPercentageShovel + ""));
+ Minecraft.getMinecraft().displayGuiScreen(new GuiChat());
+ }
+ }
+}
diff --git a/src/main/resources/addon.json b/src/main/resources/addon.json
new file mode 100644
index 0000000..8358bab
--- /dev/null
+++ b/src/main/resources/addon.json
@@ -0,0 +1,10 @@
+{
+ "uuid": "%uuid%",
+ "name": "ToolBreak Warning",
+ "mainClass": "com.rappytv.prevtb.main.Main",
+ "description": "Stops you from using your currently used tool when its almost destroyed. [CUSTOMIZABLE]",
+ "version": 1.0,
+ "author": "RappyTV#6969",
+ "category": 2,
+ "icon": "https://cdn.discordapp.com/attachments/962708390805655593/974731356137467995/icon.png"
+}
\ No newline at end of file
diff --git a/src/main/resources/icon.png b/src/main/resources/icon.png
new file mode 100644
index 0000000..604f684
Binary files /dev/null and b/src/main/resources/icon.png differ