diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..a03fe74 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,42 @@ +# Automatically build the project and run any configured tests for every push +# and submitted pull request. This can help catch issues that only occur on +# certain platforms or Java versions, and provides a first line of defence +# against bad commits. + +name: build +on: [pull_request, push] + +jobs: + build: + strategy: + matrix: + # Use these Java versions + java: [ + 17, # Current Java LTS & minimum supported by Minecraft + ] + # and run on both Linux and Windows + os: [ubuntu-22.04, windows-2022] + runs-on: ${{ matrix.os }} + steps: + - name: checkout repository + uses: actions/checkout@v3 + - name: validate gradle wrapper + uses: gradle/wrapper-validation-action@v1 + - name: setup jdk ${{ matrix.java }} + uses: actions/setup-java@v3 + with: + java-version: ${{ matrix.java }} + distribution: 'microsoft' + - name: make gradle wrapper executable + if: ${{ runner.os != 'Windows' }} + run: chmod +x ./gradlew + - name: generate build config + run: ./gradlew generateBuildConfig + - name: build + run: ./gradlew build + - name: capture build artifacts + if: ${{ runner.os == 'Linux' && matrix.java == '17' }} # Only upload artifacts built from latest java on one OS + uses: actions/upload-artifact@v3 + with: + name: Artifacts + path: build/libs/ diff --git a/.github/workflows/todo-issue.yml b/.github/workflows/todo-issue.yml new file mode 100644 index 0000000..8dfeafd --- /dev/null +++ b/.github/workflows/todo-issue.yml @@ -0,0 +1,33 @@ +name: Create issues from TODOs + +on: + workflow_dispatch: + inputs: + importAll: + default: 'false' + required: false + type: boolean + description: Enable, if you want to import all TODOs. Runs on checked out branch! Only use if you're sure what you are doing. + push: + branches: # do not set multiple branches, todos might be added and then get referenced by themselves in case of a merge + - main + - master + +permissions: + issues: write + repository-projects: read + contents: read + +jobs: + todos: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - name: Run Issue Bot + uses: derjuulsn/todo-issue@main + with: + excludePattern: '^(node_modules/)' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c476faf --- /dev/null +++ b/.gitignore @@ -0,0 +1,40 @@ +# gradle + +.gradle/ +build/ +out/ +classes/ + +# eclipse + +*.launch + +# idea + +.idea/ +*.iml +*.ipr +*.iws + +# vscode + +.settings/ +.vscode/ +bin/ +.classpath +.project + +# macos + +*.DS_Store + +# fabric + +run/ + +# java + +hs_err_*.log +replay_*.log +*.hprof +*.jfr diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..0e259d4 --- /dev/null +++ b/LICENSE @@ -0,0 +1,121 @@ +Creative Commons Legal Code + +CC0 1.0 Universal + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator +and subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for +the purpose of contributing to a commons of creative, cultural and +scientific works ("Commons") that the public can reliably and without fear +of later claims of infringement build upon, modify, incorporate in other +works, reuse and redistribute as freely as possible in any form whatsoever +and for any purposes, including without limitation commercial purposes. +These owners may contribute to the Commons to promote the ideal of a free +culture and the further production of creative, cultural and scientific +works, or to gain reputation or greater distribution for their Work in +part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any +expectation of additional consideration or compensation, the person +associating CC0 with a Work (the "Affirmer"), to the extent that he or she +is an owner of Copyright and Related Rights in the Work, voluntarily +elects to apply CC0 to the Work and publicly distribute the Work under its +terms, with knowledge of his or her Copyright and Related Rights in the +Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not +limited to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); +iii. publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and +vii. other similar, equivalent or corresponding rights throughout the + world based on applicable law or treaty, and any national + implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention +of, applicable law, Affirmer hereby overtly, fully, permanently, +irrevocably and unconditionally waives, abandons, and surrenders all of +Affirmer's Copyright and Related Rights and associated claims and causes +of action, whether now known or unknown (including existing as well as +future claims and causes of action), in the Work (i) in all territories +worldwide, (ii) for the maximum duration provided by applicable law or +treaty (including future time extensions), (iii) in any current or future +medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional +purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each +member of the public at large and to the detriment of Affirmer's heirs and +successors, fully intending that such Waiver shall not be subject to +revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason +be judged legally invalid or ineffective under applicable law, then the +Waiver shall be preserved to the maximum extent permitted taking into +account Affirmer's express Statement of Purpose. In addition, to the +extent the Waiver is so judged Affirmer hereby grants to each affected +person a royalty-free, non transferable, non sublicensable, non exclusive, +irrevocable and unconditional license to exercise Affirmer's Copyright and +Related Rights in the Work (i) in all territories worldwide, (ii) for the +maximum duration provided by applicable law or treaty (including future +time extensions), (iii) in any current or future medium and for any number +of copies, and (iv) for any purpose whatsoever, including without +limitation commercial, advertising or promotional purposes (the +"License"). The License shall be deemed effective as of the date CC0 was +applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder +of the License, and in such case Affirmer hereby affirms that he or she +will not (i) exercise any of his or her remaining Copyright and Related +Rights in the Work or (ii) assert any associated claims and causes of +action with respect to the Work, in either case contrary to Affirmer's +express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. diff --git a/README.md b/README.md new file mode 100644 index 0000000..812647a --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +# paragon updated +paragon for the latest version of minecraft + +uses fabric, needs fabric api \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..249bf30 --- /dev/null +++ b/build.gradle @@ -0,0 +1,135 @@ +/** + * To anyone reading this, if you wonder why the class "BuildConfig" is not found, sync + * your gradle and open the gradle tab, other -> generateBuildConfig + * + * from yours truly, aesthetical + */ + +plugins { + id 'fabric-loom' version '1.1-SNAPSHOT' + id 'de.fuerstenau.buildconfig' version '1.1.4' + id 'org.jetbrains.kotlin.jvm' version '1.8.10' +} + +sourceCompatibility = JavaVersion.VERSION_17 +targetCompatibility = JavaVersion.VERSION_17 + +archivesBaseName = project.archives_base_name +version = project.mod_version +group = project.maven_group + +configurations { + library + noRuntimeLibrary + + // https://github.com/mfuerstenau/gradle-buildconfig-plugin/issues/30#issuecomment-910241307 + create("compile") +} + +buildConfig { + buildConfigField "String", "HASH", "${execute("git rev-parse --short HEAD")}" + buildConfigField "String", "BRANCH", "${execute("git branch").replace("* ", "")}" + buildConfigField "String", "VERSION", "${project.version}" + + packageName "com.paragon.util.BuildConfig" +} + +sourceSets.main.java.srcDirs += "build/gen/buildconfig/src/main" + +loom { + accessWidenerPath = file("src/main/resources/paragon.accesswidener") +} + +repositories { + mavenCentral() + maven { url "https://jitpack.io" } + maven { + name = "meteor-maven-snapshots" + url = "https://maven.meteordev.org/snapshots" + } +} + +dependencies { + minecraft "com.mojang:minecraft:${project.minecraft_version}" + mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" + modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" + modImplementation "net.fabricmc:fabric-language-kotlin:${project.kotlin_language_fabric}" + + // i love meteor + modImplementation "baritone:fabric:${project.baritone}" + noRuntimeLibrary "baritone:fabric:${project.baritone}" + + library platform("org.lwjgl:lwjgl-bom:3.3.1") + library "org.lwjgl:lwjgl-nanovg" + + // lets just include ALL the natives! who cares about file sizes, right? + library "org.lwjgl:lwjgl-nanovg::natives-windows" + library "org.lwjgl:lwjgl-nanovg::natives-macos" + library "org.lwjgl:lwjgl-nanovg::natives-linux" + library "org.lwjgl:lwjgl-nanovg::natives-macos-arm64" + library "org.lwjgl:lwjgl-nanovg::natives-linux-arm64" + library "org.lwjgl:lwjgl-nanovg::natives-linux-arm32" + + library "com.github.therealbush:eventbus:${project.eventbus}" + library "com.github.wolfsurge:javaanimationsystem:${project.animation_system}" + library "com.github.Litarvan:OpenAuth:${project.open_auth}" + library "org.json:json:${project.json}" + + // kotlin shit + library "org.jetbrains.kotlin:${project.kotlin}" + library "org.jetbrains.kotlinx:kotlinx-coroutines-core:${project.kotlin_coroutines}" + + implementation configurations.library +} + +processResources { + inputs.property "version", project.version + + filesMatching("fabric.mod.json") { + expand "version": project.version + } +} + +jar { + from("LICENSE") { + rename { "${it}_${project.archivesBaseName}"} + } + + // https://github.com/mfuerstenau/gradle-buildconfig-plugin/issues/30#issuecomment-910241307 + duplicatesStrategy = DuplicatesStrategy.WARN + + from(configurations.library.collect { if (it.isDirectory()) it else zipTree(it) }) +} + +tasks.withType(JavaCompile).configureEach { + it.options.release = 17 +} + +compileKotlin { + kotlinOptions { + jvmTarget = JavaVersion.VERSION_17 + } +} + +compileTestKotlin { + kotlinOptions { + jvmTarget = JavaVersion.VERSION_17 + } +} + +// functions + +def execute(String cmd) { + try { + def stdout = new ByteArrayOutputStream() + + exec { + commandLine cmd.split(" ") + standardOutput = stdout + } + + return stdout.toString().trim() + } catch (ignored) { + return null + } +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..380d350 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,26 @@ +# 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.19.3 + yarn_mappings=1.19.3+build.1 + loader_version=0.14.11 + kotlin_language_fabric=1.9.1+kotlin.1.8.10 + +# Mod Properties + mod_version = 1.0.0 + maven_group = com.example + archives_base_name = Paragon-Updated + +# Dependencies + fabric_version=0.68.1+1.19.3 + baritone=1.19.3-SNAPSHOT + eventbus=1.0.2 + animation_system=1.11 + open_auth=1.1.4 + json=20220924 + + kotlin=kotlin-stdlib-jdk8 + kotlin_coroutines=1.6.4 \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..943f0cb 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..f398c33 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip +networkTimeout=10000 +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100644 index 0000000..65dcd68 --- /dev/null +++ b/gradlew @@ -0,0 +1,244 @@ +#!/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. +# + +############################################################################## +# +# 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/subprojects/plugins/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##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# 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"' + +# 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 + 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" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + 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=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 + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +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/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..93e3f59 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,92 @@ +@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 + +@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. +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 execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +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/libraries/lwjgl-nanovg.jar b/libraries/lwjgl-nanovg.jar new file mode 100644 index 0000000..7823896 Binary files /dev/null and b/libraries/lwjgl-nanovg.jar differ diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..b02216b --- /dev/null +++ b/settings.gradle @@ -0,0 +1,10 @@ +pluginManagement { + repositories { + maven { + name = 'Fabric' + url = 'https://maven.fabricmc.net/' + } + mavenCentral() + gradlePluginPortal() + } +} diff --git a/src/main/java/com/paragon/mixin/duck/IClientConnection.java b/src/main/java/com/paragon/mixin/duck/IClientConnection.java new file mode 100644 index 0000000..c2e0b6c --- /dev/null +++ b/src/main/java/com/paragon/mixin/duck/IClientConnection.java @@ -0,0 +1,11 @@ +package com.paragon.mixin.duck; + +import net.minecraft.network.Packet; + +/** + * @author aesthetical + * @since 02/18/23 + */ +public interface IClientConnection { + void sendPacketNoEvent(Packet packet); +} diff --git a/src/main/java/com/paragon/mixin/duck/IClientPlayerInteractionManager.java b/src/main/java/com/paragon/mixin/duck/IClientPlayerInteractionManager.java new file mode 100644 index 0000000..2f26e5f --- /dev/null +++ b/src/main/java/com/paragon/mixin/duck/IClientPlayerInteractionManager.java @@ -0,0 +1,12 @@ +package com.paragon.mixin.duck; + +import net.minecraft.client.network.SequencedPacketCreator; +import net.minecraft.client.world.ClientWorld; + +/** + * @author aesthetical + * @since 02/18/23 + */ +public interface IClientPlayerInteractionManager { + void hookSendSequencedPacket(ClientWorld world, SequencedPacketCreator packetCreator); +} diff --git a/src/main/java/com/paragon/mixin/duck/IGameRenderer.java b/src/main/java/com/paragon/mixin/duck/IGameRenderer.java new file mode 100644 index 0000000..c8ff042 --- /dev/null +++ b/src/main/java/com/paragon/mixin/duck/IGameRenderer.java @@ -0,0 +1,13 @@ +package com.paragon.mixin.duck; + +import net.minecraft.client.util.math.MatrixStack; + +/** + * @author aesthetical + * @since 02/19/23 + */ +public interface IGameRenderer { + + void hookBobView(MatrixStack matrices, float tickDelta); + +} diff --git a/src/main/java/com/paragon/mixin/duck/ILivingEntity.java b/src/main/java/com/paragon/mixin/duck/ILivingEntity.java new file mode 100644 index 0000000..73c721a --- /dev/null +++ b/src/main/java/com/paragon/mixin/duck/ILivingEntity.java @@ -0,0 +1,12 @@ +package com.paragon.mixin.duck; + +/** + * @author aesthetical + * @since 02/19/23 + */ +public interface ILivingEntity { + int getLastAttackedTicks(); + + float[] getRenderRotations(); + float[] getPreviousRenderRotations(); +} diff --git a/src/main/java/com/paragon/mixin/duck/IMinecraftClient.java b/src/main/java/com/paragon/mixin/duck/IMinecraftClient.java new file mode 100644 index 0000000..2efc5e1 --- /dev/null +++ b/src/main/java/com/paragon/mixin/duck/IMinecraftClient.java @@ -0,0 +1,16 @@ +package com.paragon.mixin.duck; + +import net.minecraft.client.render.RenderTickCounter; +import net.minecraft.client.util.Session; + +/** + * @author aesthetical + * @since 02/17/23 + */ +public interface IMinecraftClient { + RenderTickCounter getRenderTickCounter(); + + void setItemUseCooldown(int itemUseCooldown); + + void setSession(Session session); +} diff --git a/src/main/java/com/paragon/mixin/duck/IMouse.java b/src/main/java/com/paragon/mixin/duck/IMouse.java new file mode 100644 index 0000000..6cd0920 --- /dev/null +++ b/src/main/java/com/paragon/mixin/duck/IMouse.java @@ -0,0 +1,11 @@ +package com.paragon.mixin.duck; + +/** + * @author surge + * @since 24/02/2023 + */ +public interface IMouse { + + double getScrollDelta(); + +} diff --git a/src/main/java/com/paragon/mixin/duck/IPlayerInteractEntityC2SPacket.java b/src/main/java/com/paragon/mixin/duck/IPlayerInteractEntityC2SPacket.java new file mode 100644 index 0000000..4eadeb8 --- /dev/null +++ b/src/main/java/com/paragon/mixin/duck/IPlayerInteractEntityC2SPacket.java @@ -0,0 +1,14 @@ +package com.paragon.mixin.duck; + +import net.minecraft.entity.Entity; +import net.minecraft.network.packet.c2s.play.PlayerInteractEntityC2SPacket; + +/** + * @author aesthetical + * @since 02/17/23 + */ +public interface IPlayerInteractEntityC2SPacket { + PlayerInteractEntityC2SPacket.InteractType getType(); + + Entity getEntity(); +} diff --git a/src/main/java/com/paragon/mixin/duck/IRenderTickCounter.java b/src/main/java/com/paragon/mixin/duck/IRenderTickCounter.java new file mode 100644 index 0000000..1b89ab6 --- /dev/null +++ b/src/main/java/com/paragon/mixin/duck/IRenderTickCounter.java @@ -0,0 +1,12 @@ +package com.paragon.mixin.duck; + +/** + * @author aesthetical + * @since 02/17/23 + */ +public interface IRenderTickCounter { + + void setTickLength(float tickLength); + float getTickLength(); + +} diff --git a/src/main/java/com/paragon/mixin/duck/IVec3d.java b/src/main/java/com/paragon/mixin/duck/IVec3d.java new file mode 100644 index 0000000..47125d6 --- /dev/null +++ b/src/main/java/com/paragon/mixin/duck/IVec3d.java @@ -0,0 +1,16 @@ +package com.paragon.mixin.duck; + +/** + * @author aesthetical + * @since 02/17/23 + */ +public interface IVec3d { + + void setX(double xIn); + void setY(double yIn); + void setZ(double zIn); + + void set(double xIn, double yIn, double zIn); + void set(double xIn, double zIn); + +} diff --git a/src/main/java/com/paragon/mixin/mixins/MinecraftClientMixin.java b/src/main/java/com/paragon/mixin/mixins/MinecraftClientMixin.java new file mode 100644 index 0000000..d162220 --- /dev/null +++ b/src/main/java/com/paragon/mixin/mixins/MinecraftClientMixin.java @@ -0,0 +1,94 @@ +package com.paragon.mixin.mixins; + +import com.paragon.Paragon; +import com.paragon.backend.event.events.mc.ShutdownEvent; +import com.paragon.backend.event.events.mc.TickEvent; +import com.paragon.backend.event.events.mc.TitleEvent; +import com.paragon.backend.event.events.render.FPSLimitEvent; +import com.paragon.backend.event.events.render.SetScreenEvent; +import com.paragon.mixin.duck.IMinecraftClient; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.client.render.RenderTickCounter; +import net.minecraft.client.util.Session; +import net.minecraft.client.world.ClientWorld; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +/** + * @author surge, aesthetical + * @since 11/02/2023 + */ +@Mixin(MinecraftClient.class) +public class MinecraftClientMixin implements IMinecraftClient { + + @Shadow public ClientWorld world; + @Shadow public ClientPlayerEntity player; + @Shadow public Screen currentScreen; + + @Shadow private int itemUseCooldown; + + @Shadow @Final + private RenderTickCounter renderTickCounter; + + @Shadow @Final @Mutable + private Session session; + + @Inject(method = "tick", at = @At("TAIL")) + public void hookOnTick(CallbackInfo ci) { + if (world != null && player != null) { + Paragon.bus.post(new TickEvent()); + } + } + + @Inject(method = "close", at = @At("HEAD")) + public void hookClose(CallbackInfo ci) { + Paragon.bus.post(new ShutdownEvent()); + } + + @Inject(method = "getWindowTitle", at = @At("RETURN"), cancellable = true) + public void hookGetWindowTitle(CallbackInfoReturnable info) { + TitleEvent event = new TitleEvent(info.getReturnValue()); + Paragon.bus.post(event); + info.setReturnValue(event.title); + } + + @Inject(method = "setScreen", at = @At("HEAD")) + public void hookSetScreen(Screen screen, CallbackInfo info) { + Paragon.bus.post(new SetScreenEvent(currentScreen, screen)); + } + + @Inject(method = "getFramerateLimit", at = @At("HEAD"), cancellable = true) + public void hookGetFramerateLimit(CallbackInfoReturnable cir) { + FPSLimitEvent event = new FPSLimitEvent(); + Paragon.bus.post(event); + + if (event.isCancelled()) { + cir.cancel(); + cir.setReturnValue(event.getLimit()); + } + } + + @Override + public RenderTickCounter getRenderTickCounter() { + return renderTickCounter; + } + + @Override + public void setItemUseCooldown(int itemUseCooldown) { + this.itemUseCooldown = itemUseCooldown; + } + + @Override + public void setSession(Session session) { + this.session = session; + } + +} diff --git a/src/main/java/com/paragon/mixin/mixins/MixinSplashTextResourceSupplier.java b/src/main/java/com/paragon/mixin/mixins/MixinSplashTextResourceSupplier.java new file mode 100644 index 0000000..c55e589 --- /dev/null +++ b/src/main/java/com/paragon/mixin/mixins/MixinSplashTextResourceSupplier.java @@ -0,0 +1,16 @@ +package com.paragon.mixin.mixins; + +import net.minecraft.client.resource.SplashTextResourceSupplier; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(SplashTextResourceSupplier.class) +public class MixinSplashTextResourceSupplier { + + @Inject(method = "get", at = @At("HEAD"), cancellable = true) + public void hookGet(CallbackInfoReturnable info) { + + } +} diff --git a/src/main/java/com/paragon/mixin/mixins/entity/MixinClientPlayerEntity.java b/src/main/java/com/paragon/mixin/mixins/entity/MixinClientPlayerEntity.java new file mode 100644 index 0000000..3abccd7 --- /dev/null +++ b/src/main/java/com/paragon/mixin/mixins/entity/MixinClientPlayerEntity.java @@ -0,0 +1,165 @@ +package com.paragon.mixin.mixins.entity; + +import com.mojang.authlib.GameProfile; +import com.paragon.Paragon; +import com.paragon.backend.event.EventEra; +import com.paragon.backend.event.events.input.control.ItemSlowdownEvent; +import com.paragon.backend.event.events.input.control.SneakSlowdownEvent; +import com.paragon.backend.event.events.move.MoveEvent; +import com.paragon.backend.event.events.move.MoveUpdateEvent; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.input.Input; +import net.minecraft.client.network.AbstractClientPlayerEntity; +import net.minecraft.client.network.ClientPlayNetworkHandler; +import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.entity.MovementType; +import net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket; +import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +/** + * @author aesthetical + * @since 02/17/23 + */ +@Mixin(ClientPlayerEntity.class) +public abstract class MixinClientPlayerEntity extends AbstractClientPlayerEntity { + + @Shadow private double lastX; + @Shadow private double lastBaseY; + @Shadow private double lastZ; + @Shadow private float lastYaw; + @Shadow private float lastPitch; + + @Shadow private boolean lastSneaking; + @Shadow private boolean lastOnGround; + @Shadow private boolean autoJumpEnabled; + + @Shadow @Final protected MinecraftClient client; + @Shadow @Final public ClientPlayNetworkHandler networkHandler; + @Shadow public Input input; + + @Shadow private int ticksSinceLastPositionPacketSent; + + public MixinClientPlayerEntity(ClientWorld world, GameProfile profile) { + super(world, profile); + } + + @Shadow protected abstract boolean isCamera(); + @Shadow protected abstract void sendSprintingPacket(); + + @Shadow public float renderPitch; + + @Inject(method = "sendMovementPackets", at = @At("HEAD"), cancellable = true) + public void hookSendMovementPacketsPre(CallbackInfo info) { + MoveUpdateEvent event = new MoveUpdateEvent(EventEra.PRE, + getX(), getY(), getZ(), getYaw(), getPitch(), isOnGround()); + if (Paragon.bus.post(event)) { + info.cancel(); + handleMovementPackets(event); + } + } + + @Inject(method = "sendMovementPackets", at = @At("TAIL")) + public void hookSendMovementPacketsPost(CallbackInfo info) { + Paragon.bus.post(new MoveUpdateEvent(EventEra.POST, + getX(), getY(), getZ(), getYaw(), getPitch(), isOnGround())); + } + + @Redirect( + method = "tickMovement", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/network/ClientPlayerEntity;isUsingItem()Z", + ordinal = 0)) + public boolean hookTickMovement(ClientPlayerEntity instance) { + if (Paragon.bus.post(new ItemSlowdownEvent((ClientPlayerEntity) (Object) this))) { + return false; + } + + return instance.isUsingItem(); + } + + @Inject(method = "shouldSlowDown", at = @At("HEAD"), cancellable = true) + public void hookShouldSlowDown(CallbackInfoReturnable info) { + if (Paragon.bus.post(new SneakSlowdownEvent((ClientPlayerEntity) (Object) this))) { + info.setReturnValue(false); + } + } + + @Redirect( + method = "move", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/network/AbstractClientPlayerEntity;move(Lnet/minecraft/entity/MovementType;Lnet/minecraft/util/math/Vec3d;)V")) + public void redirectMove$Move(AbstractClientPlayerEntity instance, MovementType movementType, Vec3d vec3d) { + MoveEvent event = new MoveEvent(vec3d); + Paragon.bus.post(event); + super.move(movementType, event.getMotionVec()); + } + + private void handleMovementPackets(MoveUpdateEvent event) { + + sendSprintingPacket(); + + if (isSneaking() != lastSneaking) { + networkHandler.sendPacket(new ClientCommandC2SPacket(this, isSneaking() + ? ClientCommandC2SPacket.Mode.PRESS_SHIFT_KEY : ClientCommandC2SPacket.Mode.RELEASE_SHIFT_KEY)); + lastSneaking = isSneaking(); + } + + if (isCamera()) { + double d = event.x - lastX; + double e = event.y - lastBaseY; + double f = event.z - lastZ; + double g = event.yaw - lastYaw; + double h = event.pitch - lastPitch; + + ++ticksSinceLastPositionPacketSent; + + boolean moved = MathHelper.squaredMagnitude(d, e, f) > MathHelper.square(2.0E-4) || ticksSinceLastPositionPacketSent >= 20; + boolean rotated = g != 0.0 || h != 0.0; + + if (hasVehicle()) { + Vec3d vec3d = getVelocity(); + networkHandler.sendPacket(new PlayerMoveC2SPacket.Full(vec3d.x, -999.0, vec3d.z, event.yaw, event.pitch, event.onGround)); + moved = false; + } else if (moved && rotated) { + networkHandler.sendPacket(new PlayerMoveC2SPacket.Full(event.x, event.y, event.z, event.yaw, event.pitch, event.onGround)); + } else if (moved) { + networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(event.x, event.y, event.z, event.onGround)); + } else if (rotated) { + networkHandler.sendPacket(new PlayerMoveC2SPacket.LookAndOnGround(event.yaw, event.pitch, event.onGround)); + } else if (lastOnGround != event.onGround) { + networkHandler.sendPacket(new PlayerMoveC2SPacket.OnGroundOnly(event.onGround)); + } + + if (moved) { + lastX = event.x; + lastBaseY = event.y; + lastZ = event.z; + ticksSinceLastPositionPacketSent = 0; + } + + if (rotated) { + lastYaw = event.yaw; + lastPitch = event.pitch; + } + + lastOnGround = onGround; + autoJumpEnabled = client.options.getAutoJump().getValue(); + } + + Paragon.bus.post(new MoveUpdateEvent(EventEra.POST, + event.x, event.y, event.z, event.yaw, event.pitch, event.onGround)); + } +} diff --git a/src/main/java/com/paragon/mixin/mixins/entity/MixinLivingEntity.java b/src/main/java/com/paragon/mixin/mixins/entity/MixinLivingEntity.java new file mode 100644 index 0000000..24622a9 --- /dev/null +++ b/src/main/java/com/paragon/mixin/mixins/entity/MixinLivingEntity.java @@ -0,0 +1,70 @@ +package com.paragon.mixin.mixins.entity; + +import com.paragon.Paragon; +import com.paragon.backend.event.EventEra; +import com.paragon.backend.event.events.entity.EntityTickEvent; +import com.paragon.mixin.duck.ILivingEntity; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.LivingEntity; +import net.minecraft.world.World; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +/** + * @author aesthetical + * @since 02/19/23 + */ +@Mixin(LivingEntity.class) +public abstract class MixinLivingEntity extends Entity implements ILivingEntity { + @Shadow protected int lastAttackedTicks; + + private float[] renderRotations; + private float[] prevRenderRotations; + + public MixinLivingEntity(EntityType type, World world) { + super(type, world); + } + + @Inject(method = "", at = @At("TAIL")) + public void hookInit(CallbackInfo info) { + renderRotations = new float[2]; + prevRenderRotations = new float[2]; + + renderRotations[0] = getYaw(); + renderRotations[1] = getPitch(); + prevRenderRotations[0] = getYaw(); + prevRenderRotations[1] = getPitch(); + } + + @Inject(method = "baseTick", at = @At("HEAD")) + public void hookBaseTickPre(CallbackInfo info) { + Paragon.bus.post(new EntityTickEvent(EventEra.PRE, (LivingEntity) (Object) this)); + } + + @Inject(method = "baseTick", at = @At("TAIL")) + public void hookBaseTickPost(CallbackInfo info) { + Paragon.bus.post(new EntityTickEvent(EventEra.POST, (LivingEntity) (Object) this)); + + prevRenderRotations[0] = renderRotations[0]; + prevRenderRotations[1] = renderRotations[1]; + } + + @Override + public int getLastAttackedTicks() { + return lastAttackedTicks; + } + + @Override + public float[] getRenderRotations() { + return renderRotations; + } + + @Override + public float[] getPreviousRenderRotations() { + return prevRenderRotations; + } +} diff --git a/src/main/java/com/paragon/mixin/mixins/input/MixinClientPlayerInteractionManager.java b/src/main/java/com/paragon/mixin/mixins/input/MixinClientPlayerInteractionManager.java new file mode 100644 index 0000000..50d07a8 --- /dev/null +++ b/src/main/java/com/paragon/mixin/mixins/input/MixinClientPlayerInteractionManager.java @@ -0,0 +1,67 @@ +package com.paragon.mixin.mixins.input; + +import com.paragon.Paragon; +import com.paragon.backend.event.events.input.control.AttackBlockEvent; +import com.paragon.mixin.duck.IClientPlayerInteractionManager; +import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.client.network.ClientPlayerInteractionManager; +import net.minecraft.client.network.SequencedPacketCreator; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.item.ItemStack; +import net.minecraft.util.Hand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +/** + * @author aesthetical + * @since 02/18/23 + */ +@Mixin(ClientPlayerInteractionManager.class) +public abstract class MixinClientPlayerInteractionManager implements IClientPlayerInteractionManager { + + @Shadow + protected abstract void sendSequencedPacket(ClientWorld world, SequencedPacketCreator packetCreator); + + @Inject(method = "attackBlock", at = @At("HEAD"), cancellable = true) + public void hookAttackBlock(BlockPos pos, Direction direction, CallbackInfoReturnable info) { + if (Paragon.bus.post(new AttackBlockEvent(pos, direction))) { + info.setReturnValue(false); + } + } + + // these below two redirects is for silent swap + + @Redirect( + method = "interactBlockInternal", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/network/ClientPlayerEntity;getStackInHand(Lnet/minecraft/util/Hand;)Lnet/minecraft/item/ItemStack;")) + private ItemStack hookRedirectInteractBlockInternal$getStackInHand(ClientPlayerEntity instance, Hand hand) { + if (hand.equals(Hand.OFF_HAND)) { + return instance.getStackInHand(hand); + } + + return Paragon.inventoryManager.isDesynced() ? Paragon.inventoryManager.getServerStack() : instance.getStackInHand(Hand.MAIN_HAND); + } + + @Redirect( + method = "interactBlockInternal", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/item/ItemStack;isEmpty()Z", + ordinal = 0)) + private boolean hookRedirectInteractBlockInternal$getMainHandStack(ItemStack instance) { + return Paragon.inventoryManager.isDesynced() ? Paragon.inventoryManager.getServerStack().isEmpty() : instance.isEmpty(); + } + + @Override + public void hookSendSequencedPacket(ClientWorld world, SequencedPacketCreator packetCreator) { + sendSequencedPacket(world, packetCreator); + } +} diff --git a/src/main/java/com/paragon/mixin/mixins/input/MixinItemUsageContext.java b/src/main/java/com/paragon/mixin/mixins/input/MixinItemUsageContext.java new file mode 100644 index 0000000..1e3ff16 --- /dev/null +++ b/src/main/java/com/paragon/mixin/mixins/input/MixinItemUsageContext.java @@ -0,0 +1,21 @@ +package com.paragon.mixin.mixins.input; + +import com.paragon.Paragon; +import net.minecraft.client.MinecraftClient; +import net.minecraft.item.ItemStack; +import net.minecraft.item.ItemUsageContext; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(ItemUsageContext.class) +public class MixinItemUsageContext { + + @Inject(method = "getStack", at = @At("RETURN"), cancellable = true) + public void hookGetStack(CallbackInfoReturnable info) { + if (info.getReturnValue().equals(MinecraftClient.getInstance().player.getMainHandStack()) && Paragon.inventoryManager.isDesynced()) { + info.setReturnValue(Paragon.inventoryManager.getServerStack()); + } + } +} diff --git a/src/main/java/com/paragon/mixin/mixins/input/io/KeyboardMixin.java b/src/main/java/com/paragon/mixin/mixins/input/io/KeyboardMixin.java new file mode 100644 index 0000000..937e8b3 --- /dev/null +++ b/src/main/java/com/paragon/mixin/mixins/input/io/KeyboardMixin.java @@ -0,0 +1,24 @@ +package com.paragon.mixin.mixins.input.io; + +import com.paragon.Paragon; +import com.paragon.backend.event.events.input.io.KeyEvent; +import net.minecraft.client.Keyboard; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +/** + * @author surge + * @since 11/02/2023 + */ +@Mixin(Keyboard.class) +public class KeyboardMixin { + + @Inject(method = "onKey", at = @At("HEAD")) + public void onKey(long window, int key, int scancode, int action, int modifiers, CallbackInfo ci) { + Paragon.bus.post(new KeyEvent(key, action)); + } + +} + diff --git a/src/main/java/com/paragon/mixin/mixins/input/io/MouseMixin.java b/src/main/java/com/paragon/mixin/mixins/input/io/MouseMixin.java new file mode 100644 index 0000000..991f2ad --- /dev/null +++ b/src/main/java/com/paragon/mixin/mixins/input/io/MouseMixin.java @@ -0,0 +1,32 @@ +package com.paragon.mixin.mixins.input.io; + +import com.paragon.Paragon; +import com.paragon.backend.event.events.input.io.MouseEvent; +import com.paragon.mixin.duck.IMouse; +import net.minecraft.client.Mouse; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +/** + * @author aesthetical + * @since 02/17/23 + */ +@Mixin(Mouse.class) +public class MouseMixin implements IMouse { + + @Shadow private double eventDeltaWheel; + + @Inject(method = "onMouseButton", at = @At("HEAD")) + public void hookOnMouseButton(long window, int button, int action, int mods, CallbackInfo info) { + Paragon.bus.post(new MouseEvent(button, action)); + } + + @Override + public double getScrollDelta() { + return eventDeltaWheel; + } + +} diff --git a/src/main/java/com/paragon/mixin/mixins/item/TridentItemMixin.java b/src/main/java/com/paragon/mixin/mixins/item/TridentItemMixin.java new file mode 100644 index 0000000..bb7c026 --- /dev/null +++ b/src/main/java/com/paragon/mixin/mixins/item/TridentItemMixin.java @@ -0,0 +1,26 @@ +package com.paragon.mixin.mixins.item; + +import com.paragon.Paragon; +import com.paragon.backend.event.events.move.TridentVelocityEvent; +import net.minecraft.item.TridentItem; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyArgs; +import org.spongepowered.asm.mixin.injection.invoke.arg.Args; + +/** + * @author surge + * @since 24/02/2023 + */ +@Mixin(TridentItem.class) +public class TridentItemMixin { + + @ModifyArgs(method = "onStoppedUsing", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/player/PlayerEntity;addVelocity(DDD)V")) + private void hookOnStoppedUsing(Args args) { + TridentVelocityEvent event = new TridentVelocityEvent(args.get(0), args.get(1), args.get(2)); + Paragon.bus.post(event); + + args.setAll(event.getX(), event.getY(), event.getZ()); + } + +} diff --git a/src/main/java/com/paragon/mixin/mixins/math/MixinVec3d.java b/src/main/java/com/paragon/mixin/mixins/math/MixinVec3d.java new file mode 100644 index 0000000..d80f3bf --- /dev/null +++ b/src/main/java/com/paragon/mixin/mixins/math/MixinVec3d.java @@ -0,0 +1,53 @@ +package com.paragon.mixin.mixins.math; + +import com.paragon.mixin.duck.IVec3d; +import net.minecraft.util.math.Vec3d; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.Shadow; + +/** + * @author aesthetical + * @since 02/17/23 + */ +@Mixin(Vec3d.class) +public class MixinVec3d implements IVec3d { + + @Shadow @Final @Mutable + public double x; + + @Shadow @Final @Mutable + public double y; + + @Shadow @Final @Mutable + public double z; + + @Override + public void setX(double xIn) { + x = xIn; + } + + @Override + public void setY(double yIn) { + y = yIn; + } + + @Override + public void setZ(double zIn) { + z = zIn; + } + + @Override + public void set(double xIn, double yIn, double zIn) { + x = xIn; + y = yIn; + z = zIn; + } + + @Override + public void set(double xIn, double zIn) { + x = xIn; + z = zIn; + } +} diff --git a/src/main/java/com/paragon/mixin/mixins/net/MixinClientConnection.java b/src/main/java/com/paragon/mixin/mixins/net/MixinClientConnection.java new file mode 100644 index 0000000..0ce1bab --- /dev/null +++ b/src/main/java/com/paragon/mixin/mixins/net/MixinClientConnection.java @@ -0,0 +1,50 @@ +package com.paragon.mixin.mixins.net; + +import com.paragon.Paragon; +import com.paragon.backend.event.events.net.PacketEvent; +import com.paragon.backend.event.events.net.PacketEvent.Inbound; +import com.paragon.backend.event.events.net.PacketEvent.Outbound; +import com.paragon.mixin.duck.IClientConnection; +import io.netty.channel.ChannelHandlerContext; +import net.minecraft.network.ClientConnection; +import net.minecraft.network.Packet; +import net.minecraft.network.PacketCallbacks; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +/** + * @author aesthetical + * @since 02/17/23 + */ +@Mixin(ClientConnection.class) +public abstract class MixinClientConnection implements IClientConnection { + + @Shadow + protected abstract void sendImmediately(Packet packet, @Nullable PacketCallbacks callbacks); + + @Inject(method = "send(Lnet/minecraft/network/Packet;Lnet/minecraft/network/PacketCallbacks;)V", at = @At("HEAD"), cancellable = true) + public void hookSend(Packet packet, PacketCallbacks callbacks, CallbackInfo info) { + PacketEvent.Outbound outbound = new Outbound(packet); + if (Paragon.bus.post(outbound)) { + info.cancel(); + } + } + + @Inject(method = "channelRead0(Lio/netty/channel/ChannelHandlerContext;Lnet/minecraft/network/Packet;)V", at = @At("HEAD"), cancellable = true) + public void hookChannelRead0(ChannelHandlerContext channelHandlerContext, Packet packet, CallbackInfo info) { + PacketEvent.Inbound inbound = new Inbound(packet); + if (Paragon.bus.post(inbound)) { + info.cancel(); + } + } + + @Override + public void sendPacketNoEvent(Packet packet) { + sendImmediately(packet, null); + } + +} diff --git a/src/main/java/com/paragon/mixin/mixins/net/packet/c2s/IPlayerMoveC2SPacket.java b/src/main/java/com/paragon/mixin/mixins/net/packet/c2s/IPlayerMoveC2SPacket.java new file mode 100644 index 0000000..3e3fb37 --- /dev/null +++ b/src/main/java/com/paragon/mixin/mixins/net/packet/c2s/IPlayerMoveC2SPacket.java @@ -0,0 +1,19 @@ +package com.paragon.mixin.mixins.net.packet.c2s; + +import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.gen.Accessor; + +/** + * @author aesthetical + * @since 02/18/23 + */ +@Mixin(PlayerMoveC2SPacket.class) +public interface IPlayerMoveC2SPacket { + + @Accessor("onGround") @Final @Mutable + void setOnGround(boolean onGround); + +} diff --git a/src/main/java/com/paragon/mixin/mixins/net/packet/c2s/MixinPlayerInteractEntityC2SPacket.java b/src/main/java/com/paragon/mixin/mixins/net/packet/c2s/MixinPlayerInteractEntityC2SPacket.java new file mode 100644 index 0000000..1510eb3 --- /dev/null +++ b/src/main/java/com/paragon/mixin/mixins/net/packet/c2s/MixinPlayerInteractEntityC2SPacket.java @@ -0,0 +1,29 @@ +package com.paragon.mixin.mixins.net.packet.c2s; + +import com.paragon.mixin.duck.IPlayerInteractEntityC2SPacket; +import net.minecraft.entity.Entity; +import net.minecraft.network.packet.c2s.play.PlayerInteractEntityC2SPacket; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import static com.paragon.util.MiscKt.getMc; + +@Mixin(PlayerInteractEntityC2SPacket.class) +public class MixinPlayerInteractEntityC2SPacket implements IPlayerInteractEntityC2SPacket { + + @Shadow @Final private int entityId; + + @Shadow @Final private PlayerInteractEntityC2SPacket.InteractTypeHandler type; + + @Override + public PlayerInteractEntityC2SPacket.InteractType getType() { + return type.getType(); + } + + @Override + public Entity getEntity() { + return getMc().world.getEntityById(entityId); + } + +} diff --git a/src/main/java/com/paragon/mixin/mixins/net/packet/s2c/IEntityVelocityUpdateS2CPacket.java b/src/main/java/com/paragon/mixin/mixins/net/packet/s2c/IEntityVelocityUpdateS2CPacket.java new file mode 100644 index 0000000..9234ae8 --- /dev/null +++ b/src/main/java/com/paragon/mixin/mixins/net/packet/s2c/IEntityVelocityUpdateS2CPacket.java @@ -0,0 +1,28 @@ +package com.paragon.mixin.mixins.net.packet.s2c; + +import net.minecraft.network.packet.s2c.play.EntityVelocityUpdateS2CPacket; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.gen.Accessor; + +/** + * @author aesthetical + * @since 02/18/23 + */ +@Mixin(EntityVelocityUpdateS2CPacket.class) +public interface IEntityVelocityUpdateS2CPacket { + + @Accessor("velocityX") + @Final @Mutable + void setVelocityX(int velocityX); + + @Accessor("velocityY") + @Final @Mutable + void setVelocityY(int velocityY); + + @Accessor("velocityZ") + @Final @Mutable + void setVelocityZ(int velocityZ); + +} diff --git a/src/main/java/com/paragon/mixin/mixins/net/packet/s2c/IExplosionS2CPacket.java b/src/main/java/com/paragon/mixin/mixins/net/packet/s2c/IExplosionS2CPacket.java new file mode 100644 index 0000000..85ebc7c --- /dev/null +++ b/src/main/java/com/paragon/mixin/mixins/net/packet/s2c/IExplosionS2CPacket.java @@ -0,0 +1,29 @@ +package com.paragon.mixin.mixins.net.packet.s2c; + +import net.minecraft.network.packet.s2c.play.ExplosionS2CPacket; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.gen.Accessor; + +/** + * @author aesthetical + * @since 02/18/23 + */ +@Mixin(ExplosionS2CPacket.class) +public interface IExplosionS2CPacket { + + @Accessor("playerVelocityX") + @Final + @Mutable + void setVelocityX(float velocityX); + + @Accessor("playerVelocityY") + @Final @Mutable + void setVelocityY(float velocityY); + + @Accessor("playerVelocityZ") + @Final @Mutable + void setVelocityZ(float velocityZ); + +} diff --git a/src/main/java/com/paragon/mixin/mixins/render/GameRendererMixin.java b/src/main/java/com/paragon/mixin/mixins/render/GameRendererMixin.java new file mode 100644 index 0000000..50bfdde --- /dev/null +++ b/src/main/java/com/paragon/mixin/mixins/render/GameRendererMixin.java @@ -0,0 +1,81 @@ +package com.paragon.mixin.mixins.render; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.paragon.Paragon; +import com.paragon.backend.event.events.entity.EntityTraceEvent; +import com.paragon.backend.event.events.entity.RaycastEvent; +import com.paragon.backend.event.events.render.GameRenderEvent; +import com.paragon.backend.event.events.render.PreGameRenderEvent; +import com.paragon.backend.framebuffer.MultiSampledFramebuffer; +import com.paragon.mixin.duck.IGameRenderer; +import com.paragon.util.rendering.Renderer; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.render.GameRenderer; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.util.hit.HitResult; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.ModifyArgs; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.invoke.arg.Args; + +/** + * @author surge + * @since 12/02/2023 + */ +@Mixin(GameRenderer.class) +public abstract class GameRendererMixin implements IGameRenderer { + + @Shadow protected abstract void bobView(MatrixStack matrices, float tickDelta); + + @Shadow public abstract MinecraftClient getClient(); + + @Inject(method = "renderWorld", at = @At(value = "FIELD", target = "Lnet/minecraft/client/render/GameRenderer;renderHand:Z")) + public void hookRenderWorld(float tickDelta, long limitTime, MatrixStack matrices, CallbackInfo ci) { + RenderSystem.backupProjectionMatrix(); + Paragon.bus.post(new GameRenderEvent(matrices, tickDelta)); + MultiSampledFramebuffer.use(Renderer::drawAndClear); + RenderSystem.restoreProjectionMatrix(); + } + + @Inject(method = "render", at = @At("HEAD"), cancellable = true) + public void hookRenderHead(float tickDelta, long startTime, boolean tick, CallbackInfo ci) { + PreGameRenderEvent event = new PreGameRenderEvent(); + Paragon.bus.post(event); + + if (event.isCancelled()) { + ci.cancel(); + } + } + + @ModifyArgs(method = "updateTargetedEntity", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/Entity;raycast(DFZ)Lnet/minecraft/util/hit/HitResult;")) + public void hookUpdateTargetedEntityRaycast(Args args) { + RaycastEvent event = new RaycastEvent(args.get(0), args.get(1), args.get(2)); + Paragon.bus.post(event); + + args.setAll( + event.getDistance(), + event.getTickDelta(), + event.getIncludeFluids() + ); + } + + @Inject(method = "updateTargetedEntity", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/projectile/ProjectileUtil;raycast(Lnet/minecraft/entity/Entity;Lnet/minecraft/util/math/Vec3d;Lnet/minecraft/util/math/Vec3d;Lnet/minecraft/util/math/Box;Ljava/util/function/Predicate;D)Lnet/minecraft/util/hit/EntityHitResult;"), cancellable = true) + public void hookUpdateTargetedEntity(float tickDelta, CallbackInfo ci) { + EntityTraceEvent event = new EntityTraceEvent(getClient().crosshairTarget); + Paragon.bus.post(event); + + if (event.isCancelled()) { + getClient().getProfiler().pop(); + ci.cancel(); + } + } + + @Override + public void hookBobView(MatrixStack matrices, float tickDelta) { + bobView(matrices, tickDelta); + } + +} diff --git a/src/main/java/com/paragon/mixin/mixins/render/MixinCamera.java b/src/main/java/com/paragon/mixin/mixins/render/MixinCamera.java new file mode 100644 index 0000000..bab915e --- /dev/null +++ b/src/main/java/com/paragon/mixin/mixins/render/MixinCamera.java @@ -0,0 +1,26 @@ +package com.paragon.mixin.mixins.render; + +import com.paragon.Paragon; +import com.paragon.backend.event.events.render.ClipToSpaceEvent; +import net.minecraft.client.render.Camera; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +/** + * @author aesthetical + * @since 02/19/23 + */ +@Mixin(Camera.class) +public class MixinCamera { + + @Inject(method = "clipToSpace", at = @At("HEAD"), cancellable = true) + public void hookClipToSpace(double desiredCameraDistance, CallbackInfoReturnable info) { + ClipToSpaceEvent event = new ClipToSpaceEvent(desiredCameraDistance); + if (Paragon.bus.post(event)) { + info.setReturnValue(event.getDistance()); + } + } + +} diff --git a/src/main/java/com/paragon/mixin/mixins/render/MixinLightmapTextureManager.java b/src/main/java/com/paragon/mixin/mixins/render/MixinLightmapTextureManager.java new file mode 100644 index 0000000..111e0a3 --- /dev/null +++ b/src/main/java/com/paragon/mixin/mixins/render/MixinLightmapTextureManager.java @@ -0,0 +1,24 @@ +package com.paragon.mixin.mixins.render; + +import com.paragon.Paragon; +import com.paragon.backend.event.events.render.GammaModifyEvent; +import net.minecraft.client.render.LightmapTextureManager; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +/** + * @author aesthetical + * @since 02/18/23 + */ +@Mixin(LightmapTextureManager.class) +public class MixinLightmapTextureManager { + + // this is the only place getGamma() is used, so this has to be it? + @Redirect(method = "update", at = @At(value = "INVOKE", target = "Ljava/lang/Double;floatValue()F", ordinal = 1)) + public float redirectUpdate$floatValue(Double instance) { + GammaModifyEvent event = new GammaModifyEvent(instance.floatValue()); + return Paragon.bus.post(event) ? event.gamma : instance.floatValue(); + } + +} diff --git a/src/main/java/com/paragon/mixin/mixins/render/MixinRenderTickCounter.java b/src/main/java/com/paragon/mixin/mixins/render/MixinRenderTickCounter.java new file mode 100644 index 0000000..9b24335 --- /dev/null +++ b/src/main/java/com/paragon/mixin/mixins/render/MixinRenderTickCounter.java @@ -0,0 +1,30 @@ +package com.paragon.mixin.mixins.render; + +import com.paragon.mixin.duck.IRenderTickCounter; +import net.minecraft.client.render.RenderTickCounter; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.Shadow; + +/** + * @author aesthetical + * @since 02/17/23 + */ +@Mixin(RenderTickCounter.class) +public class MixinRenderTickCounter implements IRenderTickCounter { + + @Shadow @Final @Mutable + private float tickTime; + + @Override + public void setTickLength(float tickLength) { + tickTime = tickLength; + } + + @Override + public float getTickLength() { + return tickTime; + } + +} diff --git a/src/main/java/com/paragon/mixin/mixins/render/WindowMixin.java b/src/main/java/com/paragon/mixin/mixins/render/WindowMixin.java new file mode 100644 index 0000000..01d98c8 --- /dev/null +++ b/src/main/java/com/paragon/mixin/mixins/render/WindowMixin.java @@ -0,0 +1,31 @@ +package com.paragon.mixin.mixins.render; + +import com.paragon.Paragon; +import com.paragon.util.calculations.Timer; +import com.paragon.util.rendering.NVGWrapper; +import net.minecraft.client.WindowEventHandler; +import net.minecraft.client.WindowSettings; +import net.minecraft.client.util.MonitorTracker; +import net.minecraft.client.util.Window; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +/** + * @author surge + * @since 11/02/2023 + */ +@Mixin(Window.class) +public class WindowMixin { + + @Inject(method = "", at = @At("TAIL")) + public void hookInit(WindowEventHandler eventHandler, MonitorTracker monitorTracker, WindowSettings settings, String videoMode, String title, CallbackInfo info) { + Paragon.getLogger().info("Initialising NanoVG"); + Timer timer = new Timer(); + timer.reset(); + NVGWrapper.initialise(); + Paragon.getLogger().info("Initialised NanoVG in {}ms", timer.timeMs()); + } + +} diff --git a/src/main/java/com/paragon/mixin/mixins/render/entity/MixinLivingEntityRenderer.java b/src/main/java/com/paragon/mixin/mixins/render/entity/MixinLivingEntityRenderer.java new file mode 100644 index 0000000..ab69b99 --- /dev/null +++ b/src/main/java/com/paragon/mixin/mixins/render/entity/MixinLivingEntityRenderer.java @@ -0,0 +1,74 @@ +package com.paragon.mixin.mixins.render.entity; + +import com.paragon.mixin.duck.ILivingEntity; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.entity.EntityRenderer; +import net.minecraft.client.render.entity.EntityRendererFactory.Context; +import net.minecraft.client.render.entity.LivingEntityRenderer; +import net.minecraft.client.render.entity.feature.FeatureRendererContext; +import net.minecraft.client.render.entity.model.EntityModel; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.entity.LivingEntity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +/** + * @author aesthetical + * @since 02/17/23 + */ + +/** + * TODO: Make these smooth (rotations, I assume??) + */ +@Mixin(LivingEntityRenderer.class) +public abstract class MixinLivingEntityRenderer> + extends EntityRenderer + implements FeatureRendererContext { + + private float headYaw, prevHeadYaw; + private float pitch, prevPitch; + private boolean modified = false; + + protected MixinLivingEntityRenderer(Context ctx) { + super(ctx); + } + + @Inject(method = "render(Lnet/minecraft/entity/LivingEntity;FFLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;I)V", at = @At("HEAD")) + public void hookRenderPre(T livingEntity, float f, float g, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, CallbackInfo info) { + if (livingEntity != null && livingEntity.equals(MinecraftClient.getInstance().player)) { + + modified = true; + + headYaw = livingEntity.headYaw; + prevHeadYaw = livingEntity.prevHeadYaw; + + pitch = livingEntity.getPitch(); + prevPitch = livingEntity.prevPitch; + + float[] rots = ((ILivingEntity) livingEntity).getRenderRotations(); + float[] prevRots = ((ILivingEntity) livingEntity).getPreviousRenderRotations(); + + livingEntity.headYaw = rots[0]; + livingEntity.prevHeadYaw = prevRots[0]; + + livingEntity.setPitch(rots[1]); + livingEntity.prevPitch = prevRots[1]; + } + } + + @Inject(method = "render(Lnet/minecraft/entity/LivingEntity;FFLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;I)V", at = @At("TAIL")) + public void hookRenderPost(T livingEntity, float f, float g, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, CallbackInfo info) { + if (livingEntity != null && livingEntity.equals(MinecraftClient.getInstance().player) && modified) { + modified = false; + + livingEntity.headYaw = headYaw; + livingEntity.prevHeadYaw = prevHeadYaw; + + livingEntity.setPitch(pitch); + livingEntity.prevPitch = prevPitch; + } + } +} diff --git a/src/main/java/com/paragon/mixin/mixins/render/entity/MixinPlayerEntityRenderer.java b/src/main/java/com/paragon/mixin/mixins/render/entity/MixinPlayerEntityRenderer.java new file mode 100644 index 0000000..55e7363 --- /dev/null +++ b/src/main/java/com/paragon/mixin/mixins/render/entity/MixinPlayerEntityRenderer.java @@ -0,0 +1,29 @@ +package com.paragon.mixin.mixins.render.entity; + +import com.paragon.Paragon; +import com.paragon.backend.event.events.render.RenderNameplateEvent; +import net.minecraft.client.network.AbstractClientPlayerEntity; +import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.entity.PlayerEntityRenderer; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.text.Text; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +/** + * @author aesthetical + * @since 02/19/23 + */ +@Mixin(PlayerEntityRenderer.class) +public class MixinPlayerEntityRenderer { + + @Inject(method = "renderLabelIfPresent(Lnet/minecraft/client/network/AbstractClientPlayerEntity;Lnet/minecraft/text/Text;Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;I)V", at = @At("HEAD"), cancellable = true) + public void hookRenderLabelIfPresent(AbstractClientPlayerEntity abstractClientPlayerEntity, Text text, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, CallbackInfo info) { + if (Paragon.bus.post(new RenderNameplateEvent(abstractClientPlayerEntity))) { + info.cancel(); + } + } + +} diff --git a/src/main/java/com/paragon/mixin/mixins/render/gui/MixinInGameHud.java b/src/main/java/com/paragon/mixin/mixins/render/gui/MixinInGameHud.java new file mode 100644 index 0000000..c1feb29 --- /dev/null +++ b/src/main/java/com/paragon/mixin/mixins/render/gui/MixinInGameHud.java @@ -0,0 +1,53 @@ +package com.paragon.mixin.mixins.render.gui; + +import com.paragon.Paragon; +import com.paragon.backend.event.events.render.RenderHUDEvent; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.hud.InGameHud; +import net.minecraft.client.util.Window; +import net.minecraft.client.util.math.MatrixStack; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.At.Shift; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.ModifyArg; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +/** + * @author aesthetical + * @since 02/17/23 + */ +@Mixin(InGameHud.class) +public class MixinInGameHud { + + @Shadow @Final private MinecraftClient client; + @Shadow private int scaledWidth; + + @Inject( + method = "render", + at = @At( + value = "INVOKE", + target = "Lcom/mojang/blaze3d/systems/RenderSystem;setShaderColor(FFFF)V", + ordinal = 4, + shift = Shift.BEFORE)) + public void hookRender(MatrixStack stack, float deltaTick, CallbackInfo info) { + Window window = client.getWindow(); + Paragon.bus.post(new RenderHUDEvent(stack, deltaTick, window.getWidth(), window.getHeight())); + } + + @ModifyArg( + method = "renderHotbar", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/gui/hud/InGameHud;drawTexture(Lnet/minecraft/client/util/math/MatrixStack;IIIIII)V", + ordinal = 1), + index = 1) + public int hookModifyRenderHotbar$selectedSlot(int selectedSlotIn) { + int slot = Paragon.inventoryManager.isDesynced() ? Paragon.inventoryManager.getSlot() : client.player.getInventory().selectedSlot; + int i = this.scaledWidth / 2; + return i - 91 - 1 + slot * 20; + } + +} diff --git a/src/main/java/com/paragon/mixin/mixins/render/gui/TitleScreenMixin.java b/src/main/java/com/paragon/mixin/mixins/render/gui/TitleScreenMixin.java new file mode 100644 index 0000000..ae28c9b --- /dev/null +++ b/src/main/java/com/paragon/mixin/mixins/render/gui/TitleScreenMixin.java @@ -0,0 +1,67 @@ +package com.paragon.mixin.mixins.render.gui; + +import com.paragon.client.ui.title.MainMenuHook; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.screen.TitleScreen; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.text.Text; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import static com.paragon.util.MiscKt.getMc; + +@Mixin(TitleScreen.class) +public class TitleScreenMixin extends Screen { + + protected TitleScreenMixin(Text title) { + super(title); + } + + @Inject(method = "init", at = @At(value = "TAIL")) + public void hookInit(CallbackInfo ci) { + MainMenuHook.INSTANCE.init(); + } + + @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/Screen;render(Lnet/minecraft/client/util/math/MatrixStack;IIF)V", shift = At.Shift.AFTER)) + public void hookRender(MatrixStack matrices, int mouseX, int mouseY, float delta, CallbackInfo info) { + MainMenuHook.INSTANCE.setHeight(height); + MainMenuHook.INSTANCE.render(matrices, (int) getMc().mouse.getX(), (int) getMc().mouse.getY(), delta); + } + + @Inject(method = "mouseClicked", at = @At(value = "RETURN", shift = At.Shift.BEFORE)) + public void hookMouseClicked(double mouseX, double mouseY, int button, CallbackInfoReturnable cir) { + if (MainMenuHook.INSTANCE.mouseClicked((int) getMc().mouse.getX(), (int) getMc().mouse.getY(), button)) { + cir.setReturnValue(true); + } + } + + @Override + public boolean mouseScrolled(double mouseX, double mouseY, double amount) { + if (MainMenuHook.INSTANCE.mouseScrolled((int) getMc().mouse.getX(), (int) getMc().mouse.getY(), (float) amount)) { + return true; + } + + return super.mouseScrolled(mouseX, mouseY, amount); + } + + @Override + public boolean keyPressed(int keyCode, int scanCode, int modifiers) { + if (MainMenuHook.INSTANCE.keyPressed(keyCode, scanCode, modifiers)) { + return true; + } + + return super.keyPressed(keyCode, scanCode, modifiers); + } + + @Override + public boolean charTyped(char chr, int modifiers) { + MainMenuHook.INSTANCE.charTyped(chr, modifiers); + + return super.charTyped(chr, modifiers); + } + +} diff --git a/src/main/java/com/paragon/mixin/mixins/world/block/MixinAbstractBlockState.java b/src/main/java/com/paragon/mixin/mixins/world/block/MixinAbstractBlockState.java new file mode 100644 index 0000000..10ab6cc --- /dev/null +++ b/src/main/java/com/paragon/mixin/mixins/world/block/MixinAbstractBlockState.java @@ -0,0 +1,26 @@ +package com.paragon.mixin.mixins.world.block; + +import com.paragon.Paragon; +import com.paragon.backend.event.events.render.BlockAmbientLightLevelEvent; +import net.minecraft.block.AbstractBlock.AbstractBlockState; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.BlockView; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +/** + * @author aesthetical + * @since 02/20/23 + */ +@Mixin(AbstractBlockState.class) +public class MixinAbstractBlockState { + @Inject(method = "getAmbientOcclusionLightLevel", at = @At("RETURN"), cancellable = true) + public void hookGetAmbientOcclusionLightLevel(BlockView world, BlockPos pos, CallbackInfoReturnable info) { + BlockAmbientLightLevelEvent event = new BlockAmbientLightLevelEvent(pos, info.getReturnValue()); + if (Paragon.bus.post(event)) { + info.setReturnValue(event.getLightLevel()); + } + } +} diff --git a/src/main/java/com/paragon/mixin/mixins/world/block/MixinBlock.java b/src/main/java/com/paragon/mixin/mixins/world/block/MixinBlock.java new file mode 100644 index 0000000..5e47183 --- /dev/null +++ b/src/main/java/com/paragon/mixin/mixins/world/block/MixinBlock.java @@ -0,0 +1,30 @@ +package com.paragon.mixin.mixins.world.block; + +import com.paragon.Paragon; +import com.paragon.backend.event.events.render.DrawSideOfBlockEvent; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.world.BlockView; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +/** + * @author aesthetical + * @since 02/20/23 + */ +@Mixin(Block.class) +public class MixinBlock { + + @Inject(method = "shouldDrawSide", at = @At("RETURN"), cancellable = true) + private static void shouldDrawSide(BlockState state, BlockView world, BlockPos pos, Direction side, BlockPos otherPos, CallbackInfoReturnable info) { + DrawSideOfBlockEvent event = new DrawSideOfBlockEvent(state.getBlock(), pos, state, info.getReturnValue()); + if (Paragon.bus.post(event)) { + info.setReturnValue(event.getDrawSide()); + } + } + +} diff --git a/src/main/kotlin/com/paragon/Paragon.kt b/src/main/kotlin/com/paragon/Paragon.kt new file mode 100644 index 0000000..3e811a2 --- /dev/null +++ b/src/main/kotlin/com/paragon/Paragon.kt @@ -0,0 +1,98 @@ +package com.paragon + +import com.paragon.backend.Feature +import com.paragon.backend.event.EventProcessor +import com.paragon.backend.managers.* +import com.paragon.backend.managers.placement.PlacementManager +import com.paragon.backend.module.Module +import com.paragon.client.modules.visual.ClickGUI +import com.paragon.client.ui.configuration.aesthetical.AestheticalUI +import com.paragon.client.ui.configuration.surge.SurgeUI +import com.paragon.util.BuildConfig.BuildConfig +import com.paragon.util.io.FileUtil +import me.bush.eventbus.bus.EventBus +import net.fabricmc.api.ClientModInitializer +import org.slf4j.LoggerFactory +import kotlin.math.log + +/** + * @author surge + * @since 19/02/2023 + */ +class Paragon : ClientModInitializer { + + override fun onInitializeClient() { + logger.info("Initialising Paragon") + + if (!FileUtil.PARAGON_PATH.exists()) { + logger.info("Created ${FileUtil.PARAGON_PATH} ${if (FileUtil.PARAGON_PATH.mkdir()) "successfully" else "unsuccessfully"}") + } + + logger.info("Initialising event bus") + bus = EventBus() + processor = EventProcessor() + + logger.info("Initialising config manager") + configManager = ConfigManager() + + logger.info("Initialising keyboard manager") + keyboardManager = KeyboardManager() + + logger.info("Initialising toast manager") + toastManager = ToastManager() + + logger.info("Initialising baritone manager") + baritoneManager = BaritoneManager() + + logger.info("Initialising module manager") + moduleManager = ModuleManager() + + logger.info("Initialising command manager") + commandManager = CommandManager() + + logger.info("Initialising rotation manager") + rotationManager = RotationManager() + + logger.info("Initialising inventory manager") + inventoryManager = InventoryManager() + + logger.info("Initialising alt manager") + altManager = AltManager() + + logger.info("Initialising placement manager") + placementManager = PlacementManager() + + logger.info("Loading configurations & data") + moduleManager.load("current") + configManager.loadAll() + + logger.info("Running post load methods") + moduleManager.modules.forEach(Feature::postLoad) + + logger.info("Initialising uis") + ClickGUI.surgeUi = SurgeUI() + ClickGUI.aestheticalUI = AestheticalUI() + + logger.info("Initialised Paragon $version") + } + + companion object { + @JvmStatic val version: String = BuildConfig.VERSION + @JvmStatic var logger = LoggerFactory.getLogger("paragon") + + @JvmStatic lateinit var bus: EventBus + @JvmStatic lateinit var processor: EventProcessor + + @JvmStatic lateinit var keyboardManager: KeyboardManager + @JvmStatic lateinit var moduleManager: ModuleManager + @JvmStatic lateinit var commandManager: CommandManager + @JvmStatic lateinit var rotationManager: RotationManager + @JvmStatic lateinit var inventoryManager: InventoryManager + @JvmStatic lateinit var toastManager: ToastManager + @JvmStatic lateinit var configManager: ConfigManager + @JvmStatic lateinit var altManager: AltManager + @JvmStatic lateinit var baritoneManager: BaritoneManager + @JvmStatic lateinit var placementManager: PlacementManager + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/Feature.kt b/src/main/kotlin/com/paragon/backend/Feature.kt new file mode 100644 index 0000000..e4bfa02 --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/Feature.kt @@ -0,0 +1,13 @@ +package com.paragon.backend + +import com.paragon.backend.setting.SettingContainer + +/** + * @author surge + * @since 11/02/2023 + */ +open class Feature(val name: String, val description: String) : SettingContainer() { + + open fun postLoad() {} + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/ToggleFeature.kt b/src/main/kotlin/com/paragon/backend/ToggleFeature.kt new file mode 100644 index 0000000..33cf5a7 --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/ToggleFeature.kt @@ -0,0 +1,25 @@ +package com.paragon.backend + +/** + * @author aesthetical + * @since 02/17/23 + */ +open class ToggleFeature(name: String, description: String) : Feature(name, description) { + + var isEnabled = false + protected set + + open fun enable() {} + open fun disable() {} + + open fun setState(state: Boolean) { + isEnabled = state + + if (state) { + enable() + } else { + disable() + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/alt/Alt.kt b/src/main/kotlin/com/paragon/backend/alt/Alt.kt new file mode 100644 index 0000000..8ebf2bc --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/alt/Alt.kt @@ -0,0 +1,32 @@ +package com.paragon.backend.alt + +import net.minecraft.client.util.Session +import net.minecraft.client.util.Session.AccountType + +/** + * @author surge + * @since 02/22/23 + */ +data class Alt(val email: String, val password: String?) { + + var accountType: AccountType = AccountType.MSA + + init { + if (password.isNullOrEmpty()) { + accountType = AccountType.LEGACY + } + } + + var refreshToken: String? = null + set(value) { + if (accountType != AccountType.MSA) { + throw IllegalStateException("Cannot set refresh token for a non MSA account") + } + + field = value + } + + var session: Session? = null + var cachedUsername = email + +} diff --git a/src/main/kotlin/com/paragon/backend/bind/Bind.kt b/src/main/kotlin/com/paragon/backend/bind/Bind.kt new file mode 100644 index 0000000..a7a83a6 --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/bind/Bind.kt @@ -0,0 +1,306 @@ +package com.paragon.backend.bind + +import com.paragon.backend.ToggleFeature +import org.lwjgl.glfw.GLFW +import java.util.* + +/** + * @author surge, aesthetical + * @since 11/02/2023 + */ +class Bind(val feature: ToggleFeature, var type: DeviceType = DeviceType.KEYBOARD, var code: Int = GLFW.GLFW_KEY_UNKNOWN) { + + private var inhibitor: BindInhibitor? = null + + var state = false + set(state) { + field = state + + if (inhibitor != null) { + inhibitor!!.act(feature, this) + } + } + + var isPersistent = true + + fun setInhibitor(inhibitor: BindInhibitor) { + this.inhibitor = inhibitor + } + + override fun toString(): String { + return when (type) { + DeviceType.MOUSE -> getMouseName(code) + DeviceType.KEYBOARD -> getKeyName(code) + else -> "?" + } + } + + companion object { + /** + * Completely and utterly YOINKED from meteor + */ + fun getKeyName(key: Int): String { + return when (key) { + GLFW.GLFW_KEY_UNKNOWN -> { + "None" + } + + GLFW.GLFW_KEY_ESCAPE -> { + "Esc" + } + + GLFW.GLFW_KEY_GRAVE_ACCENT -> { + "Grave Accent" + } + + GLFW.GLFW_KEY_WORLD_1 -> { + "World 1" + } + + GLFW.GLFW_KEY_WORLD_2 -> { + "World 2" + } + + GLFW.GLFW_KEY_PRINT_SCREEN -> { + "Print Screen" + } + + GLFW.GLFW_KEY_PAUSE -> { + "Pause" + } + + GLFW.GLFW_KEY_INSERT -> { + "Insert" + } + + GLFW.GLFW_KEY_DELETE -> { + "Delete" + } + + GLFW.GLFW_KEY_HOME -> { + "Home" + } + + GLFW.GLFW_KEY_PAGE_UP -> { + "Page Up" + } + + GLFW.GLFW_KEY_PAGE_DOWN -> { + "Page Down" + } + + GLFW.GLFW_KEY_END -> { + "End" + } + + GLFW.GLFW_KEY_TAB -> { + "Tab" + } + + GLFW.GLFW_KEY_LEFT_CONTROL -> { + "Left Control" + } + + GLFW.GLFW_KEY_RIGHT_CONTROL -> { + "Right Control" + } + + GLFW.GLFW_KEY_LEFT_ALT -> { + "Left Alt" + } + + GLFW.GLFW_KEY_RIGHT_ALT -> { + "Right Alt" + } + + GLFW.GLFW_KEY_LEFT_SHIFT -> { + "Left Shift" + } + + GLFW.GLFW_KEY_RIGHT_SHIFT -> { + "Right Shift" + } + + GLFW.GLFW_KEY_UP -> { + "Arrow Up" + } + + GLFW.GLFW_KEY_DOWN -> { + "Arrow Down" + } + + GLFW.GLFW_KEY_LEFT -> { + "Arrow Left" + } + + GLFW.GLFW_KEY_RIGHT -> { + "Arrow Right" + } + + GLFW.GLFW_KEY_APOSTROPHE -> { + "Apostrophe" + } + + GLFW.GLFW_KEY_BACKSPACE -> { + "Backspace" + } + + GLFW.GLFW_KEY_CAPS_LOCK -> { + "Caps Lock" + } + + GLFW.GLFW_KEY_MENU -> { + "Menu" + } + + GLFW.GLFW_KEY_LEFT_SUPER -> { + "Left Super" + } + + GLFW.GLFW_KEY_RIGHT_SUPER -> { + "Right Super" + } + + GLFW.GLFW_KEY_ENTER -> { + "Enter" + } + + GLFW.GLFW_KEY_KP_ENTER -> { + "Numpad Enter" + } + + GLFW.GLFW_KEY_NUM_LOCK -> { + "Num Lock" + } + + GLFW.GLFW_KEY_SPACE -> { + "Space" + } + + GLFW.GLFW_KEY_F1 -> { + "F1" + } + + GLFW.GLFW_KEY_F2 -> { + "F2" + } + + GLFW.GLFW_KEY_F3 -> { + "F3" + } + + GLFW.GLFW_KEY_F4 -> { + "F4" + } + + GLFW.GLFW_KEY_F5 -> { + "F5" + } + + GLFW.GLFW_KEY_F6 -> { + "F6" + } + + GLFW.GLFW_KEY_F7 -> { + "F7" + } + + GLFW.GLFW_KEY_F8 -> { + "F8" + } + + GLFW.GLFW_KEY_F9 -> { + "F9" + } + + GLFW.GLFW_KEY_F10 -> { + "F10" + } + + GLFW.GLFW_KEY_F11 -> { + "F11" + } + + GLFW.GLFW_KEY_F12 -> { + "F12" + } + + GLFW.GLFW_KEY_F13 -> { + "F13" + } + + GLFW.GLFW_KEY_F14 -> { + "F14" + } + + GLFW.GLFW_KEY_F15 -> { + "F15" + } + + GLFW.GLFW_KEY_F16 -> { + "F16" + } + + GLFW.GLFW_KEY_F17 -> { + "F17" + } + + GLFW.GLFW_KEY_F18 -> { + "F18" + } + + GLFW.GLFW_KEY_F19 -> { + "F19" + } + + GLFW.GLFW_KEY_F20 -> { + "F20" + } + + GLFW.GLFW_KEY_F21 -> { + "F21" + } + + GLFW.GLFW_KEY_F22 -> { + "F22" + } + + GLFW.GLFW_KEY_F23 -> { + "F23" + } + + GLFW.GLFW_KEY_F24 -> { + "F24" + } + + GLFW.GLFW_KEY_F25 -> { + "F25" + } + + else -> { + val keyName = GLFW.glfwGetKeyName(key, 0) ?: return "None" + keyName.uppercase(Locale.getDefault()) + } + } + } + + fun getMouseName(button: Int): String { + return if (button == GLFW.GLFW_KEY_UNKNOWN) { + "None" + } else when (button) { + 0 -> "Left Click" + 1 -> "Right Click" + 2 -> "Middle Click" + else -> "MButton " + (button + 1) + } + + // ima need some whiskey glasses... + // cause ion wanna see the truth + // shes prolly making out on the couch right now + // with someone newwwwwwwwww + + // TODO: Add more mouse names + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/bind/BindInhibitor.kt b/src/main/kotlin/com/paragon/backend/bind/BindInhibitor.kt new file mode 100644 index 0000000..957e30e --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/bind/BindInhibitor.kt @@ -0,0 +1,11 @@ +package com.paragon.backend.bind + +import com.paragon.backend.Feature + +/** + * @author aesthetical + * @since 02/17/23 + */ +fun interface BindInhibitor { + fun act(feature: Feature, bind: Bind) +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/bind/DeviceType.kt b/src/main/kotlin/com/paragon/backend/bind/DeviceType.kt new file mode 100644 index 0000000..4d8a732 --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/bind/DeviceType.kt @@ -0,0 +1,11 @@ +package com.paragon.backend.bind + +/** + * @author aesthetical + * @since 02/17/23 + */ +enum class DeviceType { + KEYBOARD, + MOUSE, + UNKNOWN +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/command/Command.kt b/src/main/kotlin/com/paragon/backend/command/Command.kt new file mode 100644 index 0000000..9646fe7 --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/command/Command.kt @@ -0,0 +1,18 @@ +package com.paragon.backend.command + +import com.mojang.brigadier.Command.SINGLE_SUCCESS +import com.mojang.brigadier.builder.LiteralArgumentBuilder + +/** + * @author aesthetical + * @since 02/24/23 + */ +abstract class Command(val aliases: Array, val description: String = "No command description provided", val usage: String = "") { + + abstract fun run(ctx: LiteralArgumentBuilder) + + companion object { + const val SUCCESS = SINGLE_SUCCESS + const val INVALID_USAGE = SINGLE_SUCCESS + 1 + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/command/argument/EnumArgumentType.kt b/src/main/kotlin/com/paragon/backend/command/argument/EnumArgumentType.kt new file mode 100644 index 0000000..f9d1daa --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/command/argument/EnumArgumentType.kt @@ -0,0 +1,41 @@ +package com.paragon.backend.command.argument + +import com.mojang.brigadier.StringReader +import com.mojang.brigadier.arguments.ArgumentType +import com.mojang.brigadier.context.CommandContext +import com.mojang.brigadier.exceptions.CommandExceptionType +import com.mojang.brigadier.exceptions.CommandSyntaxException + +/** + * @author aesthetical + * @since 02/26/23 + */ +class EnumArgumentType>(private val enum: Class) : ArgumentType>, CommandExceptionType { + override fun parse(reader: StringReader): T { + val input = reader.readString() + if (input.isNullOrEmpty()) { + throw CommandSyntaxException(this) { "Cannot be null or empty" } + } + + for (constant in enum.enumConstants) { + if (input.equals(constant.toString(), ignoreCase = true)) { + return constant + } + } + + throw CommandSyntaxException(this) { "\"$input\" is not a valid enum type" } + } + + companion object { + + @JvmStatic + inline fun > enum(ctx: CommandContext, name: String): T { + return ctx.getArgument(name, Enum::class.java) as T + } + + @JvmStatic + inline fun > enum(enum: Class): EnumArgumentType { + return EnumArgumentType(enum) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/command/argument/ModuleArgumentType.kt b/src/main/kotlin/com/paragon/backend/command/argument/ModuleArgumentType.kt new file mode 100644 index 0000000..f5ef5a9 --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/command/argument/ModuleArgumentType.kt @@ -0,0 +1,36 @@ +package com.paragon.backend.command.argument + +import com.mojang.brigadier.StringReader +import com.mojang.brigadier.arguments.ArgumentType +import com.mojang.brigadier.context.CommandContext +import com.mojang.brigadier.exceptions.CommandExceptionType +import com.mojang.brigadier.exceptions.CommandSyntaxException +import com.paragon.Paragon +import com.paragon.backend.module.Module + +/** + * @author aesthetical + * @since 02/24/23 + */ +class ModuleArgumentType : ArgumentType, CommandExceptionType { + override fun parse(reader: StringReader): Module { + val s = reader.readString() + val parsed = s.lowercase().replace(" ", "") + return Paragon.moduleManager.getModules { + it.name.lowercase().replace(" ", "").equals(parsed, ignoreCase = true) + }.firstOrNull() ?: throw CommandSyntaxException(this) { "\"$s\" is a non-existent (null) module." } + } + + companion object { + + @JvmStatic + fun module(ctx: CommandContext, name: String): Module { + return ctx.getArgument(name, Module::class.java) + } + + @JvmStatic + fun module(): ModuleArgumentType { + return ModuleArgumentType() + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/config/Config.kt b/src/main/kotlin/com/paragon/backend/config/Config.kt new file mode 100644 index 0000000..5a46941 --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/config/Config.kt @@ -0,0 +1,29 @@ +package com.paragon.backend.config + +import com.paragon.Paragon +import com.paragon.util.io.FileUtil + +/** + * @author aesthetical + * @since 02/20/23 + */ +abstract class Config(path: String, create: Boolean = true) { + + val file = FileUtil.PARAGON_PATH.resolve(path) + + init { + if (create && !file.exists()) { + if (path.endsWith("/")) { + file.mkdirs() + } else { + file.createNewFile() + } + } + + Paragon.configManager.add(this) + } + + abstract fun save() + abstract fun load() + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/event/EventEra.kt b/src/main/kotlin/com/paragon/backend/event/EventEra.kt new file mode 100644 index 0000000..2afdf69 --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/event/EventEra.kt @@ -0,0 +1,10 @@ +package com.paragon.backend.event + +/** + * @author surge + * @since 19/02/2023 + */ +enum class EventEra { + PRE, + POST +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/event/EventProcessor.kt b/src/main/kotlin/com/paragon/backend/event/EventProcessor.kt new file mode 100644 index 0000000..a417ca7 --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/event/EventProcessor.kt @@ -0,0 +1,31 @@ +package com.paragon.backend.event + +import com.paragon.Paragon +import com.paragon.Paragon.Companion.version +import com.paragon.backend.event.events.mc.ShutdownEvent +import com.paragon.backend.event.events.mc.TitleEvent +import com.paragon.util.rendering.NVGWrapper +import me.bush.eventbus.annotation.EventListener + +/** + * @author surge + * @since 19/02/2023 + */ +class EventProcessor { + + init { + Paragon.bus.subscribe(this) + } + + @EventListener + fun onTitle(event: TitleEvent) { + event.title = "Paragon v" + version + " | " + String(TitleEvent.funnyArrays[(Math.random() * TitleEvent.funnyArrays.size).toInt()]) + } + + @EventListener + fun onShutdown(event: ShutdownEvent) { + NVGWrapper.terminate() + Paragon.moduleManager.save("current") + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/event/events/entity/EntityTickEvent.kt b/src/main/kotlin/com/paragon/backend/event/events/entity/EntityTickEvent.kt new file mode 100644 index 0000000..5e8181f --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/event/events/entity/EntityTickEvent.kt @@ -0,0 +1,17 @@ +package com.paragon.backend.event.events.entity + +import com.paragon.backend.event.EventEra +import me.bush.eventbus.event.Event +import net.minecraft.entity.LivingEntity + +/** + * @author aesthetical + * @since 02/19/23 + */ +class EntityTickEvent(val era: EventEra, val entity: LivingEntity) : Event() { + + override fun isCancellable(): Boolean { + return false + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/event/events/entity/EntityTraceEvent.kt b/src/main/kotlin/com/paragon/backend/event/events/entity/EntityTraceEvent.kt new file mode 100644 index 0000000..57aa2bc --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/event/events/entity/EntityTraceEvent.kt @@ -0,0 +1,14 @@ +package com.paragon.backend.event.events.entity + +import me.bush.eventbus.event.Event +import net.minecraft.util.hit.HitResult + +/** + * @author surge + * @since 28/02/2023 + */ +class EntityTraceEvent(val result: HitResult?) : Event() { + + override fun isCancellable() = true + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/event/events/entity/RaycastEvent.kt b/src/main/kotlin/com/paragon/backend/event/events/entity/RaycastEvent.kt new file mode 100644 index 0000000..886bd17 --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/event/events/entity/RaycastEvent.kt @@ -0,0 +1,13 @@ +package com.paragon.backend.event.events.entity + +import me.bush.eventbus.event.Event + +/** + * @author surge + * @since 13/03/2023 + */ +class RaycastEvent(var distance: Double, var tickDelta: Float, var includeFluids: Boolean) : Event() { + + override fun isCancellable() = false + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/event/events/input/control/AttackBlockEvent.kt b/src/main/kotlin/com/paragon/backend/event/events/input/control/AttackBlockEvent.kt new file mode 100644 index 0000000..667e61f --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/event/events/input/control/AttackBlockEvent.kt @@ -0,0 +1,15 @@ +package com.paragon.backend.event.events.input.control + +import me.bush.eventbus.event.Event +import net.minecraft.util.math.BlockPos +import net.minecraft.util.math.Direction + +/** + * @author aesthetical + * @since 02/20/23 + */ +class AttackBlockEvent(val blockPos: BlockPos, val direction: Direction) : Event() { + override fun isCancellable(): Boolean { + return true + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/event/events/input/control/ItemSlowdownEvent.kt b/src/main/kotlin/com/paragon/backend/event/events/input/control/ItemSlowdownEvent.kt new file mode 100644 index 0000000..93f68ad --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/event/events/input/control/ItemSlowdownEvent.kt @@ -0,0 +1,11 @@ +package com.paragon.backend.event.events.input.control + +import me.bush.eventbus.event.Event +import net.minecraft.client.network.ClientPlayerEntity + +class ItemSlowdownEvent(@JvmField val entity: ClientPlayerEntity) : Event() { + + override fun isCancellable(): Boolean { + return true + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/event/events/input/control/SneakSlowdownEvent.kt b/src/main/kotlin/com/paragon/backend/event/events/input/control/SneakSlowdownEvent.kt new file mode 100644 index 0000000..47ba58e --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/event/events/input/control/SneakSlowdownEvent.kt @@ -0,0 +1,11 @@ +package com.paragon.backend.event.events.input.control + +import me.bush.eventbus.event.Event +import net.minecraft.client.network.ClientPlayerEntity + +class SneakSlowdownEvent(@JvmField val entity: ClientPlayerEntity) : Event() { + + override fun isCancellable(): Boolean { + return true + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/event/events/input/io/KeyEvent.kt b/src/main/kotlin/com/paragon/backend/event/events/input/io/KeyEvent.kt new file mode 100644 index 0000000..bf9b31b --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/event/events/input/io/KeyEvent.kt @@ -0,0 +1,14 @@ +package com.paragon.backend.event.events.input.io + +import me.bush.eventbus.event.Event + +/** + * @author surge + * @since 11/02/2023 + */ +class KeyEvent(@JvmField val code: Int, @JvmField val action: Int) : Event() { + + override fun isCancellable(): Boolean { + return false + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/event/events/input/io/MouseEvent.kt b/src/main/kotlin/com/paragon/backend/event/events/input/io/MouseEvent.kt new file mode 100644 index 0000000..0d3654e --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/event/events/input/io/MouseEvent.kt @@ -0,0 +1,14 @@ +package com.paragon.backend.event.events.input.io + +import me.bush.eventbus.event.Event + +/** + * @author aesthetical + * @since 02/17/23 + */ +class MouseEvent(@JvmField val button: Int, @JvmField val action: Int) : Event() { + + override fun isCancellable(): Boolean { + return false + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/event/events/mc/ShutdownEvent.kt b/src/main/kotlin/com/paragon/backend/event/events/mc/ShutdownEvent.kt new file mode 100644 index 0000000..22068ed --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/event/events/mc/ShutdownEvent.kt @@ -0,0 +1,15 @@ +package com.paragon.backend.event.events.mc + +import me.bush.eventbus.event.Event + +/** + * @author surge + * @since 20/02/2023 + */ +class ShutdownEvent : Event() { + + override fun isCancellable(): Boolean { + return false + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/event/events/mc/TickEvent.kt b/src/main/kotlin/com/paragon/backend/event/events/mc/TickEvent.kt new file mode 100644 index 0000000..e91d3b1 --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/event/events/mc/TickEvent.kt @@ -0,0 +1,13 @@ +package com.paragon.backend.event.events.mc + +import me.bush.eventbus.event.Event + +/** + * @author surge + * @since 11/02/2023 + */ +class TickEvent : Event() { + + override fun isCancellable() = false + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/event/events/mc/TitleEvent.kt b/src/main/kotlin/com/paragon/backend/event/events/mc/TitleEvent.kt new file mode 100644 index 0000000..f2c2190 --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/event/events/mc/TitleEvent.kt @@ -0,0 +1,681 @@ +package com.paragon.backend.event.events.mc + +import me.bush.eventbus.event.Event +import java.util.* + +class TitleEvent(@JvmField var title: String) : Event() { + + override fun isCancellable(): Boolean { + return false + } + + companion object { + val funnyArrays: List = ArrayList( + listOf( + byteArrayOf(115, 117, 114, 103, 101, 32, 108, 105, 107, 101, 115, 32, 100, 105, 99, 107), + byteArrayOf(106, 101, 115, 115, 32, 105, 115, 32, 116, 97, 108, 108), + byteArrayOf( + 118, + 101, + 114, + 117, + 115, + 32, + 97, + 105, + 114, + 108, + 105, + 110, + 101, + 115, + 32, + 115, + 105, + 110, + 99, + 101, + 32, + 50, + 48, + 49, + 57 + ), + byteArrayOf( + 112, + 97, + 114, + 97, + 103, + 111, + 110, + 32, + 115, + 116, + 97, + 121, + 32, + 119, + 105, + 110, + 110, + 105, + 110, + 103 + ), + byteArrayOf( + 112, + 97, + 115, + 116, + 105, + 110, + 103, + 32, + 102, + 117, + 116, + 117, + 114, + 101, + 32, + 99, + 108, + 105, + 101, + 110, + 116 + ), + byteArrayOf( + 100, + 117, + 109, + 112, + 105, + 110, + 103, + 32, + 107, + 111, + 110, + 97, + 115, + 32, + 40, + 99, + 108, + 97, + 115, + 115, + 32, + 56, + 56, + 56, + 53, + 47, + 49, + 50, + 53, + 56, + 53, + 41 + ), + byteArrayOf(99, 104, 105, 99, 107, 32, 119, 105, 116, 104, 32, 97, 32, 100, 105, 99, 107), + byteArrayOf(112, 97, 115, 116, 105, 110, 103, 32, 115, 105, 110, 99, 101, 32, 50, 48, 49, 52), + byteArrayOf( + 112, + 97, + 99, + 107, + 101, + 116, + 102, + 108, + 121, + 105, + 110, + 103, + 32, + 119, + 105, + 116, + 104, + 32, + 115, + 107, + 105, + 100, + 100, + 101, + 100, + 32, + 107, + 111, + 110, + 97, + 115, + 32, + 112, + 97, + 99, + 107, + 101, + 116, + 102, + 108, + 121 + ), + byteArrayOf( + 115, + 101, + 110, + 100, + 105, + 110, + 103, + 32, + 114, + 101, + 113, + 117, + 101, + 115, + 116, + 32, + 116, + 111, + 32, + 99, + 104, + 101, + 99, + 107, + 105, + 112, + 46, + 97, + 109, + 97, + 122, + 111, + 110, + 97, + 119, + 115, + 46, + 99, + 111, + 109, + 46, + 46, + 46 + ), + byteArrayOf( + 115, + 110, + 111, + 114, + 116, + 105, + 110, + 103, + 32, + 99, + 111, + 107, + 101, + 32, + 111, + 102, + 102, + 32, + 97, + 32, + 115, + 116, + 114, + 105, + 112, + 112, + 101, + 114, + 32, + 97, + 115, + 115 + ), + byteArrayOf( + 102, + 101, + 101, + 100, + 105, + 110, + 103, + 32, + 104, + 97, + 117, + 115, + 101, + 109, + 97, + 115, + 116, + 101, + 114, + 115, + 32, + 99, + 111, + 107, + 101, + 32, + 97, + 100, + 100, + 105, + 99, + 116, + 105, + 111, + 110 + ), + byteArrayOf( + 99, + 114, + 121, + 105, + 110, + 103, + 32, + 111, + 118, + 101, + 114, + 32, + 97, + 32, + 103, + 114, + 105, + 101, + 102, + 101, + 100, + 32, + 98, + 108, + 111, + 99, + 107, + 32, + 103, + 97, + 109, + 101, + 32, + 98, + 97, + 115, + 101 + ), + byteArrayOf( + 77, + 89, + 32, + 69, + 78, + 68, + 75, + 82, + 73, + 83, + 84, + 65, + 76, + 46, + 77, + 69, + 32, + 66, + 65, + 83, + 69, + 32, + 73, + 83, + 32, + 66, + 69, + 84, + 84, + 69, + 82, + 33, + 33, + 33, + 33 + ), + byteArrayOf(98, 114, 111, 32, 49, 118, 49, 32, 111, 110, 32, 99, 99, 32, 114, 110), + byteArrayOf( + 114, + 101, + 118, + 101, + 114, + 116, + 105, + 110, + 103, + 32, + 65, + 108, + 112, + 104, + 97, + 115, + 32, + 83, + 116, + 97, + 99, + 107, + 101, + 100, + 32, + 51, + 50, + 107, + 115 + ), + byteArrayOf( + 109, + 97, + 107, + 105, + 110, + 103, + 32, + 74, + 101, + 115, + 115, + 32, + 98, + 108, + 111, + 99, + 107, + 32, + 109, + 101 + ), + byteArrayOf( + 99, + 97, + 117, + 115, + 105, + 110, + 103, + 32, + 109, + 105, + 110, + 111, + 114, + 32, + 105, + 110, + 99, + 111, + 110, + 118, + 101, + 110, + 105, + 101, + 110, + 99, + 101, + 115 + ), + byteArrayOf( + 98, + 97, + 105, + 116, + 105, + 110, + 103, + 32, + 107, + 105, + 100, + 115, + 32, + 111, + 110, + 32, + 50, + 98, + 50, + 116, + 112, + 118, + 112, + 46, + 110, + 101, + 116 + ), + byteArrayOf( + 99, + 114, + 121, + 105, + 110, + 103, + 32, + 111, + 118, + 101, + 114, + 32, + 99, + 104, + 105, + 110, + 97, + 119, + 97, + 114, + 101, + 46, + 99, + 99, + 32, + 108, + 101, + 97, + 107 + ), + byteArrayOf( + 110, + 111, + 33, + 33, + 33, + 32, + 105, + 32, + 100, + 105, + 100, + 110, + 116, + 32, + 112, + 97, + 115, + 116, + 101, + 32, + 102, + 114, + 111, + 109, + 32, + 112, + 104, + 111, + 98, + 111, + 115, + 33, + 33, + 33, + 32, + 105, + 32, + 99, + 104, + 97, + 110, + 103, + 101, + 100, + 32, + 116, + 104, + 101, + 32, + 118, + 97, + 114, + 105, + 97, + 98, + 108, + 101, + 32, + 110, + 97, + 109, + 101, + 115, + 33, + 33, + 33, + 33 + ), + byteArrayOf( + 105, + 110, + 115, + 117, + 108, + 116, + 105, + 110, + 103, + 32, + 119, + 101, + 108, + 115, + 104, + 32, + 112, + 101, + 111, + 112, + 108, + 101 + ), + byteArrayOf( + 109, + 97, + 107, + 105, + 110, + 103, + 32, + 102, + 117, + 110, + 32, + 111, + 102, + 32, + 102, + 114, + 101, + 101, + 100, + 111, + 109, + 32, + 117, + 110, + 105, + 116, + 115 + ), + byteArrayOf( + 115, + 101, + 110, + 100, + 105, + 110, + 103, + 32, + 100, + 111, + 117, + 98, + 108, + 101, + 32, + 116, + 104, + 101, + 32, + 112, + 97, + 99, + 107, + 101, + 116, + 115, + 32, + 116, + 111, + 32, + 100, + 111, + 32, + 100, + 111, + 117, + 98, + 108, + 101, + 32, + 116, + 104, + 101, + 32, + 100, + 97, + 109, + 97, + 103, + 101 + ) + ) + ) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/event/events/move/MoveEvent.kt b/src/main/kotlin/com/paragon/backend/event/events/move/MoveEvent.kt new file mode 100644 index 0000000..8d37d6d --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/event/events/move/MoveEvent.kt @@ -0,0 +1,41 @@ +package com.paragon.backend.event.events.move + +import com.paragon.mixin.duck.IVec3d +import com.paragon.util.calculations.MoveUtil.strafe +import me.bush.eventbus.event.Event +import net.minecraft.util.math.Vec3d + +/** + * @author aesthetical + * @since 02/18/23 + */ +class MoveEvent(val motionVec: Vec3d) : Event() { + + fun setX(x: Double) { + (motionVec as IVec3d).setX(x) + } + + fun setY(y: Double) { + (motionVec as IVec3d).setY(y) + } + + fun setZ(z: Double) { + (motionVec as IVec3d).setZ(z) + } + + fun nullOutVelocity() { + setX(0.0) + setZ(0.0) + } + + fun setSpeed(speed: Double) { + val strafe = strafe(speed) + setX(strafe[0]) + setZ(strafe[1]) + } + + override fun isCancellable(): Boolean { + return false + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/event/events/move/MoveUpdateEvent.kt b/src/main/kotlin/com/paragon/backend/event/events/move/MoveUpdateEvent.kt new file mode 100644 index 0000000..ae54019 --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/event/events/move/MoveUpdateEvent.kt @@ -0,0 +1,22 @@ +package com.paragon.backend.event.events.move + +import com.paragon.backend.event.EventEra +import me.bush.eventbus.event.Event + +/** + * @author aesthetical + * @since 02/17/23 + */ +class MoveUpdateEvent( + @JvmField val era: EventEra, + @JvmField var x: Double, + @JvmField var y: Double, + @JvmField var z: Double, + @JvmField var yaw: Float, + @JvmField var pitch: Float, + @JvmField var onGround: Boolean +) : Event() { + override fun isCancellable(): Boolean { + return true + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/event/events/move/TridentVelocityEvent.kt b/src/main/kotlin/com/paragon/backend/event/events/move/TridentVelocityEvent.kt new file mode 100644 index 0000000..a40ca3d --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/event/events/move/TridentVelocityEvent.kt @@ -0,0 +1,15 @@ +package com.paragon.backend.event.events.move + +import me.bush.eventbus.event.Event + +/** + * @author surge + * @since 24/02/2023 + */ +class TridentVelocityEvent(var x: Double, var y: Double, var z: Double) : Event() { + + override fun isCancellable(): Boolean { + return false + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/event/events/net/PacketEvent.kt b/src/main/kotlin/com/paragon/backend/event/events/net/PacketEvent.kt new file mode 100644 index 0000000..cc4c495 --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/event/events/net/PacketEvent.kt @@ -0,0 +1,19 @@ +package com.paragon.backend.event.events.net + +import me.bush.eventbus.event.Event +import net.minecraft.network.Packet + +/** + * @author aesthetical + * @since 02/17/23 + */ +open class PacketEvent(val packet: Packet<*>) : Event() { + + override fun isCancellable(): Boolean { + return true + } + + class Inbound(packet: Packet<*>) : PacketEvent(packet) + class Outbound(packet: Packet<*>) : PacketEvent(packet) + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/event/events/paragon/SettingUpdateEvent.kt b/src/main/kotlin/com/paragon/backend/event/events/paragon/SettingUpdateEvent.kt new file mode 100644 index 0000000..18350cd --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/event/events/paragon/SettingUpdateEvent.kt @@ -0,0 +1,14 @@ +package com.paragon.backend.event.events.paragon + +import com.paragon.backend.setting.Setting +import me.bush.eventbus.event.Event + +/** + * @author surge + * @since 11/02/2023 + */ +class SettingUpdateEvent(val setting: Setting<*>) : Event() { + + override fun isCancellable() = true + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/event/events/render/BlockAmbientLightLevelEvent.kt b/src/main/kotlin/com/paragon/backend/event/events/render/BlockAmbientLightLevelEvent.kt new file mode 100644 index 0000000..67c0ebf --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/event/events/render/BlockAmbientLightLevelEvent.kt @@ -0,0 +1,14 @@ +package com.paragon.backend.event.events.render + +import me.bush.eventbus.event.Event +import net.minecraft.util.math.BlockPos + +/** + * @author aesthetical + * @since 02/20/23 + */ +class BlockAmbientLightLevelEvent(val pos: BlockPos, var lightLevel: Float) : Event() { + override fun isCancellable(): Boolean { + return true + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/event/events/render/ClipToSpaceEvent.kt b/src/main/kotlin/com/paragon/backend/event/events/render/ClipToSpaceEvent.kt new file mode 100644 index 0000000..fa1ae92 --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/event/events/render/ClipToSpaceEvent.kt @@ -0,0 +1,13 @@ +package com.paragon.backend.event.events.render + +import me.bush.eventbus.event.Event + +/** + * @author aesthetical + * @since 02/19/23 + */ +class ClipToSpaceEvent(var distance: Double) : Event() { + override fun isCancellable(): Boolean { + return true + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/event/events/render/DrawSideOfBlockEvent.kt b/src/main/kotlin/com/paragon/backend/event/events/render/DrawSideOfBlockEvent.kt new file mode 100644 index 0000000..f26f90a --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/event/events/render/DrawSideOfBlockEvent.kt @@ -0,0 +1,16 @@ +package com.paragon.backend.event.events.render + +import me.bush.eventbus.event.Event +import net.minecraft.block.Block +import net.minecraft.block.BlockState +import net.minecraft.util.math.BlockPos + +/** + * @author aesthetical + * @since 02/20/23 + */ +class DrawSideOfBlockEvent(val block: Block, val pos: BlockPos, val state: BlockState, var drawSide: Boolean) : Event() { + override fun isCancellable(): Boolean { + return true + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/event/events/render/FPSLimitEvent.kt b/src/main/kotlin/com/paragon/backend/event/events/render/FPSLimitEvent.kt new file mode 100644 index 0000000..5ca17a1 --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/event/events/render/FPSLimitEvent.kt @@ -0,0 +1,17 @@ +package com.paragon.backend.event.events.render + +import me.bush.eventbus.event.Event + +/** + * @author surge + * @since 24/02/2023 + */ +class FPSLimitEvent : Event() { + + var limit: Int = 0 + + override fun isCancellable(): Boolean { + return true + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/event/events/render/GameRenderEvent.kt b/src/main/kotlin/com/paragon/backend/event/events/render/GameRenderEvent.kt new file mode 100644 index 0000000..5e0bb5a --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/event/events/render/GameRenderEvent.kt @@ -0,0 +1,15 @@ +package com.paragon.backend.event.events.render + +import me.bush.eventbus.event.Event +import net.minecraft.client.util.math.MatrixStack + +/** + * @author surge, aesthetical + * @since 12/02/2023 + */ +class GameRenderEvent(@JvmField val matrices: MatrixStack, @JvmField val tickDelta: Float) : Event() { + + override fun isCancellable(): Boolean { + return false + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/event/events/render/GammaModifyEvent.kt b/src/main/kotlin/com/paragon/backend/event/events/render/GammaModifyEvent.kt new file mode 100644 index 0000000..6c4df22 --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/event/events/render/GammaModifyEvent.kt @@ -0,0 +1,10 @@ +package com.paragon.backend.event.events.render + +import me.bush.eventbus.event.Event + +class GammaModifyEvent(@JvmField var gamma: Float) : Event() { + + override fun isCancellable(): Boolean { + return true + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/event/events/render/PreGameRenderEvent.kt b/src/main/kotlin/com/paragon/backend/event/events/render/PreGameRenderEvent.kt new file mode 100644 index 0000000..8ee5339 --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/event/events/render/PreGameRenderEvent.kt @@ -0,0 +1,15 @@ +package com.paragon.backend.event.events.render + +import me.bush.eventbus.event.Event + +/** + * @author surge + * @since 24/02/2023 + */ +class PreGameRenderEvent : Event() { + + override fun isCancellable(): Boolean { + return true + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/event/events/render/RenderHUDEvent.kt b/src/main/kotlin/com/paragon/backend/event/events/render/RenderHUDEvent.kt new file mode 100644 index 0000000..c7cf713 --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/event/events/render/RenderHUDEvent.kt @@ -0,0 +1,15 @@ +package com.paragon.backend.event.events.render + +import me.bush.eventbus.event.Event +import net.minecraft.client.util.math.MatrixStack + +/** + * @author aesthetical + * @since 02/17/23 + */ +class RenderHUDEvent(val stack: MatrixStack, val partialTicks: Float, @JvmField val width: Float, val height: Float) : Event() { + + override fun isCancellable(): Boolean { + return false + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/event/events/render/RenderNameplateEvent.kt b/src/main/kotlin/com/paragon/backend/event/events/render/RenderNameplateEvent.kt new file mode 100644 index 0000000..8ddb777 --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/event/events/render/RenderNameplateEvent.kt @@ -0,0 +1,16 @@ +package com.paragon.backend.event.events.render + +import me.bush.eventbus.event.Event +import net.minecraft.client.network.AbstractClientPlayerEntity + +/** + * @author aesthetical + * @since 02/19/23 + */ +class RenderNameplateEvent(val entity: AbstractClientPlayerEntity) : Event() { + + override fun isCancellable(): Boolean { + return true + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/event/events/render/SetScreenEvent.kt b/src/main/kotlin/com/paragon/backend/event/events/render/SetScreenEvent.kt new file mode 100644 index 0000000..3d97783 --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/event/events/render/SetScreenEvent.kt @@ -0,0 +1,16 @@ +package com.paragon.backend.event.events.render + +import me.bush.eventbus.event.Event +import net.minecraft.client.gui.screen.Screen + +/** + * @author aesthetical + * @since 02/18/23 + */ +class SetScreenEvent(val current: Screen?, val input: Screen?) : Event() { + + override fun isCancellable(): Boolean { + return false + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/framebuffer/MultiSampledFramebuffer.kt b/src/main/kotlin/com/paragon/backend/framebuffer/MultiSampledFramebuffer.kt new file mode 100644 index 0000000..c4e72f4 --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/framebuffer/MultiSampledFramebuffer.kt @@ -0,0 +1,152 @@ +package com.paragon.backend.framebuffer + +import com.mojang.blaze3d.platform.GlStateManager +import com.mojang.blaze3d.platform.GlStateManager.* +import com.mojang.blaze3d.systems.RenderSystem +import com.paragon.util.mc +import net.minecraft.client.gl.Framebuffer +import org.lwjgl.opengl.GL11 +import org.lwjgl.opengl.GL30 +import org.lwjgl.opengl.GL30.* + +/** + * Coffee Client's MSAA framebuffer used for reference because I have no fucking clue what I'm doing + * @author surge + * @since 17/02/2023 + */ +class MultiSampledFramebuffer(private val samples: Int) : Framebuffer(true) { + + private var rboColour = 0 + private var rboDepth = 0 + private var using = false + + init { + setClearColor(1f, 1f, 1f, 0f) + } + + override fun resize(width: Int, height: Int, getError: Boolean) { + if (textureWidth != width || textureHeight != height) { + super.resize(width, height, getError) + } + } + + override fun initFbo(width: Int, height: Int, getError: Boolean) { + RenderSystem.assertOnRenderThreadOrInit() + val maxSize = RenderSystem.maxSupportedTextureSize() + + require(!(width <= 0 || width > maxSize || height <= 0 || height > maxSize)) { "Window " + width + "x" + height + " size out of bounds (max. size: " + maxSize + ")" } + + viewportWidth = width + viewportHeight = height + textureWidth = width + textureHeight = height + + fbo = GL30.glGenFramebuffers() + + _glBindFramebuffer(GL_FRAMEBUFFER, fbo) + + rboColour = GL30.glGenRenderbuffers() + + _glBindRenderbuffer(GL_RENDERBUFFER, rboColour) + glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, GL11.GL_RGBA8, width, height) + _glBindRenderbuffer(GL_RENDERBUFFER, 0) + + rboDepth = GL30.glGenRenderbuffers() + + _glBindRenderbuffer(GL_RENDERBUFFER, rboDepth) + glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, GL11.GL_DEPTH_COMPONENT, width, height) + _glBindRenderbuffer(GL_RENDERBUFFER, 0) + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rboColour) + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rboDepth) + + colorAttachment = mc.framebuffer.colorAttachment + depthAttachment = mc.framebuffer.depthAttachment + + checkFramebufferStatus() + this.clear(getError) + endRead() + } + + override fun delete() { + RenderSystem.assertOnRenderThreadOrInit() + endRead() + endWrite() + + if (fbo > -1) { + _glBindFramebuffer(GL_FRAMEBUFFER, 0) + GlStateManager._glDeleteFramebuffers(fbo) + fbo = -1 + } + + if (rboColour > -1) { + GlStateManager._glDeleteRenderbuffers(rboColour) + + rboColour = -1 + } + if (rboDepth > -1) { + GlStateManager._glDeleteRenderbuffers(rboDepth) + rboDepth = -1 + } + + colorAttachment = -1 + depthAttachment = -1 + textureWidth = -1 + textureHeight = -1 + } + + override fun beginWrite(setViewport: Boolean) { + super.beginWrite(setViewport) + + if (!using) { + ACTIVE.add(this) + using = true + } + } + + override fun endWrite() { + super.endWrite() + + if (using) { + ACTIVE.remove(this) + using = false + } + } + + companion object { + private const val MINIMUM = 2 + private val INSTANCES: MutableMap = HashMap() + private val ACTIVE: MutableList = ArrayList() + + fun getInstance(samples: Int): MultiSampledFramebuffer { + return INSTANCES.computeIfAbsent(samples) { x: Int? -> MultiSampledFramebuffer(samples) } + } + + @JvmStatic + fun use(block: Runnable) { + use(32.coerceAtMost(MINIMUM), mc.framebuffer, block) + } + + private fun use(samples: Int, main: Framebuffer, block: Runnable) { + RenderSystem.assertOnRenderThread() + + val framebuffer = getInstance(samples) + framebuffer.resize(main.textureWidth, main.textureHeight, true) + + _glBindFramebuffer(GL_READ_FRAMEBUFFER, main.fbo) + _glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer.fbo) + _glBlitFrameBuffer(0, 0, framebuffer.textureWidth, framebuffer.textureHeight, 0, 0, framebuffer.textureWidth, framebuffer.textureHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR) + + framebuffer.beginWrite(true) + block.run() + framebuffer.endWrite() + + _glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer.fbo) + _glBindFramebuffer(GL_DRAW_FRAMEBUFFER, main.fbo) + _glBlitFrameBuffer(0, 0, framebuffer.textureWidth, framebuffer.textureHeight, 0, 0, framebuffer.textureWidth, framebuffer.textureHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR) + + framebuffer.clear(true) + main.beginWrite(false) + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/managers/AltManager.kt b/src/main/kotlin/com/paragon/backend/managers/AltManager.kt new file mode 100644 index 0000000..1220bbd --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/managers/AltManager.kt @@ -0,0 +1,164 @@ +package com.paragon.backend.managers + +import com.paragon.Paragon +import com.paragon.backend.alt.Alt +import com.paragon.backend.config.Config +import com.paragon.mixin.duck.IMinecraftClient +import com.paragon.util.backgroundThread +import com.paragon.util.io.FileUtil +import com.paragon.util.mc +import fr.litarvan.openauth.microsoft.MicrosoftAuthenticationException +import fr.litarvan.openauth.microsoft.MicrosoftAuthenticator +import net.minecraft.client.util.Session +import org.json.JSONObject +import java.util.* + +/** + * @author surge + * @since 22/02/2023 + */ +class AltManager { + + private val microshitAuth = MicrosoftAuthenticator() + val alts = mutableListOf() + + var status = "Logged in as ${mc.session.username}" + + init { + + object : Config("alts.json") { + override fun save() { + val json = JSONObject() + + alts.forEach { + val altJson = JSONObject() + altJson.put("password", it.password) + altJson.put("cachedUsername", it.cachedUsername) + + if (it.accountType == Session.AccountType.MSA && !it.refreshToken.isNullOrEmpty()) { + // TODO: don't store in plaintext + altJson.put("refreshToken", it.refreshToken) + } + + json.put(it.email, altJson) + } + + if (!file.exists()) { + file.createNewFile() + } + + FileUtil.write(file, json.toString(4)) + } + + override fun load() { + if (!file.exists()) { + return + } + + val content = FileUtil.read(file) + if (content.isNullOrEmpty()) { + return + } + + try { + val json = JSONObject(content) + + json.keySet().forEach { + val altJson = json.getJSONObject(it) + + val alt = Alt(it, altJson.getString("password")) + if (altJson.has("cachedUsername")) { + alt.cachedUsername = altJson.getString("cachedUsername") + } + + if (altJson.has("refreshToken") && alt.accountType == Session.AccountType.MSA) { + alt.refreshToken = altJson.getString("refreshToken") + } + + alts.add(alt) + } + } catch (e: Exception) { + e.printStackTrace() + } + } + + } + } + + fun login(alt: Alt) { + + // run in a different thread to not freeze up the main thread + backgroundThread { + when (alt.accountType) { + Session.AccountType.MSA -> { + if (alt.session == null) { + Paragon.logger.info("Logging in with ${alt.email}") + status = "Logging in with ${alt.cachedUsername}" + + if (alt.refreshToken.isNullOrEmpty()) { + try { + val result = microshitAuth.loginWithCredentials(alt.email, alt.password) // Get auth result + + // Set alt session + alt.refreshToken = result.refreshToken + alt.session = Session(result.profile.name, result.profile.id, result.accessToken, Optional.empty(), Optional.empty(), Session.AccountType.MSA) + + status = "Logged in as ${alt.cachedUsername}" + } catch (e: MicrosoftAuthenticationException) { + status = "Couldn't log in as ${alt.cachedUsername}" + e.printStackTrace() + return@backgroundThread + } + } else { + if (!loginWithRefreshToken(alt)) { + // re-login + Paragon.logger.info("Failed to use refresh token. Re-logging in") + alt.refreshToken = null + login(alt) + + return@backgroundThread + } + } + + } + } + + Session.AccountType.LEGACY -> { + alt.session = Session(alt.email, UUID.randomUUID().toString(), "", Optional.empty(), Optional.empty(), Session.AccountType.LEGACY) + status = "Logged in as ${alt.cachedUsername}" + return@backgroundThread + } + + else -> { + Paragon.logger.warn("Unknown state with alt ${alt.email}") + status = "Unknown state with ${alt.cachedUsername}" + return@backgroundThread + } + } + }.invokeOnCompletion { + alt.cachedUsername = alt.session!!.username + (mc as IMinecraftClient).setSession(alt.session) + } + } + + private fun loginWithRefreshToken(alt: Alt): Boolean { + if (alt.accountType != Session.AccountType.MSA || alt.refreshToken.isNullOrEmpty()) { + login(alt) + return false + } + + return try { + val result = microshitAuth.loginWithRefreshToken(alt.refreshToken) + + // Set alt session + alt.session = Session(result.profile.name, result.profile.id, result.accessToken, Optional.empty(), Optional.empty(), Session.AccountType.MSA) + status = "Logged in as ${alt.cachedUsername}" + + true + } catch (e: MicrosoftAuthenticationException) { + status = "Failed to log in as ${alt.cachedUsername}" + e.printStackTrace() + false + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/managers/BaritoneManager.kt b/src/main/kotlin/com/paragon/backend/managers/BaritoneManager.kt new file mode 100644 index 0000000..b8c2cb7 --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/managers/BaritoneManager.kt @@ -0,0 +1,71 @@ +package com.paragon.backend.managers + +import baritone.api.BaritoneAPI +import baritone.api.Settings.Setting +import com.paragon.Paragon + +/** + * @author aesthetical + * @since 02/23/23 + */ +class BaritoneManager { + + private val saveStates = mutableMapOf() + + // TODO: Add ease of use methods here + + fun set(name: String, value: Any) { + val settingsProvider = BaritoneAPI.getSettings() + + try { + val field = settingsProvider.javaClass.getField(name) + val settingObject = field.get(settingsProvider) as Setting<*> + + if (saveStates.containsKey(name) && saveStates[name] == value) { + saveStates -= name + } else { + saveStates[name] = settingObject.value + } + + // fuck kotlin this piece of shit language oh my god + settingObject.javaClass.getField("value").set(settingObject, value) + } catch (e: Exception) { + Paragon.logger.warn("Tried to access baritone setting name $name while it does not exist") + } + } + + inline fun get(name: String): T? { + val settingsProvider = BaritoneAPI.getSettings() + + return try { + val field = settingsProvider.javaClass.getField(name) + val settingObject = field.get(settingsProvider) as Setting<*> + + settingObject.value as T + } catch (e: Exception) { + Paragon.logger.warn("Tried to access baritone setting name $name while it does not exist") + + null + } + } + + fun restoreValue(name: String) { + if (saveStates.containsKey(name)) { + set(name, saveStates[name]!!) + saveStates -= name + } + } + + fun restoreValues() { + if (saveStates.isNotEmpty()) { + println("Reverting ${saveStates.size} baritone state${if (saveStates.size != 1) "s" else ""} to previous states") + + for ((k, v) in saveStates) { + set(k, v) + } + + saveStates.clear() + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/managers/CommandManager.kt b/src/main/kotlin/com/paragon/backend/managers/CommandManager.kt new file mode 100644 index 0000000..9bbed20 --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/managers/CommandManager.kt @@ -0,0 +1,102 @@ +package com.paragon.backend.managers + +import com.mojang.brigadier.CommandDispatcher +import com.mojang.brigadier.builder.LiteralArgumentBuilder +import com.mojang.brigadier.exceptions.CommandSyntaxException +import com.paragon.Paragon +import com.paragon.backend.command.Command +import com.paragon.backend.config.Config +import com.paragon.backend.event.events.net.PacketEvent +import com.paragon.client.command.Configuration +import com.paragon.client.command.Drawn +import com.paragon.client.command.Prefix +import com.paragon.client.command.Toggle +import com.paragon.util.io.FileUtil +import com.paragon.util.mc +import com.paragon.util.print +import me.bush.eventbus.annotation.EventListener +import net.minecraft.network.packet.c2s.play.ChatMessageC2SPacket + + +/** + * @author aesthetical + * @since 02/24/23 + */ +class CommandManager { + + private val dispatcher = CommandDispatcher() + val commandMap = mutableMapOf() + + var prefix = "." + + init { + Paragon.bus.subscribe(this) + + dispatcher.setConsumer { context, _, result -> + val command = commandMap[context.input.split(" ")[0]] + if (command == null) { + mc.inGameHud.print("Unknown command execution. Run ${prefix}help") + return@setConsumer + } + + when (result) { + Command.INVALID_USAGE -> mc.inGameHud.print("Incorrect usage. Usage: ${command.usage}") + } + } + + object : Config("command_prefix.txt") { + override fun save() { + FileUtil.write(file, prefix) + } + + override fun load() { + val content = FileUtil.read(file) + if (content.isNullOrEmpty()) { + return + } + + prefix = content.trim().replace(" ", "").replace("\n", "") + } + + } + + register(Configuration, Drawn, Prefix, Toggle) + + // TODO: command autocomplete in chat gui + } + + @EventListener + fun onPacketOutbound(event: PacketEvent.Outbound) { + if (event.packet is ChatMessageC2SPacket) { + val packet = event.packet + if (packet.chatMessage.startsWith(prefix)) { + + event.isCancelled = true + + try { + Paragon.logger.info("Dispatching command with input ${packet.chatMessage}") + dispatcher.execute(dispatcher.parse(packet.chatMessage.substring(prefix.length), Command.SUCCESS)) + } catch (e: CommandSyntaxException) { + mc.inGameHud.print(e.rawMessage.string) + } + + } + } + } + + private fun register(vararg commands: Command) { + + commands.forEach { command -> + command.aliases.forEach { + commandMap[it] = command + + val argumentBuilder = LiteralArgumentBuilder.literal(it) + .executes { return@executes Command.INVALID_USAGE } + + command.run(argumentBuilder) + dispatcher.register(argumentBuilder) + } + } + + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/managers/ConfigManager.kt b/src/main/kotlin/com/paragon/backend/managers/ConfigManager.kt new file mode 100644 index 0000000..a92b855 --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/managers/ConfigManager.kt @@ -0,0 +1,46 @@ +package com.paragon.backend.managers + +import com.paragon.Paragon +import com.paragon.backend.config.Config +import com.paragon.util.calculations.Timer + +/** + * @author aesthetical + * @since 02/20/23 + */ +class ConfigManager { + + private val configList = mutableListOf() + + init { + Runtime.getRuntime().addShutdownHook(Thread { + println("Saving ${configList.size} config${if (configList.size != 1) "s" else ""}...") + val timer = Timer() + timer.reset() + + for (config in configList) { + try { + config.save() + } catch (e: Exception) { + Paragon.logger.error("Exception while saving ${config}, stacktrace is below") + e.printStackTrace() + } + } + + val ms = timer.timeMs() + println("Saved data in ${ms}ms.") + + println("Reverting baritone states...") + Paragon.baritoneManager.restoreValues() + }) + } + + fun add(config: Config) { + configList.add(config) + } + + fun loadAll() { + configList.forEach { it.load() } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/managers/InventoryManager.kt b/src/main/kotlin/com/paragon/backend/managers/InventoryManager.kt new file mode 100644 index 0000000..7f0528e --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/managers/InventoryManager.kt @@ -0,0 +1,89 @@ +package com.paragon.backend.managers + +import com.paragon.Paragon +import com.paragon.backend.event.events.net.PacketEvent.Inbound +import com.paragon.backend.event.events.net.PacketEvent.Outbound +import com.paragon.util.mc +import me.bush.eventbus.annotation.EventListener +import net.minecraft.item.ItemStack +import net.minecraft.network.packet.c2s.play.UpdateSelectedSlotC2SPacket +import net.minecraft.network.packet.s2c.play.UpdateSelectedSlotS2CPacket + +/** + * @author aesthetical + * @since 02/18/23 + */ +class InventoryManager { + + /** + * The server-side slot. This allows us to keep track of silent swaps + */ + var serverSlot = -1 + private set + + /** + * If the player's inventory is opened + */ + private val openedInventory = false + + init { + Paragon.bus.subscribe(this) + } + + @EventListener + fun onPacketOutbound(event: Outbound) { + if (event.packet is UpdateSelectedSlotC2SPacket) { + serverSlot = event.packet.selectedSlot + } + } + + @EventListener + fun onPacketInbound(event: Inbound) { + // if for whatever reason the server decides to switch ur slot, here we go + if (event.packet is UpdateSelectedSlotS2CPacket) { + serverSlot = event.packet.slot + } + } + + /** + * Swaps to this slot server-side + * @param slot the slot to swap to + */ + fun swap(slot: Int) { + if (serverSlot != slot) { + mc.player!!.networkHandler.sendPacket(UpdateSelectedSlotC2SPacket(slot)) + } + } + + /** + * Syncs the server slot with the client slot + */ + fun sync() { + if (serverSlot != mc.player!!.inventory.selectedSlot) { + mc.player!!.networkHandler.sendPacket(UpdateSelectedSlotC2SPacket(mc.player!!.inventory.selectedSlot)) + } + } + + /** + * Checks if the [serverSlot] is not equal to the client slot + */ + val isDesynced: Boolean + get() { + return serverSlot != mc.player!!.inventory.selectedSlot + } + + val serverStack: ItemStack + get() { + if (serverSlot == -1) { + serverSlot = mc.player!!.inventory.selectedSlot + } + + return mc.player!!.inventory.main[serverSlot] + } + + val slot: Int + get() { + return if (serverSlot == -1) mc.player!!.inventory.selectedSlot else serverSlot + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/managers/KeyboardManager.kt b/src/main/kotlin/com/paragon/backend/managers/KeyboardManager.kt new file mode 100644 index 0000000..30c5cf7 --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/managers/KeyboardManager.kt @@ -0,0 +1,143 @@ +package com.paragon.backend.managers + +import com.paragon.Paragon +import com.paragon.backend.bind.Bind +import com.paragon.backend.bind.DeviceType +import com.paragon.backend.config.Config +import com.paragon.backend.event.events.input.io.KeyEvent +import com.paragon.backend.event.events.input.io.MouseEvent +import com.paragon.backend.module.Module +import com.paragon.util.io.FileUtil +import com.paragon.util.mc +import me.bush.eventbus.annotation.EventListener +import org.json.JSONObject +import org.lwjgl.glfw.GLFW +import java.util.concurrent.CopyOnWriteArrayList + +/** + * @author aesthetical + * @since 02/20/2023 + */ +class KeyboardManager { + + private val bindList = CopyOnWriteArrayList() + + init { + Paragon.bus.subscribe(this) + + object : Config("binds.json") { + + override fun save() { + val jsonObject = JSONObject() + + for (bind in bindList) { + val obj = JSONObject() + + if (bind.feature is Module) { + obj.put("featureType", "module") + } + + obj.put("code", bind.code) + obj.put("deviceType", bind.type.name) + obj.put("persistent", bind.isPersistent) + + jsonObject.put(bind.feature.name, obj) + } + + FileUtil.write(file, jsonObject.toString(4)) + } + + override fun load() { + val content = FileUtil.read(file) + + if (content.isNullOrEmpty()) { + return + } + + val jsonObject = JSONObject(content) + + for ((k, v) in jsonObject.toMap()) { + if (v !is HashMap<*, *>) { + continue + } + + if (!v.containsKey("featureType")) { + continue + } + + when (v["featureType"] as String) { + "module" -> { + val module = Paragon.moduleManager.modules.find { it.name.equals(k, ignoreCase = true) } + if (module == null) { + Paragon.logger.warn("Unknown module with name $k") + continue + } + + if (v.containsKey("code")) { + module.key.code = v["code"] as Int + } + + if (v.containsKey("deviceType")) { + module.key.type = DeviceType.valueOf((v["deviceType"] as String).uppercase()) + } + + if (v.containsKey("persistent")) { + module.key.isPersistent = v["persistent"] as Boolean + } + } + + "macro" -> Paragon.logger.warn("Modified binds file! Macros not implemented. Try later... ($k)") + else -> Paragon.logger.warn("Unknown feature type ${v["featureType"] as String}") + } + } + } + } + } + + @EventListener + fun onKey(event: KeyEvent) { + if (event.code == GLFW.GLFW_KEY_UNKNOWN || mc.currentScreen != null || event.action > 1) { + return + } + + bindList.forEach { bind -> + if (bind.code == event.code && bind.type == DeviceType.KEYBOARD) { + if (!bind.isPersistent) { + bind.state = event.action == GLFW.GLFW_PRESS + } else { + if (event.action == GLFW.GLFW_RELEASE) { + bind.state = !bind.state + } + } + } + } + } + + @EventListener + fun onMouse(event: MouseEvent) { + if (event.button == GLFW.GLFW_KEY_UNKNOWN || mc.currentScreen != null || event.action > 1) { + return + } + + bindList.forEach { bind -> + if (bind.code == event.button && bind.type == DeviceType.MOUSE) { + if (!bind.isPersistent) { + bind.state = event.action == GLFW.GLFW_PRESS + } else { + if (event.action == GLFW.GLFW_RELEASE) { + bind.state = !bind.state + } + } + } + } + } + + fun addBind(bind: Bind) { + bindList.add(bind) + + if (bind.type == DeviceType.UNKNOWN) { + Paragon.logger.warn("Bind with code {} signed to unknown device with feature {} linked", bind.code, bind.feature) + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/managers/ModuleManager.kt b/src/main/kotlin/com/paragon/backend/managers/ModuleManager.kt new file mode 100644 index 0000000..afefe27 --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/managers/ModuleManager.kt @@ -0,0 +1,171 @@ +package com.paragon.backend.managers + +import com.paragon.Paragon +import com.paragon.backend.bind.Bind +import com.paragon.backend.module.Module +import com.paragon.client.modules.combat.* +import com.paragon.client.modules.exploit.Disabler +import com.paragon.client.modules.exploit.FastProjectile +import com.paragon.client.modules.exploit.PingSpoof +import com.paragon.client.modules.exploit.ThunderLocator +import com.paragon.client.modules.movement.* +import com.paragon.client.modules.player.* +import com.paragon.client.modules.visual.* +import com.paragon.util.io.FileUtil +import org.json.JSONObject +import java.nio.charset.Charset +import java.util.stream.Collectors + +/** + * @author surge + * @since 11/02/2023 + */ +class ModuleManager { + + val modules: List + + init { + Paragon.bus.subscribe(this) + + modules = listOf( + // Combat + Aura, + AutoTotem, + Burrow, + Criticals, + Velocity, + + // Exploit + Disabler, + FastProjectile, + PingSpoof, + ThunderLocator, + + // Movement + AntiVoid, + AutoJump, + ElytraFlight, + Flight, + InventoryMove, + LongJump, + NoFall, + NoSlowDown, + Speed, + Sprint, + Step, + TridentBoost, + + // Player + AirPlace, + AutoElytra, + AutoRespawn, + AutoTool, + BlockFly, + FakePlayer, + FastPlace, + GameSpeed, + LiquidPlace, + NoTrace, + PacketMine, + Replenish, + RotationLock, + Stealer, + + // Visual + ChinaHat, + ClickGUI, + ESP, + FullBright, + HoleESP, + HUD, + Tags, + Tracers, + Trajectories, + UnfocusedCPU, + ViewClip, + Xray + ) + + if (FileUtil.PARAGON_PATH.resolve("configs").exists()) { + FileUtil.PARAGON_PATH.resolve("configs").mkdir() + } + } + + fun load(name: String): String { + val file = FileUtil.PARAGON_PATH.resolve("configs").resolve("$name.json") + + if (!file.exists()) { + return "'$name.json' wasn't found in paragon/configs." + } + + val json = JSONObject(file.readText(Charset.defaultCharset())) + + val modules = json.getJSONObject("modules") ?: return "'modules' group wasn't found!" + + Paragon.moduleManager.modules.forEach { module -> + try { + val data = modules.getJSONObject(module.name) + + try { + module.setState(data.getBoolean("enabled")) + } catch (exception: Exception) { + Paragon.logger.warn("Failed to load state for ${module.name}") + } + + module.settingMap.forEach { (name, setting) -> + + if (setting.name == "Key" && setting.value is Bind) { + return@forEach + } + + try { + setting.load(data) + } catch (exception: Exception) { + Paragon.logger.warn("Failed to load $name") + } + } + } catch (exception: Exception) { + Paragon.logger.warn("Failed to load ${module.name}") + } + } + + return "Successfully loaded '$name.json'" + } + + fun save(name: String) { + val json = JSONObject() + val modules = JSONObject() + + Paragon.moduleManager.modules.forEach { module -> + val moduleJson = JSONObject() + + moduleJson.put("enabled", module.isEnabled) + + module.settingMap.forEach { (_, setting) -> + if (setting.name == "Key" && setting.value is Bind) { + return@forEach + } + + setting.write(moduleJson) + } + + modules.put(module.name, moduleJson) + } + + json.put("modules", modules) + json.put("version", Paragon.version) + + val file = FileUtil.PARAGON_PATH.resolve("configs").resolve("$name.json") + + if (!file.exists()) { + file.createNewFile() + } + + FileUtil.write(file, json.toString(4)) + } + + fun getModules(predicate: (Module) -> Boolean): List { + return modules.stream().filter(predicate).collect(Collectors.toList()) + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/managers/RotationManager.kt b/src/main/kotlin/com/paragon/backend/managers/RotationManager.kt new file mode 100644 index 0000000..8d45572 --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/managers/RotationManager.kt @@ -0,0 +1,120 @@ +package com.paragon.backend.managers + +import com.paragon.Paragon +import com.paragon.backend.event.EventEra +import com.paragon.backend.event.events.move.MoveUpdateEvent +import com.paragon.backend.event.events.net.PacketEvent.Outbound +import com.paragon.mixin.duck.ILivingEntity +import com.paragon.util.calculations.Timer +import com.paragon.util.calculations.rotation.RotationUtil +import com.paragon.util.mc +import me.bush.eventbus.annotation.EventListener +import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket +import net.minecraft.util.math.MathHelper + + +/** + * @author aesthetical + * @since 02/17/23 + */ +class RotationManager { + + private val releaseTimer: Timer + + val client: FloatArray + val server: FloatArray + + init { + Paragon.bus.subscribe(this) + + client = floatArrayOf(Float.NaN, Float.NaN) + server = floatArrayOf(0.0f, 0.0f) + releaseTimer = Timer() + } + + @EventListener + fun onPacketOutbound(event: Outbound) { + if (event.packet is PlayerMoveC2SPacket && event.packet.changesLook()) { + server[0] = event.packet.getYaw(mc.player!!.yaw) + server[1] = event.packet.getPitch(mc.player!!.pitch) + } + } + + @EventListener(recieveCancelled = true) + fun onMoveUpdate(event: MoveUpdateEvent) { + if (event.era == EventEra.PRE && mc.player != null) { + (mc.player as ILivingEntity?)!!.renderRotations[0] = server[0] + (mc.player as ILivingEntity?)!!.renderRotations[1] = server[1] + } + + if (RotationUtil.isValid(client)) { + if (releaseTimer.elapsed(KEEP_TIME.toDouble())) { + client[0] = Float.NaN + client[1] = Float.NaN + return + } + + event.yaw = client[0] + event.pitch = client[1] + event.isCancelled = true + + if (event.era == EventEra.PRE) { + rotateBody() + } + } + } + + private fun rotateBody() { + val xDiff = mc.player!!.x - mc.player!!.prevX + val yDiff = mc.player!!.z - mc.player!!.prevZ + + val distance = (xDiff * xDiff + yDiff * yDiff).toFloat() + var renderYawOffset = mc.player!!.bodyYaw + + if (distance > 0.0025000002f) { + renderYawOffset = Math.toDegrees(MathHelper.atan2(yDiff, xDiff)).toFloat() - 90.0f + } + + if (mc.player!!.handSwingProgress > 0.0f) { + renderYawOffset = client[0] + } + + val renderYawOffsetDiff = MathHelper.wrapDegrees(renderYawOffset - mc.player!!.bodyYaw) + mc.player!!.bodyYaw += renderYawOffsetDiff * 0.3f + + var rotationDiff = MathHelper.wrapDegrees(client[0] - mc.player!!.bodyYaw) + + if (rotationDiff < -75.0f) { + rotationDiff = -75.0f + } + + if (rotationDiff >= 75.0f) { + rotationDiff = 75.0f + } + + mc.player!!.bodyYaw = client[0] - rotationDiff + + if (rotationDiff * rotationDiff > 2500.0f) { + mc.player!!.bodyYaw += rotationDiff * 0.2f + } + } + + fun submit(yaw: Float, pitch: Float) { + releaseTimer.reset() + + client[0] = yaw + client[1] = pitch + } + + fun submit(f: FloatArray) { + releaseTimer.reset() + + client[0] = f[0] + client[1] = f[1] + } + + companion object { + private const val KEEP_TIME = 150L + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/managers/ToastManager.kt b/src/main/kotlin/com/paragon/backend/managers/ToastManager.kt new file mode 100644 index 0000000..c40eea2 --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/managers/ToastManager.kt @@ -0,0 +1,74 @@ +package com.paragon.backend.managers + +import com.paragon.Paragon +import com.paragon.backend.event.events.render.RenderHUDEvent +import com.paragon.client.toasts.Toast +import com.paragon.client.toasts.ToastType +import com.paragon.util.rendering.NVGWrapper +import me.bush.eventbus.annotation.EventListener +import java.util.concurrent.ConcurrentHashMap +import java.util.concurrent.atomic.AtomicInteger + +/** + * @author aesthetical + * @since 02/19/23 + */ +class ToastManager { + + private val toastMap: MutableMap = ConcurrentHashMap() + private val ID = AtomicInteger(0) + + init { + Paragon.bus.subscribe(this) + } + + @EventListener + fun onRenderHUD(event: RenderHUDEvent) { + NVGWrapper.scope { nvg -> + if (toastMap.isEmpty()) { + return@scope + } + + var posY = event.height - 56.0f + + for (id in toastMap.keys) { + val toast = toastMap[id] + + if (toast == null || toast.isDead) { + toastMap.remove(id) + continue + } + + toast.updateAndRender(nvg, posY, event.width) + posY -= (56.0f * toast.animation.animationFactor.toFloat()) + } + } + } + + fun info(deployer: String, content: String, lifespan: Long) { + add(ID.getAndIncrement(), Toast(ToastType.INFO, deployer, content, lifespan)) + } + + fun info(id: Int, deployer: String, content: String, lifespan: Long) { + add(id, Toast(ToastType.INFO, deployer, content, lifespan)) + } + + fun warn(deployer: String, content: String, lifespan: Long) { + add(ID.getAndIncrement(), Toast(ToastType.WARNING, deployer, content, lifespan)) + } + + fun warn(id: Int, deployer: String, content: String, lifespan: Long) { + add(id, Toast(ToastType.WARNING, content, deployer, lifespan)) + } + + private fun add(id: Int, toast: Toast) { + if (!toastMap.containsKey(id)) { + toastMap[id] = toast + } else { + val t = toastMap[id] + t!!.content = toast.content + t.endTime = System.currentTimeMillis() + t.lifespan + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/managers/placement/PlacementData.kt b/src/main/kotlin/com/paragon/backend/managers/placement/PlacementData.kt new file mode 100644 index 0000000..49737e5 --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/managers/placement/PlacementData.kt @@ -0,0 +1,30 @@ +package com.paragon.backend.managers.placement + +import com.paragon.util.mc +import net.minecraft.util.ActionResult +import net.minecraft.util.Hand +import net.minecraft.util.math.Direction + +/** + * @author surge + * @since 09/03/2023 + */ +data class PlacementData(val slot: Int, val direction: Direction, val swing: Swing = Swing.CLIENT, val hand: Hand = Hand.MAIN_HAND) { + + val originalSlot = mc.player!!.inventory.selectedSlot + + var accept: (ActionResult) -> Unit = { + if (it.shouldSwingHand()) { + mc.player!!.swingHand(Hand.MAIN_HAND) + } + } + + private set + + fun accept(action: (ActionResult) -> Unit): PlacementData { + accept = action + + return this + } + +} diff --git a/src/main/kotlin/com/paragon/backend/managers/placement/PlacementManager.kt b/src/main/kotlin/com/paragon/backend/managers/placement/PlacementManager.kt new file mode 100644 index 0000000..ba5792c --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/managers/placement/PlacementManager.kt @@ -0,0 +1,69 @@ +package com.paragon.backend.managers.placement + +import com.paragon.Paragon +import com.paragon.backend.event.events.mc.TickEvent +import com.paragon.util.mc +import com.paragon.util.player.PlayerUtil +import me.bush.eventbus.annotation.EventListener +import net.minecraft.util.ActionResult +import net.minecraft.util.Hand +import net.minecraft.util.hit.BlockHitResult +import net.minecraft.util.math.BlockPos +import net.minecraft.util.math.Vec3d + +/** + * @author surge + * @since 09/03/2023 + */ +class PlacementManager { + + private val placements = LinkedHashMap() + + init { + Paragon.bus.subscribe(this) + } + + @EventListener + fun onTick(event: TickEvent) { + if (placements.isEmpty()) { + return + } + + val position = placements.keys.first() + val placement = placements[position]!! + + Paragon.inventoryManager.swap(placement.slot) + Paragon.inventoryManager.sync() + + val res: ActionResult = mc.interactionManager!!.interactBlock( + mc.player, + Hand.MAIN_HAND, + + BlockHitResult(Vec3d(position.x.toDouble(), position.y.toDouble(), position.z.toDouble()).add(0.5, 0.5, 0.5), placement.direction, position, false) + ) + + if (res.isAccepted) { + if (res.shouldSwingHand()) { + when (placement.swing) { + Swing.CLIENT -> mc.player!!.swingHand(Hand.MAIN_HAND) + Swing.SERVER -> PlayerUtil.silentSwing(Hand.MAIN_HAND) + else -> {} + } + } + + placement.accept(res) + } + + if (mc.player!!.inventory.selectedSlot != placement.slot) { + Paragon.inventoryManager.swap(placement.originalSlot) + Paragon.inventoryManager.sync() + } + + placements.remove(placements.keys.first()) + } + + fun submit(position: BlockPos, data: PlacementData) { + this.placements[position] = data + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/managers/placement/Swing.kt b/src/main/kotlin/com/paragon/backend/managers/placement/Swing.kt new file mode 100644 index 0000000..603bd81 --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/managers/placement/Swing.kt @@ -0,0 +1,28 @@ +package com.paragon.backend.managers.placement + +import com.paragon.util.mc +import com.paragon.util.player.PlayerUtil +import net.minecraft.util.Hand + +/** + * @author surge + * @since 09/03/2023 + */ +enum class Swing(val swing: (Hand) -> Unit) { + + /** + * Swing client side + */ + CLIENT({ mc.player!!.swingHand(it) }), + + /** + * Swing server side + */ + SERVER({ PlayerUtil.silentSwing(it) }), + + /** + * Don't swing + */ + NONE({}) + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/module/Category.kt b/src/main/kotlin/com/paragon/backend/module/Category.kt new file mode 100644 index 0000000..5679301 --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/module/Category.kt @@ -0,0 +1,32 @@ +package com.paragon.backend.module + +/** + * @author surge + * @since 11/02/2023 + */ +enum class Category(val displayName: String) { + /** + * Combat modules, e.g. Aura + */ + COMBAT("Combat"), + + /** + * Exploit modules, e.g. Ping Spoof, Packet Flight + */ + EXPLOIT("Exploit"), + + /** + * Movement modules, e.g. Step + */ + MOVEMENT("Movement"), + + /** + * Visual modules, e.g. ESP + */ + VISUAL("Visual"), + + /** + * Player modules, e.g. Anti Void + */ + PLAYER("Player") +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/module/Module.kt b/src/main/kotlin/com/paragon/backend/module/Module.kt new file mode 100644 index 0000000..11247dc --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/module/Module.kt @@ -0,0 +1,50 @@ +package com.paragon.backend.module + +import com.paragon.Paragon +import com.paragon.backend.ToggleFeature +import com.paragon.backend.bind.Bind +import me.surge.animation.BoundedAnimation +import me.surge.animation.Easing + +/** + * @author surge + * @since 11/02/2023 + */ +open class Module(name: String, description: String, val category: Category) : ToggleFeature(name, description) { + + val animation = BoundedAnimation(0.0f, 100.0f, 200f, false, Easing.CUBIC_IN_OUT) + + var visible by bool("Visible", true, "The module's visibility in the ClickGUI") + val key by bind("Key", Bind(this), "The key used to toggle the module") + + init { + key.setInhibitor { _, bind -> setState(bind.state) } + Paragon.keyboardManager.addBind(key) + } + + override fun enable() {} + override fun disable() {} + + override fun setState(state: Boolean) { + this.isEnabled = state + animation.state = state + + if (state) { + enable() + Paragon.bus.subscribe(this) + } else { + Paragon.bus.unsubscribe(this) + disable() + } + + Paragon.toastManager.info(this.name, "$name was toggled ${if (state) "on" else "off"}", 1000L) + } + + open val info: () -> String? = { null } + + fun toggle() { + key.state = !isEnabled + } + + fun isActive(): Boolean = isEnabled || animation.linearFactor > 0.0 +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/setting/Colour.kt b/src/main/kotlin/com/paragon/backend/setting/Colour.kt new file mode 100644 index 0000000..31ac276 --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/setting/Colour.kt @@ -0,0 +1,19 @@ +package com.paragon.backend.setting + +import java.awt.Color + +/** + * @author surge + * @since 11/02/2023 + */ +class Colour(r: Int, g: Int, b: Int, a: Int) : Color(r, g, b, a) { + + private val rainbow = false + private val rainboxSpeed = 4f + private val rainbowSaturation = 100f + private val synced = false + + fun integrateAlpha(alpha: Int): Colour { + return Colour(this.red, this.green, this.blue, alpha) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/setting/RegistrySetting.kt b/src/main/kotlin/com/paragon/backend/setting/RegistrySetting.kt new file mode 100644 index 0000000..7e97f6c --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/setting/RegistrySetting.kt @@ -0,0 +1,75 @@ +package com.paragon.backend.setting + +import com.paragon.Paragon +import net.minecraft.registry.Registry +import org.json.JSONArray +import org.json.JSONObject +import java.util.function.Predicate +import kotlin.reflect.KProperty + +/** + * TODO: Categorise by given enum, e.g. EntityType -> SpawnGroup + * + * @author surge + * @since 06/03/2023 + */ +class RegistrySetting(name: String, registry: Registry, description: String, private val default: Boolean) : Setting>(name, description, registry) { + + val states = hashMapOf().also { + registry.sortedBy { it.toString() }.forEach { registryValue -> + it[registryValue] = default + } + } + + fun getState(key: Any): Boolean { + return getStateT(key as T) + } + + fun getStateT(key: T): Boolean { + return states[key] ?: default + } + + fun setState(key: Any, value: Boolean) { + setStateT(key as T, value) + } + + fun setStateT(key: T, value: Boolean) { + states[key] = value + } + + fun enabled(): List { + return states.filter { it.value }.map { it.key } + } + + fun disabled(): List { + return states.filter { !it.value }.map { it.key } + } + + override fun write(json: JSONObject) { + val obj = JSONObject() + + states.forEach { (key, value) -> + obj.put(key.toString(), value) + } + + json.put(this.name, obj) + } + + override fun load(json: JSONObject) { + try { + val obj = json.getJSONObject(this.name) + + obj.keys().forEach { key -> + val value = obj.getBoolean(key) + val mappedKey = this.states.keys.first { it.toString() == key } + + if (mappedKey != null) { + this.states[mappedKey] = value + } + } + } catch (exception: Exception) { + Paragon.logger.warn("Failed to load $name") + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/setting/Setting.kt b/src/main/kotlin/com/paragon/backend/setting/Setting.kt new file mode 100644 index 0000000..978abe4 --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/setting/Setting.kt @@ -0,0 +1,144 @@ +package com.paragon.backend.setting + +import com.paragon.Paragon +import com.paragon.backend.Feature +import com.paragon.backend.event.events.paragon.SettingUpdateEvent +import org.json.JSONObject +import java.util.* +import kotlin.reflect.KProperty + +/** + * @author surge + * @since 11/02/2023 + */ +open class Setting(name: String, description: String, value: T) : Feature(name, description) { + + var value: T = value + private set + + // number setting bounds + var minimum: T? = null + private set + + var maximum: T? = null + private set + + var incrementation: T? = null + private set + + // enumeration ordinal + private var index = 0 + + // if the setting is visible inside the GUI + var visibility: () -> Boolean = { true } + + // values that the current value cannot be + val exclusions: List = ArrayList() + + constructor(name: String, description: String, value: T, minimum: T, maximum: T, incrementation: T) : this(name, description, value) { + this.minimum = minimum + this.maximum = maximum + this.incrementation = incrementation + + if (value is Enum<*>) { + index = nextIndex + } + } + + fun setValue(value: T) { + if (value != this.value) { + Paragon.bus.post(SettingUpdateEvent(this)) + } + + if (value is Enum<*>) { + index = nextIndex + } + + this.value = value + + if (value is Enum<*> && exclusions.contains(value)) { + setValue(nextEnum) + } + } + + open fun write(json: JSONObject) { + json.put(this.name, this.value) + } + + open fun load(json: JSONObject) { + try { + this.value = when (this.value) { + is Int -> json.getInt(name) as T + is Float -> json.getFloat(name) as T + is Double -> json.getDouble(name) as T + is Boolean -> json.getBoolean(name) as T + is Enum<*> -> { + val enum = value as Enum<*> + val value = java.lang.Enum.valueOf(enum::class.java, json.getString(name)) + + run breakLoop@{ + enum::class.java.enumConstants.forEachIndexed { index, enumValue -> + if (enumValue.name == value.name) { + this.index = index + return@breakLoop + } + } + } + + value as T + } + + else -> { + this.value + } + } + } catch (exception: Exception) { + Paragon.logger.warn("Failed to load $name") + } + } + + val nextEnum: T + get() { + val enum = value as Enum<*> + + return java.lang.Enum.valueOf( + enum::class.java, + enum.javaClass.enumConstants.map { it.name }[nextIndex] + ) as T + } + + val previousEnum: T + get() { + val enum = value as Enum<*> + + var prevIndex = index - 1 + if (prevIndex < 0) { + prevIndex = enum.javaClass.enumConstants.size - 1 + } + + return java.lang.Enum.valueOf( + enum::class.java, + enum.javaClass.enumConstants.map { it.name }[prevIndex] + ) as T + } + + private val nextIndex: Int + get() { + val enum = value as Enum<*> + + return if (index + 1 > enum.javaClass.enumConstants.map { it.name }.size - 1) 0 else index + 1 + } + + operator fun getValue(thisRef: Any?, property: KProperty<*>): T = value + + operator fun setValue(thisRef: Any?, property: KProperty<*>, v: T) { + value = v + } + + infix fun visibility(condition: () -> Boolean): Setting { + this.visibility = condition + + return this + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/backend/setting/SettingContainer.kt b/src/main/kotlin/com/paragon/backend/setting/SettingContainer.kt new file mode 100644 index 0000000..488f48c --- /dev/null +++ b/src/main/kotlin/com/paragon/backend/setting/SettingContainer.kt @@ -0,0 +1,121 @@ +package com.paragon.backend.setting + +import com.paragon.backend.bind.Bind +import net.minecraft.predicate.NumberRange +import net.minecraft.registry.Registry + +/** + * @author aesthetical + * @since 02/20/23 + */ +open class SettingContainer { + val settingMap = mutableMapOf>() + + protected fun bool(name: String, value: Boolean, description: String = "No description provided"): Setting { + return setting(name, description, value) + } + + // bad color spelling "colour" bruh + protected fun colour(name: String, value: Colour, description: String = "No description provided"): Setting { + return setting(name, description, value) + } + + protected fun bind(name: String, value: Bind, description: String = "No description provided"): Setting { + return setting(name, description, value) + } + + protected inline fun > enum(name: String, value: T, description: String = "No description provided"): Setting { + return setting(name, description, value) + } + + protected fun float( + name: String, + value: Float, + incrementation: Float, + range: ClosedRange, + description: String = "No description provided" + ): Setting { + + val setting = Setting(name, description, value, range.start, range.endInclusive, incrementation) + settingMap[name] = setting + return setting + } + + protected fun double( + name: String, + value: Double, + incrementation: Double, + range: ClosedRange, + description: String = "No description provided" + ): Setting { + + val setting = Setting(name, description, value, range.start, range.endInclusive, incrementation) + settingMap[name] = setting + return setting + } + + protected fun int( + name: String, + value: Int, + incrementation: Int, + range: IntRange, + description: String = "No description provided" + ): Setting { + + val setting = Setting(name, description, value, range.first, range.last, incrementation) + settingMap[name] = setting + return setting + } + + protected inline fun number( + name: String, + value: T, + incrementation: T, + range: NumberRange, + description: String = "No description provided" + ): Setting { + + val setting = Setting(name, description, value, range.min as T, range.max as T, incrementation) + settingMap[name] = setting + return setting + } + + protected inline fun registry( + name: String, + registry: Registry, + default: Boolean, + description: String = "No description provided" + ): RegistrySetting<*> { + + val setting = RegistrySetting(name, registry, description, default) + settingMap[name] = setting + return setting + } + + protected inline fun setting(name: String, description: String, value: T): Setting { + val setting = Setting(name, description, value) + settingMap[name] = setting + return setting + } + + protected fun register(container: SettingContainer) { + container.getSettings().forEach { + settingMap[it.name] = it + } + } + + fun visibleWhen(condition: () -> Boolean) { + this.getSettings().forEach { + val original = it.visibility + + it.visibility = { original() && condition() } + } + } + + fun getSettings(): Collection> = settingMap.values + + fun get(name: String): Setting<*>? { + return settingMap[name] + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/command/Configuration.kt b/src/main/kotlin/com/paragon/client/command/Configuration.kt new file mode 100644 index 0000000..2724741 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/command/Configuration.kt @@ -0,0 +1,90 @@ +package com.paragon.client.command + +import com.mojang.brigadier.arguments.StringArgumentType +import com.mojang.brigadier.builder.LiteralArgumentBuilder +import com.mojang.brigadier.builder.RequiredArgumentBuilder +import com.paragon.Paragon +import com.paragon.backend.command.Command +import com.paragon.backend.command.argument.EnumArgumentType +import com.paragon.util.io.FileUtil +import com.paragon.util.mc +import com.paragon.util.print +import java.util.* + +/** + * @author aesthetical + * @since 02/26/23 + */ +object Configuration : Command( + arrayOf("config", "configuration", "cfg", "preset"), + usage = "[save | load | delete | list] ", + description = "Manages configurations") { + + override fun run(ctx: LiteralArgumentBuilder) { + ctx.then(RequiredArgumentBuilder.argument?>("action", EnumArgumentType.enum(Action::class.java)) + .executes { + + when (EnumArgumentType.enum(it, "action")) { + Action.LIST -> { + val fileList = FileUtil.PARAGON_PATH.resolve("configs").listFiles() + if (fileList == null) { + mc.inGameHud.print("There are no saved configurations") + return@executes SUCCESS + } + + mc.inGameHud.print(StringBuilder().apply { + + append("Config${if (fileList.size != 1) "s" else ""} list (${fileList.size})") + append(": ") + + val joiner = StringJoiner(", ") + for (file in fileList) { + joiner.add(file.nameWithoutExtension) + } + + append(joiner) + }.toString()) + } + + else -> mc.inGameHud.print("Please provide a configuration name to load, save or delete") + } + + return@executes SUCCESS + } + .then(RequiredArgumentBuilder.argument("configName", StringArgumentType.word()) + .executes { + + val configName = StringArgumentType.getString(it, "configName") + if (configName.isNullOrEmpty()) { + mc.inGameHud.print("Please provide a configuration name to load, save or delete") + return@executes SUCCESS + } + + when (EnumArgumentType.enum(it, "action")) { + Action.LOAD -> mc.inGameHud.print(Paragon.moduleManager.load(configName)) + Action.SAVE -> { + Paragon.moduleManager.save(configName) + mc.inGameHud.print("Saved config to file \"$configName.json\"") + } + Action.DELETE -> { + + if (configName.equals("current")) { + mc.inGameHud.print("You cannot delete the current configuration") + return@executes SUCCESS + } + + mc.inGameHud.print( + if (FileUtil.delete(FileUtil.PARAGON_PATH.resolve("configs").resolve("$configName.json"))) + "Deleted config file \"$configName.json\" successfully." + else "Unable to delete config file \"$configName.json\". Make sure it exists") + } + else -> mc.inGameHud.print("Cannot list a config (yet)") + } + return@executes SUCCESS + })) + } + + enum class Action { + SAVE, LOAD, DELETE, LIST + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/command/Drawn.kt b/src/main/kotlin/com/paragon/client/command/Drawn.kt new file mode 100644 index 0000000..e8d640c --- /dev/null +++ b/src/main/kotlin/com/paragon/client/command/Drawn.kt @@ -0,0 +1,25 @@ +package com.paragon.client.command + +import com.mojang.brigadier.builder.LiteralArgumentBuilder +import com.mojang.brigadier.builder.RequiredArgumentBuilder +import com.paragon.backend.command.Command +import com.paragon.backend.command.argument.ModuleArgumentType +import com.paragon.backend.module.Module +import com.paragon.util.mc +import com.paragon.util.print + +/** + * @author aesthetical + * @since 02/24/23 + */ +object Drawn : Command(arrayOf("drawn", "hide", "hid"), usage = "[module]") { + override fun run(ctx: LiteralArgumentBuilder) { + ctx.then(RequiredArgumentBuilder.argument("module", ModuleArgumentType.module()) + .executes { + val module = ModuleArgumentType.module(it, "module") + module.visible = !module.visible + mc.inGameHud.print("Module is now ${if (module.visible) "shown" else "hidden"} on the arraylist") + return@executes SUCCESS + }) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/command/Prefix.kt b/src/main/kotlin/com/paragon/client/command/Prefix.kt new file mode 100644 index 0000000..f111272 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/command/Prefix.kt @@ -0,0 +1,28 @@ +package com.paragon.client.command + +import com.mojang.brigadier.arguments.StringArgumentType +import com.mojang.brigadier.builder.LiteralArgumentBuilder +import com.mojang.brigadier.builder.RequiredArgumentBuilder +import com.paragon.Paragon +import com.paragon.backend.command.Command +import com.paragon.util.mc +import com.paragon.util.print + +/** + * @author aesthetical + * @since 02/24/23 + */ +object Prefix : Command(arrayOf("prefix", "pfx", "setprefix"), description = "Sets the command prefix") { + override fun run(ctx: LiteralArgumentBuilder) { + ctx.then(RequiredArgumentBuilder.argument("prefix", StringArgumentType.word()) + .executes { + Paragon.commandManager.prefix = StringArgumentType.getString(it, "prefix") + mc.inGameHud.print("Set the new command prefix to \"${Paragon.commandManager.prefix}\"") + return@executes SUCCESS + }) + .executes { + mc.inGameHud.print("Your current prefix is \"${Paragon.commandManager.prefix}\" (obviously dumbass)") + return@executes SUCCESS + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/command/Toggle.kt b/src/main/kotlin/com/paragon/client/command/Toggle.kt new file mode 100644 index 0000000..5c862c8 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/command/Toggle.kt @@ -0,0 +1,26 @@ +package com.paragon.client.command + +import com.mojang.brigadier.builder.LiteralArgumentBuilder +import com.mojang.brigadier.builder.RequiredArgumentBuilder +import com.paragon.backend.command.Command +import com.paragon.backend.command.argument.ModuleArgumentType +import com.paragon.backend.module.Module +import com.paragon.util.mc +import com.paragon.util.print + +/** + * @author aesthetical + * @since 02/24/23 + */ +object Toggle : Command(arrayOf("toggle", "t"), usage = "[module name]", description = "Toggles a module on or off") { + override fun run(ctx: LiteralArgumentBuilder) { + ctx.then(RequiredArgumentBuilder.argument("moduleName", ModuleArgumentType.module()) + .executes { + val module = ModuleArgumentType.module(it, "moduleName") + module.toggle() + + mc.inGameHud.print("Toggled ${module.name} ${if (module.isEnabled) "on" else "off"}.") + return@executes SUCCESS + }) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/combat/Aura.kt b/src/main/kotlin/com/paragon/client/modules/combat/Aura.kt new file mode 100644 index 0000000..b4cf350 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/combat/Aura.kt @@ -0,0 +1,128 @@ +package com.paragon.client.modules.combat + +import com.paragon.Paragon +import com.paragon.backend.event.EventEra +import com.paragon.backend.event.events.move.MoveUpdateEvent +import com.paragon.backend.event.events.render.GameRenderEvent +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import com.paragon.util.calculations.rotation.RotationUtil.calcToEntity +import com.paragon.util.calculations.rotation.Target +import com.paragon.util.getClientColour +import com.paragon.util.mc +import com.paragon.util.rendering.Renderer +import com.paragon.util.unattackables +import me.bush.eventbus.annotation.EventListener +import net.minecraft.entity.LivingEntity +import net.minecraft.registry.Registries +import net.minecraft.util.Hand +import kotlin.math.cos + +/** + * @author surge, aesthetical + * @since 11/02/2023 + */ +object Aura : Module("Aura", "Automatically attacks entities", Category.COMBAT) { + + private val filter = registry("Filter", Registries.ENTITY_TYPE, true, "Which entities to attack").also { + unattackables.forEach { type -> + it.setState(type, false) + } + } + + private val era by enum("Era", EventEra.PRE, "The time to attack at") + private val mode by enum("Mode", Mode.SWITCH, "How to target entities") + private val sort by enum("Sort", Sort.HEALTH, "How to sort targets") + private val range by double("Range", 4.0, 0.1, 1.0..6.0, "How far to attack from") + private val wallRange by double("Wall Range", 3.0, 0.1, 1.0..6.0, "How far to attack from through walls") + private val rotate by bool("Rotate", true, "If to rotate towards the entity") + private val target by enum("Target", Target.TORSO, "Where to rotate on the entity") + private val render by enum("Render", DrawMode.BOTH, "Render a polygon around the target") + private val sides by int("Sides", 8, 1, 3..120, "The amount of sides the polygon has") visibility { render != DrawMode.NONE } + private val alpha by int("Alpha", 100, 1, 0..255, "The alpha of the fill") visibility { render == DrawMode.FILL || render == DrawMode.BOTH } + + private var current: LivingEntity? = null + + override val info = { mode.name + ", " + range } + + override fun disable() { + current = null + } + + @EventListener(recieveCancelled = true) + fun onWalkingUpdate(event: MoveUpdateEvent) { + if (!isValidTarget(current) || mode == Mode.SWITCH) { + current = null + + val entities: MutableList = ArrayList() + + for (entity in mc.world!!.entities) { + if (entity is LivingEntity && isValidTarget(entity)) { + entities.add(entity) + } + } + + if (entities.isNotEmpty()) { + current = entities.stream() + .min(sort.comparator) + .orElse(null) + } + } + + if (current != null) { + if (rotate) { + Paragon.rotationManager.submit(calcToEntity(current!!, target)) + } + + if (event.era == era && mc.player!!.getAttackCooldownProgress(1.0f) == 1.0f) { + mc.interactionManager!!.attackEntity(mc.player, current) + mc.player!!.swingHand(Hand.MAIN_HAND) + } + } + } + + @EventListener(recieveCancelled = true) + fun onGameRender(event: GameRenderEvent) { + if (render != DrawMode.NONE && current != null) { + if (render == DrawMode.FILL || render == DrawMode.BOTH) { + Renderer.polygon(event.matrices, current!!.pos.add(0.0, current!!.height * (0.5 * (cos((mc.player!!.age * 4) * (Math.PI / 180)) + 1)), 0.0), current!!.width.toDouble(), getClientColour().integrateAlpha(alpha), Renderer.DrawMode.FILL, sides) + } + + if (render == DrawMode.OUTLINE || render == DrawMode.BOTH) { + Renderer.polygon(event.matrices, current!!.pos.add(0.0, current!!.height * (0.5 * (cos((mc.player!!.age * 4) * (Math.PI / 180)) + 1)), 0.0), current!!.width.toDouble(), getClientColour(), Renderer.DrawMode.LINES, sides) + } + } + } + + private fun isValidTarget(entity: LivingEntity?): Boolean { + if (entity == null || entity == mc.player || entity.isDead || entity.health <= 0.0f) { + return false + } + + if (entity.type !in filter.enabled()) { + return false + } + + val dist = if (mc.player!!.canSee(entity)) range else wallRange + + return mc.player!!.squaredDistanceTo(entity) <= dist * dist + } + + enum class Mode { + SINGLE, + SWITCH + } + + enum class Sort(val comparator: Comparator) { + HEALTH(Comparator.comparingDouble { obj: LivingEntity? -> obj!!.health.toDouble() }), + DISTANCE(Comparator.comparingDouble { entity: LivingEntity? -> entity!!.distanceTo(mc.player).toDouble() }) + } + + enum class DrawMode { + FILL, + OUTLINE, + BOTH, + NONE + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/combat/AutoTotem.kt b/src/main/kotlin/com/paragon/client/modules/combat/AutoTotem.kt new file mode 100644 index 0000000..76fcff3 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/combat/AutoTotem.kt @@ -0,0 +1,162 @@ +package com.paragon.client.modules.combat + +import com.paragon.backend.event.events.mc.TickEvent +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import com.paragon.util.calculations.Timer +import com.paragon.util.inventory.InventoryUtil +import com.paragon.util.inventory.InventoryUtil.normalize +import com.paragon.util.mc +import me.bush.eventbus.annotation.EventListener +import net.minecraft.block.Block +import net.minecraft.block.Blocks +import net.minecraft.entity.effect.StatusEffects +import net.minecraft.item.Item +import net.minecraft.item.Items +import net.minecraft.item.SwordItem +import net.minecraft.screen.slot.SlotActionType +import net.minecraft.util.Hand +import net.minecraft.util.math.BlockPos +import net.minecraft.util.math.MathHelper +import kotlin.math.roundToInt + +/** + * @author aesthetical + * @since 02/25/23 + */ +object AutoTotem : Module("Auto Totem", "Replaces items in your offhand", Category.COMBAT) { + + private val item by enum("Item", ItemType.TOTEM, "The item type") + private val health by float("Health", 16.0f, 0.1f, 1.0f..19.0f, "The health to swap to a totem") + private val delay by double("Delay", 0.1, 0.1, 0.0..3.5, "How long before replenishing the offhand slot") + private val gapple by bool("Gapple", true, "If to offhand gapple") + + private val timer = Timer() + + override val info = { getDisplayInfo().toString() } + + @EventListener + fun onTick(event: TickEvent) { + val fallDist = getMaxFallDist() + val items = if (mc.player!!.health < health || (fallDist > 0.0f && fallDist <= health)) { + ItemType.TOTEM.items + } else if (mc.options.useKey.isPressed && gapple && InventoryUtil.hasStackIn(Hand.MAIN_HAND, SwordItem::class.java)) { + ItemType.GAPPLE.items + } else { + item.items + } + + if (!InventoryUtil.hasStackIn(Hand.OFF_HAND, items) && timer.elapsed(delay * 1000.0)) { + timer.reset() + replaceInOffhand(items) + } + } + + private fun replaceInOffhand(items: Array) { + if (InventoryUtil.hasStackIn(Hand.OFF_HAND, items)) { + return + } + + var slot = -1 + for (i in 0..36) { + val itemStack = mc.player!!.inventory.getStack(i) + if (!itemStack.isEmpty) { + for (item in items) { + if (itemStack.item == item) { + slot = i + break + } + } + } + } + + if (slot == -1) { + return + } + + val hadInOffhand = !mc.player!!.getStackInHand(Hand.OFF_HAND).isEmpty + val syncId = mc.player!!.currentScreenHandler.syncId + mc.interactionManager!!.clickSlot(syncId, normalize(slot), 0, SlotActionType.PICKUP, mc.player) + mc.interactionManager!!.clickSlot(syncId, 45, 0, SlotActionType.PICKUP, mc.player) + if (hadInOffhand) { + mc.interactionManager!!.clickSlot(syncId, normalize(slot), 0, SlotActionType.PICKUP, mc.player) + } + + } + + private fun getMaxFallDist(): Float { + val multiplier = if (isBlockUnderSafe()) 0.0f else 1.0f + var reduction = 0.0f + if (mc.player!!.hasStatusEffect(StatusEffects.JUMP_BOOST)) { + reduction = (mc.player!!.getStatusEffect(StatusEffects.JUMP_BOOST)!!.amplifier + 1).toFloat() + } + + val dmg = MathHelper.ceil((getFirstBlockPosY() - 3.0f - reduction) * multiplier).toFloat() + return (mc.player!!.health - dmg).coerceAtLeast(0.0f) + } + + private fun getFirstBlockPosY(): Double { + for (y in 1 until 256 - (mc.player!!.y + 1.0).roundToInt()) { + val block: Block = mc.world!!.getBlockState(BlockPos( + mc.player!!.x + mc.player!!.velocity.x * 1.5, + (mc.player!!.y - y.toFloat()), + mc.player!!.z + mc.player!!.velocity.z * 1.5)).block + if (block != Blocks.AIR) { + return mc.player!!.y - y + } + } + + return -1.0 + } + + private fun isBlockUnderSafe(): Boolean { + for (y in 1 until 256 - (mc.player!!.y + 1.0).roundToInt()) { + val block: Block = mc.world!!.getBlockState(BlockPos( + mc.player!!.x + mc.player!!.velocity.x * 1.5, + (mc.player!!.y - y.toFloat()), + mc.player!!.z + mc.player!!.velocity.z * 1.5)).block + if (block == Blocks.SLIME_BLOCK && !mc.player!!.isSneaking || block == Blocks.COBWEB || block == Blocks.WATER) { + return true + } + } + + return false + } + + private fun getDisplayInfo(): Int { + val offhandStack = mc.player!!.getStackInHand(Hand.OFF_HAND) + return getItemCount(offhandStack.item) + } + + private fun getItemCount(vararg items: Item): Int { + var count = 0 + for (i in 0..36) { + val itemStack = mc.player!!.inventory.getStack(i) + if (!itemStack.isEmpty) { + for (item in items) { + if (itemStack.item == item) { + count += itemStack.count + } + } + } + } + + if (!mc.player!!.getStackInHand(Hand.OFF_HAND).isEmpty) { + val offhandStack = mc.player!!.getStackInHand(Hand.OFF_HAND) + for (item in items) { + if (offhandStack.item == item) { + count += offhandStack.count + } + } + } + + return count + } + + + enum class ItemType(vararg val items: Item) { + TOTEM(Items.TOTEM_OF_UNDYING), + CRYSTAL(Items.END_CRYSTAL), + GAPPLE(Items.GOLDEN_APPLE, Items.ENCHANTED_GOLDEN_APPLE) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/combat/Burrow.kt b/src/main/kotlin/com/paragon/client/modules/combat/Burrow.kt new file mode 100644 index 0000000..545ae1d --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/combat/Burrow.kt @@ -0,0 +1,185 @@ +package com.paragon.client.modules.combat + +import com.paragon.Paragon +import com.paragon.backend.event.EventEra +import com.paragon.backend.event.events.move.MoveUpdateEvent +import com.paragon.backend.event.events.net.PacketEvent +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import com.paragon.util.calculations.rotation.RotationUtil +import com.paragon.util.mc +import com.paragon.util.nullCheck +import com.paragon.util.player.PlayerUtil +import me.bush.eventbus.annotation.EventListener +import net.minecraft.block.Blocks +import net.minecraft.item.BlockItem +import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket +import net.minecraft.network.packet.s2c.play.BlockUpdateS2CPacket +import net.minecraft.util.Hand +import net.minecraft.util.hit.BlockHitResult +import net.minecraft.util.math.BlockPos +import net.minecraft.util.math.Direction +import net.minecraft.util.math.Vec3d +import java.lang.Double.isNaN + +/** + * @author aesthetical + * @since 02/20/23 + */ +object Burrow : Module("Burrow", "Lags you back into a block", Category.COMBAT) { + + private val vanillaJumpHeights = listOf(0.419999986886978, 0.7531999805212015, 1.001335979112147, 1.166109260938214) + private val validBlocks = listOf(Blocks.OBSIDIAN, Blocks.CRYING_OBSIDIAN, Blocks.BEDROCK, Blocks.ENDER_CHEST) + + private val rotate by bool("Rotate", true, "If to rotate towards the block you're placing on") + private val swing by bool("Swing", true, "If to swing client side") + private val autoSwap by enum("Auto Swap", AutoSwap.SERVER, "How to swap to the block") + private val replace by bool("Replace", false, "Keeps the module on and automatically replaces the burrow block") + + private var startY = Double.NaN + private var burrowing = false + private var swapped = false; + + override fun disable() { + super.disable() + startY = Double.NaN + burrowing = false + + if (swapped && !nullCheck()) { + Paragon.inventoryManager.sync() + } + + swapped = false + } + + @EventListener + fun onMoveUpdate(event: MoveUpdateEvent) { + + if (event.era == EventEra.POST) { + if (isNaN(startY)) { + startY = mc.player!!.y + } + + if (mc.player!!.y - startY > 0.2) { + toggle() + return + } + + val blockPos = BlockPos(mc.player!!.pos) + if (mc.world!!.getBlockState(blockPos).material.isReplaceable) { + burrow(blockPos) + if (!replace) { + toggle() + } + } + } + } + + @EventListener + fun onPacketInbound(event: PacketEvent.Inbound) { + if (nullCheck() || !replace) { + return + } + + if (event.packet is BlockUpdateS2CPacket) { + val packet = event.packet + if (packet.pos.equals(BlockPos(mc.player!!.pos)) && packet.state.isReplaceable) { + burrow(packet.pos) + } + } + } + + private fun burrow(blockPos: BlockPos) { + if (burrowing) { + return + } + + burrowing = true + + var result: PlaceResult? = null + for (facing in Direction.values()) { + val n = blockPos.offset(facing) + if (!mc.world!!.getBlockState(n).material.isReplaceable) { + result = PlaceResult(n, facing.opposite) + break + } + } + + if (result == null) { + burrowing = false + return + } + + var slot = -1 + for (i in 0..8) { + val itemStack = mc.player!!.inventory.getStack(i) + if (!itemStack.isEmpty && itemStack.item is BlockItem) { + val block = (itemStack.item as BlockItem).block + if (validBlocks.contains(block)) { + slot = i + break + } + } + } + + if (slot == -1) { + burrowing = false + return + } + + if (rotate) { + val rotations = RotationUtil.calcAngleToBlock(result.pos, result.direction) + Paragon.rotationManager.submit(rotations) + mc.player!!.networkHandler.sendPacket(PlayerMoveC2SPacket.LookAndOnGround(rotations[0], rotations[1], mc.player!!.isOnGround)) + } + + var oldSlot = -1 + swapped = true + if (autoSwap == AutoSwap.CLIENT) { + oldSlot = mc.player!!.inventory.selectedSlot + mc.player!!.inventory.selectedSlot = slot + } else { + Paragon.inventoryManager.swap(slot) + } + + for (value in vanillaJumpHeights) { + mc.player!!.networkHandler.sendPacket(PlayerMoveC2SPacket.PositionAndOnGround( + mc.player!!.x, mc.player!!.y + value, mc.player!!.z, false)) + } + + val actionResult = mc.interactionManager!!.interactBlock(mc.player, Hand.MAIN_HAND, + BlockHitResult( + Vec3d(result.pos.x.toDouble(), result.pos.y.toDouble(), result.pos.z.toDouble()) + .add(0.5, 0.5, 0.5), + result.direction, result.pos, false)) + + if (actionResult.isAccepted) { + if (swing) { + mc.player!!.swingHand(Hand.MAIN_HAND) + } else { + PlayerUtil.silentSwing(Hand.MAIN_HAND) + } + } + + // TODO: Stop this flagging! + mc.player!!.networkHandler.sendPacket(PlayerMoveC2SPacket.PositionAndOnGround( + mc.player!!.x, mc.player!!.y + 2.3, mc.player!!.z, false)) + + burrowing = false + + if (autoSwap == AutoSwap.CLIENT) { + mc.player!!.inventory.selectedSlot = oldSlot + } else { + Paragon.inventoryManager.sync() + } + + swapped = false + } + + private data class PlaceResult(val pos: BlockPos, val direction: Direction) + + enum class AutoSwap { + CLIENT, SERVER + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/combat/Criticals.kt b/src/main/kotlin/com/paragon/client/modules/combat/Criticals.kt new file mode 100644 index 0000000..5a8390a --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/combat/Criticals.kt @@ -0,0 +1,96 @@ +package com.paragon.client.modules.combat + +import com.paragon.backend.event.events.net.PacketEvent.Outbound +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import com.paragon.mixin.duck.IPlayerInteractEntityC2SPacket +import com.paragon.util.mc +import me.bush.eventbus.annotation.EventListener +import net.minecraft.entity.LivingEntity +import net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket +import net.minecraft.network.packet.c2s.play.PlayerInteractEntityC2SPacket +import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket.PositionAndOnGround +import net.minecraft.util.math.Vec3d + +/** + * @author aesthetical + * @since 02/17/22 + */ +object Criticals : Module("Criticals", "does funny extra damage", Category.COMBAT) { + + private val mode by enum("Mode", Mode.PACKET, "The anti-cheat bypass mode") + private val stopSprint by bool("Keep Sprint", true, "Allows you to crit even when sprinting") + + override val info = { mode.toString() } + + @EventListener + fun onPacket(event: Outbound) { + if (event.packet is IPlayerInteractEntityC2SPacket) { + if (event.packet.type == PlayerInteractEntityC2SPacket.InteractType.ATTACK && event.packet.entity is LivingEntity) { + if (!mc.player!!.isOnGround || mc.player!!.isHoldingOntoLadder || mc.player!!.isSubmergedInWater || mc.player!!.isInLava) { + return + } + + val sprint: Boolean = mc.player!!.isSprinting + + if (stopSprint && sprint) { + mc.player!!.networkHandler.sendPacket( + ClientCommandC2SPacket( + mc.player, + ClientCommandC2SPacket.Mode.STOP_SPRINTING + ) + ) + } + + when (mode) { + + Mode.PACKET -> { + mc.player!!.networkHandler.sendPacket( + PositionAndOnGround( + mc.player!!.x, + mc.player!!.y + 0.0625, + mc.player!!.z, + false + ) + ) + + mc.player!!.networkHandler.sendPacket( + PositionAndOnGround( + mc.player!!.x, + mc.player!!.y, + mc.player!!.z, + false + ) + ) + } + + Mode.NEW_NCP -> { + // TODO: Find NCP Updated bypasses + } + + Mode.MOTION -> { + val vel: Vec3d = mc.player!!.getVelocity() + mc.player!!.setVelocity(vel.x, vel.y + 0.2, vel.z) + } + + } + + if (stopSprint && sprint) { + mc.player!!.networkHandler.sendPacket( + ClientCommandC2SPacket( + mc.player, + ClientCommandC2SPacket.Mode.START_SPRINTING + ) + ) + } + } + } + } + + enum class Mode { + PACKET, + NEW_NCP, + MOTION + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/combat/Velocity.kt b/src/main/kotlin/com/paragon/client/modules/combat/Velocity.kt new file mode 100644 index 0000000..bf0f8a6 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/combat/Velocity.kt @@ -0,0 +1,50 @@ +package com.paragon.client.modules.combat + +import com.paragon.backend.event.events.net.PacketEvent.Inbound +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import com.paragon.mixin.mixins.net.packet.s2c.IEntityVelocityUpdateS2CPacket +import com.paragon.mixin.mixins.net.packet.s2c.IExplosionS2CPacket +import com.paragon.util.mc +import me.bush.eventbus.annotation.EventListener +import net.minecraft.network.packet.s2c.play.EntityVelocityUpdateS2CPacket +import net.minecraft.network.packet.s2c.play.ExplosionS2CPacket + +/** + * @author KassuK, aesthetical + * @since 02/18/23 + */ +object Velocity : Module("Velocity", "Modifies your velocity", Category.COMBAT) { + + private val cancelNull by bool("Cancel Null", true, "If to cancel velocity packets if H and V % is 0.0") + private val horizontal by float("Horizontal", 0.0f, 1.0f, 0f..100.0f, "How much horizontal kb") + private val vertical by float("Vertical", 0.0f, 1.0f, 0f..100.0f, "How much vertical kb") + + override val info = { "H: ${horizontal}%, V: ${vertical}%" } + + @EventListener + fun onPacketReceive(event: Inbound) { + if (event.packet is EntityVelocityUpdateS2CPacket && event.packet.id == mc.player!!.id) { + if (horizontal == 0.0f && vertical == 0.0f && cancelNull) { + event.isCancelled = true + return + } + + (event.packet as IEntityVelocityUpdateS2CPacket).setVelocityX((event.packet.velocityX * (horizontal / 100.0f)).toInt()) + (event.packet as IEntityVelocityUpdateS2CPacket).setVelocityY((event.packet.velocityY * (vertical / 100.0f)).toInt()) + (event.packet as IEntityVelocityUpdateS2CPacket).setVelocityZ((event.packet.velocityZ * (horizontal / 100.0f)).toInt()) + } + + if (event.packet is ExplosionS2CPacket) { + if (horizontal == 0.0f && vertical == 0.0f && cancelNull) { + event.isCancelled = true + return + } + + (event.packet as IExplosionS2CPacket).setVelocityX(event.packet.playerVelocityX * (horizontal / 100.0f)) + (event.packet as IExplosionS2CPacket).setVelocityY(event.packet.playerVelocityY * (vertical / 100.0f)) + (event.packet as IExplosionS2CPacket).setVelocityZ(event.packet.playerVelocityZ * (horizontal / 100.0f)) + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/exploit/Disabler.kt b/src/main/kotlin/com/paragon/client/modules/exploit/Disabler.kt new file mode 100644 index 0000000..65cd5ef --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/exploit/Disabler.kt @@ -0,0 +1,36 @@ +package com.paragon.client.modules.exploit + +import com.paragon.backend.event.events.net.PacketEvent +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import com.paragon.mixin.duck.IClientPlayerInteractionManager +import com.paragon.util.mc +import me.bush.eventbus.annotation.EventListener +import net.minecraft.network.packet.c2s.play.KeepAliveC2SPacket +import net.minecraft.network.packet.c2s.play.PlayerInteractBlockC2SPacket +import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket +import net.minecraft.util.Hand +import net.minecraft.util.hit.BlockHitResult +import net.minecraft.util.math.Direction +import net.minecraft.util.math.Vec3d + +/** + * @author aesthetical + * @since 04/09/23 + */ +object Disabler : Module("Disabler", "Disables anticheats", Category.EXPLOIT) { + + @EventListener + fun onPacketOutbound(event: PacketEvent.Outbound) { + if (event.packet is KeepAliveC2SPacket) { + event.cancel() + } else if (event.packet is PlayerMoveC2SPacket) { + (mc.interactionManager as IClientPlayerInteractionManager).hookSendSequencedPacket(mc.world) { seq -> + return@hookSendSequencedPacket PlayerInteractBlockC2SPacket( + Hand.MAIN_HAND, + BlockHitResult(Vec3d.ZERO, Direction.DOWN, mc.player!!.blockPos, false), + seq) + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/exploit/FastProjectile.kt b/src/main/kotlin/com/paragon/client/modules/exploit/FastProjectile.kt new file mode 100644 index 0000000..a5b7c30 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/exploit/FastProjectile.kt @@ -0,0 +1,32 @@ +package com.paragon.client.modules.exploit + +import com.paragon.backend.event.events.net.PacketEvent +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import com.paragon.util.mc +import me.bush.eventbus.annotation.EventListener +import net.minecraft.item.Items +import net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket +import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket +import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket.Full + +/** + * @author surge + * @since 27/02/2023 + */ +object FastProjectile : Module("Fast Projectile", "Manipulate the velocity of bows to give you a higher damage output", Category.EXPLOIT) { + private val shots by int("Shots", 10, 1, 1..300, "How many shots to take") + + @EventListener + fun onOutbound(event: PacketEvent.Outbound) { + if (event.packet is PlayerActionC2SPacket && event.packet.action == PlayerActionC2SPacket.Action.RELEASE_USE_ITEM && mc.player!!.mainHandStack.item == Items.BOW) { + mc.player!!.networkHandler!!.sendPacket(ClientCommandC2SPacket(mc.player, ClientCommandC2SPacket.Mode.START_SPRINTING)) + + for (i in 0..shots) { + mc.player!!.networkHandler!!.sendPacket(Full(mc.player!!.x, mc.player!!.y + 1e-10, mc.player!!.z, mc.player!!.yaw, mc.player!!.pitch, false)) + mc.player!!.networkHandler!!.sendPacket(Full(mc.player!!.x, mc.player!!.y - 1e-10, mc.player!!.z, mc.player!!.yaw, mc.player!!.pitch, true)) + } + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/exploit/PingSpoof.kt b/src/main/kotlin/com/paragon/client/modules/exploit/PingSpoof.kt new file mode 100644 index 0000000..c3e1a1c --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/exploit/PingSpoof.kt @@ -0,0 +1,63 @@ +package com.paragon.client.modules.exploit + +import com.paragon.backend.event.events.mc.TickEvent +import com.paragon.backend.event.events.net.PacketEvent +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import com.paragon.mixin.duck.IClientConnection +import com.paragon.util.calculations.Timer +import com.paragon.util.mc +import me.bush.eventbus.annotation.EventListener +import net.minecraft.network.Packet +import net.minecraft.network.packet.c2s.play.KeepAliveC2SPacket +import java.util.concurrent.ConcurrentHashMap + +/** + * @author surge + * @since 19/02/2023 + */ +object PingSpoof : Module("Ping Spoof", "Spoofs your latency", Category.EXPLOIT) { + + private val delay by double("Delay", 125.0, 0.1, 25.0..1000.0, "The time before releasing packets") + private val sequential by bool("Sequential", true, "If to send packets exactly at the original time sent + the delay") + + private val packetQueue = ConcurrentHashMap>() + private val timer = Timer() + + override val info = { delay.toString() } + + override fun enable() { + if (!sequential) { + timer.reset() + } + } + + @EventListener + fun onTick(event: TickEvent) { + if (sequential) { + packetQueue.forEach { (id: Long, packet: Packet<*>?) -> + if (System.currentTimeMillis() - id >= delay) { + (mc.player!!.networkHandler.connection as IClientConnection).sendPacketNoEvent(packet) + packetQueue.remove(id) + } + } + } else { + if (timer.elapsed(delay)) { + timer.reset() + packetQueue.forEach { (id: Long?, packet: Packet<*>?) -> + (mc.player!!.networkHandler.connection as IClientConnection).sendPacketNoEvent(packet) + packetQueue.remove(id) + } + } + } + } + + @EventListener + fun onPacketOutbound(event: PacketEvent.Outbound) { + if (event.packet is KeepAliveC2SPacket) { + event.isCancelled = true + packetQueue[System.currentTimeMillis()] = event.packet + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/exploit/ThunderLocator.kt b/src/main/kotlin/com/paragon/client/modules/exploit/ThunderLocator.kt new file mode 100644 index 0000000..3da16b0 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/exploit/ThunderLocator.kt @@ -0,0 +1,33 @@ +package com.paragon.client.modules.exploit + +import com.paragon.Paragon +import com.paragon.backend.event.events.net.PacketEvent +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import me.bush.eventbus.annotation.EventListener +import net.minecraft.network.packet.s2c.play.PlaySoundS2CPacket +import net.minecraft.sound.SoundEvent +import net.minecraft.sound.SoundEvents + +/** + * @author aesthetical + * @since 02/25/23 + */ +object ThunderLocator : Module("Thunder Locator", "Locates thunder", Category.EXPLOIT) { + + @EventListener + fun onPacketInbound(event: PacketEvent.Inbound) { + if (event.packet is PlaySoundS2CPacket) { + val packet = event.packet + + val soundEvent = (packet.sound.value() as SoundEvent) + if (soundEvent == SoundEvents.ENTITY_LIGHTNING_BOLT_THUNDER || soundEvent == SoundEvents.ENTITY_LIGHTNING_BOLT_IMPACT) { + Paragon.toastManager.info(this.name, + "Thunder sounded at ${String.format("%.1f", packet.x)}, ${String.format("%.1f", packet.y)}, ${String.format("%.1f", packet.z)}", + 5000L) + + } + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/movement/AntiVoid.kt b/src/main/kotlin/com/paragon/client/modules/movement/AntiVoid.kt new file mode 100644 index 0000000..8495516 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/movement/AntiVoid.kt @@ -0,0 +1,38 @@ +package com.paragon.client.modules.movement + +import com.paragon.backend.event.events.mc.TickEvent +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import com.paragon.mixin.duck.IVec3d +import com.paragon.util.mc +import me.bush.eventbus.annotation.EventListener +import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket.PositionAndOnGround + +/** + * @author aesthetical + * @since 02/18/23 + */ +object AntiVoid : Module("Anti Void", "Stops you from falling into the void", Category.MOVEMENT) { + + private val mode by enum("Mode", Mode.LAGBACK, "How to get you out of the void") + + override val info = { mode.toString() } + + @EventListener + fun onTick(event: TickEvent?) { + if (mc.player!!.y < mc.world!!.bottomY) { + when (mode) { + Mode.FLOAT -> (mc.player!!.velocity as IVec3d).setY(0.42) + Mode.LAGBACK -> mc.player!!.networkHandler.sendPacket(PositionAndOnGround(mc.player!!.x, mc.player!!.y + 0.1, mc.player!!.z, false)) + Mode.SUSPEND -> (mc.player!!.velocity as IVec3d).setY(0.0) + } + } + } + + enum class Mode { + SUSPEND, + FLOAT, + LAGBACK + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/movement/AutoJump.kt b/src/main/kotlin/com/paragon/client/modules/movement/AutoJump.kt new file mode 100644 index 0000000..8ef5200 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/movement/AutoJump.kt @@ -0,0 +1,31 @@ +package com.paragon.client.modules.movement + +import com.paragon.backend.event.events.mc.TickEvent +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import com.paragon.util.mc +import me.bush.eventbus.annotation.EventListener + +/** + * @author surge + * @since 06/03/2023 + */ +object AutoJump : Module("Auto Jump", "Automatically jumps for you", Category.MOVEMENT) { + + private val mode by enum("Mode", Mode.SPRINTING, "When to jump") + + @EventListener + fun onTick(event: TickEvent) { + if (mc.player!!.isOnGround && mode.check() && !mc.player!!.isSneaking) { + mc.player!!.jump() + } + } + + enum class Mode(val check: () -> Boolean) { + CONSTANT({ true }), + MOVING({ mc.player!!.lastRenderX != mc.player!!.x || mc.player!!.lastRenderZ != mc.player!!.z }), + SPRINTING({ (mc.player!!.forwardSpeed != 0f || mc.player!!.sidewaysSpeed != 0f) && mc.player!!.isSprinting }), + UNDER_BLOCK_SPRINT({ SPRINTING.check() && !mc.world!!.getBlockState(mc.player!!.blockPos.up(2)).isReplaceable }) + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/movement/ElytraFlight.kt b/src/main/kotlin/com/paragon/client/modules/movement/ElytraFlight.kt new file mode 100644 index 0000000..57b8da1 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/movement/ElytraFlight.kt @@ -0,0 +1,297 @@ +package com.paragon.client.modules.movement + +import com.paragon.Paragon +import com.paragon.backend.event.events.mc.TickEvent +import com.paragon.backend.event.events.move.MoveEvent +import com.paragon.backend.event.events.paragon.SettingUpdateEvent +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import com.paragon.backend.setting.Setting +import com.paragon.backend.setting.SettingContainer +import com.paragon.mixin.duck.IVec3d +import com.paragon.util.calculations.Timer +import com.paragon.util.inventory.InventoryUtil +import com.paragon.util.mc +import com.paragon.util.nullCheck +import com.paragon.util.truncate +import me.bush.eventbus.annotation.EventListener +import net.minecraft.enchantment.EnchantmentHelper +import net.minecraft.item.FireworkRocketItem +import net.minecraft.item.ItemStack +import net.minecraft.item.Items +import net.minecraft.item.TridentItem +import net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket +import net.minecraft.util.Hand +import net.minecraft.util.math.Vec3d +import kotlin.math.cos +import kotlin.math.sin + +/** + * @author surge + * @since 13/03/2023 + */ +object ElytraFlight : Module("Elytra Flight", "Allows you to fly easier with elytra", Category.MOVEMENT) { + + private var modeInstance: Setting + + private val mode by enum("Mode", Mode.VANILLA, "How to apply easier flight").also { + modeInstance = it + } + + private val vanillaSettings = object : SettingContainer() { + + val horizontalSpeed by double("Horizontal", 1.0, 0.1, 0.1..5.0, "How fast you move horizontally") + val verticalSpeed by double("Vertical", 1.0, 0.1, 0.1..5.0, "How fast you move vertically") + + }.also { + it.visibleWhen { mode == Mode.VANILLA } + register(it) + } + + private val fireworkSettings = object : SettingContainer() { + + val delay by double("Delay", 10.0, 0.1, 1.0..20.0, "The delay (in seconds) between using firework rockets") + val resetIdle by bool("Reset Idle", false, "Reset the timer when not flying") + val autoSwap by enum("Auto Swap", AutoSwap.CLIENT, "How to swap to rockets") + val swapBack by bool("Swap Back", true, "Automatically swap back to your original slot") visibility { autoSwap != AutoSwap.NONE } + val substituteTrident by bool("Substitute Trident", true, "Use a trident in place of fireworks if the conditions are met") + + }.also { + it.visibleWhen { mode == Mode.FIREWORK } + register(it) + } + + private val autoTakeoff by bool("Auto Takeoff", true, "Automatically starts flying when you press the jump button") + + private val takeoffSettings = object : SettingContainer() { + + val delay by int("Takeoff Delay", 8, 1, 0..20, "How many ticks to wait before flying") + + }.also { + it.visibleWhen { autoTakeoff } + register(it) + } + + private var jumpDelay = 0 + + override val info = { + when (mode) { + Mode.VANILLA -> "" + else -> (fireworkSettings.delay - (FireworkProcessor.timer.timeMs() / 1000f)).truncate(1) + } + } + + override fun postLoad() { + if (this.isEnabled) { + this.mode.processor.enable() + } + } + + override fun enable() { + jumpDelay = 0 + this.mode.processor.enable() + } + + override fun disable() { + if (!nullCheck()) { + Paragon.inventoryManager.sync() + } + + this.mode.processor.disable() + } + + @EventListener + fun onSettingUpdate(event: SettingUpdateEvent) { + if (event.setting == modeInstance) { + this.mode.processor.disable() + } + } + + @EventListener + fun onTick(event: TickEvent) { + if (autoTakeoff && mc.options.jumpKey.isPressed && !mc.player!!.isFallFlying && mc.player!!.armorItems.any { it.item == Items.ELYTRA && it.damage != it.maxDamage }) { + if (jumpDelay < takeoffSettings.delay) { + jumpDelay++ + } else { + jumpDelay = 0 + + if (mc.player!!.isOnGround) { + mc.player!!.setJumping(false) + mc.player!!.jump() + } + + mc.networkHandler!!.sendPacket(ClientCommandC2SPacket(mc.player, ClientCommandC2SPacket.Mode.START_FALL_FLYING)) + mc.player!!.startFallFlying() + + Paragon.toastManager.info(this.name, "Deploying Elytra!", 2000L) + } + } else { + jumpDelay = 0 + } + + mode.processor.onTick() + } + + private abstract class ModeProcessor { + + fun enable() { + Paragon.bus.subscribe(this) + } + + fun disable() { + Paragon.bus.unsubscribe(this) + } + + abstract fun onTick() + + } + + private object VanillaProcessor : ModeProcessor() { + + override fun onTick() {} + + @EventListener + fun onMove(event: MoveEvent) { + if (mc.player!!.isFallFlying) { + var forward = if (mc.options.forwardKey.isPressed) 1f else if (mc.options.backKey.isPressed) -1f else 0f + var strafe = if (mc.options.leftKey.isPressed) 1f else if (mc.options.rightKey.isPressed) -1f else 0f + val vertical = if (mc.options.jumpKey.isPressed) 1f else if (mc.options.sneakKey.isPressed) -1f else 0f + + var playerYaw = mc.player!!.yaw + + if (forward != 0f) { + if (strafe >= 1) { + playerYaw += (if (forward > 0) -45 else 45).toFloat() + strafe = 0f + } else if (strafe <= -1) { + playerYaw += (if (forward > 0) 45 else -45).toFloat() + strafe = 0f + } + + forward = if (forward > 0) { + 1f + } else { + -1f + } + } + + val sin = sin(Math.toRadians((playerYaw + 90).toDouble())) + val cos = cos(Math.toRadians((playerYaw + 90).toDouble())) + + val velocity = Vec3d(forward.toDouble() * vanillaSettings.horizontalSpeed * cos + strafe.toDouble() * vanillaSettings.horizontalSpeed * sin, vertical * vanillaSettings.verticalSpeed, forward.toDouble() * vanillaSettings.horizontalSpeed * sin - strafe.toDouble() * vanillaSettings.horizontalSpeed * cos) + + event.setX(velocity.x) + event.setY(velocity.y) + event.setZ(velocity.z) + } + } + + } + + private object FireworkProcessor : ModeProcessor() { + + val timer = Timer() + + override fun onTick() { + if (mc.player!!.isFallFlying && !mc.isPaused) { + if (timer.elapsed(fireworkSettings.delay, Timer.Format.SECONDS)) { + var hand = Hand.MAIN_HAND + + val original = mc.player!!.inventory.selectedSlot + + val tridentFound = InventoryUtil.find(InventoryUtil.HOTBAR) { + it.item is TridentItem && EnchantmentHelper.getRiptide(it) > 0 + } + + val shouldTrident = fireworkSettings.substituteTrident && tridentFound > -1 && mc.player!!.isTouchingWaterOrRain + + if (InventoryUtil.hasStackIn(Hand.OFF_HAND, FireworkRocketItem::class.java)) { + hand = Hand.OFF_HAND + } else { + when (fireworkSettings.autoSwap) { + AutoSwap.NONE -> { + if (mc.player!!.mainHandStack.item !is FireworkRocketItem && shouldTrident && mc.player!!.mainHandStack.item !is TridentItem) { + return + } + } + + AutoSwap.CLIENT, AutoSwap.SERVER -> { + val slot = if (shouldTrident) tridentFound else nextSlot + + if (slot == -1) { + return + } + + if (fireworkSettings.autoSwap == AutoSwap.CLIENT) { + mc.player!!.inventory.selectedSlot = slot + } else { + Paragon.inventoryManager.swap(slot) + } + } + } + } + + if (shouldTrident) { + mc.player!!.mainHandStack.onStoppedUsing(mc.world!!, mc.player!!, 0) + } else { + val result = mc.interactionManager!!.interactItem(mc.player, hand) + + if (result.shouldSwingHand()) { + mc.player!!.swingHand(hand) + } + } + + if (fireworkSettings.swapBack && mc.player!!.inventory.selectedSlot != original && hand == Hand.MAIN_HAND) { + if (fireworkSettings.autoSwap == AutoSwap.CLIENT || fireworkSettings.autoSwap == AutoSwap.SERVER) { + if (fireworkSettings.autoSwap == AutoSwap.CLIENT) { + mc.player!!.inventory.selectedSlot = original + } else { + Paragon.inventoryManager.swap(original) + } + } + } + + timer.reset() + } + } else if (fireworkSettings.resetIdle) { + timer.reset() + } + } + + private val nextSlot: Int + get() { + var slot: Int = mc.player!!.inventory.selectedSlot + var count = 0 + + if (mc.player!!.inventory.getStack(slot).item is FireworkRocketItem) { + count = mc.player!!.inventory.getStack(slot).count + } else { + slot = -1 + } + + for (i in 0..8) { + val stack: ItemStack = mc.player!!.inventory.getStack(i) + + if (stack.item is FireworkRocketItem && stack.count > count) { + slot = i + count = stack.count + } + } + + return slot + } + + } + + private enum class Mode(val processor: ModeProcessor) { + VANILLA(VanillaProcessor), + FIREWORK(FireworkProcessor) + } + + private enum class AutoSwap { + NONE, + CLIENT, + SERVER + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/movement/Flight.kt b/src/main/kotlin/com/paragon/client/modules/movement/Flight.kt new file mode 100644 index 0000000..f769ad1 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/movement/Flight.kt @@ -0,0 +1,70 @@ +package com.paragon.client.modules.movement + +import com.paragon.backend.event.events.mc.TickEvent +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import com.paragon.mixin.duck.IVec3d +import com.paragon.util.calculations.MoveUtil.moving +import com.paragon.util.calculations.MoveUtil.strafe +import com.paragon.util.mc +import me.bush.eventbus.annotation.EventListener + +/** + * @author surge, aesthetical + * @since 11/02/2023 + */ +object Flight : Module("Flight", "Lets you fly in survival mode", Category.MOVEMENT) { + + private val mode by enum("Mode", Mode.MOTION, "How to fly") + private val speed by float("Speed", 0.07f, 0.01f, 0.01f..0.5f, "How fast you fly") + + override val info = { mode.toString() } + + override fun disable() { + if (mode == Mode.CREATIVE) { + mc.player!!.abilities.flying = false + mc.player!!.abilities.flySpeed = 0.05f + + if (!mc.player!!.abilities.creativeMode) { + mc.player!!.abilities.allowFlying = false + } + } + } + + @EventListener + fun onTick(event: TickEvent?) { + when (mode) { + Mode.MOTION -> { + if (moving()) { + val strafe = strafe(speed * 10.0) + (mc.player!!.velocity as IVec3d).set(strafe[0], strafe[1]) + } else { + (mc.player!!.velocity as IVec3d).set(0.0, 0.0) + } + + if (mc.options.jumpKey.isPressed) { + (mc.player!!.velocity as IVec3d).setY(speed * 10.0) + } else if (mc.options.sneakKey.isPressed) { + (mc.player!!.velocity as IVec3d).setY(-speed * 10.0) + } else { + (mc.player!!.velocity as IVec3d).setY(0.0) + } + } + + Mode.CREATIVE -> { + mc.player!!.abilities.flySpeed = speed + mc.player!!.abilities.allowFlying = true + + if (!mc.player!!.abilities.creativeMode) { + mc.player!!.abilities.flying = true + } + } + } + } + + enum class Mode { + MOTION, + CREATIVE + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/movement/InventoryMove.kt b/src/main/kotlin/com/paragon/client/modules/movement/InventoryMove.kt new file mode 100644 index 0000000..615e063 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/movement/InventoryMove.kt @@ -0,0 +1,62 @@ +package com.paragon.client.modules.movement + +import com.paragon.backend.event.events.mc.TickEvent +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import com.paragon.util.mc +import me.bush.eventbus.annotation.EventListener +import net.minecraft.client.gui.screen.ChatScreen +import net.minecraft.client.gui.screen.ingame.AnvilScreen +import net.minecraft.client.gui.screen.ingame.CreativeInventoryScreen +import net.minecraft.client.option.KeyBinding +import net.minecraft.client.util.InputUtil +import net.minecraft.util.math.MathHelper +import org.lwjgl.glfw.GLFW + +/** + * @author aesthetical + * @since 02/18/23 + */ +object InventoryMove : Module("Inventory Move", "Lets you walk around in inventories", Category.MOVEMENT) { + + private val arrowRotate by bool("Arrow Rotate", true, "If to rotate in guis with the arrow keys") + private val speed by float("Rotate Speed", 5.0f, 0.1f, 1.0f..20.0f, "The speed to rotate with the arrow keys") + + private var bindings: Array? = null + + override fun disable() { + super.disable() + bindings = null + } + + @EventListener + fun onTick(event: TickEvent?) { + if (mc.currentScreen != null && mc.currentScreen !is ChatScreen && mc.currentScreen !is AnvilScreen && mc.currentScreen !is CreativeInventoryScreen) { + if (bindings == null) { + bindings = arrayOf(mc.options.forwardKey, mc.options.backKey, mc.options.rightKey, mc.options.leftKey) + return + } + + val handle = mc.window.handle + + for (binding in bindings!!) { + binding.isPressed = InputUtil.isKeyPressed(handle, binding.defaultKey.code) + } + + if (arrowRotate) { + if (InputUtil.isKeyPressed(handle, GLFW.GLFW_KEY_UP)) { + mc.player!!.pitch = mc.player!!.pitch - speed + } else if (InputUtil.isKeyPressed(handle, GLFW.GLFW_KEY_DOWN)) { + mc.player!!.pitch = mc.player!!.pitch + speed + } else if (InputUtil.isKeyPressed(handle, GLFW.GLFW_KEY_RIGHT)) { + mc.player!!.yaw = mc.player!!.yaw + speed + } else if (InputUtil.isKeyPressed(handle, GLFW.GLFW_KEY_LEFT)) { + mc.player!!.yaw = mc.player!!.yaw - speed + } + + mc.player!!.pitch = MathHelper.clamp(mc.player!!.pitch, -90.0f, 90.0f) + } + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/movement/LongJump.kt b/src/main/kotlin/com/paragon/client/modules/movement/LongJump.kt new file mode 100644 index 0000000..f6a1ff7 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/movement/LongJump.kt @@ -0,0 +1,80 @@ +package com.paragon.client.modules.movement + +import com.paragon.backend.event.events.move.MoveEvent +import com.paragon.backend.event.events.move.MoveUpdateEvent +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import com.paragon.mixin.duck.IVec3d +import com.paragon.util.calculations.MoveUtil +import com.paragon.util.calculations.MoveUtil.moving +import com.paragon.util.mc +import me.bush.eventbus.annotation.EventListener +import kotlin.math.sqrt + +/** + * @author aesthetical + * @since 02/19/23 + */ +object LongJump : Module("Long Jump", "jumps longer than ur mom to a mcdonalds", Category.MOVEMENT) { + + private var mode by enum("Mode", Mode.NCP, "How to long jump") + private var boost by double("Boost", 1.5, 0.1, 0.1..8.0, "Boost speed for jumping") + + private var moveSpeed = 0.0 + private var travelDistance = 0.0 + private var stage = 0 + + override val info = { mode.toString() } + + override fun enable() { + super.enable() + moveSpeed = 0.0 + travelDistance = 0.0 + stage = 0 + } + + @EventListener + fun onMove(event: MoveEvent) { + if (moving()) { + + if (mode == Mode.NCP) { + when (stage) { + 0 -> moveSpeed = boost + MoveUtil.getBaseNcpSpeed(0) - 0.05 + 1 -> { + event.setY(0.42) + (mc.player!!.velocity as IVec3d).setY(0.42) + moveSpeed *= 2.13 + } + 2 -> { + val diff: Double = 0.66 * (travelDistance - MoveUtil.getBaseNcpSpeed(0)) + moveSpeed = travelDistance - diff + } + else -> moveSpeed = travelDistance - travelDistance / 159.0 + } + + moveSpeed = moveSpeed.coerceAtLeast(MoveUtil.getBaseNcpSpeed(0)) + event.setSpeed(moveSpeed) + + ++stage + } else if (mode == Mode.VANILLA) { + if (mc.player!!.isOnGround) { + event.setY(0.42) + (mc.player!!.velocity as IVec3d).setY(0.42) + } + + event.setSpeed(boost) + } + } + } + + @EventListener + fun onMoveUpdate(event: MoveUpdateEvent?) { + val diffX: Double = mc.player!!.getX() - mc.player!!.prevX + val diffZ: Double = mc.player!!.getZ() - mc.player!!.prevZ + travelDistance = sqrt(diffX * diffX + diffZ * diffZ) + } + + enum class Mode { + NCP, VANILLA + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/movement/NoFall.kt b/src/main/kotlin/com/paragon/client/modules/movement/NoFall.kt new file mode 100644 index 0000000..2f59403 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/movement/NoFall.kt @@ -0,0 +1,43 @@ +package com.paragon.client.modules.movement + +import com.paragon.backend.event.events.net.PacketEvent.Outbound +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import com.paragon.mixin.mixins.net.packet.c2s.IPlayerMoveC2SPacket +import com.paragon.util.mc +import com.paragon.util.nullCheck +import me.bush.eventbus.annotation.EventListener +import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket + +/** + * @author KassuK, aesthetical + * @since 02/18/23 + */ +object NoFall : Module("No Fall", "Prevents fall damage", Category.MOVEMENT) { + + private val mode by enum("Mode", Mode.SPOOF, "The anti-cheat bypass mode") + private val distance by float("Fall Distance", 3.0f, 0.1f,3.0f..120.0f, "The distance required to have fallen before reducing more fall damage") + + override val info = { mode.toString() } + + @EventListener + fun onPacketOutbound(event: Outbound) { + if (nullCheck()) { + return + } + + if (event.packet is PlayerMoveC2SPacket && mc.player!!.fallDistance >= distance) { + (event.packet as IPlayerMoveC2SPacket).setOnGround(true) + + if (mode == Mode.REDUCE) { + mc.player!!.fallDistance = 0.0f + } + } + } + + enum class Mode { + SPOOF, + REDUCE + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/movement/NoSlowDown.kt b/src/main/kotlin/com/paragon/client/modules/movement/NoSlowDown.kt new file mode 100644 index 0000000..2e02a7d --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/movement/NoSlowDown.kt @@ -0,0 +1,49 @@ +package com.paragon.client.modules.movement + +import com.paragon.backend.event.events.input.control.ItemSlowdownEvent +import com.paragon.backend.event.events.input.control.SneakSlowdownEvent +import com.paragon.backend.event.events.move.MoveUpdateEvent +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import com.paragon.util.mc +import me.bush.eventbus.annotation.EventListener +import net.minecraft.network.packet.c2s.play.UpdateSelectedSlotC2SPacket + +/** + * @author aesthetical + * @since 02/17/23 + */ +object NoSlowDown : Module("No Slow Down", "Stops you from getting slowed down", Category.MOVEMENT) { + + private val mode by enum("Mode", Mode.VANILLA, "How to bypass the anti-cheat") + private val sneak by bool("Sneak", false, "Stops sneaking from slowing you down") + + override val info = { mode.toString() } + + @EventListener + fun onItemSlowdown(event: ItemSlowdownEvent) { + if (mc.player!!.isUsingItem && !mc.player!!.isRiding && event.entity == mc.player) { + event.isCancelled = true + } + } + + @EventListener + fun onMoveUpdate(event: MoveUpdateEvent) { + if (mc.player!!.isUsingItem && !mc.player!!.isRiding && mode == Mode.NEW_NCP) { + mc.player!!.networkHandler.sendPacket(UpdateSelectedSlotC2SPacket(mc.player!!.inventory.selectedSlot)) + } + } + + @EventListener + fun onSneakSlowdown(event: SneakSlowdownEvent) { + if (event.entity == mc.player && sneak) { + event.isCancelled = true + } + } + + enum class Mode { + VANILLA, + NEW_NCP + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/movement/Speed.kt b/src/main/kotlin/com/paragon/client/modules/movement/Speed.kt new file mode 100644 index 0000000..e3b2b00 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/movement/Speed.kt @@ -0,0 +1,154 @@ +package com.paragon.client.modules.movement + +import com.paragon.backend.event.events.mc.TickEvent +import com.paragon.backend.event.events.move.MoveEvent +import com.paragon.backend.event.events.move.MoveUpdateEvent +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import com.paragon.client.modules.player.GameSpeed.setTimerSpeed +import com.paragon.mixin.duck.IVec3d +import com.paragon.util.calculations.MoveUtil +import com.paragon.util.calculations.MoveUtil.moving +import com.paragon.util.mc +import me.bush.eventbus.annotation.EventListener +import kotlin.math.sqrt + + +/** + * @author aesthetical + * @since 02/19/23 + */ +object Speed : Module("Speed", "Speedy speed", Category.MOVEMENT) { + + private var mode by enum("Mode", Mode.OLD_NCP_HOP, "How to go vroom vroom") + private var useTimer by bool("Timer", true, "Use timer to give an extra speed boost") + + private var moveSpeed = 0.0 + private var travelDistance = 0.0 + private var boost = false + private var hopStage = 0 + + override val info = { mode.name } + + override fun enable() { + super.enable() + hopStage = 4 + moveSpeed = 0.0 + travelDistance = 0.0 + boost = false + } + + @EventListener + fun onTick(event: TickEvent) { + if (mode == Mode.OLD_NCP_YPORT) { + if (moving()) { + mc.player!!.isSprinting = true + moveSpeed = 1.25 * MoveUtil.getBaseNcpSpeed(0) - 0.1 + if (mc.player!!.isOnGround) { + mc.player!!.jump() + moveSpeed *= if (useTimer) { + if (mc.player!!.age % 10 == 0) { + setTimerSpeed(1.35f) + } else { + setTimerSpeed(if (boost) 1.088f else 1.098f) + } + if (boost) 1.62 else 1.526 + } else { + setTimerSpeed(1.0f) + if (boost) 1.622 else 1.545 + } + } else { + boost = !boost + (mc.player!!.velocity as IVec3d).setY(-4.0) + setTimerSpeed(1.0f) + } + } + } + } + + @EventListener + fun onMove(event: MoveEvent) { + when (mode) { + Mode.OLD_NCP_YPORT -> { + if (moving()) { + event.setSpeed(moveSpeed) + } else { + event.nullOutVelocity() + } + } + + Mode.OLD_NCP_HOP, Mode.NEW_NCP_HOP -> { + val oldNcp: Boolean = mode == Mode.OLD_NCP_HOP + if (mc.player!!.isOnGround && moving()) { + hopStage = 2 + } + + if (hopStage == 1) { + val factor = if (oldNcp) 1.37 else 1.6 + moveSpeed = factor * MoveUtil.getBaseNcpSpeed(15) - 0.01 + hopStage = 2 + } else if (hopStage == 2) { + if (mc.player!!.isOnGround && moving()) { + val height = MoveUtil.getJumpHeight(0.3995) + event.setY(height) + (mc.player!!.velocity as IVec3d).setY(height) + + moveSpeed *= if (oldNcp) { + if (boost) 1.624 else 1.543 + } else { + if (boost) 1.53 else 1.41 + } + + setTimerSpeed(1.0f) + } + + hopStage = 3 + } else if (hopStage == 3) { + if (useTimer) { + if (oldNcp) { + setTimerSpeed(1.088f) + } else { + setTimerSpeed(if (boost) 1.088f else 1.073f) + } + } else { + setTimerSpeed(1.0f) + } + + val adjustment: Double = (if (boost) 0.72 else 0.66) * (travelDistance - MoveUtil.getBaseNcpSpeed(15)) + moveSpeed = travelDistance - adjustment + boost = !boost + hopStage = 4 + } else if (hopStage == 4) { + if (mc.world!!.getEntityCollisions(mc.player, mc.player!!.boundingBox.offset(0.0, mc.player!!.velocity.y, 0.0)).isNotEmpty()) { + hopStage = 1 + } + + moveSpeed = travelDistance - travelDistance / 150.0 + } + + moveSpeed = Math.max(moveSpeed, MoveUtil.getBaseNcpSpeed(15)) + if (moving()) { + event.setSpeed(moveSpeed) + } else { + event.nullOutVelocity() + } + } + + else -> { + // empty, kys kotlin + } + } + } + + @EventListener + fun onMoveUpdate(event: MoveUpdateEvent?) { + val diffX = mc.player!!.x - mc.player!!.prevX + val diffZ = mc.player!!.z - mc.player!!.prevZ + travelDistance = sqrt(diffX * diffX + diffZ * diffZ) + } + + enum class Mode { + OLD_NCP_HOP, OLD_NCP_YPORT, NEW_NCP_HOP + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/movement/Sprint.kt b/src/main/kotlin/com/paragon/client/modules/movement/Sprint.kt new file mode 100644 index 0000000..77a2391 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/movement/Sprint.kt @@ -0,0 +1,49 @@ +package com.paragon.client.modules.movement + +import com.paragon.backend.event.events.mc.TickEvent +import com.paragon.backend.event.events.net.PacketEvent.Outbound +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import com.paragon.util.calculations.MoveUtil.moving +import com.paragon.util.mc +import me.bush.eventbus.annotation.EventListener +import net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket + +/** + * @author aesthetical, KassuK + * @since 02/18/23 + */ +object Sprint : Module("Sprint", "Automatically sprints for you", Category.MOVEMENT) { + + private val mode by enum("Mode", Mode.LEGIT, "How to sprint") + private val fullRage by bool("Full Rage", true, "If to never stop sprinting server side") visibility { mode == Mode.RAGE } + + override val info = { mode.toString() } + + @EventListener + fun onTick(event: TickEvent) { + if (!mc.player!!.isSprinting) { + mc.player!!.isSprinting = when (mode) { + Mode.LEGIT -> (mc.player!!.input.movementForward > 0.0f && !mc.player!!.isSneaking && !mc.player!!.isUsingItem && mc.player!!.hungerManager.foodLevel > 6) && !mc.player!!.horizontalCollision + Mode.OMNI -> moving() && !mc.player!!.horizontalCollision && mc.player!!.hungerManager.foodLevel > 6 + else -> true + } + } + } + + @EventListener + fun onPacketOutbound(event: Outbound) { + if (mode == Mode.RAGE && fullRage && event.packet is ClientCommandC2SPacket) { + if (event.packet.mode == ClientCommandC2SPacket.Mode.STOP_SPRINTING) { + event.isCancelled = true + } + } + } + + enum class Mode { + LEGIT, + RAGE, + OMNI + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/movement/Step.kt b/src/main/kotlin/com/paragon/client/modules/movement/Step.kt new file mode 100644 index 0000000..19eeef6 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/movement/Step.kt @@ -0,0 +1,44 @@ +package com.paragon.client.modules.movement + +import com.paragon.Paragon +import com.paragon.backend.event.events.mc.TickEvent +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import com.paragon.util.mc +import com.paragon.util.nullCheck +import me.bush.eventbus.annotation.EventListener + +/** + * @author surge + * @since 11/02/2023 + */ +object Step : Module("Step", "Lets you instantly walk up blocks", Category.MOVEMENT) { + + private val height by float("Height", 1.0f, 0.1f, 0.5f..2.5f, "The maximum height you can step up") + + override val info = { height.toString() } + + override fun enable() { + super.enable() + Paragon.baritoneManager.set("assumeStep", true) + } + + override fun disable() { + Paragon.baritoneManager.set("assumeStep", false) + if (nullCheck()) { + return + } + + mc.player!!.stepHeight = 0.6f + } + + @EventListener + fun onTick(event: TickEvent) { + if (nullCheck()) { + return + } + + mc.player!!.stepHeight = height + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/movement/TridentBoost.kt b/src/main/kotlin/com/paragon/client/modules/movement/TridentBoost.kt new file mode 100644 index 0000000..7681688 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/movement/TridentBoost.kt @@ -0,0 +1,23 @@ +package com.paragon.client.modules.movement + +import com.paragon.backend.event.events.move.TridentVelocityEvent +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import me.bush.eventbus.annotation.EventListener + +/** + * @author surge + * @since 24/02/2023 + */ +object TridentBoost : Module("Trident Boost", "Adds an additional boost when you use a trident", Category.MOVEMENT) { + + private val multiplier by double("Multiplier", 1.5, 0.1, 0.1..3.0, "How much your velocity is multiplied by") + + @EventListener + fun onTridentVelocity(event: TridentVelocityEvent) { + event.x *= multiplier + event.y *= multiplier + event.z *= multiplier + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/player/AirPlace.kt b/src/main/kotlin/com/paragon/client/modules/player/AirPlace.kt new file mode 100644 index 0000000..2fbc551 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/player/AirPlace.kt @@ -0,0 +1,87 @@ +package com.paragon.client.modules.player + +import com.paragon.Paragon +import com.paragon.backend.event.events.mc.TickEvent +import com.paragon.backend.event.events.render.GameRenderEvent +import com.paragon.backend.managers.placement.PlacementData +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import com.paragon.util.box +import com.paragon.util.getClientColour +import com.paragon.util.getPlaceableSide +import com.paragon.util.mc +import com.paragon.util.rendering.Renderer +import me.bush.eventbus.annotation.EventListener +import net.minecraft.item.BlockItem +import net.minecraft.util.hit.BlockHitResult +import net.minecraft.util.hit.HitResult +import net.minecraft.util.math.Direction + +/** + * @author surge + * @since 12/03/2023 + */ +object AirPlace : Module("Air Place", "Allows you to place blocks wherever you are looking", Category.PLAYER) { + + private val pause by int("Pause", 5, 1, 0..20, "The delay (in ticks) between placing blocks") + + private val box by enum("Box", Box.BOTH, "How to draw the box") + private val alpha by int("Alpha", 100, 1, 0..255, "The alpha of the fill") visibility { box == Box.FILL || box == Box.BOTH } + + private var tick = 0 + private var result: HitResult? = null + + @EventListener + fun onTick(event: TickEvent) { + result = mc.cameraEntity!!.raycast(mc.interactionManager!!.reachDistance.toDouble(), 0f, false) + + if (result !is BlockHitResult || mc.player!!.mainHandStack.item !is BlockItem) { + return + } + + if (mc.options.useKey.isPressed) { + if (tick >= pause) { + Paragon.placementManager.submit( + (result as BlockHitResult).blockPos, + PlacementData( + mc.player!!.inventory.selectedSlot, + (result as BlockHitResult).blockPos.getPlaceableSide() ?: Direction.UP + ) + ) + + tick = 0 + } else { + tick++ + } + } else { + tick = 0 + } + } + + @EventListener + fun onGameRender(event: GameRenderEvent) { + if (box == Box.NONE) { + return + } + + result?.let { + it as BlockHitResult + + if (box == Box.FILL || box == Box.BOTH) { + Renderer.box(event.matrices, it.blockPos.box(), getClientColour().integrateAlpha(alpha), Renderer.DrawMode.FILL) + } + + if (box == Box.OUTLINE || box == Box.BOTH) { + Renderer.box(event.matrices, it.blockPos.box(), getClientColour(), Renderer.DrawMode.LINES) + } + } + } + + private enum class Box { + FILL, + OUTLINE, + BOTH, + NONE + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/player/AutoElytra.kt b/src/main/kotlin/com/paragon/client/modules/player/AutoElytra.kt new file mode 100644 index 0000000..819d6da --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/player/AutoElytra.kt @@ -0,0 +1,53 @@ +package com.paragon.client.modules.player + +import com.paragon.Paragon +import com.paragon.backend.event.events.mc.TickEvent +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import com.paragon.util.mc +import me.bush.eventbus.annotation.EventListener +import net.minecraft.item.Items +import net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket + +/** + * @author surge + * @since 28/02/2023 + */ +object AutoElytra : Module("Auto Elytra", "Automatically starts gliding if you are falling", Category.PLAYER) { + + /** + * TODO: Auto equip Elytra if not already equipped + */ + + private val distance by double("Distance", 5.0, 0.5, 1.0..50.0, "The fall distance to start gliding at") + + private var warned = false + + override val info = { + if (mc.player!!.isOnGround || mc.player!!.isFallFlying || mc.player!!.fallDistance > distance) { + null + } else { + String.format("%.2f", (distance - mc.player!!.fallDistance).toFloat()) + } + } + + @EventListener + fun onTick(event: TickEvent) { + if (mc.player!!.fallDistance >= distance && !mc.player!!.isFallFlying) { + if (mc.player!!.armorItems.any { it.item == Items.ELYTRA && it.damage != it.maxDamage }) { + mc.player!!.networkHandler.sendPacket(ClientCommandC2SPacket(mc.player, ClientCommandC2SPacket.Mode.START_FALL_FLYING)) + mc.player!!.startFallFlying() + + Paragon.toastManager.info(this.name, "Deploying Elytra!", 2000L) + } else if (!warned) { + Paragon.toastManager.warn(this.name, "Elytra not found!", 2000L) + warned = true + } + } + + if (mc.player!!.isOnGround) { + warned = false + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/player/AutoRespawn.kt b/src/main/kotlin/com/paragon/client/modules/player/AutoRespawn.kt new file mode 100644 index 0000000..6103329 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/player/AutoRespawn.kt @@ -0,0 +1,23 @@ +package com.paragon.client.modules.player + +import com.paragon.backend.event.events.mc.TickEvent +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import com.paragon.util.mc +import me.bush.eventbus.annotation.EventListener +import net.minecraft.network.packet.c2s.play.ClientStatusC2SPacket + +/** + * @author aesthetical + * @since 02/18/23 + */ +object AutoRespawn : Module("Auto Respawn", "Automatically respawns you", Category.PLAYER) { + + @EventListener + fun onTick(event: TickEvent?) { + if (mc.player!!.isDead || mc.player!!.health <= 0.0f) { + mc.player!!.networkHandler.sendPacket(ClientStatusC2SPacket(ClientStatusC2SPacket.Mode.PERFORM_RESPAWN)) + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/player/AutoTool.kt b/src/main/kotlin/com/paragon/client/modules/player/AutoTool.kt new file mode 100644 index 0000000..ca5e5b9 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/player/AutoTool.kt @@ -0,0 +1,65 @@ +package com.paragon.client.modules.player + +import com.paragon.Paragon +import com.paragon.backend.event.events.input.control.AttackBlockEvent +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import com.paragon.util.mc +import me.bush.eventbus.annotation.EventListener +import net.minecraft.util.math.BlockPos + +/** + * @author aesthetical + * @since 02/22/23 + */ +object AutoTool : Module("Auto Tool", "Automatically swaps to the best tool", Category.PLAYER) { + + override fun enable() { + super.enable() + Paragon.baritoneManager.set("autoTool", false) + Paragon.baritoneManager.set("useSwordToMine", false) + } + + override fun disable() { + super.disable() + Paragon.baritoneManager.restoreValue("autoTool") + Paragon.baritoneManager.restoreValue("useSwordToMine") + } + + @EventListener + fun onAttackBlock(event: AttackBlockEvent) { + val slot = bestSlot(event.blockPos) + if (slot == -1 || slot == Paragon.inventoryManager.slot) { + return + } + + mc.player!!.inventory.selectedSlot = slot + } + + @JvmStatic + fun bestSlot(pos: BlockPos): Int { + val state = mc.world!!.getBlockState(pos) + if (state.getHardness(null, null) == -1.0f) { + return -1 + } + + var slot = -1 + var dmg = 0.0f + + for (i in 0..8) { + val stack = mc.player!!.inventory.getStack(i) + if (stack.isEmpty) { + continue + } + + val toolDmg = stack.item.getMiningSpeedMultiplier(stack, state) + if (toolDmg > dmg) { + slot = i + dmg = toolDmg + } + } + + return if (slot == -1) Paragon.inventoryManager.slot else slot + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/player/BlockFly.kt b/src/main/kotlin/com/paragon/client/modules/player/BlockFly.kt new file mode 100644 index 0000000..7dd9e48 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/player/BlockFly.kt @@ -0,0 +1,150 @@ +package com.paragon.client.modules.player + +import com.paragon.Paragon +import com.paragon.backend.event.EventEra +import com.paragon.backend.event.events.move.MoveUpdateEvent +import com.paragon.backend.managers.placement.PlacementData +import com.paragon.backend.managers.placement.Swing +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import com.paragon.mixin.duck.IVec3d +import com.paragon.util.calculations.MoveUtil.getVanillaJumpVelocity +import com.paragon.util.calculations.rotation.RotationUtil +import com.paragon.util.mc +import com.paragon.util.nullCheck +import me.bush.eventbus.annotation.EventListener +import net.minecraft.item.BlockItem +import net.minecraft.item.ItemStack +import net.minecraft.util.math.BlockPos +import net.minecraft.util.math.Direction + +/** + * @author aesthetical + * @since 02/17/23 + */ +object BlockFly : Module("Block Fly", "Rapidly places blocks under your feet", Category.PLAYER) { + + private val rotate by bool("Rotate", true, "If to rotate where you're placing") + private val swing by enum("Swing", Swing.CLIENT, "How to swing") + private val autoSwap by enum("Auto Swap", AutoSwap.SERVER, "Automatically swap to a block slot") + private val tower by bool("Tower", true, "If to tower") + + private var prev: PlaceResult? = null + private var curr: PlaceResult? = null + + override fun disable() { + curr = null + prev = curr + + if (!nullCheck()) { + Paragon.inventoryManager.sync() + } + } + + @EventListener(recieveCancelled = true) + fun onMoveUpdate(event: MoveUpdateEvent) { + prev = curr + curr = next() + + if (rotate && prev != null) { + Paragon.rotationManager.submit(RotationUtil.calcAngleToBlock(prev!!.pos, prev!!.direction)) + } + + if (curr == null) { + return + } + + if (event.era == EventEra.POST) { + when (autoSwap) { + AutoSwap.NONE -> { + if (mc.player!!.mainHandStack.item !is BlockItem) { + return + } + } + + AutoSwap.CLIENT, AutoSwap.SERVER -> { + val slot = nextSlot + + if (slot == -1) { + return + } + + if (autoSwap == AutoSwap.CLIENT) { + mc.player!!.inventory.selectedSlot = slot + } else { + Paragon.inventoryManager.swap(slot) + } + } + } + + Paragon.placementManager.submit(curr!!.pos, PlacementData(mc.player!!.inventory.selectedSlot, curr!!.direction, swing).accept { + if (tower && mc.options.jumpKey.isPressed) { + (mc.player!!.velocity as IVec3d).setY(getVanillaJumpVelocity().toDouble()) + + if (mc.player!!.age % 4 == 0 || mc.player!!.isOnGround) { + (mc.player!!.velocity as IVec3d).setY(getVanillaJumpVelocity().toDouble()) + } + } + }) + } + } + + private val nextSlot: Int + get() { + var slot: Int = mc.player!!.inventory.selectedSlot + var count = 0 + + if (mc.player!!.inventory.getStack(slot).item is BlockItem) { + count = mc.player!!.inventory.getStack(slot).count + } else { + slot = -1 + } + + for (i in 0..8) { + val stack: ItemStack = mc.player!!.inventory.getStack(i) + + if (stack.item is BlockItem && stack.count > count) { + slot = i + count = stack.count + } + } + + return slot + } + + private operator fun next(): PlaceResult? { + val pos: BlockPos = BlockPos(mc.player!!.pos).down() + + for (direction in Direction.values()) { + val n = pos.offset(direction) + + if (!mc.world!!.getBlockState(n).material.isReplaceable) { + return PlaceResult(n, direction.opposite) + } + } + + for (direction in Direction.values()) { + val n = pos.offset(direction) + + if (mc.world!!.getBlockState(n).material.isReplaceable) { + for (d in Direction.values()) { + val nn = n.offset(d) + + if (!mc.world!!.getBlockState(nn).material.isReplaceable) { + return PlaceResult(nn, d.opposite) + } + } + } + } + return null + } + + private data class PlaceResult(val pos: BlockPos, val direction: Direction) + + enum class AutoSwap { + NONE, + CLIENT, + SERVER + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/player/FakePlayer.kt b/src/main/kotlin/com/paragon/client/modules/player/FakePlayer.kt new file mode 100644 index 0000000..1f44f2b --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/player/FakePlayer.kt @@ -0,0 +1,102 @@ +package com.paragon.client.modules.player + +import com.mojang.authlib.GameProfile +import com.paragon.backend.event.events.mc.TickEvent +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import com.paragon.util.mc +import com.paragon.util.nullCheck +import me.bush.eventbus.annotation.EventListener +import net.minecraft.client.network.OtherClientPlayerEntity +import net.minecraft.client.world.ClientWorld +import net.minecraft.entity.Entity +import net.minecraft.entity.Entity.RemovalReason +import net.minecraft.entity.damage.DamageSource +import net.minecraft.entity.effect.StatusEffectInstance +import net.minecraft.entity.effect.StatusEffects +import net.minecraft.item.ItemStack +import net.minecraft.item.Items +import net.minecraft.network.packet.s2c.play.EntityStatusS2CPacket +import net.minecraft.util.Hand +import java.util.* + +/** + * @author aesthetical + * @since 02/19/23 + */ +object FakePlayer : Module("Fake Player", "Spawns a fake player", Category.PLAYER) { + + private var fake: EntityFakePlayer? = null + + override fun enable() { + if (nullCheck()) { + toggle() + return + } + + fake = EntityFakePlayer(mc.world!!, GameProfile(UUID.randomUUID(), "Fake")) + + fake!!.copyPositionAndRotation(mc.player) + fake!!.inventory.clone(mc.player!!.inventory) + fake!!.id = -137769420 + + mc.world!!.spawnEntity(fake) + mc.world!!.addEntity(fake!!.id, fake) + } + + override fun disable() { + if (!nullCheck()) { + mc.world!!.removeEntity(fake!!.id, RemovalReason.KILLED) + } + + fake = null + } + + @EventListener + fun onTick(event: TickEvent?) { + if (mc.player!!.age < 5) { + toggle() + return + } + } + + private class EntityFakePlayer(clientWorld: ClientWorld, gameProfile: GameProfile) : OtherClientPlayerEntity(clientWorld, gameProfile) { + + override fun damage(source: DamageSource, amount: Float): Boolean { + health -= amount + return true + } + + override fun tick() { + super.tick() + + if (getStackInHand(Hand.OFF_HAND).item != Items.TOTEM_OF_UNDYING) { + setStackInHand(Hand.OFF_HAND, ItemStack(Items.TOTEM_OF_UNDYING)) + } + + if (health <= 0.0f) { + mc.networkHandler!!.onEntityStatus(EntityStatusS2CPacket(this, 35.toByte())) + + health = 1.0f + absorptionAmount = 8.0f + + clearActiveItem() + addStatusEffect(StatusEffectInstance(StatusEffects.REGENERATION, 900, 1)) + addStatusEffect(StatusEffectInstance(StatusEffects.ABSORPTION, 100, 1)) + } + } + + override fun isAttackable(): Boolean { + return true + } + + override fun handleAttack(attacker: Entity): Boolean { + return false + } + + override fun canTakeDamage(): Boolean { + return true + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/player/FastPlace.kt b/src/main/kotlin/com/paragon/client/modules/player/FastPlace.kt new file mode 100644 index 0000000..ce4718d --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/player/FastPlace.kt @@ -0,0 +1,51 @@ +package com.paragon.client.modules.player + +import com.paragon.backend.event.events.mc.TickEvent +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import com.paragon.mixin.duck.IMinecraftClient +import com.paragon.util.mc +import me.bush.eventbus.annotation.EventListener +import net.minecraft.item.BlockItem +import net.minecraft.item.ItemStack +import net.minecraft.item.Items +import net.minecraft.util.Hand + +/** + * @author aesthetical + * @since 02/18/23 + */ +object FastPlace : Module("Fast Place", "Places items fast", Category.PLAYER) { + + private val speed by int("Speed", 4, 1, 1..4, "How fast to place items at") + private val exp by bool("EXP", true, "If to place exp fast") + private val blocks by bool("Blocks", true, "If to place blocks fast") + private val fireworks by bool("Fireworks", true, "If to place fireworks fast") + private val crystals by bool("Crystals", true, "If to place end crystals fast") + + @EventListener + fun onTick(event: TickEvent?) { + + // 10/10 code i love this + if (shouldFastPlace(mc.player!!.getStackInHand(Hand.MAIN_HAND)) || shouldFastPlace(mc.player!!.getStackInHand(Hand.OFF_HAND))) { + (mc as IMinecraftClient).setItemUseCooldown(4 - speed) + } + } + + private fun shouldFastPlace(activeStack: ItemStack): Boolean { + if (!exp && activeStack.item == Items.EXPERIENCE_BOTTLE) { + return false + } + + if (!blocks && activeStack.item is BlockItem) { + return false + } + + if (!fireworks && activeStack.item == Items.FIREWORK_ROCKET) { + return false + } + + return !(!crystals && activeStack.item == Items.END_CRYSTAL) + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/player/GameSpeed.kt b/src/main/kotlin/com/paragon/client/modules/player/GameSpeed.kt new file mode 100644 index 0000000..3e23eb0 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/player/GameSpeed.kt @@ -0,0 +1,38 @@ +package com.paragon.client.modules.player + +import com.paragon.backend.event.events.mc.TickEvent +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import com.paragon.mixin.duck.IMinecraftClient +import com.paragon.mixin.duck.IRenderTickCounter +import com.paragon.util.mc +import com.paragon.util.nullCheck +import me.bush.eventbus.annotation.EventListener + +/** + * @author aesthetical + * @since 02/17/23 + */ +object GameSpeed : Module("Game Speed", "makes ur game go zoom zoom verus airlines", Category.PLAYER) { + + private val speed by float("Speed", 1.0f, 0.01f, 0.1f..20.0f, "The timer speed") + + override val info = { speed.toString() } + + override fun disable() { + if (!nullCheck()) { + setTimerSpeed(1.0f) + } + } + + @EventListener + fun onTick(event: TickEvent?) { + setTimerSpeed(speed) + } + + @JvmStatic + fun setTimerSpeed(speed: Float) { + ((mc as IMinecraftClient).renderTickCounter as IRenderTickCounter).tickLength = 50.0f / speed + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/player/InventoryManager.kt b/src/main/kotlin/com/paragon/client/modules/player/InventoryManager.kt new file mode 100644 index 0000000..5cbdb6f --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/player/InventoryManager.kt @@ -0,0 +1,4 @@ +package com.paragon.client.modules.player + +object InventoryManager { +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/player/LiquidPlace.kt b/src/main/kotlin/com/paragon/client/modules/player/LiquidPlace.kt new file mode 100644 index 0000000..d3ea8e2 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/player/LiquidPlace.kt @@ -0,0 +1,19 @@ +package com.paragon.client.modules.player + +import com.paragon.backend.event.events.entity.RaycastEvent +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import me.bush.eventbus.annotation.EventListener + +/** + * @author surge + * @since 13/03/2023 + */ +object LiquidPlace : Module("Liquid Place", "Allows you to place blocks on liquids", Category.PLAYER) { + + @EventListener + fun onRaycast(event: RaycastEvent) { + event.includeFluids = true + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/player/NoTrace.kt b/src/main/kotlin/com/paragon/client/modules/player/NoTrace.kt new file mode 100644 index 0000000..c094889 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/player/NoTrace.kt @@ -0,0 +1,32 @@ +package com.paragon.client.modules.player + +import com.paragon.Paragon +import com.paragon.backend.bind.Bind +import com.paragon.backend.event.events.entity.EntityTraceEvent +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import com.paragon.util.mc +import me.bush.eventbus.annotation.EventListener +import net.minecraft.item.PickaxeItem + +/** + * @author surge + * @since 28/02/2023 + */ +object NoTrace : Module("No Trace", "Allows you to interact through entities", Category.PLAYER) { + + private val pickaxe by bool("Pickaxe", true, "Apply when holding a pickaxe") + private val bind by bind("Force Bind", Bind(this)) + + init { + Paragon.keyboardManager.addBind(bind) + } + + @EventListener + fun onEntityTrace(event: EntityTraceEvent) { + if (pickaxe && mc.player!!.isHolding { it.item is PickaxeItem } || bind.state) { + event.cancel() + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/player/PacketMine.kt b/src/main/kotlin/com/paragon/client/modules/player/PacketMine.kt new file mode 100644 index 0000000..22892e4 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/player/PacketMine.kt @@ -0,0 +1,232 @@ +package com.paragon.client.modules.player + +import com.paragon.Paragon +import com.paragon.backend.event.events.input.control.AttackBlockEvent +import com.paragon.backend.event.events.mc.TickEvent +import com.paragon.backend.event.events.render.GameRenderEvent +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import com.paragon.backend.setting.Colour +import com.paragon.client.modules.player.AutoTool.bestSlot +import com.paragon.mixin.duck.IClientPlayerInteractionManager +import com.paragon.util.calculations.rotation.RotationUtil +import com.paragon.util.mc +import com.paragon.util.nullCheck +import com.paragon.util.player.PlayerUtil +import com.paragon.util.rendering.Renderer +import me.bush.eventbus.annotation.EventListener +import net.minecraft.enchantment.EnchantmentHelper +import net.minecraft.enchantment.Enchantments +import net.minecraft.entity.effect.StatusEffects +import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket +import net.minecraft.util.Hand +import net.minecraft.util.math.BlockPos +import net.minecraft.util.math.Box +import net.minecraft.util.math.Direction +import net.minecraft.util.math.MathHelper + +/** + * @author aesthetical + * @since 02/20/23 + */ +object PacketMine : Module("Packet Mine", "Mines blocks with packets", Category.PLAYER) { + + private val percentage by float("Percentage", 0.95f, 0.05f, 0.0f..1.0f, "At what percentage to try and break the block") + private val click by bool("Self Click", false, "If to require client input to finish breaking the block") + private val rotate by bool("Rotate", false, "If to rotate towards the block you are breaking") + private val render by bool("Render", true, "If to render the block progress") + + private var blockPos: BlockPos? = null + private var direction: Direction? = null + private var sentBreak = false + private var sentStopBreak = false + private var spoofItem = false + private var override = false + private var progress = 0.0 + + override fun disable() { + super.disable() + + if (!nullCheck()) { + stopBlockBreaking() + + if (spoofItem) { + Paragon.inventoryManager.sync() + spoofItem = false + } + } + + override = false + sentBreak = false + blockPos = null + direction = null + progress = 0.0 + } + + @EventListener + fun onGameRender(event: GameRenderEvent) { + if (blockPos != null && render) { + var box = Box(0.0, 0.0, 0.0, 1.0, 1.0, 1.0) + box = box.offset(blockPos!!.x.toDouble(), blockPos!!.y.toDouble(), blockPos!!.z.toDouble()) + + val center = box.center + var bb = Box(center, center) + + val factor: Double = MathHelper.clamp(progress, 0.0, 1.0) + bb = bb.expand(factor * 0.5, factor * 0.5, factor * 0.5) + + val color = (if (factor >= percentage) Colour(0, 255, 0, 100) else Colour(255, 0, 0, 100)) + Renderer.box(event.matrices, bb, color, Renderer.DrawMode.FILL) + Renderer.box(event.matrices, bb, color, Renderer.DrawMode.LINES) + } + } + + @EventListener + fun onTick(event: TickEvent) { + if (blockPos != null && direction != null) { + val blockState = mc.world!!.getBlockState(blockPos) + if (blockState.material.isReplaceable || blockState.isAir || blockState.getHardness(null, null) == -1.0f) { + stopBlockBreaking() + + sentStopBreak = false + override = false + + if (spoofItem) { + Paragon.inventoryManager.sync() + spoofItem = false + } + return + } + + val slot = bestSlot(blockPos!!) + progress += getStrength(blockPos!!, slot) + if (progress >= percentage || override) { + + if (Paragon.inventoryManager.slot != slot && progress >= percentage) { + spoofItem = true + Paragon.inventoryManager.swap(slot) + } + + if (rotate) { + Paragon.rotationManager.submit(RotationUtil.calcAngleToBlock(blockPos!!, direction!!)) + } + + if (!sentStopBreak) { + + if (click && !override) { + return + } + + sentStopBreak = true + (mc.interactionManager as IClientPlayerInteractionManager).hookSendSequencedPacket(mc.world) { + return@hookSendSequencedPacket PlayerActionC2SPacket(PlayerActionC2SPacket.Action.STOP_DESTROY_BLOCK, blockPos, direction, it) + } + } + } + } + } + + @EventListener + fun onAttackBlock(event: AttackBlockEvent) { + if (blockPos != null && event.blockPos != blockPos) { + stopBlockBreaking() + } + + if (blockPos != null && blockPos == event.blockPos) { + event.isCancelled = true + + if (click && progress >= percentage) { + override = true + } + + return + } + + val blockState = mc.world!!.getBlockState(event.blockPos) + if (blockState.material.isReplaceable || blockState.isAir || blockState.getHardness(null, null) == -1.0f) { + return + } + + event.isCancelled = true + + blockPos = event.blockPos + direction = event.direction + + if (!sentBreak) { + sentBreak = true + + PlayerUtil.silentSwing(Hand.MAIN_HAND) + (mc.interactionManager as IClientPlayerInteractionManager).hookSendSequencedPacket(mc.world) { + return@hookSendSequencedPacket PlayerActionC2SPacket(PlayerActionC2SPacket.Action.START_DESTROY_BLOCK, blockPos, direction, it) + } + } + } + + private fun stopBlockBreaking() { + if (sentBreak) { + mc.player!!.networkHandler.sendPacket(PlayerActionC2SPacket(PlayerActionC2SPacket.Action.ABORT_DESTROY_BLOCK, blockPos, direction)) + } + + override = false + progress = 0.0 + sentBreak = false + blockPos = null + direction = null + sentStopBreak = false + } + + private fun getStrength(blockPos: BlockPos, slot: Int): Double { + val at = mc.world!!.getBlockState(blockPos) + val held = mc.player!!.inventory.getStack(slot) + val hardness = at.getHardness(null, null) + if (hardness < 0.0f) { + return 0.0 + } + + val s = getDestroySpeed(blockPos, slot) + val f = (if (!held.isEmpty && held.isSuitableFor(at)) 30.0f else 100.0f).toDouble() + return s / hardness / f + } + + private fun getDestroySpeed(blockPos: BlockPos, slot: Int): Double { + val at = mc.world!!.getBlockState(blockPos) + val held = mc.player!!.inventory.getStack(slot) + + var breakSpeed = 1.0f + if (!held.isEmpty) { + breakSpeed *= held.getMiningSpeedMultiplier(at) + } + + if (breakSpeed > 1.0f) { + val effMod: Int = EnchantmentHelper.getLevel(Enchantments.EFFICIENCY, held) + if (effMod > 0) { + val mod = effMod * effMod + 1.0f + breakSpeed += if (!held.isSuitableFor(at)) { + mod * 0.08f + } else { + mod + } + } + } + + if (mc.player!!.hasStatusEffect(StatusEffects.HASTE)) { + val amp = mc.player!!.getStatusEffect(StatusEffects.HASTE)!!.amplifier + if (amp > 0) { + breakSpeed *= 1.0f + (amp + 1.0f) * 0.2f + } + } + + if (mc.player!!.hasStatusEffect(StatusEffects.MINING_FATIGUE)) { + val amp = mc.player!!.getStatusEffect(StatusEffects.MINING_FATIGUE)!!.amplifier + if (amp > 0) { + breakSpeed *= 1.0f + (amp + 1.0f) * 0.2f + } + } + + if (mc.player!!.isSubmergedInWater && !EnchantmentHelper.hasAquaAffinity(mc.player)) { + breakSpeed /= 5.0f + } + + return breakSpeed.toDouble() + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/player/Replenish.kt b/src/main/kotlin/com/paragon/client/modules/player/Replenish.kt new file mode 100644 index 0000000..43bcf20 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/player/Replenish.kt @@ -0,0 +1,104 @@ +package com.paragon.client.modules.player + +import com.paragon.backend.event.events.mc.TickEvent +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import com.paragon.util.calculations.Timer +import com.paragon.util.inventory.InventoryUtil +import com.paragon.util.mc +import me.bush.eventbus.annotation.EventListener +import net.minecraft.item.BlockItem +import net.minecraft.item.ItemStack +import net.minecraft.screen.slot.SlotActionType + +/** + * @author aesthetical + * @since 02/18/23 + */ +object Replenish : Module("Replenish", "Automatically replenishes your hotbar", Category.PLAYER) { + + private val delay = double("Delay", 0.1, 0.1, 0.0..3.5, "How long before replenishing the next item") + private val percentage = float("Percentage", 75.0f, 0.1f, 1.0f..99.0f, "The percentage of item depletion before replenishing") + + private val hotbarCache: MutableMap = HashMap() + private val timer = Timer() + + override fun disable() { + super.disable() + hotbarCache.clear() + } + + @EventListener + fun onTick(event: TickEvent?) { + for (i in 0..8) { + val stack: ItemStack = mc.player!!.inventory.getStack(i) + + if (!stack.isEmpty) { + hotbarCache[i] = stack + } + } + + if (timer.elapsed((delay.value * 1000.0).toLong().toDouble())) { + for (i in 0..8) { + val stack: ItemStack = mc.player!!.inventory.getStack(i) + val percent = stack.count.toFloat() / stack.maxCount.toFloat() * 100.0f + + if (percent < percentage.value && replenishItem(i)) { + timer.reset() + break + } + } + } + } + + private fun replenishItem(slot: Int): Boolean { + if (!hotbarCache.containsKey(slot)) { + return false + } + + val itemStack = hotbarCache[slot] + var s = -1 + var count = 0 + + for (i in 9..35) { + val stack: ItemStack = mc.player!!.inventory.getStack(i) + + if (stack.isEmpty) { + continue + } + + if (InventoryUtil.getStackName(stack) != InventoryUtil.getStackName(itemStack!!)) { + continue + } + + if (itemStack.item is BlockItem && stack.item is BlockItem && (stack.item as BlockItem).block == (itemStack.item as BlockItem).block) { + s = i + count = stack.count + break + } + + if (itemStack.item == stack.item) { + s = i + count = stack.count + break + } + } + + if (s == -1) { + return false + } + + val placeBack = count + itemStack!!.count > itemStack.maxCount + val syncId: Int = mc.player!!.currentScreenHandler.syncId + + mc.interactionManager!!.clickSlot(syncId, s, 0, SlotActionType.PICKUP, mc.player) + mc.interactionManager!!.clickSlot(syncId, InventoryUtil.normalize(slot), 0, SlotActionType.PICKUP, mc.player) + + if (placeBack) { + mc.interactionManager!!.clickSlot(syncId, s, 0, SlotActionType.PICKUP, mc.player) + } + + return true + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/player/RotationLock.kt b/src/main/kotlin/com/paragon/client/modules/player/RotationLock.kt new file mode 100644 index 0000000..52f7086 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/player/RotationLock.kt @@ -0,0 +1,39 @@ +package com.paragon.client.modules.player + +import com.paragon.backend.event.events.mc.TickEvent +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import com.paragon.util.mc +import com.paragon.util.nullCheck +import me.bush.eventbus.annotation.EventListener + +/** + * @author aesthetical, finnish kid + * @since 02/22/23 + */ +object RotationLock : Module("Rotation Lock", "Locks your rotations", Category.PLAYER) { + + private var yaw = 0f + private var pitch = 0f + + override fun enable() { + if (nullCheck()) { + return + } + + yaw = mc.player!!.yaw + pitch = mc.player!!.pitch + } + + @EventListener + fun onTick(event: TickEvent?) { + if (nullCheck()) { + return + } + + mc.player!!.setHeadYaw(yaw) + mc.player!!.setBodyYaw(yaw) + mc.player!!.yaw = yaw + mc.player!!.pitch = pitch + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/player/Stealer.kt b/src/main/kotlin/com/paragon/client/modules/player/Stealer.kt new file mode 100644 index 0000000..e955c06 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/player/Stealer.kt @@ -0,0 +1,45 @@ +package com.paragon.client.modules.player + +import com.paragon.backend.event.events.mc.TickEvent +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import com.paragon.util.calculations.Timer +import com.paragon.util.mc +import me.bush.eventbus.annotation.EventListener +import net.minecraft.screen.GenericContainerScreenHandler +import net.minecraft.screen.slot.SlotActionType + +/** + * @author aesthetical + * @since 02/22/23 + */ +object Stealer : Module("Stealer", "Automatically steals from chests", Category.PLAYER) { + private val delay by int("Delay", 50, 1, 0..1000, "How long to wait before stealing the next item") + private val autoClose by bool("Auto Close", true, "If to automatically close the chest after stealing everything") + + private val timer = Timer() + + override val info = { delay.toString() } + + @EventListener + fun onTick(event: TickEvent) { + if (mc.player!!.currentScreenHandler is GenericContainerScreenHandler) { + val handler = mc.player!!.currentScreenHandler as GenericContainerScreenHandler + + if (timer.elapsed(delay.toDouble())) { + for (i in 0..(handler.rows * 9)) { + val stack = handler.inventory.getStack(i) + if (!stack.isEmpty) { + mc.interactionManager!!.clickSlot(handler.syncId, i, 0, SlotActionType.QUICK_MOVE, mc.player) + timer.reset() + return + } + } + + if (autoClose) { + mc.player!!.closeHandledScreen() + } + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/visual/ChinaHat.kt b/src/main/kotlin/com/paragon/client/modules/visual/ChinaHat.kt new file mode 100644 index 0000000..a5788bd --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/visual/ChinaHat.kt @@ -0,0 +1,35 @@ +package com.paragon.client.modules.visual + +import com.paragon.backend.event.events.render.GameRenderEvent +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import com.paragon.util.calculations.MathsUtil +import com.paragon.util.getClientColour +import com.paragon.util.mc +import com.paragon.util.rendering.Renderer +import me.bush.eventbus.annotation.EventListener +import net.minecraft.client.option.Perspective +import net.minecraft.util.math.Vec3d + +/** + * @author surge + * @since 06/03/2023 + */ +object ChinaHat : Module("China Hat", "-1000 social credit", Category.VISUAL) { + + private val offset by double("Offset", -0.25, 0.01, -2.0..0.0, "The Y offset of the outside edge") + private val alpha by int("Alpha", 150, 1, 0..255, "The alpha of the fill") + + @EventListener + fun onGameRender(event: GameRenderEvent) { + mc.world!!.players.forEach { + if (it != mc.player || mc.options.perspective != Perspective.FIRST_PERSON) { + val pos = MathsUtil.interpolate(it, event.tickDelta) + + Renderer.polygon(event.matrices, pos.add(0.0, it.height.toDouble() + 0.25, 0.0), 0.65, getClientColour().integrateAlpha(alpha), Renderer.DrawMode.FILL, 120, offset) + Renderer.polygon(event.matrices, pos.add(0.0, it.height.toDouble() + 0.25, 0.0), 0.65, getClientColour(), Renderer.DrawMode.LINES, 120, offset) + } + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/visual/ClickGUI.kt b/src/main/kotlin/com/paragon/client/modules/visual/ClickGUI.kt new file mode 100644 index 0000000..2e38304 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/visual/ClickGUI.kt @@ -0,0 +1,48 @@ +package com.paragon.client.modules.visual + +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import com.paragon.client.ui.configuration.aesthetical.AestheticalUI +import com.paragon.client.ui.configuration.surge.SurgeUI +import com.paragon.util.mc +import com.paragon.util.nullCheck +import org.lwjgl.glfw.GLFW + +/** + * @author surge + * @since 11/02/2023 + */ +object ClickGUI : Module("Click GUI", "The main GUI of the client", Category.VISUAL) { + + private val mode by enum("Mode", Mode.SURGE, "The type of click gui") + + var surgeUi: SurgeUI? = null + var aestheticalUI: AestheticalUI? = null + + init { + key.code = GLFW.GLFW_KEY_RIGHT_SHIFT + visible = false + } + + override fun enable() { + if (nullCheck()) { + return + } + + mc.setScreen( + when (mode) { + Mode.SURGE -> surgeUi + Mode.AESTHETICAL -> aestheticalUI + else -> null + } + ) + + toggle() + } + + enum class Mode { + SURGE, AESTHETICAL + } + + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/visual/ESP.kt b/src/main/kotlin/com/paragon/client/modules/visual/ESP.kt new file mode 100644 index 0000000..44c4907 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/visual/ESP.kt @@ -0,0 +1,62 @@ +package com.paragon.client.modules.visual + +import com.paragon.backend.event.events.render.GameRenderEvent +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import com.paragon.backend.setting.Colour +import com.paragon.util.getClientColour +import com.paragon.util.mc +import com.paragon.util.rendering.Renderer +import me.bush.eventbus.annotation.EventListener +import net.minecraft.entity.Entity +import net.minecraft.entity.mob.HostileEntity +import net.minecraft.entity.passive.PassiveEntity +import net.minecraft.entity.player.PlayerEntity + +/** + * @author surge + * @since 22/02/2023 + */ +object ESP : Module("ESP", "Highlights entities in the world", Category.VISUAL) { + + private val box by enum("Box", Box.BOTH, "How to draw the box") + private val passive by bool("Passive", true, "Highlight passive entities") + private val hostile by bool("Hostile", true, "Highlight hostile entities") + private val players by bool("Players", true, "Highlight players") + private val alpha by int("Alpha", 100, 1, 0..255, "The alpha of the fill") visibility { box == Box.FILL || box == Box.BOTH } + + @EventListener + fun onGameRender(event: GameRenderEvent) { + filtered().forEach { (entity, colour) -> + if (box == Box.FILL || box == Box.BOTH) { + Renderer.box(event.matrices, entity.boundingBox, colour.integrateAlpha(alpha), Renderer.DrawMode.FILL) + } + + if (box == Box.OUTLINE || box == Box.BOTH) { + Renderer.box(event.matrices, entity.boundingBox, colour, Renderer.DrawMode.LINES) + } + } + } + + private fun filtered(): Map { + val entities: MutableMap = HashMap() + + mc.world!!.entities.filter { it is PassiveEntity && passive || it is HostileEntity && hostile || it is PlayerEntity && players && it != mc.player }.forEach { + entities[it] = when (it) { + is PassiveEntity -> Colour(0, 255, 0, 255) + is HostileEntity -> Colour(255, 0, 0, 255) + is PlayerEntity -> getClientColour().integrateAlpha(255) + else -> Colour(0, 0, 0, 0) + } + } + + return entities + } + + private enum class Box { + FILL, + OUTLINE, + BOTH + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/visual/FullBright.kt b/src/main/kotlin/com/paragon/client/modules/visual/FullBright.kt new file mode 100644 index 0000000..221636b --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/visual/FullBright.kt @@ -0,0 +1,59 @@ +package com.paragon.client.modules.visual + +import com.paragon.backend.event.events.mc.TickEvent +import com.paragon.backend.event.events.render.GammaModifyEvent +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import com.paragon.util.mc +import com.paragon.util.nullCheck +import me.bush.eventbus.annotation.EventListener +import net.minecraft.entity.effect.StatusEffectInstance +import net.minecraft.entity.effect.StatusEffects + +/** + * @author KassuK, aesthetical + * @since 02/17/23 + */ +object FullBright : Module("Full Bright", "Makes the game brighter", Category.VISUAL) { + + private var gavePotion = false + + private val mode by enum("Mode", Mode.GAMMA, "How to brighten up your game") + + override val info = { mode.name } + + override fun disable() { + if (!nullCheck() && gavePotion) { + mc.player!!.removeStatusEffect(StatusEffects.NIGHT_VISION) + } + + gavePotion = false + } + + @EventListener + fun onTick(event: TickEvent?) { + if (mode == Mode.EFFECT) { + if (mc.player!!.hasStatusEffect(StatusEffects.NIGHT_VISION)) { + return + } + + gavePotion = true + + mc.player!!.addStatusEffect(StatusEffectInstance(StatusEffects.NIGHT_VISION, 400, 1)) + } + } + + @EventListener + fun onGammaModify(event: GammaModifyEvent) { + if (mode == Mode.GAMMA) { + event.gamma = 100.0f + event.isCancelled = true + } + } + + enum class Mode { + GAMMA, + EFFECT + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/visual/HUD.kt b/src/main/kotlin/com/paragon/client/modules/visual/HUD.kt new file mode 100644 index 0000000..c0110d3 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/visual/HUD.kt @@ -0,0 +1,108 @@ +package com.paragon.client.modules.visual + +import com.paragon.Paragon +import com.paragon.backend.event.events.render.RenderHUDEvent +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import com.paragon.util.BuildConfig.BuildConfig +import com.paragon.util.formatCapitalised +import com.paragon.util.getClientColour +import com.paragon.util.mc +import com.paragon.util.rendering.ColorUtil +import com.paragon.util.rendering.NVGWrapper +import me.bush.eventbus.annotation.EventListener +import me.surge.animation.BoundedAnimation +import me.surge.animation.Easing +import net.minecraft.client.gui.screen.ChatScreen +import java.awt.Color + +/** + * @author aesthetical + * @since 02/17/23 + */ +object HUD : Module("HUD", "Renders an overlay", Category.VISUAL) { + + private val yAnimation = BoundedAnimation(0.0f, 30.0f, 200.0f, false, Easing.CUBIC_IN_OUT) + + init { + // auto-enable + if (!isEnabled) { + toggle() + } + + visible = false + } + + @EventListener + fun onRenderHUD(event: RenderHUDEvent) { + NVGWrapper.scope { r: NVGWrapper -> + r.text("P", 4.0f, 4.0f, getClientColour(), size = 17f, shadow = true) + r.text( + "aragon " + BuildConfig.BRANCH + "/" + BuildConfig.HASH, + 4.0f + r.textWidth("P"), + 4.0f, + Color.white, + size = 17f, + shadow = true + ) + + val enabled: List = Paragon.moduleManager.modules + .filter { module: Module -> module.isActive() && module.visible } + .sortedBy { + r.textWidth(it.name + if (it.info() == null) "" else " " + it.info()!!.replace("_", " ")) + } + .reversed() + + if (enabled.isNotEmpty()) { + var y = 4.0f + if (mc.player!!.activeStatusEffects.isNotEmpty()) { + y += 52.0f + } + + for (i in enabled.indices) { + val module = enabled[i] + val c = module.name + var textWidth = r.textWidth(c, size = 17.0f) + + if (module.info() != null) { + textWidth += r.textWidth(" " + module.info()!!.replace("_", " ").formatCapitalised(), size = 17.0f) + } + + module.animation.maximum = textWidth + + val x = (event.width - textWidth * module.animation.animationFactor - 8.0f).toFloat() + val rectWidth = textWidth + 8.0f + val color = ColorUtil.gradientRainbow(getClientColour(), 0.72f, i * 200 + 150) + + r.quad(x - 4.0f, y, rectWidth, (22.0f * module.animation.animationFactor).toFloat(), Color(0, 0, 0, 145)) + r.quad(x + rectWidth - 6.0f, y, 2.0f, 22.0f, color) + r.text(c, x, y + 3, color, size = 17f, shadow = true) + + if (module.info() != null) { + r.text( + module.info()!!.replace("_", " ").formatCapitalised(), + x + 2.0f + r.textWidth(module.name + " ", size = 17.0f), + y + 3, + Color.gray, + size = 17f, + shadow = true + ) + } + + y += (22.0f * module.animation.animationFactor).toFloat() + } + } + + yAnimation.state = mc.currentScreen is ChatScreen + var y = event.height - 20.0f - (yAnimation.animationFactor.toFloat() * yAnimation.maximum) + + r.text("XYZ: ", 1.5f, y, Color.GRAY, shadow = true) + r.text(String.format("%.1f", mc.player!!.x) + + " " + String.format("%.1f", mc.player!!.y) + " " + + String.format("%.1f", mc.player!!.z), + 2.0f + r.textWidth("XYZ: "), y, Color.WHITE, shadow = true) + + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/visual/HoleESP.kt b/src/main/kotlin/com/paragon/client/modules/visual/HoleESP.kt new file mode 100644 index 0000000..83ea904 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/visual/HoleESP.kt @@ -0,0 +1,128 @@ +package com.paragon.client.modules.visual + +import com.paragon.backend.event.events.mc.TickEvent +import com.paragon.backend.event.events.render.GameRenderEvent +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import com.paragon.backend.setting.Colour +import com.paragon.util.backgroundThread +import com.paragon.util.box +import com.paragon.util.mc +import com.paragon.util.rendering.Renderer +import me.bush.eventbus.annotation.EventListener +import net.minecraft.block.Blocks +import net.minecraft.util.math.BlockPos +import java.util.concurrent.ConcurrentHashMap +import kotlin.math.sqrt + +/** + * @author surge + * @since 22/02/2023 + */ +object HoleESP : Module("Hole ESP", "Highlights safe holes", Category.VISUAL) { + + private val range by int("Range", 5, 1, 1..10, "The range to search for holes in") + private val box by enum("Box", Box.BOTH, "How to draw the box") + private val obsidian by bool("Passive", true, "Highlight holes surrounded by obsidian") + private val mixed by bool("Hostile", true, "Highlight holes surrounded by obsidian or bedrock") + private val bedrock by bool("Players", true, "Highlight holes surrounded by bedrock") + private val alpha by int("Alpha", 100, 1, 0..255, "The alpha of the fill") visibility { box == Box.FILL || box == Box.BOTH } + private val height by double("Height", 0.2, 0.01, 0.0..1.0, "The height of the box") + private val dynamicHeight by bool("DynamicHeight", false, "Shrinks the boxes the closer they are to you") + private val reverseDynamic by bool("ReverseDynamic", false, "Expands the boxes the closer they are to you") visibility { dynamicHeight } + + private val holes = ConcurrentHashMap() + + @EventListener + fun onTick(event: TickEvent) { + backgroundThread { + for (x in -range..range) { + for (y in -range..range) { + for (z in -range..range) { + val pos = BlockPos(mc.player!!.blockPos.x + x, mc.player!!.blockPos.y + y,mc.player!!.blockPos.z + z) + + val type = getType(pos) + + if (type != null) { + holes[pos] = type + } + } + } + } + + // hopefully prevent the flickering thing?? + + val removeBuffer = mutableListOf() + + holes.forEach { (pos, type) -> + if (sqrt(pos.getSquaredDistance(mc.player!!.x, mc.player!!.y, mc.player!!.z)) > range || getType(pos) != type) { + removeBuffer.add(pos) + } + } + + removeBuffer.forEach { + holes.remove(it) + } + } + } + + @EventListener + fun onGameRender(event: GameRenderEvent) { + holes.forEach { (position, type) -> + var bb = position.box() + bb = bb.withMaxY(bb.minY + height) + + if (dynamicHeight) { + bb = if (reverseDynamic) { + bb.withMaxY(bb.minY + (height * (1 - (sqrt(position.getSquaredDistance(mc.player!!.x, mc.player!!.y, mc.player!!.z)) / range)))) + } else { + bb.withMaxY(bb.minY + (height * (sqrt(position.getSquaredDistance(mc.player!!.x, mc.player!!.y, mc.player!!.z)) / range))) + } + } + + if (box == Box.FILL || box == Box.BOTH) { + Renderer.box(event.matrices, bb, type.colour.integrateAlpha(alpha), Renderer.DrawMode.FILL) + } + + if (box == Box.OUTLINE || box == Box.BOTH) { + Renderer.box(event.matrices, bb, type.colour, Renderer.DrawMode.LINES) + } + } + } + + fun getType(position: BlockPos): Type? { + if (!mc.world!!.getBlockState(position).isReplaceable || mc.world!!.getBlockState(position.down()).isReplaceable) { + return null + } + + val surrounding = arrayListOf( + mc.world!!.getBlockState(position.north()), + mc.world!!.getBlockState(position.east()), + mc.world!!.getBlockState(position.south()), + mc.world!!.getBlockState(position.west()) + ) + + if (surrounding.all { it.block == Blocks.OBSIDIAN } && obsidian) { + return Type.OBSIDIAN + } else if (surrounding.all { it.block == Blocks.BEDROCK } && bedrock) { + return Type.BEDROCK + } else if (surrounding.all { it.block == Blocks.OBSIDIAN || it.block == Blocks.BEDROCK } && mixed) { + return Type.MIXED + } + + return null + } + + enum class Type(val colour: Colour) { + OBSIDIAN(Colour(255, 0, 0, 255)), + MIXED(Colour(255, 140, 0, 255)), + BEDROCK(Colour(0, 255, 0, 255)) + } + + private enum class Box { + FILL, + OUTLINE, + BOTH + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/visual/Tags.kt b/src/main/kotlin/com/paragon/client/modules/visual/Tags.kt new file mode 100644 index 0000000..5aee77d --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/visual/Tags.kt @@ -0,0 +1,193 @@ +package com.paragon.client.modules.visual + +import com.mojang.blaze3d.systems.RenderSystem +import com.paragon.backend.event.events.render.GameRenderEvent +import com.paragon.backend.event.events.render.RenderNameplateEvent +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import com.paragon.backend.setting.Colour +import com.paragon.util.calculations.MathsUtil.interpolate +import com.paragon.util.mc +import com.paragon.util.rendering.Renderer +import me.bush.eventbus.annotation.EventListener +import net.minecraft.client.render.* +import net.minecraft.client.render.VertexFormat.DrawMode +import net.minecraft.client.render.model.json.ModelTransformation +import net.minecraft.client.util.math.MatrixStack +import net.minecraft.entity.player.PlayerEntity +import net.minecraft.item.ItemStack +import net.minecraft.util.Formatting +import net.minecraft.util.Hand +import net.minecraft.util.math.Vec3d +import org.lwjgl.opengl.GL11 +import java.lang.Double.max + +/** + * @author aesthetical + * @since 02/19/23 + */ +object Tags : Module("Tags", "Draws tags over players heads", Category.VISUAL) { + + private val scale = float("Scale", 0.25f, 0.05f, 0.1f..0.8f, "The scaling of tags based off distance") + + @EventListener + fun onGameRender(event: GameRenderEvent) { + if (mc.cameraEntity != null) { + for (entity in mc.world!!.players) { + if (entity == null || entity == mc.player || entity.isDead) { + continue + } + + val camera: Vec3d = mc.gameRenderer.camera.pos + val pos = interpolate(entity, event.tickDelta).subtract(camera) + Renderer.submit { render(event.matrices, entity, pos) } + } + } + } + + @EventListener + fun onRenderNameplate(event: RenderNameplateEvent) { + if (event.entity != null && !event.entity.isDead) { + event.isCancelled = true + } + } + + private fun render(matrices: MatrixStack, player: PlayerEntity, pos: Vec3d) { + matrices.push() + + RenderSystem.enablePolygonOffset() + RenderSystem.polygonOffset(1.0f, -1500000.0f) + RenderSystem.disableDepthTest() + + matrices.translate(pos.x, pos.y + player.height + 0.12, pos.z) + matrices.multiply(mc.entityRenderDispatcher.rotation) + + val distance = mc.cameraEntity!!.distanceTo(player).toDouble() + val scaling = scale.value * max(distance, 4.0).toFloat() / 50.0f + + matrices.scale(-scaling, -scaling, scaling) + + val content = getPlayerInfo(player) + val width: Int = mc.textRenderer.getWidth(content) / 2 + + rectangle( + matrices, + (-width - 2).toDouble(), + -(mc.textRenderer.fontHeight + 1).toDouble(), + width * 2.0 + 4.0, + mc.textRenderer.fontHeight + 3.0, + Colour(0, 0, 0, 120) + ) + + mc.textRenderer.draw(matrices, content, -width.toFloat(), -(mc.textRenderer.fontHeight - 1).toFloat(), -1) + + var itemRenderX = -24 / 2 * player.inventory.armor.size + 16 + + if (!player.getStackInHand(Hand.OFF_HAND).isEmpty) { + renderItem(matrices, player.getStackInHand(Hand.OFF_HAND), itemRenderX) + itemRenderX += 12 + } + + for (i in 3 downTo 0) { + val stack = player.inventory.getArmorStack(i) + + if (!stack.isEmpty) { + renderItem(matrices, stack, itemRenderX) + itemRenderX += 12 + } + } + + if (!player.getStackInHand(Hand.MAIN_HAND).isEmpty) { + renderItem(matrices, player.getStackInHand(Hand.MAIN_HAND), itemRenderX) + } + + RenderSystem.enableDepthTest() + RenderSystem.polygonOffset(1.0f, 1500000.0f) + RenderSystem.disablePolygonOffset() + + matrices.pop() + } + + private fun renderItem(matrices: MatrixStack, stack: ItemStack, x: Int) { + matrices.push() + matrices.translate(x.toFloat(), -18f, 0f) + matrices.scale(-12f, -12f, 0f) + + RenderSystem.enableDepthTest() + RenderSystem.enableBlend() + DiffuseLighting.disableGuiDepthLighting() + + val z: Float = mc.itemRenderer.zOffset + mc.itemRenderer.zOffset = -150f + mc.itemRenderer.renderItem( + stack, + ModelTransformation.Mode.GUI, + 0xF000F0, + OverlayTexture.DEFAULT_UV, + matrices, + mc.bufferBuilders.entityVertexConsumers, + 0 + ) + + mc.bufferBuilders.entityVertexConsumers.draw() + mc.itemRenderer.zOffset = z + + DiffuseLighting.enableGuiDepthLighting() + RenderSystem.disableBlend() + RenderSystem.disableDepthTest() + + matrices.pop() + } + + private fun rectangle(matrices: MatrixStack, x: Double, y: Double, w: Double, h: Double, colour: Colour) { + val matrix = matrices.peek().positionMatrix + val builder = Tessellator.getInstance().buffer + + GL11.glDepthFunc(GL11.GL_ALWAYS) + GL11.glEnable(GL11.GL_BLEND) + + RenderSystem.enableBlend() + RenderSystem.blendFuncSeparate(770, 771, 1, 0) + RenderSystem.setShader { GameRenderer.getPositionColorProgram() } + + builder.begin(DrawMode.QUADS, VertexFormats.POSITION_COLOR) + + builder.vertex(matrix, x.toFloat(), y.toFloat(), 0.0f).color(colour.red / 255f, colour.green / 255f, colour.blue / 255f, colour.alpha / 255f).next() + builder.vertex(matrix, x.toFloat(), (y + h).toFloat(), 0.0f).color(colour.red / 255f, colour.green / 255f, colour.blue / 255f, colour.alpha / 255f).next() + builder.vertex(matrix, (x + w).toFloat(), (y + h).toFloat(), 0.0f).color(colour.red / 255f, colour.green / 255f, colour.blue / 255f, colour.alpha / 255f).next() + builder.vertex(matrix, (x + w).toFloat(), y.toFloat(), 0.0f).color(colour.red / 255f, colour.green / 255f, colour.blue / 255f, colour.alpha / 255f).next() + + BufferRenderer.drawWithGlobalProgram(builder.end()) + RenderSystem.disableBlend() + + GL11.glDisable(GL11.GL_BLEND) + GL11.glDepthFunc(GL11.GL_LEQUAL) + } + + private fun getPlayerInfo(entity: PlayerEntity): String { + val builder = StringBuilder() + builder.append(entity.gameProfile.name) + builder.append(" ") + + val playerHealth = entity.health + entity.absorptionAmount + var formatting = Formatting.DARK_RED + + if (playerHealth > 18.0f) { + formatting = Formatting.GREEN + } else if (playerHealth > 16.0f) { + formatting = Formatting.DARK_GREEN + } else if (playerHealth > 12.0f) { + formatting = Formatting.YELLOW + } else if (playerHealth > 8.0f) { + formatting = Formatting.GOLD + } else if (playerHealth > 5.0f) { + formatting = Formatting.RED + } + + builder.append(formatting) + builder.append(String.format("%.1f", entity.health + entity.absorptionAmount)) + + return builder.toString() + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/visual/Toasts.kt b/src/main/kotlin/com/paragon/client/modules/visual/Toasts.kt new file mode 100644 index 0000000..58a44c9 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/visual/Toasts.kt @@ -0,0 +1,20 @@ +package com.paragon.client.modules.visual + +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module + +/** + * @author aesthetical + * @since 02/20/23 + */ +object Toasts : Module("Toasts", "Configures toasts", Category.VISUAL) { + + init { + visible = false + setState(true) + } + + val toggle by bool("Toggle", true, description = "If to show toasts for toggled modules") + val totems by bool("Totems", true, description = "If to show toasts for totem pops") + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/visual/Tracers.kt b/src/main/kotlin/com/paragon/client/modules/visual/Tracers.kt new file mode 100644 index 0000000..9b447aa --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/visual/Tracers.kt @@ -0,0 +1,59 @@ +package com.paragon.client.modules.visual + +import com.paragon.backend.event.events.render.GameRenderEvent +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import com.paragon.backend.setting.Colour +import com.paragon.util.calculations.MathsUtil +import com.paragon.util.getClientColour +import com.paragon.util.mc +import com.paragon.util.rendering.Renderer +import me.bush.eventbus.annotation.EventListener +import net.minecraft.entity.Entity +import net.minecraft.entity.mob.HostileEntity +import net.minecraft.entity.passive.PassiveEntity +import net.minecraft.entity.player.PlayerEntity + +/** + * @author surge, aesthetical + * @since 12/02/2023 + */ +object Tracers : Module("Tracers", "Draws lines to entities", Category.VISUAL) { + + private val passive by bool("Passive", true, "Draw lines to passive entities") + private val hostile by bool("Hostile", true, "Draw lines to hostile entities") + private val players by bool("Players", true, "Draw lines to players") + private val lineWidth by float("Line Width", 1.5f, 0.1f, 0.1f..5.0f, "The width of the tracer line") + + private val stem by bool("Stem", false, "If to draw a stem on the entity") + private val stemFade by bool("Stem Fade", true, "Fade the stem at the top") visibility { stem } + + private val alpha by int("Alpha", 50, 1, 0..255) + + @EventListener + fun onGameRender(event: GameRenderEvent) { + filtered().forEach { (entity: Entity, colour: Colour?) -> + val entityPosition = MathsUtil.interpolate(entity, event.tickDelta) + + Renderer + .submit(Renderer.line(event.matrices, Renderer.crosshair(), entityPosition, lineWidth, colour)) + .optional(stem, Renderer.line(event.matrices, entityPosition, entityPosition.add(0.0, entity.height.toDouble(), 0.0), lineWidth, colour, secondary = colour.integrateAlpha(if (stemFade) 0 else 255))) + } + } + + private fun filtered(): Map { + val entities: MutableMap = HashMap() + + mc.world!!.entities.filter { it is PassiveEntity && passive || it is HostileEntity && hostile || it is PlayerEntity && players && it != mc.player }.forEach { + entities[it] = when (it) { + is PassiveEntity -> Colour(0, 255, 0, alpha) + is HostileEntity -> Colour(255, 0, 0, alpha) + is PlayerEntity -> getClientColour().integrateAlpha(alpha) + else -> Colour(0, 0, 0, 0) + } + } + + return entities + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/visual/Trajectories.kt b/src/main/kotlin/com/paragon/client/modules/visual/Trajectories.kt new file mode 100644 index 0000000..38c7336 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/visual/Trajectories.kt @@ -0,0 +1,161 @@ +package com.paragon.client.modules.visual + +import com.paragon.Paragon +import com.paragon.backend.event.events.render.GameRenderEvent +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import com.paragon.backend.setting.Colour +import com.paragon.util.calculations.MathsUtil.interpolate +import com.paragon.util.component1 +import com.paragon.util.component2 +import com.paragon.util.component3 +import com.paragon.util.mc +import com.paragon.util.rendering.Renderer +import me.bush.eventbus.annotation.EventListener +import net.minecraft.entity.player.PlayerEntity +import net.minecraft.entity.projectile.ProjectileUtil +import net.minecraft.item.* +import net.minecraft.util.Hand +import net.minecraft.util.hit.HitResult +import net.minecraft.util.math.Box +import net.minecraft.util.math.MathHelper +import net.minecraft.util.math.Vec3d +import net.minecraft.world.RaycastContext + + +/** + * @author aesthetical + * @since 02/25/23 + */ +object Trajectories : Module("Trajectories", "Shows the landing path of a throwable", Category.VISUAL) { + + @EventListener + fun onGameRender(event: GameRenderEvent) { + if (mc.player == null) { + return + } + + val landingPath = calcPath(mc.player!!, event.tickDelta) + if (landingPath != null) { + Renderer.box(event.matrices, Box(landingPath.final, landingPath.final.add(1.0, 1.0, 1.0)), Colour(255, 255, 255, 100), Renderer.DrawMode.FILL) + } + } + + private fun calcPath(e: PlayerEntity, tickDelta: Float): LandingPath? { + if (e == null || e.isDead) { + return null + } + + val stack = if (mc.player!!.activeHand == Hand.OFF_HAND) { + mc.player!!.getStackInHand(Hand.OFF_HAND) + } else Paragon.inventoryManager.serverStack + + if ((stack.item !is BowItem && stack.item !is PotionItem && stack.item !is TridentItem && stack.item !is EnderPearlItem && stack.item !is SnowballItem && stack.item !is EggItem)) { + return null + } + + val yaw = Paragon.rotationManager.server[0] + val pitch = Paragon.rotationManager.server[1] + + var (x, y, z) = interpolate(e, tickDelta) + + var velocity = 0.0f + var inaccuracy = 0.0f + + when (stack.item) { + + is EnderPearlItem, is EggItem, is SnowballItem -> velocity = 1.5f + is ExperienceBottleItem -> { + velocity = 0.7f + inaccuracy = -20.0f + } + is PotionItem -> velocity = 0.5f + is BowItem -> { + velocity = BowItem.getPullProgress(stack.maxUseTime - e.itemUseTimeLeft) * 1.5f + inaccuracy = 1.0f + } + } + + var motionX = (-MathHelper.sin(yaw / 180.0f * Math.PI.toFloat()) * MathHelper.cos(pitch / 180.0f * Math.PI.toFloat()) * 0.4f).toDouble() + var motionY = (-MathHelper.sin((pitch + inaccuracy) / 180.0f * Math.PI.toFloat()) * 0.4f).toDouble() + var motionZ = (MathHelper.cos(yaw / 180.0f * Math.PI.toFloat()) * MathHelper.cos(pitch / 180.0f * Math.PI.toFloat()) * 0.4f).toDouble() + + val distance: Double = MathHelper.square(motionX * motionX + motionY * motionY + motionZ * motionZ) + + motionX /= distance + motionY /= distance + motionZ /= distance + + motionX += 0.007499999832361937 * inaccuracy + motionY += 0.007499999832361937 * inaccuracy + motionZ += 0.007499999832361937 * inaccuracy + + motionX *= velocity.toDouble() + motionY *= velocity.toDouble() + motionZ *= velocity.toDouble() + + val size = if (stack.item is BowItem) 0.5 else 0.25 + val path = mutableListOf() + + var finalResult: HitResult? = null + + while (y > 0.0) { + val pos = Vec3d(x, y, z) + val motion = Vec3d(x + motionX, y + motionY, z + motionZ) + + // TODO: raycastBlocks or find a better way (this is kinda shit) + val result = mc.world!!.raycast(RaycastContext(pos, motion, RaycastContext.ShapeType.COLLIDER, RaycastContext.FluidHandling.NONE, e)) + if (result != null && result.type.equals(HitResult.Type.BLOCK)) { + finalResult = result + break + } + + val bb = Box( + x - size, y - size, z - size, + x + size, y + size, z + size) + .stretch(motionX, motionY, motionZ) + .expand(1.0, 1.0, 1.0) + + val entitiesColliding = mc.world!!.getOtherEntities(e, bb) + if (entitiesColliding.isNotEmpty()) { + for (entity in entitiesColliding) { + if (!entity.isCollidable || entity.equals(e)) { + continue + } + + val box = entity.boundingBox.expand(0.3) + val r = ProjectileUtil.getEntityCollision(mc.world, entity, pos, motion, box) { it != null && !it.isSpectator && !it.equals(e) } + if (r != null) { + println("collided with $entity") + finalResult = r + break + } + } + } + + x += motionX + y += motionY + z += motionZ + + motionX *= 0.99 + motionY *= 0.99 + motionZ *= 0.99 + + motionY -= if (stack.item is ExperienceBottleItem) { + 0.07 + } else if (stack.item is BowItem || stack.item is PotionItem) { + 0.6 + } else { + 0.03 + } + + println("pathed +(${path.size})") + path.add(Vec3d(x, y, z)) + } + + println("final: $x, $y, $z with ${path.size} paths. final result class: ${if (finalResult == null) "null" else finalResult.javaClass.simpleName}") + return LandingPath(Vec3d(x, y, z), path, finalResult) + } + + data class LandingPath(val final: Vec3d, val path: List, val result: HitResult?) +} diff --git a/src/main/kotlin/com/paragon/client/modules/visual/UnfocusedCPU.kt b/src/main/kotlin/com/paragon/client/modules/visual/UnfocusedCPU.kt new file mode 100644 index 0000000..8a2da47 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/visual/UnfocusedCPU.kt @@ -0,0 +1,33 @@ +package com.paragon.client.modules.visual + +import com.paragon.backend.event.events.render.FPSLimitEvent +import com.paragon.backend.event.events.render.PreGameRenderEvent +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import com.paragon.util.mc +import me.bush.eventbus.annotation.EventListener + +/** + * @author surge + * @since 24/02/2023 + */ +object UnfocusedCPU : Module("Unfocused CPU", "Stops world rendering when the window isn't focused", Category.VISUAL) { + + private var limit by int("Limit", 5, 1, 1..60, "The FPS limit to apply when the window isn't focused") + + @EventListener + fun onPreGameRender(event: PreGameRenderEvent) { + if (!mc.isWindowFocused) { + event.cancel() + } + } + + @EventListener + fun onFPSLimit(event: FPSLimitEvent) { + if (!mc.isWindowFocused) { + event.cancel() + event.limit = limit + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/visual/ViewClip.kt b/src/main/kotlin/com/paragon/client/modules/visual/ViewClip.kt new file mode 100644 index 0000000..867304a --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/visual/ViewClip.kt @@ -0,0 +1,22 @@ +package com.paragon.client.modules.visual + +import com.paragon.backend.event.events.render.ClipToSpaceEvent +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import me.bush.eventbus.annotation.EventListener + +/** + * @author aesthetical + * @since 02/19/23 + */ +object ViewClip : Module("View Clip", "Clips your camera out of bounds", Category.VISUAL) { + + private val distance by double("Distance", 3.0, 0.5, 1.0..50.0, "The camera clip distance") + + @EventListener + fun onClipToSpace(event: ClipToSpaceEvent) { + event.distance = distance + event.isCancelled = true + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/modules/visual/Xray.kt b/src/main/kotlin/com/paragon/client/modules/visual/Xray.kt new file mode 100644 index 0000000..3d1269e --- /dev/null +++ b/src/main/kotlin/com/paragon/client/modules/visual/Xray.kt @@ -0,0 +1,77 @@ +package com.paragon.client.modules.visual + +import com.paragon.backend.event.events.render.BlockAmbientLightLevelEvent +import com.paragon.backend.event.events.render.DrawSideOfBlockEvent +import com.paragon.backend.event.events.render.GammaModifyEvent +import com.paragon.backend.module.Category +import com.paragon.backend.module.Module +import com.paragon.util.mc +import com.paragon.util.nullCheck +import me.bush.eventbus.annotation.EventListener +import net.minecraft.block.Block +import net.minecraft.block.Blocks + +/** + * @author aesthetical + * @since 02/20/23 + */ +object Xray : Module("Xray", "Lets you see ores through blocks", Category.VISUAL) { + + @JvmStatic + val blocks = mutableListOf() + + init { + // TODO: Make this load from a config + + blocks += Blocks.COAL_ORE + blocks += Blocks.COPPER_ORE + blocks += Blocks.IRON_ORE + blocks += Blocks.LAPIS_ORE + blocks += Blocks.GOLD_ORE + blocks += Blocks.EMERALD_ORE + blocks += Blocks.DIAMOND_ORE + blocks += Blocks.REDSTONE_ORE + blocks += Blocks.NETHER_QUARTZ_ORE + blocks += Blocks.ANCIENT_DEBRIS + blocks += Blocks.DEEPSLATE_COAL_ORE + blocks += Blocks.DEEPSLATE_COPPER_ORE + blocks += Blocks.DEEPSLATE_IRON_ORE + blocks += Blocks.DEEPSLATE_LAPIS_ORE + blocks += Blocks.DEEPSLATE_GOLD_ORE + blocks += Blocks.DEEPSLATE_EMERALD_ORE + blocks += Blocks.DEEPSLATE_DIAMOND_ORE + blocks += Blocks.DEEPSLATE_REDSTONE_ORE + } + + override fun enable() { + super.enable() + if (!nullCheck()) { + mc.worldRenderer.reload() + } + } + + override fun disable() { + super.disable() + if (!nullCheck()) { + mc.worldRenderer.reload() + } + } + + @EventListener + fun onDrawSideOfBlock(event: DrawSideOfBlockEvent) { + event.drawSide = blocks.contains(event.block) + event.isCancelled = true + } + + @EventListener + fun onBlockAmbientLightLevel(event: BlockAmbientLightLevelEvent) { + event.lightLevel = 100.0f + event.isCancelled = true + } + + @EventListener + fun onGammaModify(event: GammaModifyEvent) { + event.gamma = 100.0f + event.isCancelled = true + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/toasts/Toast.kt b/src/main/kotlin/com/paragon/client/toasts/Toast.kt new file mode 100644 index 0000000..f48fcdf --- /dev/null +++ b/src/main/kotlin/com/paragon/client/toasts/Toast.kt @@ -0,0 +1,57 @@ +package com.paragon.client.toasts + +import com.paragon.backend.setting.Colour +import com.paragon.util.getClientColour +import com.paragon.util.rendering.NVGWrapper +import me.surge.animation.Animation +import me.surge.animation.Easing +import java.awt.Color + +/** + * @author aesthetical + * @since 02/19/23 + */ +class Toast(val toastType: ToastType, var deployer: String, var content: String, val lifespan: Long) { + + var endTime: Long = System.currentTimeMillis() + lifespan + var isDead = false + private set + + val animation = Animation(200f, true, Easing.CUBIC_IN_OUT) + + fun updateAndRender(nvg: NVGWrapper, posY: Float, screenWidth: Float) { + if (System.currentTimeMillis() > endTime) { + animation.state = false + + if (animation.animationFactor <= 0.0) { + isDead = true + } + } else { + animation.state = true + } + + val width: Float = nvg.textWidth(content, size = 14.0f) + + val x: Float = screenWidth - 8.0f - (width * animation.animationFactor).toFloat() + + nvg.roundedQuad(x - 4.0f, posY, width + 8.0f, 50.0f, 4.5f, Colour(23, 23, 23, 185)) + + val percent = (endTime - System.currentTimeMillis()).toDouble() / lifespan.toDouble() + val barWidth = ((width + 8.0f) * percent).toFloat() + + val colour = when (toastType) { + ToastType.ERROR -> Colour(245, 66, 66, 255) + ToastType.SUCCESS -> Colour(66, 245, 117, 255) + ToastType.WARNING -> Colour(245, 126, 66, 255) + else -> getClientColour() + } + + nvg.scissor(x - 4.0f, posY + 46f, barWidth, 4f) { + nvg.roundedQuad(x - 4.0f, posY, barWidth.coerceAtLeast(9f), 50.0f, 4.5f, colour) + } + + nvg.text(deployer, x, posY + 9.0F, Color.white, size = 16.0f, shadow = false) + nvg.text(content, x, posY + 28.0f, Color.white, size = 14.0f, shadow = false) + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/toasts/ToastType.kt b/src/main/kotlin/com/paragon/client/toasts/ToastType.kt new file mode 100644 index 0000000..c96a279 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/toasts/ToastType.kt @@ -0,0 +1,12 @@ +package com.paragon.client.toasts + +/** + * @author aesthetical + * @since 02/19/23 + */ +enum class ToastType { + INFO, + SUCCESS, + WARNING, + ERROR +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/ui/configuration/aesthetical/AestheticalUI.kt b/src/main/kotlin/com/paragon/client/ui/configuration/aesthetical/AestheticalUI.kt new file mode 100644 index 0000000..2944734 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/ui/configuration/aesthetical/AestheticalUI.kt @@ -0,0 +1,77 @@ +package com.paragon.client.ui.configuration.aesthetical + +import com.paragon.Paragon +import com.paragon.backend.module.Category +import com.paragon.client.ui.configuration.aesthetical.elements.ModuleCategoryPanel +import com.paragon.util.mc +import com.paragon.util.rendering.NVGWrapper +import net.minecraft.client.gui.screen.Screen +import net.minecraft.client.util.math.MatrixStack +import net.minecraft.text.Text + +/** + * @author aesthetical + * @since 02/23/23 + */ +class AestheticalUI : Screen(Text.of("ballsack")) { + + private val panels = mutableListOf() + + init { + var x = 4.0f + for (category in Category.values()) { + val moduleList = Paragon.moduleManager.getModules { it.category == category } + if (moduleList.isNotEmpty()) { + val panel = ModuleCategoryPanel(category.displayName, moduleList) + panel.x = x + panel.y = 14.0f + panel.width = 120.0f + panel.height = 16.5f + + x += (panel.width * 2) + 6.0f + panels += panel + } + } + } + + override fun render(matrices: MatrixStack, mouseX: Int, mouseY: Int, delta: Float) { + super.render(matrices, mouseX, mouseY, delta) + + NVGWrapper.scope { nvg -> + //nvg.quad(0f, 0f, width.toFloat() * 2, height.toFloat() * 2, Color(0, 0, 0, 150)) + + panels.forEach { + it.render( + nvg, + mc.mouse.x.toInt(), + mc.mouse.y.toInt(), + 0f + ) + } + } + } + + override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean { + panels.forEach { it.mouseClick(mc.mouse.x.toInt(), mc.mouse.y.toInt(), button) } + return super.mouseClicked(mouseX, mouseY, button) + } + + override fun mouseReleased(mouseX: Double, mouseY: Double, button: Int): Boolean { + panels.forEach { it.mouseRelease(mc.mouse.x.toInt(), mc.mouse.y.toInt(), button) } + return super.mouseReleased(mouseX, mouseY, button) + } + + override fun keyPressed(keyCode: Int, scanCode: Int, modifiers: Int): Boolean { + panels.forEach { it.keyTyped(keyCode, scanCode, modifiers) } + return super.keyPressed(keyCode, scanCode, modifiers) + } + + override fun shouldPause(): Boolean { + return false + } + + override fun close() { + Paragon.moduleManager.save("current") + super.close() + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/ui/configuration/aesthetical/elements/ModuleCategoryPanel.kt b/src/main/kotlin/com/paragon/client/ui/configuration/aesthetical/elements/ModuleCategoryPanel.kt new file mode 100644 index 0000000..ddfb040 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/ui/configuration/aesthetical/elements/ModuleCategoryPanel.kt @@ -0,0 +1,68 @@ +package com.paragon.client.ui.configuration.aesthetical.elements + +import com.paragon.backend.module.Module +import com.paragon.util.rendering.NVGWrapper +import java.awt.Color + +/** + * @author aesthetical + * @since 02/23/23 + */ +class ModuleCategoryPanel(private val categoryName: String, modules: List) : SettingElement() { + + private val children = mutableListOf() + + init { + modules.forEach { children.add(ModuleElement(it)) } + } + + override fun render(nvg: NVGWrapper, mouseX: Int, mouseY: Int, mouseDelta: Float) { + + nvg.quad(x, y, width * 2, getTotalHeight() * 2, PANEL_COLOR) + nvg.text(categoryName, x + 4.0f, y + (((height * 2) / 2.0f) - 16.0f / 2.0f), Color.WHITE, "axiforma", shadow = true) + + var posY = y + (height * 2) + (PADDING * 2) + for (child in children) { + if (!child.visible()) { + continue + } + + child.x = x + (PADDING * 2) + child.width = (width * 2) - (PADDING * 4.0f) + child.y = posY + child.height = 13.5f + + child.render(nvg, mouseX, mouseY, mouseDelta) + posY += child.getTotalHeight() * 2 + } + + } + + override fun mouseClick(mouseX: Int, mouseY: Int, button: Int): Boolean { + children.forEach { it.mouseClick(mouseX, mouseY, button) } + return super.mouseClick(mouseX, mouseY, button) + } + + override fun mouseRelease(mouseX: Int, mouseY: Int, button: Int): Boolean { + children.forEach { it.mouseRelease(mouseX, mouseY, button) } + return super.mouseRelease(mouseX, mouseY, button) + } + + override fun keyTyped(keyCode: Int, scanCode: Int, modifiers: Int) { + children.forEach { it.keyTyped(keyCode, scanCode, modifiers) } + super.keyTyped(keyCode, scanCode, modifiers) + } + + override fun getTotalHeight(): Float { + var height = height + PADDING + for (component in children) { + height += component.getTotalHeight() + } + return (height + PADDING) + } + + companion object { + private val PANEL_COLOR = Color(30, 30, 30) + private const val PADDING = 1.0f + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/ui/configuration/aesthetical/elements/ModuleElement.kt b/src/main/kotlin/com/paragon/client/ui/configuration/aesthetical/elements/ModuleElement.kt new file mode 100644 index 0000000..60f1d26 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/ui/configuration/aesthetical/elements/ModuleElement.kt @@ -0,0 +1,133 @@ +package com.paragon.client.ui.configuration.aesthetical.elements + +import com.paragon.backend.bind.Bind +import com.paragon.backend.module.Module +import com.paragon.backend.setting.Setting +import com.paragon.client.ui.configuration.aesthetical.elements.setting.BindSettingElement +import com.paragon.client.ui.configuration.aesthetical.elements.setting.BooleanSettingElement +import com.paragon.client.ui.configuration.aesthetical.elements.setting.EnumSettingElement +import com.paragon.client.ui.configuration.aesthetical.elements.setting.NumberSettingElement +import com.paragon.util.getClientColour +import com.paragon.util.rendering.NVGWrapper +import me.surge.animation.BoundedAnimation +import me.surge.animation.Easing +import org.lwjgl.glfw.GLFW.GLFW_MOUSE_BUTTON_1 +import org.lwjgl.glfw.GLFW.GLFW_MOUSE_BUTTON_2 +import java.awt.Color + +/** + * @author aesthetical + * @since 02/23/23 + */ +class ModuleElement(private val module: Module) : SettingElement() { + + private val hoverAnimation = BoundedAnimation(0.0f, 2.0f, 20.0f, false, Easing.LINEAR) + private val openAnimation = BoundedAnimation(0.0f, 2.0f, 200.0f, false, Easing.LINEAR) + + private val children = mutableListOf() + private var opened = false + + init { + module.settingMap.forEach { (_, v) -> + when (v.value) { + is Bind -> children.add(BindSettingElement(v as Setting)) + is Boolean -> children.add(BooleanSettingElement(v as Setting)) + is Enum<*> -> children.add(EnumSettingElement(v as Setting>)) + is Number -> children.add(NumberSettingElement(v as Setting)) + } + } + } + + override fun render(nvg: NVGWrapper, mouseX: Int, mouseY: Int, mouseDelta: Float) { + hoverAnimation.state = hovered(mouseX, mouseY, h = height * 2) + openAnimation.maximum = getComponentHeight() //- (if (openAnimation.animationValue > 0.0) height else 0.0f) + + nvg.quad(x, y, width, height * 2, if (module.isEnabled) getClientColour() else UNTOGGLED_BG) + nvg.text(module.name, x + 4.0f + (hoverAnimation.animationFactor.toFloat() * 2.0f), y + (((height * 2) / 2.0f) - 16.0f / 2.0f), Color.WHITE, "axiforma", shadow = true) + + openAnimation.state = opened + + if (openAnimation.animationValue > 0.0) { + var posY = y + (height * 2) + PADDING + + nvg.scissor(x, y, width, (getTotalHeight()) * 2) { + for (child in children) { + if (!child.visible()) { + continue + } + + child.x = x + PADDING + child.width = width - (PADDING * 2.0f) + child.y = posY + child.height = 13.5f + + child.render(nvg, mouseX, mouseY, mouseDelta) + + posY += child.getTotalHeight() * 2 + } + } + } + } + + override fun mouseClick(mouseX: Int, mouseY: Int, button: Int): Boolean { + if (hovered(mouseX, mouseY, h = height * 2)) { + if (button == GLFW_MOUSE_BUTTON_1) { + module.toggle() + } else if (button == GLFW_MOUSE_BUTTON_2) { + opened = !opened + } + } + + if (opened) { + children.forEach { it.mouseClick(mouseX, mouseY, button) } + } + + return super.mouseClick(mouseX, mouseY, button) + } + + override fun mouseRelease(mouseX: Int, mouseY: Int, button: Int): Boolean { + if (opened) { + children.forEach { it.mouseRelease(mouseX, mouseY, button) } + } + + return super.mouseRelease(mouseX, mouseY, button) + } + + override fun keyTyped(keyCode: Int, scanCode: Int, modifiers: Int) { + if (opened) { + children.forEach { it.keyTyped(keyCode, scanCode, modifiers) } + } + + super.keyTyped(keyCode, scanCode, modifiers) + } + + override fun getTotalHeight(): Float { + return if (openAnimation.animationValue > 0.0) (getComponentHeight()) else height + } + + private fun getComponentHeight(): Float { + var h = height + + if (openAnimation.animationValue > 0.0) { + var additional = 0.0 + + for (component in children) { + if (component.visible()) { + additional += component.getTotalHeight() + } + } + + additional += 2.0f + + h += (additional * openAnimation.animationFactor).toFloat() + } + + return h + } + + companion object { + private val PADDING = 1.5f + private val UNTOGGLED_BG = Color(35, 35, 35) + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/ui/configuration/aesthetical/elements/SettingElement.kt b/src/main/kotlin/com/paragon/client/ui/configuration/aesthetical/elements/SettingElement.kt new file mode 100644 index 0000000..e395275 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/ui/configuration/aesthetical/elements/SettingElement.kt @@ -0,0 +1,11 @@ +package com.paragon.client.ui.configuration.aesthetical.elements + +import com.paragon.util.rendering.ui.Element + +abstract class SettingElement : Element() { + open val visible: () -> Boolean = { true } + + open fun getTotalHeight(): Float { + return height + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/ui/configuration/aesthetical/elements/setting/BindSettingElement.kt b/src/main/kotlin/com/paragon/client/ui/configuration/aesthetical/elements/setting/BindSettingElement.kt new file mode 100644 index 0000000..12051fb --- /dev/null +++ b/src/main/kotlin/com/paragon/client/ui/configuration/aesthetical/elements/setting/BindSettingElement.kt @@ -0,0 +1,71 @@ +package com.paragon.client.ui.configuration.aesthetical.elements.setting + +import com.paragon.backend.bind.Bind +import com.paragon.backend.bind.DeviceType +import com.paragon.backend.setting.Setting +import com.paragon.client.ui.configuration.aesthetical.elements.SettingElement +import com.paragon.util.rendering.NVGWrapper +import me.surge.animation.BoundedAnimation +import me.surge.animation.Easing +import org.lwjgl.glfw.GLFW.GLFW_KEY_UNKNOWN +import org.lwjgl.glfw.GLFW.GLFW_MOUSE_BUTTON_2 +import java.awt.Color + +/** + * @author aesthetical + * @since 02/23/23 + */ +class BindSettingElement(private val setting: Setting) : SettingElement() { + private val hoverAnimation = BoundedAnimation(0.0f, 2.0f, 20.0f, false, Easing.LINEAR) + private var listening = false + + override fun render(nvg: NVGWrapper, mouseX: Int, mouseY: Int, mouseDelta: Float) { + hoverAnimation.state = hovered(mouseX, mouseY, h = height * 2) + + nvg.quad(x, y, width, height * 2, SETTING_BG) + + val midPoint = (((height * 2) / 2.0f) - 16.0f / 2.0f) + nvg.text(if (listening) "Listening..." else setting.name, x + 4.0f + (hoverAnimation.animationFactor.toFloat() * 2.0f), y + midPoint, Color.WHITE, "axiforma", shadow = true) + if (!listening) { + val text = setting.value.toString() + nvg.text(text, x + width - (nvg.textWidth(text, face = "axiforma", size = 16.0f) + 4.0f), y + midPoint, Color.GRAY, "axiforma", shadow = true) + } + } + + override fun keyTyped(keyCode: Int, scanCode: Int, modifiers: Int) { + + if (listening) { + listening = false + setting.value.type = DeviceType.KEYBOARD + setting.value.code = keyCode + } + + super.keyTyped(keyCode, scanCode, modifiers) + } + + override fun mouseClick(mouseX: Int, mouseY: Int, button: Int): Boolean { + if (hovered(mouseX, mouseY, h = height * 2) && button == 0) { + listening = !listening + return true // wait next mouse tick + } + + // this is so we can attack/place without binds interfering + // if someone really wants a mouse bind on 0 or 1, they can edit their binds file + if (listening) { + if (button > GLFW_MOUSE_BUTTON_2) { + listening = false + setting.value.type = DeviceType.MOUSE + setting.value.code = button + } else if (button == GLFW_MOUSE_BUTTON_2) { + listening = false + setting.value.code = GLFW_KEY_UNKNOWN + } + } + + return super.mouseClick(mouseX, mouseY, button) + } + + companion object { + private val SETTING_BG = Color(19, 19, 19) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/ui/configuration/aesthetical/elements/setting/BooleanSettingElement.kt b/src/main/kotlin/com/paragon/client/ui/configuration/aesthetical/elements/setting/BooleanSettingElement.kt new file mode 100644 index 0000000..5cae4de --- /dev/null +++ b/src/main/kotlin/com/paragon/client/ui/configuration/aesthetical/elements/setting/BooleanSettingElement.kt @@ -0,0 +1,43 @@ +package com.paragon.client.ui.configuration.aesthetical.elements.setting + +import com.paragon.backend.setting.Setting +import com.paragon.client.ui.configuration.aesthetical.elements.SettingElement +import com.paragon.util.getClientColour +import com.paragon.util.rendering.NVGWrapper +import me.surge.animation.BoundedAnimation +import me.surge.animation.Easing +import org.lwjgl.glfw.GLFW.GLFW_MOUSE_BUTTON_1 +import java.awt.Color + +/** + * @author aesthetical + * @since 02/23/23 + */ +class BooleanSettingElement(private val setting: Setting) : SettingElement() { + private val hoverAnimation = BoundedAnimation(0.0f, 2.0f, 20.0f, false, Easing.LINEAR) + + override fun render(nvg: NVGWrapper, mouseX: Int, mouseY: Int, mouseDelta: Float) { + hoverAnimation.state = hovered(mouseX, mouseY, h = height * 2) + + nvg.quad(x, y, width, height * 2, SETTING_BG) + + val midPoint = (((height * 2) / 2.0f) - 16.0f / 2.0f) + nvg.text(setting.name, x + 4.0f + (hoverAnimation.animationFactor.toFloat() * 2.0f), y + midPoint, Color.WHITE, "axiforma", shadow = true) + + val dimension = ((height - 4) * 2) + nvg.roundedQuad(x + width - (dimension + 4.0f), y + midPoint, dimension, dimension, 2.5f, if (setting.value) getClientColour() else SETTING_BG.brighter()) + } + + override fun mouseClick(mouseX: Int, mouseY: Int, button: Int): Boolean { + + if (hovered(mouseX, mouseY, h = height * 2) && button == GLFW_MOUSE_BUTTON_1) { + setting.setValue(!setting.value) + } + + return super.mouseClick(mouseX, mouseY, button) + } + + companion object { + private val SETTING_BG = Color(19, 19, 19) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/ui/configuration/aesthetical/elements/setting/EnumSettingElement.kt b/src/main/kotlin/com/paragon/client/ui/configuration/aesthetical/elements/setting/EnumSettingElement.kt new file mode 100644 index 0000000..4330d11 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/ui/configuration/aesthetical/elements/setting/EnumSettingElement.kt @@ -0,0 +1,47 @@ +package com.paragon.client.ui.configuration.aesthetical.elements.setting + +import com.paragon.backend.setting.Setting +import com.paragon.client.ui.configuration.aesthetical.elements.SettingElement +import com.paragon.util.formatCapitalised +import com.paragon.util.rendering.NVGWrapper +import me.surge.animation.BoundedAnimation +import me.surge.animation.Easing +import org.lwjgl.glfw.GLFW.GLFW_MOUSE_BUTTON_1 +import org.lwjgl.glfw.GLFW.GLFW_MOUSE_BUTTON_2 +import java.awt.Color + +/** + * @author aesthetical + * @since 02/24/23 + */ +class EnumSettingElement(private val setting: Setting>) : SettingElement() { + private val hoverAnimation = BoundedAnimation(0.0f, 2.0f, 20.0f, false, Easing.LINEAR) + + override fun render(nvg: NVGWrapper, mouseX: Int, mouseY: Int, mouseDelta: Float) { + hoverAnimation.state = hovered(mouseX, mouseY, h = height * 2) + + nvg.quad(x, y, width, height * 2, SETTING_BG) + + val midPoint = (((height * 2) / 2.0f) - 16.0f / 2.0f) + nvg.text(setting.name, x + 4.0f + (hoverAnimation.animationFactor.toFloat() * 2.0f), y + midPoint, Color.WHITE, "axiforma", shadow = true) + val t = setting.value.toString().formatCapitalised() + nvg.text(t, x + width - (nvg.textWidth(t, face = "axiforma", size = 16.0f) + 4.0f), y + midPoint, Color.GRAY, "axiforma", shadow = true) + } + + override fun mouseClick(mouseX: Int, mouseY: Int, button: Int): Boolean { + + if (hovered(mouseX, mouseY, h = height * 2)) { + if (button == GLFW_MOUSE_BUTTON_1) { + setting.setValue(setting.nextEnum) + } else if (button == GLFW_MOUSE_BUTTON_2) { + setting.setValue(setting.previousEnum) + } + } + + return super.mouseClick(mouseX, mouseY, button) + } + + companion object { + private val SETTING_BG = Color(19, 19, 19) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/ui/configuration/aesthetical/elements/setting/NumberSettingElement.kt b/src/main/kotlin/com/paragon/client/ui/configuration/aesthetical/elements/setting/NumberSettingElement.kt new file mode 100644 index 0000000..7de964d --- /dev/null +++ b/src/main/kotlin/com/paragon/client/ui/configuration/aesthetical/elements/setting/NumberSettingElement.kt @@ -0,0 +1,80 @@ +package com.paragon.client.ui.configuration.aesthetical.elements.setting + +import com.paragon.backend.setting.Setting +import com.paragon.client.ui.configuration.aesthetical.elements.SettingElement +import com.paragon.util.calculations.MathsUtil +import com.paragon.util.getClientColour +import com.paragon.util.rendering.NVGWrapper +import me.surge.animation.BoundedAnimation +import me.surge.animation.Easing +import java.awt.Color +import kotlin.math.roundToInt + +/** + * @author aesthetical + * @since 02/24/23 + */ +class NumberSettingElement(private val setting: Setting) : SettingElement() { + private val hoverAnimation = BoundedAnimation(0.0f, 2.0f, 20.0f, false, Easing.LINEAR) + private var dragging = false + + override fun render(nvg: NVGWrapper, mouseX: Int, mouseY: Int, mouseDelta: Float) { + hoverAnimation.state = hovered(mouseX, mouseY, h = height * 2) + + nvg.quad(x, y, width, height * 2, SETTING_BG) + + val difference = width.coerceAtMost(0f.coerceAtLeast(mouseX - (x + 4))).toDouble() + + val minimum = setting.minimum!!.toDouble() + val maximum = setting.maximum!!.toDouble() + + val value: Double + + if (dragging) { + value = if (difference == 0.0) { + minimum + } else { + val newValue = MathsUtil.roundDouble(difference / (width - 8) * (maximum - minimum) + minimum, 2) + val precision = 1 / setting.incrementation!!.toDouble() + (minimum.coerceAtLeast(maximum.coerceAtMost(newValue)) * precision).roundToInt() / precision + } + + when (setting.value) { + is Int -> setting.setValue(value.toInt()) + is Float -> setting.setValue(value.toFloat()) + is Double -> setting.setValue(value) + } + } + + val renderWidth = ((width - 4) * (setting.value.toDouble() - minimum) / (maximum - minimum)).toFloat() + nvg.quad(x, y, renderWidth, height * 2, getClientColour()) + + val midPoint = (((height * 2) / 2.0f) - 16.0f / 2.0f) + nvg.text(setting.name, x + 4.0f + (hoverAnimation.animationFactor.toFloat() * 2.0f), y + midPoint, Color.WHITE, "axiforma", shadow = true) + + val t = setting.value.toString() + nvg.text(t, x + width - (nvg.textWidth(t, face = "axiforma", size = 16.0f) + 4.0f), y + midPoint, Color.GRAY, "axiforma", shadow = true) + } + + override fun mouseClick(mouseX: Int, mouseY: Int, button: Int): Boolean { + if (hovered(mouseX, mouseY, h = height * 2) && button == 0) { + dragging = true + return true + } + + return super.mouseClick(mouseX, mouseY, button) + } + + override fun mouseRelease(mouseX: Int, mouseY: Int, button: Int): Boolean { + if (dragging) { + dragging = false + return true + } + + return super.mouseRelease(mouseX, mouseY, button) + } + + companion object { + private val SETTING_BG = Color(19, 19, 19) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/ui/configuration/surge/SurgeUI.kt b/src/main/kotlin/com/paragon/client/ui/configuration/surge/SurgeUI.kt new file mode 100644 index 0000000..ae63c62 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/ui/configuration/surge/SurgeUI.kt @@ -0,0 +1,93 @@ +package com.paragon.client.ui.configuration.surge + +import com.paragon.Paragon +import com.paragon.backend.module.Category +import com.paragon.client.ui.configuration.surge.panel.Panel +import com.paragon.mixin.duck.IMouse +import com.paragon.util.mc +import com.paragon.util.rendering.NVGWrapper +import net.minecraft.client.gui.screen.Screen +import net.minecraft.client.util.math.MatrixStack +import net.minecraft.text.Text +import java.awt.Color + +/** + * @author surge + * @since 11/02/2023 + */ +class SurgeUI : Screen(Text.of("")) { + + private val panels: MutableList = ArrayList() + + init { + var x = 20f + + for (category in Category.values()) { + panels.add(Panel(category, x, 20f)) + x += 200f + } + } + + override fun render(matrices: MatrixStack, mouseX: Int, mouseY: Int, delta: Float) { + super.render(matrices, mouseX, mouseY, delta) + + NVGWrapper.scope { nvg -> + nvg.quad(0f, 0f, width.toFloat() * 2, height.toFloat() * 2, Color(0, 0, 0, 150)) + + panels.forEach { panel: Panel -> + panel.render( + nvg, + mc.mouse.x.toInt(), + mc.mouse.y.toInt(), + 0f + ) + } + } + } + + override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean { + panels.forEach { + if (it.mouseClick(mc.mouse.x.toInt(), mc.mouse.y.toInt(), button)) { + return true + } + } + + return super.mouseClicked(mouseX, mouseY, button) + } + + override fun mouseReleased(mouseX: Double, mouseY: Double, button: Int): Boolean { + panels.forEach { + if (it.mouseRelease(mc.mouse.x.toInt(), mc.mouse.y.toInt(), button)) { + return true + } + } + + return super.mouseReleased(mouseX, mouseY, button) + } + + override fun mouseScrolled(mouseX: Double, mouseY: Double, amount: Double): Boolean { + panels.forEach { + if (it.scroll(mc.mouse.x.toInt(), mc.mouse.y.toInt(), amount)) { + return true + } + } + + return super.mouseScrolled(mouseX, mouseY, amount) + } + + override fun keyPressed(keyCode: Int, scanCode: Int, modifiers: Int): Boolean { + panels.forEach { it.keyTyped(keyCode, scanCode, modifiers) } + + return super.keyPressed(keyCode, scanCode, modifiers) + } + + override fun shouldPause(): Boolean { + return false + } + + override fun close() { + Paragon.moduleManager.save("current") + super.close() + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/ui/configuration/surge/module/ModuleElement.kt b/src/main/kotlin/com/paragon/client/ui/configuration/surge/module/ModuleElement.kt new file mode 100644 index 0000000..825b353 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/ui/configuration/surge/module/ModuleElement.kt @@ -0,0 +1,115 @@ +package com.paragon.client.ui.configuration.surge.module + +import com.paragon.backend.bind.Bind +import com.paragon.backend.module.Module +import com.paragon.backend.setting.RegistrySetting +import com.paragon.backend.setting.Setting +import com.paragon.client.ui.configuration.surge.setting.* +import com.paragon.client.ui.configuration.surge.setting.registry.RegistrySettingElement +import com.paragon.util.fade +import com.paragon.util.getClientColour +import com.paragon.util.rendering.NVGWrapper +import com.paragon.util.rendering.ui.Element +import me.surge.animation.Animation +import me.surge.animation.Easing +import java.awt.Color + +/** + * @author surge + * @since 11/02/2023 + */ +class ModuleElement(private val module: Module, x: Float, y: Float, width: Float, height: Float) : Element(x, y, width, height) { + + private val enabled = Animation({ 150f }, false) { Easing.LINEAR } + private val expanded = Animation({ 150f }, false) { Easing.LINEAR } + + private val children: MutableList> = ArrayList() + + init { + enabled.state = module.isEnabled + + module.settingMap.values.forEach { + when (it.value) { + is Number -> children.add(NumberSettingElement(it as Setting, x, y, width, 32f)) + is Boolean -> children.add(BooleanSettingElement(it as Setting, x, y, width, height)) + is Bind -> children.add(BindSettingElement(it as Setting, x, y, width, height)) + is Enum<*> -> children.add(EnumSettingElement(it as Setting>, x, y, width, height)) + } + + if (it is RegistrySetting<*>) { + children.add(RegistrySettingElement(it, x, y, width, height)) + } + } + } + + override fun render(nvg: NVGWrapper, mouseX: Int, mouseY: Int, mouseDelta: Float) { + enabled.state = module.isEnabled + nvg.quad(x, y, width, height, if (hovered(mouseX, mouseY)) hovered else background) + + nvg.text(module.name, x + 5, y + 7, Color.GRAY.fade(getClientColour(), enabled.animationFactor), size = 13f, shadow = false) + + if (children.size > 2) { + val ind = if (expanded.animationFactor > 0) " .." else "..." + nvg.text(ind, x + width - (nvg.textWidth(ind) + 5), y + 6, Color.WHITE, size = 12f, shadow = true) + } + + if (expanded.animationFactor > 0) { + nvg.scissor(x, y + height, width, getOffset() - height) { + var offset = y + height + + children.filter { it.setting.visibility() }.forEach { child -> + child.x = x + 2 + child.y = offset + + child.render(nvg, mouseX, mouseY, mouseDelta) + nvg.quad(x, offset, 2f, child.getOffset(), getClientColour()) + + offset += child.getOffset() + } + } + } + } + + override fun mouseClick(mouseX: Int, mouseY: Int, button: Int): Boolean { + if (hovered(mouseX, mouseY)) { + if (button == 0) { + module.toggle() + return true + } else if (button == 1) { + expanded.state = !expanded.state + return true + } + } + + if (expanded.state) { + if (children.filter { it.setting.visibility() }.any { it.mouseClick(mouseX, mouseY, button) }) { + return true + } + } + + return super.mouseClick(mouseX, mouseY, button) + } + + override fun mouseRelease(mouseX: Int, mouseY: Int, button: Int): Boolean { + if (expanded.state) { + if (children.filter { it.setting.visibility() }.any { it.mouseRelease(mouseX, mouseY, button) }) { + return true + } + } + + return super.mouseRelease(mouseX, mouseY, button) + } + + override fun keyTyped(keyCode: Int, scanCode: Int, modifiers: Int) { + if (expanded.state) { + children.filter { it.setting.visibility() }.forEach { it.keyTyped(keyCode, scanCode, modifiers) } + } + + super.keyTyped(keyCode, scanCode, modifiers) + } + + override fun getOffset(): Float { + return (super.getOffset() + children.filter { it.setting.visibility() }.sumOf { it.getOffset().toDouble() }.toFloat() * expanded.animationFactor).toFloat() + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/ui/configuration/surge/panel/Panel.kt b/src/main/kotlin/com/paragon/client/ui/configuration/surge/panel/Panel.kt new file mode 100644 index 0000000..91a36e1 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/ui/configuration/surge/panel/Panel.kt @@ -0,0 +1,108 @@ +package com.paragon.client.ui.configuration.surge.panel + +import com.paragon.Paragon +import com.paragon.backend.module.Category +import com.paragon.client.ui.configuration.surge.module.ModuleElement +import com.paragon.util.formatCapitalised +import com.paragon.util.getClientColour +import com.paragon.util.rendering.NVGWrapper +import com.paragon.util.rendering.ui.Element +import me.surge.animation.Animation +import me.surge.animation.Easing +import org.lwjgl.nanovg.NanoVG +import java.awt.Color + +/** + * @author surge + * @since 11/02/2023 + */ +class Panel(private val category: Category, x: Float, y: Float) : Element(x, y, 190f, 600f) { + + private val bar = 35f + private val elements: MutableList = ArrayList() + private val expanded = Animation({ 150f }, true) { Easing.LINEAR } + private var dragging = false + private var lastX = 0f + private var lastY = 0f + + init { + Paragon.moduleManager + .getModules { it.category == this.category } + .forEach { elements.add(ModuleElement(it, x, y, width, 24f)) } + } + + override fun render(nvg: NVGWrapper, mouseX: Int, mouseY: Int, mouseDelta: Float) { + if (dragging) { + x = mouseX - lastX + y = mouseY - lastY + } + + val scissorHeight = (moduleHeight * expanded.animationFactor).toFloat() + + nvg.quad(x, y, width, bar + scissorHeight + 4, Color(16, 16, 16)) + nvg.text(category.name.formatCapitalised(), x + width / 2, y + 9, Color.WHITE, "inter", 18f, false, NanoVG.NVG_ALIGN_CENTER or NanoVG.NVG_ALIGN_TOP) + nvg.quad(x, y + bar - 2, width, 2f, getClientColour()) + + nvg.scissor(x, y + 35, width, scissorHeight) { + nvg.quad(x, y + 35, width, scissorHeight, Color(19, 22, 24)) + + var offset = y + bar + + elements.forEach { + it.x = x + it.y = offset + it.render(nvg, mouseX, mouseY, mouseDelta) + offset += it.getOffset() + } + } + } + + override fun mouseClick(mouseX: Int, mouseY: Int, button: Int): Boolean { + if (hovered(mouseX, mouseY) && mouseY <= y + bar) { + if (button == 0) { + dragging = true + lastX = mouseX - x + lastY = mouseY - y + return true + } else if (button == 1) { + expanded.state = !expanded.state + return true + } + } + + if (elements.any { it.mouseClick(mouseX, mouseY, button) }) { + return true + } + + return super.mouseClick(mouseX, mouseY, button) + } + + override fun mouseRelease(mouseX: Int, mouseY: Int, button: Int): Boolean { + if (dragging && button == 0) { + dragging = false + return true + } + + if (elements.any { it.mouseRelease(mouseX, mouseY, button) }) { + return true + } + + return super.mouseRelease(mouseX, mouseY, button) + } + + override fun keyTyped(keyCode: Int, scanCode: Int, modifiers: Int) { + elements.forEach { it.keyTyped(keyCode, scanCode, modifiers) } + super.keyTyped(keyCode, scanCode, modifiers) + } + + private val moduleHeight: Float + get() { + var height = 0f + + for (element in elements) { + height += element.getOffset() + } + + return height + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/ui/configuration/surge/setting/BindSettingElement.kt b/src/main/kotlin/com/paragon/client/ui/configuration/surge/setting/BindSettingElement.kt new file mode 100644 index 0000000..702ed6e --- /dev/null +++ b/src/main/kotlin/com/paragon/client/ui/configuration/surge/setting/BindSettingElement.kt @@ -0,0 +1,66 @@ +package com.paragon.client.ui.configuration.surge.setting + +import com.paragon.backend.bind.Bind +import com.paragon.backend.bind.DeviceType +import com.paragon.backend.setting.Setting +import com.paragon.util.getClientColour +import com.paragon.util.rendering.NVGWrapper +import org.lwjgl.glfw.GLFW +import java.awt.Color + +/** + * @author surge, aesthetical + * @since 11/02/2023 + */ +class BindSettingElement(setting: Setting, x: Float, y: Float, width: Float, height: Float) : SettingElement(setting, x, y, width, height) { + + private var listening = false + + override fun render(nvg: NVGWrapper, mouseX: Int, mouseY: Int, mouseDelta: Float) { + nvg.quad(x, y, width, height, if (hovered(mouseX, mouseY)) hovered else background) + + if (listening) { + nvg.quad(x, y, width, height, getClientColour()) + } + + nvg.text(setting.name, x + 5, y + 7f, Color.WHITE, size = 12f, shadow = false) + nvg.text(setting.value.toString(), x + width - nvg.textWidth(setting.value.toString(), size = 12.0f) - 5, y + 7f, Color.GRAY, size = 12f, shadow = false) + + super.render(nvg, mouseX, mouseY, mouseDelta) + } + + override fun mouseClick(mouseX: Int, mouseY: Int, button: Int): Boolean { + return if (hovered(mouseX, mouseY)) { + when (button) { + 0 -> { + listening = !listening + true + } + + 1 -> { + setting.value.code = GLFW.GLFW_KEY_UNKNOWN + listening = false + true + } + + else -> { + setting.value.type = DeviceType.MOUSE + setting.value.code = button + listening = false + true + } + } + } else super.mouseClick(mouseX, mouseY, button) + } + + override fun keyTyped(keyCode: Int, scanCode: Int, modifiers: Int) { + if (listening) { + setting.value.type = DeviceType.KEYBOARD + setting.value.code = keyCode + listening = false + } + + super.keyTyped(keyCode, scanCode, modifiers) + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/ui/configuration/surge/setting/BooleanSettingElement.kt b/src/main/kotlin/com/paragon/client/ui/configuration/surge/setting/BooleanSettingElement.kt new file mode 100644 index 0000000..8709726 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/ui/configuration/surge/setting/BooleanSettingElement.kt @@ -0,0 +1,31 @@ +package com.paragon.client.ui.configuration.surge.setting + +import com.paragon.backend.setting.Setting +import com.paragon.util.getClientColour +import com.paragon.util.rendering.NVGWrapper +import java.awt.Color + +/** + * @author surge + * @since 11/02/2023 + */ +class BooleanSettingElement(setting: Setting, x: Float, y: Float, width: Float, height: Float) : SettingElement(setting, x, y, width, height) { + + override fun render(nvg: NVGWrapper, mouseX: Int, mouseY: Int, mouseDelta: Float) { + nvg.quad(x, y, width, height, if (hovered(mouseX, mouseY)) hovered else background) + + nvg.text(setting.name, x + 5, y + 7.5f, if (setting.value) getClientColour() else Color.WHITE, size = 12f, shadow = false) + + super.render(nvg, mouseX, mouseY, mouseDelta) + } + + override fun mouseClick(mouseX: Int, mouseY: Int, button: Int): Boolean { + if (hovered(mouseX, mouseY) && button == 0) { + setting.setValue(!setting.value) + return true + } + + return super.mouseClick(mouseX, mouseY, button) + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/ui/configuration/surge/setting/EnumSettingElement.kt b/src/main/kotlin/com/paragon/client/ui/configuration/surge/setting/EnumSettingElement.kt new file mode 100644 index 0000000..be5ccbd --- /dev/null +++ b/src/main/kotlin/com/paragon/client/ui/configuration/surge/setting/EnumSettingElement.kt @@ -0,0 +1,39 @@ +package com.paragon.client.ui.configuration.surge.setting + +import com.paragon.backend.setting.Setting +import com.paragon.util.formatCapitalised +import com.paragon.util.rendering.NVGWrapper +import java.awt.Color + +/** + * @author surge + * @since 11/02/2023 + */ +class EnumSettingElement(setting: Setting>, x: Float, y: Float, width: Float, height: Float) : SettingElement>(setting, x, y, width, height) { + + override fun render(nvg: NVGWrapper, mouseX: Int, mouseY: Int, mouseDelta: Float) { + nvg.quad(x, y, width, height, if (hovered(mouseX, mouseY)) hovered else background) + nvg.text(setting.name, x + 5, y + 7, Color.WHITE, size = 12f, shadow = false) + + val data = setting.value.name.formatCapitalised() + + nvg.text(data, x + width - nvg.textWidth(data, "inter", 12f) - 5, y + 7, Color.GRAY, size = 12f, shadow = false) + + super.render(nvg, mouseX, mouseY, mouseDelta) + } + + override fun mouseClick(mouseX: Int, mouseY: Int, button: Int): Boolean { + if (hovered(mouseX, mouseY)) { + if (button == 0) { + setting.setValue(setting.nextEnum) + } else if (button == 1) { + setting.setValue(setting.previousEnum) + } + + return true + } + + return super.mouseClick(mouseX, mouseY, button) + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/ui/configuration/surge/setting/NumberSettingElement.kt b/src/main/kotlin/com/paragon/client/ui/configuration/surge/setting/NumberSettingElement.kt new file mode 100644 index 0000000..4a61ce2 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/ui/configuration/surge/setting/NumberSettingElement.kt @@ -0,0 +1,74 @@ +package com.paragon.client.ui.configuration.surge.setting + +import com.paragon.backend.setting.Setting +import com.paragon.util.calculations.MathsUtil.roundDouble +import com.paragon.util.getClientColour +import com.paragon.util.rendering.NVGWrapper +import java.awt.Color +import kotlin.math.roundToInt + +/** + * @author surge + * @since 11/02/2023 + */ +class NumberSettingElement(setting: Setting, x: Float, y: Float, width: Float, height: Float) : SettingElement(setting, x, y, width, height) { + + private var dragging = false + + override fun render(nvg: NVGWrapper, mouseX: Int, mouseY: Int, mouseDelta: Float) { + nvg.quad(x, y, width, height, if (hovered(mouseX, mouseY)) hovered else background) + + val difference = width.coerceAtMost(0f.coerceAtLeast(mouseX - (x + 4))).toDouble() + + val minimum = setting.minimum!!.toDouble() + val maximum = setting.maximum!!.toDouble() + + val renderWidth = ((width - 8) * (setting.value.toDouble() - minimum) / (maximum - minimum)).toFloat() + + val value: Double + + if (dragging) { + value = if (difference == 0.0) { + minimum + } else { + val newValue = roundDouble(difference / (width - 8) * (maximum - minimum) + minimum, 2) + val precision = 1 / setting.incrementation!!.toDouble() + (minimum.coerceAtLeast(maximum.coerceAtMost(newValue)) * precision).roundToInt() / precision + } + + when (setting.value) { + is Int -> setting.setValue(value.toInt()) + is Float -> setting.setValue(value.toFloat()) + is Double -> setting.setValue(value) + } + } + + nvg.quad(x + 4, y + 24, width - 8f, 2f, Color(20, 20, 20)) + nvg.quad(x + 4, y + 24, renderWidth, 2f, getClientColour()) + nvg.quad(x + 2 + renderWidth, y + 23, 4f, 4f, Color.WHITE) + + nvg.text(setting.name, x + 5, y + 7, Color.WHITE, size = 12f, shadow = false) + nvg.text(setting.value.toString(), x + width - nvg.textWidth(setting.value.toString(), size = 12.0f) - 5, y + 7, Color.GRAY, size = 12f, shadow = false) + + super.render(nvg, mouseX, mouseY, mouseDelta) + } + + override fun mouseClick(mouseX: Int, mouseY: Int, button: Int): Boolean { + if (hovered(mouseX, mouseY) && button == 0) { + dragging = true + return true + } + + return super.mouseClick(mouseX, mouseY, button) + } + + override fun mouseRelease(mouseX: Int, mouseY: Int, button: Int): Boolean { + if (dragging) { + dragging = false + return true + } + + return super.mouseRelease(mouseX, mouseY, button) + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/ui/configuration/surge/setting/SettingElement.kt b/src/main/kotlin/com/paragon/client/ui/configuration/surge/setting/SettingElement.kt new file mode 100644 index 0000000..81c0414 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/ui/configuration/surge/setting/SettingElement.kt @@ -0,0 +1,23 @@ +package com.paragon.client.ui.configuration.surge.setting + +import com.paragon.backend.setting.Setting +import com.paragon.util.rendering.NVGWrapper +import com.paragon.util.rendering.ui.Element + +/** + * @author surge + * @since 11/02/2023 + */ +open class SettingElement(val setting: Setting, x: Float, y: Float, width: Float, height: Float) : Element(x, y, width, height) { + + override fun render(nvg: NVGWrapper, mouseX: Int, mouseY: Int, mouseDelta: Float) {} + + override fun mouseClick(mouseX: Int, mouseY: Int, button: Int): Boolean { + return super.mouseClick(mouseX, mouseY, button) + } + + override fun mouseRelease(mouseX: Int, mouseY: Int, button: Int): Boolean { + return super.mouseRelease(mouseX, mouseY, button) + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/ui/configuration/surge/setting/registry/RegistryElement.kt b/src/main/kotlin/com/paragon/client/ui/configuration/surge/setting/registry/RegistryElement.kt new file mode 100644 index 0000000..8c22eb3 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/ui/configuration/surge/setting/registry/RegistryElement.kt @@ -0,0 +1,37 @@ +package com.paragon.client.ui.configuration.surge.setting.registry + +import com.paragon.backend.setting.RegistrySetting +import com.paragon.util.fade +import com.paragon.util.formatCapitalised +import com.paragon.util.getClientColour +import com.paragon.util.rendering.NVGWrapper +import com.paragon.util.rendering.ui.Element +import me.surge.animation.Animation +import me.surge.animation.Easing +import java.awt.Color + +/** + * @author surge + * @since 06/03/2023 + */ +class RegistryElement(val element: T, val setting: RegistrySetting, x: Float, y: Float, width: Float, height: Float) : Element(x, y, width, height) { + + private val enabled = Animation(200f, element in setting.enabled(), Easing.LINEAR) + + override fun render(nvg: NVGWrapper, mouseX: Int, mouseY: Int, mouseDelta: Float) { + enabled.state = setting.getStateT(element) + + nvg.quad(x, y, width, height, if (hovered(mouseX, mouseY)) hovered else background) + nvg.text(element.toString().split('.').last().formatCapitalised(), x + 5, y + 7, Color.GRAY.fade(getClientColour(), enabled.animationFactor), size = 13f, shadow = false) + } + + override fun mouseClick(mouseX: Int, mouseY: Int, button: Int): Boolean { + if (hovered(mouseX, mouseY)) { + setting.setStateT(element, !setting.getStateT(element)) + return true + } + + return super.mouseClick(mouseX, mouseY, button) + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/ui/configuration/surge/setting/registry/RegistryScreen.kt b/src/main/kotlin/com/paragon/client/ui/configuration/surge/setting/registry/RegistryScreen.kt new file mode 100644 index 0000000..be2fb94 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/ui/configuration/surge/setting/registry/RegistryScreen.kt @@ -0,0 +1,118 @@ +package com.paragon.client.ui.configuration.surge.setting.registry + +import com.paragon.backend.setting.RegistrySetting +import com.paragon.util.getClientColour +import com.paragon.util.mc +import com.paragon.util.offset +import com.paragon.util.rendering.NVGWrapper +import com.paragon.util.tempGrow +import net.minecraft.client.gui.screen.Screen +import net.minecraft.client.util.math.MatrixStack +import net.minecraft.text.Text +import net.minecraft.util.math.MathHelper +import org.lwjgl.nanovg.NanoVG.NVG_ALIGN_CENTER +import org.lwjgl.nanovg.NanoVG.NVG_ALIGN_TOP +import java.awt.Color +import java.awt.Rectangle +import java.lang.Double.max + +/** + * @author surge + * @since 06/03/2023 + */ +class RegistryScreen(val setting: RegistrySetting, val last: Screen) : Screen(Text.of("")) { + + private val elements = mutableListOf>() + + private var bounds = Rectangle(width / 2 - 110, height / 2 - 90, 220, 180) + private var scroll = 0f + + init { + setting.states.forEach { (key, _) -> + elements.add(RegistryElement(key, setting, 0f, 0f, 200f, 24f)) + } + } + + override fun init() { + bounds = Rectangle(width - 414, height - 220, 826, 440) + } + + override fun render(matrices: MatrixStack, mouseX: Int, mouseY: Int, delta: Float) { + var totalHeight = 0.0 + + // lets just ignore this + var i = 0 + + elements.forEach { + i++ + + if (i % 4 == 0) { + totalHeight += it.height + 2f + } + } + + scroll = MathHelper.clamp(scroll.toDouble(), -max( + 0.0, + totalHeight - MathHelper.clamp(totalHeight, 0.0, bounds.height - 36.0) + ), 0.0).toFloat() + + NVGWrapper.scope { nvg -> + nvg.quad(0f, 0f, width.toFloat() * 2, height.toFloat() * 2, Color(0, 0, 0, 150)) + nvg.quad(bounds.tempGrow(0, 30), Color(16, 16, 16)) + + nvg.text(setting.name, bounds.x + bounds.width / 2f, bounds.y + 5f, size = 20f, alignment = NVG_ALIGN_CENTER or NVG_ALIGN_TOP) + nvg.quad(bounds.offset(10, 28).tempGrow(-20, -(bounds.height) + 2), getClientColour()) + + // lmao. + var i = 0 + + var offsetX = bounds.x + 10f + var offsetY = bounds.y + 30f + scroll + + nvg.scissor(bounds.x.toFloat(), bounds.y.toFloat() + 30f, bounds.width.toFloat(), bounds.height.toFloat() - 10f) { + elements.sortedBy { it.element.toString() }.forEach { + it.x = offsetX + it.y = offsetY + + it.render(nvg, mc.mouse.x.toInt(), mc.mouse.y.toInt(), delta) + + offsetX += it.width + 2f + + i++ + + if (i % 4 == 0) { + offsetX = bounds.x + 10f + offsetY += it.height + 2f + } + } + } + } + + super.render(matrices, mouseX, mouseY, delta) + } + + override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean { + if (bounds.offset(0, 30).contains(mc.mouse.x.toInt(), mc.mouse.y.toInt())) { + elements.forEach { + if (it.mouseClick(mc.mouse.x.toInt(), mc.mouse.y.toInt(), button)) { + return true + } + } + } + + return super.mouseClicked(mouseX, mouseY, button) + } + + override fun mouseScrolled(mouseX: Double, mouseY: Double, amount: Double): Boolean { + if (bounds.offset(0, 30).contains(mc.mouse.x.toInt(), mc.mouse.y.toInt())) { + scroll += amount.toFloat() * 18 + } + + return super.mouseScrolled(mouseX, mouseY, amount) + } + + override fun close() { + client!!.setScreen(last) + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/ui/configuration/surge/setting/registry/RegistrySettingElement.kt b/src/main/kotlin/com/paragon/client/ui/configuration/surge/setting/registry/RegistrySettingElement.kt new file mode 100644 index 0000000..5860bc7 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/ui/configuration/surge/setting/registry/RegistrySettingElement.kt @@ -0,0 +1,33 @@ +package com.paragon.client.ui.configuration.surge.setting.registry + +import com.paragon.backend.setting.RegistrySetting +import com.paragon.client.ui.configuration.surge.setting.SettingElement +import com.paragon.util.mc +import com.paragon.util.rendering.NVGWrapper +import net.minecraft.registry.Registry +import java.awt.Color + +/** + * @author surge + * @since 06/03/2023 + */ +class RegistrySettingElement(setting: RegistrySetting, x: Float, y: Float, width: Float, height: Float) : SettingElement>(setting, x, y, width, height) { + + override fun render(nvg: NVGWrapper, mouseX: Int, mouseY: Int, mouseDelta: Float) { + nvg.quad(x, y, width, height, if (hovered(mouseX, mouseY)) hovered else background) + + nvg.text(setting.name, x + 5, y + 7.5f, Color.WHITE, size = 12f) + + super.render(nvg, mouseX, mouseY, mouseDelta) + } + + override fun mouseClick(mouseX: Int, mouseY: Int, button: Int): Boolean { + if (hovered(mouseX, mouseY) && button == 0) { + mc.setScreen(RegistryScreen(setting as RegistrySetting, mc.currentScreen!!)) + return true + } + + return super.mouseClick(mouseX, mouseY, button) + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/ui/title/MainMenuHook.kt b/src/main/kotlin/com/paragon/client/ui/title/MainMenuHook.kt new file mode 100644 index 0000000..2536ec3 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/ui/title/MainMenuHook.kt @@ -0,0 +1,208 @@ +package com.paragon.client.ui.title + +import com.paragon.Paragon.Companion.altManager +import com.paragon.Paragon.Companion.version +import com.paragon.backend.alt.Alt +import com.paragon.client.ui.widgets.ButtonElement +import com.paragon.client.ui.widgets.ElementContainer +import com.paragon.client.ui.widgets.TextFieldElement +import com.paragon.util.BuildConfig.BuildConfig +import com.paragon.util.fade +import com.paragon.util.mc +import com.paragon.util.rendering.NVGWrapper +import com.paragon.util.rendering.NVGWrapper.scope +import me.surge.animation.Animation +import me.surge.animation.Easing +import net.minecraft.SharedConstants +import net.minecraft.client.util.math.MatrixStack +import net.minecraft.util.math.MathHelper +import org.lwjgl.glfw.GLFW.GLFW_KEY_BACKSPACE +import org.lwjgl.glfw.GLFW.GLFW_KEY_ENTER +import org.lwjgl.nanovg.NanoVG.* +import java.awt.Color +import java.lang.Double.max + +/** + * @author surge + * @since 22/02/2023 + */ +object MainMenuHook { + + var height = 0f + private var altManagerUI: AltManagerUI = AltManagerUI() + + fun init() { + altManagerUI = AltManagerUI() + } + + fun render(matrices: MatrixStack, mouseX: Int, mouseY: Int, delta: Float) { + scope { nvg -> + nvg.text("Running Paragon v" + version + " on git " + BuildConfig.BRANCH + "/" + BuildConfig.HASH, 5f, 5f, Color.WHITE, shadow = true) + altManagerUI.render(nvg, mouseX, mouseY, delta) + } + } + + fun mouseClicked(mouseX: Int, mouseY: Int, button: Int): Boolean { + altManagerUI.mouseClicked(mouseX, mouseY, button) + return false + } + + fun keyPressed(keyCode: Int, scanCode: Int, modifiers: Int): Boolean { + altManagerUI.keyTyped(keyCode, scanCode, modifiers) + return false + } + + fun mouseScrolled(mouseX: Int, mouseY: Int, amount: Float): Boolean { + altManagerUI.mouseScrolled(mouseX, mouseY, amount) + return false + } + + fun charTyped(char: Char, modifiers: Int) { + altManagerUI.charTyped(char, modifiers) + } + + private class AltManagerUI : ElementContainer() { + + private val expand = Animation(300f, false, Easing.CIRC_IN_OUT) + + private val WIDTH = 300f + + private val x: Float + get() { + return (-WIDTH + ((WIDTH + 10) * expand.animationFactor)).toFloat() + } + + private val height: Float + get() { + return mc.window.height - 60f + } + + private val altEntries = mutableListOf() + + private var scroll = 0f + + init { + altManager.alts.forEach { + altEntries.add(AltEntry(it, 0f, 0f, WIDTH - 20f, 30f)) + } + + put("email", TextFieldElement("Email", 0f, 0f, WIDTH - 20f, 25f)) + put("password", TextFieldElement("Password", 0f, 0f, WIDTH - 20f, 25f)) + + put("add", ButtonElement("Add", 0f, 0f, WIDTH - 20f, 25f) { + altManager.alts.add(Alt(get("email", TextFieldElement::class.java)!!.inputted, get("password", TextFieldElement::class.java)!!.inputted)) + + get("email", TextFieldElement::class.java)!!.inputted = "" + get("password", TextFieldElement::class.java)!!.inputted = "" + }) + } + + fun render(nvg: NVGWrapper, mouseX: Int, mouseY: Int, delta: Float) { + altEntries.removeIf { entry -> !altManager.alts.any { alt -> entry.alt.email == alt.email } } + + altManager.alts.forEach { alt -> + if (!altEntries.any { it.alt == alt }) { + altEntries.add(AltEntry(alt, 0f, 0f, WIDTH - 20f, 25f)) + } + } + + val totalHeight = altEntries.sumOf { it.height.toDouble() + 10f } + + nvg.roundedQuad(x + WIDTH - 10f, 30f + (height / 2f) - 16, 36f, 32f, 7f, Color(16, 16, 16)) + nvg.roundedQuad(x, 30f, WIDTH, height, 10f, Color(16, 16, 16)) + + nvg.text("Alt Manager", x + 10f, 39f, Color.WHITE, shadow = false) + nvg.text(altManager.status, x + WIDTH - nvg.textWidth(altManager.status, size = 12f) - 5, 44f, Color.WHITE, "inter", 12f, false) + nvg.quad(x + 5f, 65f, WIDTH - 10f, 1f, Color(55, 55, 55, 50)) + + nvg.text(if (expand.state) "<" else ">", x + WIDTH + 12f, 30f + (height / 2f) + 9, Color.WHITE, "inter", 30f, false, alignment = NVG_ALIGN_CENTER) + + scroll = MathHelper.clamp(scroll.toDouble(), -max(0.0, totalHeight - MathHelper.clamp(altEntries.sumOf { it.height.toDouble() + 10f }, 0.0, height - 60.0)), 0.0).toFloat() + + var offset = 70f + scroll + + nvg.scissor(x + 10f, offset, WIDTH - 10f, height - 20f) { + altEntries.forEach { + it.x = x + 10f + it.y = offset + it.width = WIDTH - 85f + + it.render(nvg, mouseX, mouseY, delta) + + offset += it.height + 10f + } + } + + positionAscending(x + 10f, 30f + height, 5f) + renderElements(nvg, mouseX, mouseY, delta) + } + + fun mouseClicked(mouseX: Int, mouseY: Int, button: Int) { + if (mouseX >= x + WIDTH && mouseX <= x + WIDTH + 30f && mouseY >= 30f + (height / 2f) - 13 && mouseY <= 30f + (height / 2f) + 13) { + this.expand.state = !this.expand.state + return + } + + altEntries.forEach { + it.clicked(button) + } + + clickElements(mouseX, mouseY, button) + } + + fun mouseScrolled(mouseX: Int, mouseY: Int, amount: Float) { + if (mouseX >= x && mouseX <= x + WIDTH && mouseY >= 65f && mouseY <= 30f + height) { + scroll += amount * 13 + } + } + + fun keyTyped(keyCode: Int, scanCode: Int, modifiers: Int) { + typeElements(keyCode, scanCode, modifiers) + } + + fun charTyped(char: Char, modifiers: Int) { + charElements(char, modifiers) + } + + } + + private class AltEntry(val alt: Alt, var x: Float, var y: Float, var width: Float, var height: Float) : ElementContainer() { + + private val hovered = Animation(100f, false, Easing.LINEAR) + + init { + put("delete", ButtonElement("Delete", 0f, 0f, 64f, height) { + altManager.alts.remove(this.alt) + }) + } + + fun render(nvg: NVGWrapper, mouseX: Int, mouseY: Int, delta: Float) { + hovered.state = hovered(mouseX, mouseY) + + nvg.roundedQuad(x, y, width, height, 7f, Color(23, 23, 23).fade(Color(33, 33, 33), hovered.animationFactor)) + + nvg.text(alt.cachedUsername, x + 5f, y + height / 2f, Color.WHITE, "inter", size = 14f, false, alignment = NVG_ALIGN_LEFT or NVG_ALIGN_MIDDLE) + + get("delete")!! + .position(x + width + 5f, y) + .render(nvg, mouseX, mouseY, delta) + } + + fun clicked(button: Int) { + if (get("delete")!!.hovered(mc.mouse.x.toInt(), mc.mouse.y.toInt())) { + get("delete")!!.mouseClick(mc.mouse.x.toInt(), mc.mouse.y.toInt(), button) + return + } + + if (hovered.state && button == 0) { + altManager.login(alt) + } + } + + fun hovered(mouseX: Int, mouseY: Int): Boolean { + return mouseX >= x && mouseX <= x + width && mouseY >= y && mouseY <= y + height + } + + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/ui/widgets/ButtonElement.kt b/src/main/kotlin/com/paragon/client/ui/widgets/ButtonElement.kt new file mode 100644 index 0000000..f855423 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/ui/widgets/ButtonElement.kt @@ -0,0 +1,35 @@ +package com.paragon.client.ui.widgets + +import com.paragon.util.fade +import com.paragon.util.rendering.NVGWrapper +import com.paragon.util.rendering.ui.Element +import me.surge.animation.Animation +import me.surge.animation.Easing +import org.lwjgl.nanovg.NanoVG +import java.awt.Color + +/** + * @author surge + * @since 07/03/2023 + */ +class ButtonElement(val text: String, x: Float, y: Float, width: Float, height: Float, val clicked: () -> Unit) : Element(x, y, width, height) { + + private val hover = Animation(100f, false, Easing.LINEAR) + + override fun render(nvg: NVGWrapper, mouseX: Int, mouseY: Int, delta: Float) { + hover.state = hovered(mouseX, mouseY) + + nvg.roundedQuad(x, y, width, height, 7f, Color(23, 23, 23).fade(Color(33, 33, 33), hover.animationFactor)) + nvg.text(text, x + width / 2f, y + height / 2f + 1, Color.WHITE, "inter", 12f, false, alignment = NanoVG.NVG_ALIGN_CENTER or NanoVG.NVG_ALIGN_MIDDLE) + } + + override fun mouseClick(mouseX: Int, mouseY: Int, button: Int): Boolean { + if (hover.state) { + clicked() + return true + } + + return false + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/ui/widgets/ElementContainer.kt b/src/main/kotlin/com/paragon/client/ui/widgets/ElementContainer.kt new file mode 100644 index 0000000..08b62b1 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/ui/widgets/ElementContainer.kt @@ -0,0 +1,61 @@ +package com.paragon.client.ui.widgets + +import com.paragon.util.rendering.NVGWrapper +import com.paragon.util.rendering.ui.Element + +/** + * @author surge + * @since 07/03/2023 + */ +open class ElementContainer { + + val elements = hashMapOf() + + fun renderElements(nvg: NVGWrapper, mouseX: Int, mouseY: Int, delta: Float) { + elements.forEach { + it.value.render(nvg, mouseX, mouseY, delta) + } + } + + fun clickElements(mouseX: Int, mouseY: Int, button: Int) { + elements.forEach { + it.value.mouseClick(mouseX, mouseY, button) + } + } + + fun typeElements(keyCode: Int, scanCode: Int, modifiers: Int) { + elements.forEach { (_, element) -> + element.keyTyped(keyCode, scanCode, modifiers) + } + } + + fun charElements(char: Char, modifiers: Int) { + elements.forEach { (_, element) -> + element.charTyped(char, modifiers) + } + } + + fun positionAscending(x: Float, initialY: Float, offset: Float = 10f): ElementContainer { + var y = initialY - offset + + elements.forEach { (_, element) -> + y -= element.height + offset + element.position(x, y) + } + + return this + } + + fun put(id: String, element: Element) { + elements[id] = element + } + + fun take(id: String) { + elements.remove(id) + } + + inline fun get(id: String, clazz: Class = T::class.java): T? { + return elements[id]?.let { clazz.cast(it) } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/client/ui/widgets/TextFieldElement.kt b/src/main/kotlin/com/paragon/client/ui/widgets/TextFieldElement.kt new file mode 100644 index 0000000..4b220b3 --- /dev/null +++ b/src/main/kotlin/com/paragon/client/ui/widgets/TextFieldElement.kt @@ -0,0 +1,58 @@ +package com.paragon.client.ui.widgets + +import com.paragon.util.fade +import com.paragon.util.rendering.NVGWrapper +import com.paragon.util.rendering.ui.Element +import me.surge.animation.Animation +import me.surge.animation.Easing +import net.minecraft.SharedConstants +import org.lwjgl.glfw.GLFW +import java.awt.Color + +/** +* @author surge +* @since 07/03/2023 +*/ +class TextFieldElement(val initial: String, x: Float, y: Float, width: Float, height: Float) : Element(x, y, width, height) { + + private val hover = Animation(100f, false, Easing.LINEAR) + private val listening = Animation(100f, false, Easing.LINEAR) + + var inputted: String = "" + + override fun render(nvg: NVGWrapper, mouseX: Int, mouseY: Int, delta: Float) { + hover.state = hovered(mouseX, mouseY) + + nvg.roundedQuad(x, y, width, height, 7f, Color(23, 23, 23).fade(Color(33, 33, 33), hover.animationFactor).fade(Color(43, 43, 43), listening.animationFactor)) + nvg.text(inputted.ifEmpty { initial }, x + 5, y + 8, Color.WHITE, "inter", 12f, false) + } + + override fun mouseClick(mouseX: Int, mouseY: Int, button: Int): Boolean { + if (hover.state) { + listening.state = !listening.state + return true + } + + return false + } + + override fun keyTyped(keyCode: Int, scanCode: Int, modifiers: Int) { + if (listening.state) { + if (keyCode == GLFW.GLFW_KEY_ENTER) { + listening.state = false + return + } else if (keyCode == GLFW.GLFW_KEY_BACKSPACE) { + if (inputted.isNotEmpty()) { + inputted = inputted.substring(0, inputted.length - 1) + } + } + } + } + + override fun charTyped(char: Char, modifiers: Int) { + if (listening.state && SharedConstants.isValidChar(char)) { + inputted += char.toString() + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/util/Misc.kt b/src/main/kotlin/com/paragon/util/Misc.kt new file mode 100644 index 0000000..dbb6a4d --- /dev/null +++ b/src/main/kotlin/com/paragon/util/Misc.kt @@ -0,0 +1,222 @@ +package com.paragon.util + +import com.paragon.backend.setting.Colour +import kotlinx.coroutines.* +import net.minecraft.block.* +import net.minecraft.client.MinecraftClient +import net.minecraft.client.gui.hud.InGameHud +import net.minecraft.entity.EntityType +import net.minecraft.text.Style +import net.minecraft.text.Text +import net.minecraft.util.Formatting +import net.minecraft.util.crash.CrashReport +import net.minecraft.util.math.BlockPos +import net.minecraft.util.math.Box +import net.minecraft.util.math.Direction +import net.minecraft.util.math.Vec3d +import java.awt.Color +import java.awt.Rectangle +import kotlin.coroutines.CoroutineContext +import kotlin.properties.ReadWriteProperty +import kotlin.reflect.KProperty + +/** + * @author surge, bush + * @since 19/02/2023 + */ +val mc: MinecraftClient = MinecraftClient.getInstance() + +// they aren't actually unattackable but we dont want to attack them by default +// i love chatgpt +val unattackables = arrayOf( + EntityType.ARMOR_STAND, + EntityType.ITEM_FRAME, + EntityType.LEASH_KNOT, + EntityType.PAINTING, + EntityType.END_CRYSTAL, + EntityType.EXPERIENCE_ORB, + EntityType.FIREWORK_ROCKET, + EntityType.GLOW_ITEM_FRAME, + EntityType.LIGHTNING_BOLT, + EntityType.PHANTOM, + EntityType.PUFFERFISH, + EntityType.SHULKER_BULLET, + EntityType.SMALL_FIREBALL, + EntityType.SNOWBALL, + EntityType.SPECTRAL_ARROW, + EntityType.TRIDENT, + EntityType.WITHER_SKULL, + EntityType.FALLING_BLOCK, + EntityType.EGG, + EntityType.ARROW, + EntityType.BOAT, + EntityType.MINECART, + EntityType.ENDER_PEARL, + EntityType.EYE_OF_ENDER, + EntityType.FIREBALL, + EntityType.TRADER_LLAMA, + EntityType.WANDERING_TRADER, + EntityType.FISHING_BOBBER, + EntityType.DRAGON_FIREBALL, + EntityType.LLAMA_SPIT, + EntityType.SMALL_FIREBALL + + // might be some more idk +) + +fun nullCheck() = mc.player == null || mc.world == null +fun getClientColour(): Colour = Colour(185, 19, 211, 255) + +fun Color.fade(secondary: Color, factor: Double): Color { + return Color( + (this.red + (secondary.red - this.red) * factor.coerceIn(0.0, 1.0)).toInt(), + (this.green + (secondary.green - this.green) * factor.coerceIn(0.0, 1.0)).toInt(), + (this.blue + (secondary.blue - this.blue) * factor.coerceIn(0.0, 1.0)).toInt(), + (this.alpha + (secondary.alpha - this.alpha) * factor.coerceIn(0.0, 1.0)).toInt() + ) +} + +fun BlockPos.getPlaceableSide(): Direction? { + Direction.values().forEach { + val neighbour = this.offset(it) + val opposite = it.opposite + + val state = mc.world!!.getBlockState(neighbour) + + if (state.isAir || state.block.interactable()) { + return@forEach + } + + return opposite + } + + return null +} + +fun Block.interactable(): Boolean = this is CraftingTableBlock + || this is AnvilBlock + || this is ButtonBlock + || this is AbstractPressurePlateBlock + || this is BlockWithEntity + || this is BedBlock + || this is FenceGateBlock + || this is DoorBlock + || this is NoteBlock + || this is TrapdoorBlock + +fun Number.truncate(places: Int): String { + val split = this.toString().split('.') + + var decimals = "" + + if (split.size > 1) { + decimals = '.' + split[1].substring(0, minOf(places + 1, split[1].lastIndex)) + } + + return split[0] + decimals +} + +operator fun Vec3d.component1(): Double = x +operator fun Vec3d.component2(): Double = y +operator fun Vec3d.component3(): Double = z + +fun BlockPos.box(): Box { + return Box(this.x.toDouble(), this.y.toDouble(), this.z.toDouble(), (this.x + 1).toDouble(), (this.y + 1).toDouble(), (this.z + 1).toDouble()) +} + +fun InGameHud.print(content: String, id: Int = hashCode()) { + val chatComponent = Text.literal(Formatting.LIGHT_PURPLE.toString() + "paragon" + Formatting.DARK_GRAY + " \u00BB ") + .setStyle(Style.EMPTY.withColor(Formatting.GRAY)).append(content) + chatHud.addMessage(chatComponent) +} + +fun String.formatCapitalised(): String { + return buildString(this.length) { + var isFirst = true + + this@formatCapitalised.forEach { + if (it == '_') { + isFirst = true + return@forEach + } + + if (isFirst) { + append(' ') + append(it.toString().uppercase()) + isFirst = false + } else { + append(it.toString().lowercase()) + } + } + } +} + +fun Rectangle.offset(x: Int, y: Int): Rectangle { + return Rectangle( + this.x + x, + this.y + y, + this.width, + this.height + ) +} + +fun Rectangle.tempGrow(width: Int, height: Int): Rectangle { + return Rectangle( + this.x, + this.y, + this.width + width, + this.height + height + ) +} + +// FROM 711.CLUB vvv + +private val defaultContext = Dispatchers.Default + CoroutineExceptionHandler { context, throwable -> + mc.setCrashReportSupplier( + CrashReport( + """ + Paragon: An uncaught exception was thrown from a coroutine. This means something + bad happened that would probably make the game unplayable if it wasn't shut down. + + Context: $context + + DM the devs and tell them to fix their shitcode! (also please send them this whole log) + + """.trimIndent(), throwable + ) + ) +} + +object Background : CoroutineScope by CoroutineScope(defaultContext), CoroutineContext by defaultContext + +// BIG +fun backgroundThread(block: suspend CoroutineScope.() -> Unit) = Background.launch(block = block) + +fun CoroutineScope.lazyLaunch(block: suspend CoroutineScope.() -> Unit) = launch( + start = CoroutineStart.LAZY, block = block +) + +/** + * Runs the given block on another thread. If the delegated + * property is called before the thread finishes, the + * calling thread will be paused until it finishes. + * + * @author bush + * @since 2/17/2022 + */ +class AsyncDelegate(block: suspend CoroutineScope.() -> T) : ReadWriteProperty { + private val deferred = Background.async { block() } + private var value: T? = null + + override fun getValue(thisRef: Any?, property: KProperty<*>): T { + // I know this will go every time if the .await()'ed value is null, but I cba to change this + if (value == null) value = runBlocking { deferred.await() } + return value!! + } + + override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) { + this.value = value + } +} + +fun async(block: suspend CoroutineScope.() -> T) = AsyncDelegate(block) \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/util/calculations/MathsUtil.kt b/src/main/kotlin/com/paragon/util/calculations/MathsUtil.kt new file mode 100644 index 0000000..89ccf94 --- /dev/null +++ b/src/main/kotlin/com/paragon/util/calculations/MathsUtil.kt @@ -0,0 +1,23 @@ +package com.paragon.util.calculations + +import net.minecraft.entity.Entity +import net.minecraft.util.math.Vec3d +import java.math.BigDecimal +import java.math.RoundingMode + +/** + * @author surge + * @since 11/02/2023 + */ +object MathsUtil { + + @JvmStatic + fun roundDouble(value: Double, scale: Int): Double { + return BigDecimal(value).setScale(scale, RoundingMode.HALF_DOWN).toDouble() + } + + fun interpolate(entity: Entity, partialTicks: Float): Vec3d { + return Vec3d(entity.lastRenderX, entity.lastRenderY, entity.lastRenderZ).add(Vec3d((entity.x - entity.lastRenderX) * partialTicks, (entity.y - entity.lastRenderY) * partialTicks, (entity.z - entity.lastRenderZ) * partialTicks)) + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/util/calculations/MoveUtil.kt b/src/main/kotlin/com/paragon/util/calculations/MoveUtil.kt new file mode 100644 index 0000000..89d8835 --- /dev/null +++ b/src/main/kotlin/com/paragon/util/calculations/MoveUtil.kt @@ -0,0 +1,123 @@ +package com.paragon.util.calculations + +import com.paragon.util.mc +import net.minecraft.entity.effect.StatusEffects +import net.minecraft.util.math.BlockPos +import kotlin.math.cos +import kotlin.math.sin + + +/** + * @author aesthetical + * @since 02/17/23 + */ +object MoveUtil { + + val NULL_VELOCITY = doubleArrayOf(0.0, 0.0) + + /** + * Checks if the local player is inputting + * @return if they are moving/inputting + */ + @JvmStatic + fun moving(): Boolean { + return mc.player!!.input.movementForward != 0.0f || mc.player!!.input.movementSideways != 0.0f + } + + /** + * Calculates the base NCP speed based on player conditions + * @param potionFactor once the potion (speed/slowness) duration left is less than this, it'll stop applying the potion effect to the speed + * @return the base speed + */ + @JvmStatic + fun getBaseNcpSpeed(potionFactor: Int): Double { + var baseSpeed = 0.2783 + if (mc.player!!.hasStatusEffect(StatusEffects.SPEED)) { + val effect = mc.player!!.getStatusEffect(StatusEffects.SPEED) + if (effect!!.duration > potionFactor) { + baseSpeed *= 1.0 + 0.2 * (effect.amplifier + 1) + } + } + if (mc.player!!.hasStatusEffect(StatusEffects.SLOWNESS)) { + val effect = mc.player!!.getStatusEffect(StatusEffects.SLOWNESS) + if (effect!!.duration > potionFactor) { + baseSpeed /= 1.0 + 0.2 * (effect.amplifier + 1) + } + } + return baseSpeed + } + + /** + * Calculates the jump height needed based on potions + * @param jumpHeight the base jump height + * @return the jump height calculated + */ + @JvmStatic + fun getJumpHeight(jumpHeight: Double): Double { + var jumpHeight = jumpHeight + if (mc.player!!.hasStatusEffect(StatusEffects.JUMP_BOOST)) { + jumpHeight += (mc.player!!.getStatusEffect(StatusEffects.JUMP_BOOST)!!.amplifier + 1.0) * 0.1 + } + return jumpHeight + } + + @JvmStatic + private fun getJumpVelocityMultiplier(): Float { + val f: Float = mc.world!!.getBlockState(mc.player!!.blockPos).block.jumpVelocityMultiplier + val g: Float = mc.world!!.getBlockState(BlockPos(mc.player!!.pos.x, mc.player!!.boundingBox.minY - 0.5000001, mc.player!!.pos.z)).block.jumpVelocityMultiplier + return if (f.toDouble() == 1.0) g else f + } + + @JvmStatic + fun getVanillaJumpVelocity(): Float { + return 0.42f * getJumpVelocityMultiplier() + } + + /** + * Calculates movement strafe + * @param moveSpeed the speed to go + * @return the strafe x and z values + */ + @JvmStatic + fun strafe(moveSpeed: Double): DoubleArray { + if (mc.player == null) { + return NULL_VELOCITY + } + + var forward: Float = mc.player!!.input.movementForward + var strafe: Float = mc.player!!.input.movementSideways + var yaw: Float = mc.player!!.yaw + + if (forward != 0.0f) { + if (strafe > 0.0f) { + if (forward > 0.0f) { + yaw -= 45.0f + } else { + yaw += 45.0f + } + } else if (strafe < 0.0f) { + if (forward > 0.0f) { + yaw += 45.0f + } else { + yaw -= 45.0f + } + } + + strafe = 0.0f + + if (forward > 0.0f) { + forward = 1.0f + } else if (forward < 0.0f) { + forward = -1.0f + } + } + + val sin = -sin(Math.toRadians(yaw.toDouble())) + val cos = cos(Math.toRadians(yaw.toDouble())) + + return doubleArrayOf( + forward * moveSpeed * sin + strafe * moveSpeed * cos, + forward * moveSpeed * cos - strafe * moveSpeed * sin + ) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/util/calculations/Timer.kt b/src/main/kotlin/com/paragon/util/calculations/Timer.kt new file mode 100644 index 0000000..46fe4c1 --- /dev/null +++ b/src/main/kotlin/com/paragon/util/calculations/Timer.kt @@ -0,0 +1,34 @@ +package com.paragon.util.calculations + +import java.util.function.Function + +/** + * @author surge + * @since 11/02/2023 + */ +class Timer { + + private var last: Long + + init { + last = System.currentTimeMillis() + } + + fun elapsed(delay: Double, format: Format = Format.MILLISECONDS): Boolean { + return timeMs() >= format.mutate(delay) + } + + fun reset() { + last = System.currentTimeMillis() + } + + fun timeMs(): Long { + return System.currentTimeMillis() - last + } + + enum class Format(val mutate: (Double) -> Double) { + MILLISECONDS({ it }), + SECONDS({ it * 1000 }) + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/util/calculations/rotation/RotationUtil.kt b/src/main/kotlin/com/paragon/util/calculations/rotation/RotationUtil.kt new file mode 100644 index 0000000..336dc59 --- /dev/null +++ b/src/main/kotlin/com/paragon/util/calculations/rotation/RotationUtil.kt @@ -0,0 +1,91 @@ +package com.paragon.util.calculations.rotation + +import com.paragon.util.mc +import net.minecraft.entity.LivingEntity +import net.minecraft.util.math.BlockPos +import net.minecraft.util.math.Direction +import net.minecraft.util.math.MathHelper +import net.minecraft.util.math.Vec3d +import java.lang.Float.isNaN +import kotlin.math.abs +import kotlin.math.atan2 +import kotlin.math.hypot +import kotlin.math.sqrt + +/** + * @author aesthetical + * @since 02/17/23 + */ +object RotationUtil { + + /** + * Calculates rotations towards an entity + * @param entity the entity + * @param target the place to target the entity at + * @return the rotations to the entity + */ + @JvmStatic + fun calcToEntity(entity: LivingEntity, target: Target?): FloatArray { + val playerPos: Vec3d = mc.player!!.eyePos + val entityPos = entity.pos + + val eyes = when (target) { + Target.HEAD -> entityPos.add(0.0, entity.standingEyeHeight.toDouble(), 0.0) + Target.TORSO -> entityPos.add(0.0, (entity.height * 0.75), 0.0) + Target.LEGS -> entityPos.add(0.0, (entity.height * 0.45), 0.0) + else -> entityPos + } + + val deltaX = eyes.x - playerPos.x + val deltaZ = eyes.z - playerPos.z + + val yaw = -(atan2(deltaX, deltaZ) * (180.0 / Math.PI)).toFloat() + var pitch = (-Math.toDegrees(atan2(eyes.y - playerPos.y, hypot(deltaX, deltaZ)))).toFloat() + + if (pitch > 90.0f) { + pitch = 90.0f + } else if (pitch < -90.0f) { + pitch = -90.0f + } + + return floatArrayOf(yaw, pitch) + } + + /** + * Calculates angles to a block + * @param pos the position + * @param facing the direction of the block position + * @return the rotations to the block at the direction + */ + fun calcAngleToBlock(pos: BlockPos, facing: Direction): FloatArray { + val x: Double = pos.x + 0.5 - mc.player!!.x + facing.offsetX / 2.0 + val y = pos.y + 0.5 + val z: Double = pos.z + 0.5 - mc.player!!.z + facing.offsetZ / 2.0 + + val distance = sqrt(x * x + z * z) + var yaw = (atan2(z, x) * 180.0 / Math.PI - 90.0f).toFloat() + + var pitch = (atan2(mc.player!!.y + mc.player!!.standingEyeHeight - y, distance) * 180.0 / Math.PI).toFloat() + + if (yaw < 0.0f) { + yaw += 360.0f + } + + pitch = MathHelper.clamp(pitch, -90.0f, 90.0f) + + return floatArrayOf(yaw, pitch) + } + + /** + * Checks if a rotation provided is valid + * @param rots the rotations + * @return if they are valid or not + */ + fun isValid(rots: FloatArray?): Boolean { + if (rots == null || rots.size < 2) { + return false + } + + return !isNaN(rots[0]) && !isNaN(rots[1]) && abs(rots[1]) <= 90.0f + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/util/calculations/rotation/Target.kt b/src/main/kotlin/com/paragon/util/calculations/rotation/Target.kt new file mode 100644 index 0000000..cfea445 --- /dev/null +++ b/src/main/kotlin/com/paragon/util/calculations/rotation/Target.kt @@ -0,0 +1,12 @@ +package com.paragon.util.calculations.rotation + +/** + * @author aesthetical + * @since 02/17/23 + */ +enum class Target { + HEAD, + TORSO, + LEGS, + FEET +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/util/inventory/InventoryUtil.kt b/src/main/kotlin/com/paragon/util/inventory/InventoryUtil.kt new file mode 100644 index 0000000..3ed4231 --- /dev/null +++ b/src/main/kotlin/com/paragon/util/inventory/InventoryUtil.kt @@ -0,0 +1,78 @@ +package com.paragon.util.inventory + +import com.paragon.util.mc +import net.minecraft.item.BlockItem +import net.minecraft.item.Item +import net.minecraft.item.ItemStack +import net.minecraft.nbt.NbtCompound +import net.minecraft.util.Hand + +/** + * @author aesthetical + * @since 02/18/23 + */ +object InventoryUtil { + + @JvmField val HOTBAR = 0..8 + + // fuck mojang + fun getStackName(stack: ItemStack): String { + val compound: NbtCompound? = stack.getSubNbt("display") + return if (compound == null || !compound.contains("Name")) "" else compound.getString("Name") + } + + fun hasStackIn(hand: Hand, items: Array): Boolean { + val itemStack = mc.player!!.getStackInHand(hand) + + for (item in items) { + if (!itemStack.isEmpty && itemStack.item == item) { + return true + } + } + + return false + } + + fun hasStackIn(hand: Hand, vararg items: Class<*>): Boolean { + val itemStack = mc.player!!.getStackInHand(hand) + + for (item in items) { + if (!itemStack.isEmpty && item.isInstance(itemStack.item)) { + return true + } + } + + return false + } + + fun holding(item: Item): Boolean { + return mc.player!!.isHolding(item) + } + + fun normalize(slot: Int): Int { + return if (slot < 9) slot + 36 else slot + } + + fun find(range: IntRange, condition: (ItemStack) -> Boolean): Int { + var slot: Int = mc.player!!.inventory.selectedSlot + var count = 0 + + if (condition(mc.player!!.inventory.getStack(slot))) { + count = mc.player!!.inventory.getStack(slot).count + } else { + slot = -1 + } + + for (i in range) { + val stack: ItemStack = mc.player!!.inventory.getStack(i) + + if (condition(stack) && stack.count > count) { + slot = i + count = stack.count + } + } + + return slot + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/util/io/FileUtil.kt b/src/main/kotlin/com/paragon/util/io/FileUtil.kt new file mode 100644 index 0000000..809c26d --- /dev/null +++ b/src/main/kotlin/com/paragon/util/io/FileUtil.kt @@ -0,0 +1,66 @@ +package com.paragon.util.io + +import com.paragon.util.mc +import java.io.File +import java.io.IOException +import java.io.InputStream +import java.nio.file.Files + +/** + * @author aesthetical + * @since 02/20/23 + */ +object FileUtil { + + val PARAGON_PATH = mc.runDirectory.resolve("paragon") + + fun delete(file: File): Boolean { + if (!file.exists()) { + return false + } + + return file.deleteRecursively() + } + + fun write(file: File, content: String) { + val outputStream = Files.newOutputStream(file.toPath()) + try { + outputStream.write(content.toByteArray(), 0, content.length) + } catch (e: IOException) { + e.printStackTrace() + } finally { + try { + outputStream.close() + } catch (e: IOException) { + e.printStackTrace() + } + } + } + + fun read(file: File): String? { + return read(Files.newInputStream(file.toPath())) + } + + fun read(stream: InputStream?): String? { + val builder = StringBuilder() + try { + var i: Int + while (stream!!.read().also { i = it } != -1) { + builder.append(i.toChar()) + } + } catch (e: IOException) { + return null + } finally { + if (stream != null) { + try { + stream.close() + } catch (e: IOException) { + return null + } + } + } + + return builder.toString() + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/util/player/PlayerUtil.kt b/src/main/kotlin/com/paragon/util/player/PlayerUtil.kt new file mode 100644 index 0000000..911fbe0 --- /dev/null +++ b/src/main/kotlin/com/paragon/util/player/PlayerUtil.kt @@ -0,0 +1,16 @@ +package com.paragon.util.player + +import com.paragon.util.mc +import net.minecraft.network.packet.c2s.play.HandSwingC2SPacket +import net.minecraft.util.Hand + +/** + * @author aesthetical + * @since 02/20/23 + */ +object PlayerUtil { + fun silentSwing(hand: Hand) { + mc.player!!.networkHandler.sendPacket(HandSwingC2SPacket(hand)) + mc.player!!.swingHand(Hand.MAIN_HAND, false) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/util/rendering/ColorUtil.kt b/src/main/kotlin/com/paragon/util/rendering/ColorUtil.kt new file mode 100644 index 0000000..74703ed --- /dev/null +++ b/src/main/kotlin/com/paragon/util/rendering/ColorUtil.kt @@ -0,0 +1,27 @@ +package com.paragon.util.rendering + +import java.awt.Color +import kotlin.math.abs + +/** + * @author aesthetical, linustouchtips + * @since 02/17/23 + */ +object ColorUtil { + + /** + * Creates a color gradient with HSB by cycling through the brightness + * (Credit to cosmos) + * @param c the base color + * @param min the minimum brightness value + * @param delay the delay between switching + * @return a color (brightness) gradient + */ + fun gradientRainbow(c: Color, min: Float, delay: Int): Color { + val hsb = Color.RGBtoHSB(c.red, c.green, c.blue, null) + var brightness = abs(((System.currentTimeMillis() % 2000L).toFloat() / 1000.0f + 50.0f / delay.toFloat() * 2.0f) % 2.0f - 1.0f) + brightness = (min + (1.0f - min) * brightness) % 2.0f + return Color.getHSBColor(hsb[0], hsb[1], brightness) + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/util/rendering/NVGWrapper.kt b/src/main/kotlin/com/paragon/util/rendering/NVGWrapper.kt new file mode 100644 index 0000000..5ccc7a2 --- /dev/null +++ b/src/main/kotlin/com/paragon/util/rendering/NVGWrapper.kt @@ -0,0 +1,204 @@ +package com.paragon.util.rendering + +import com.mojang.blaze3d.systems.RenderSystem +import net.minecraft.client.MinecraftClient +import org.lwjgl.BufferUtils +import org.lwjgl.nanovg.NVGColor +import org.lwjgl.nanovg.NanoVG +import org.lwjgl.nanovg.NanoVGGL3 +import org.lwjgl.opengl.GL11.GL_ONE +import org.lwjgl.opengl.GL11.GL_SRC_ALPHA +import org.lwjgl.system.MemoryUtil +import java.awt.Color +import java.awt.Rectangle +import java.nio.ByteBuffer +import java.nio.channels.Channels +import java.util.function.Consumer + +/** + * @author surge + * @since 11/02/2023 + */ +object NVGWrapper { + + private var vg: Long = 0 + + private val fontNames = arrayOf("inter", "axiforma") + + private val fonts = HashMap() + + @JvmStatic + fun initialise() { + vg = NanoVGGL3.nvgCreate(NanoVGGL3.NVG_ANTIALIAS) + + for (font in fontNames) { + try { + val buffer = getResourceBytes("font/$font.ttf", 1024) + NanoVG.nvgCreateFontMem(vg, font, buffer, 0) + fonts[font] = buffer + } catch (exception: Exception) { + exception.printStackTrace() + } + } + } + + private fun beginFrame() { + NanoVG.nvgBeginFrame( + vg, + MinecraftClient.getInstance().window.width.toFloat(), + MinecraftClient.getInstance().window.height.toFloat(), + 1f + ) + } + + private fun endFrame() { + NanoVG.nvgEndFrame(vg) + } + + fun quad(rectangle: Rectangle, colour: Color) { + quad(rectangle.x.toFloat(), rectangle.y.toFloat(), rectangle.width.toFloat(), rectangle.height.toFloat(), colour) + } + + fun quad(x: Float, y: Float, width: Float, height: Float, colour: Color) { + val colourised = convert(colour) + + NanoVG.nvgBeginPath(vg) + + NanoVG.nvgRect(vg, x, y, width, height) + NanoVG.nvgFillColor(vg, colourised) + NanoVG.nvgFill(vg) + + NanoVG.nvgClosePath(vg) + + colourised.free() + } + + fun roundedQuad(x: Float, y: Float, width: Float, height: Float, radius: Float, colour: Color) { + roundedQuad(x, y, width, height, radius, radius, radius, radius, colour) + } + + fun roundedQuad(x: Float, y: Float, width: Float, height: Float, tl: Float, tr: Float, bl: Float, br: Float, colour: Color) { + val colourised = convert(colour) + + NanoVG.nvgBeginPath(vg) + + NanoVG.nvgRoundedRectVarying(vg, x, y, width, height, tl, tr, bl, br) + NanoVG.nvgFillColor(vg, colourised) + NanoVG.nvgFill(vg) + + NanoVG.nvgClosePath(vg) + + colourised.free() + } + + fun text(text: String, x: Float, y: Float, colour: Color = Color.WHITE, face: String = "inter", size: Float = 16f, shadow: Boolean = false, alignment: Int = NanoVG.NVG_ALIGN_LEFT or NanoVG.NVG_ALIGN_TOP) { + if (shadow) { + text(text, x + 1, y + 1, Color(0, 0, 0, 150), face, size, false) + } + + val colourised = convert(colour) + + NanoVG.nvgBeginPath(vg) + + NanoVG.nvgFillColor(vg, colourised) + NanoVG.nvgFontFace(vg, face) + NanoVG.nvgFontSize(vg, size) + NanoVG.nvgTextAlign(vg, alignment) + NanoVG.nvgText(vg, x, y, text) + + NanoVG.nvgClosePath(vg) + + colourised.free() + } + + fun textWidth(text: String, face: String = "inter", size: Float = 20f): Float { + val bounds = FloatArray(4) + + NanoVG.nvgSave(vg) + + NanoVG.nvgFontFace(vg, face) + NanoVG.nvgFontSize(vg, size) + NanoVG.nvgTextBounds(vg, 0f, 0f, text, bounds) + + NanoVG.nvgRestore(vg) + + return bounds[2] + } + + fun textHeight(face: String, size: Float): Float { + val ascender = FloatArray(1) + val descender = FloatArray(1) + val height = FloatArray(1) + + NanoVG.nvgFontFace(vg, face) + NanoVG.nvgFontSize(vg, size) + NanoVG.nvgTextMetrics(vg, ascender, descender, height) + + return height[0] + } + + fun scissor(x: Float, y: Float, width: Float, height: Float, block: Runnable) { + NanoVG.nvgSave(vg) + NanoVG.nvgIntersectScissor(vg, x, y, width, height) + block.run() + NanoVG.nvgRestore(vg) + } + + fun resetScissor() { + NanoVG.nvgResetScissor(vg) + } + + fun terminate() { + NanoVGGL3.nvgDelete(vg) + } + + fun scope(block: Consumer) { + RenderSystem.enableBlend() + RenderSystem.blendFunc(GL_SRC_ALPHA, GL_ONE) + + beginFrame() + block.accept(this) + endFrame() + + RenderSystem.disableBlend() + } + + private fun convert(colour: Color): NVGColor { + return NVGColor.calloc() + .r(colour.red / 255f) + .g(colour.green / 255f) + .b(colour.blue / 255f) + .a(colour.alpha / 255f) + } + + private fun resizeBuffer(buffer: ByteBuffer, newCapacity: Int): ByteBuffer { + val newBuffer = BufferUtils.createByteBuffer(newCapacity) + buffer.flip() + newBuffer.put(buffer) + return newBuffer + } + + fun getResourceBytes(resource: String, bufferSize: Int): ByteBuffer { + var buffer: ByteBuffer + val source = javaClass.getResourceAsStream("/assets/paragon/$resource") + val rbc = Channels.newChannel(source) + + buffer = BufferUtils.createByteBuffer(bufferSize) + + while (true) { + val bytes = rbc.read(buffer) + + if (bytes == -1) { + break + } + + if (buffer.remaining() == 0) { + buffer = resizeBuffer(buffer, buffer.capacity() * 3 / 2) // 50% + } + } + + buffer.flip() + return MemoryUtil.memSlice(buffer) + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/util/rendering/Renderer.kt b/src/main/kotlin/com/paragon/util/rendering/Renderer.kt new file mode 100644 index 0000000..6f586fd --- /dev/null +++ b/src/main/kotlin/com/paragon/util/rendering/Renderer.kt @@ -0,0 +1,251 @@ +package com.paragon.util.rendering + +import com.mojang.blaze3d.systems.RenderSystem +import com.paragon.backend.setting.Colour +import com.paragon.util.mc +import net.minecraft.client.render.* +import net.minecraft.client.util.math.MatrixStack +import net.minecraft.util.math.Box +import net.minecraft.util.math.MathHelper +import net.minecraft.util.math.Vec3d +import org.joml.Matrix4f +import org.lwjgl.opengl.GL11.* +import java.util.function.Consumer +import kotlin.math.PI +import kotlin.math.cos +import kotlin.math.sin + + +/** + * @author surge + * @since 12/02/2023 + */ +object Renderer { + + private val actions: MutableList = ArrayList() + + fun submit(action: Action): Renderer { + actions.add(action) + + return this + } + + fun submit(action: () -> Unit): Renderer { + actions.add(object : Action() { + override fun draw() { + action() + } + }) + + return this + } + + fun optional(submit: Boolean, action: Action): Renderer { + if (submit) { + submit(action) + } + + return this + } + + @JvmStatic + fun drawAndClear() { + actions.forEach(Consumer { obj: Action -> obj.draw() }) + actions.clear() + } + + fun line(matrices: MatrixStack, start: Vec3d, end: Vec3d, lineWidth: Float, colour: Colour, secondary: Colour = colour): Action { + return object : Action() { + override fun draw() { + lineImplementation(matrices, start, end, lineWidth, colour, secondary) + } + } + } + + fun box(matrices: MatrixStack, bb: Box, colour: Colour, mode: DrawMode) { + submit { + boxImplementation(matrices, bb, colour, mode) + } + } + + fun polygon(matrices: MatrixStack, center: Vec3d, radius: Double, colour: Colour, mode: DrawMode, sides: Int, outsideOffset: Double = 0.0) { + submit { + polygonImplementation(matrices, center, radius, colour, mode, sides, outsideOffset) + } + } + + private fun filledBBVertices(matrix: Matrix4f, builder: BufferBuilder, box: Box, colour: Colour) { + builder.vertex(matrix, box.minX.toFloat(), box.minY.toFloat(), box.minZ.toFloat()).color(colour.red / 255f, colour.green / 255f, colour.blue / 255f, colour.alpha / 255f).next() + builder.vertex(matrix, box.maxX.toFloat(), box.minY.toFloat(), box.minZ.toFloat()).color(colour.red / 255f, colour.green / 255f, colour.blue / 255f, colour.alpha / 255f).next() + builder.vertex(matrix, box.maxX.toFloat(), box.minY.toFloat(), box.maxZ.toFloat()).color(colour.red / 255f, colour.green / 255f, colour.blue / 255f, colour.alpha / 255f).next() + builder.vertex(matrix, box.minX.toFloat(), box.minY.toFloat(), box.maxZ.toFloat()).color(colour.red / 255f, colour.green / 255f, colour.blue / 255f, colour.alpha / 255f).next() + builder.vertex(matrix, box.minX.toFloat(), box.minY.toFloat(), box.minZ.toFloat()).color(colour.red / 255f, colour.green / 255f, colour.blue / 255f, colour.alpha / 255f).next() + builder.vertex(matrix, box.minX.toFloat(), box.minY.toFloat(), box.maxZ.toFloat()).color(colour.red / 255f, colour.green / 255f, colour.blue / 255f, colour.alpha / 255f).next() + builder.vertex(matrix, box.minX.toFloat(), box.maxY.toFloat(), box.maxZ.toFloat()).color(colour.red / 255f, colour.green / 255f, colour.blue / 255f, colour.alpha / 255f).next() + builder.vertex(matrix, box.minX.toFloat(), box.maxY.toFloat(), box.minZ.toFloat()).color(colour.red / 255f, colour.green / 255f, colour.blue / 255f, colour.alpha / 255f).next() + builder.vertex(matrix, box.maxX.toFloat(), box.minY.toFloat(), box.maxZ.toFloat()).color(colour.red / 255f, colour.green / 255f, colour.blue / 255f, colour.alpha / 255f).next() + builder.vertex(matrix, box.maxX.toFloat(), box.minY.toFloat(), box.minZ.toFloat()).color(colour.red / 255f, colour.green / 255f, colour.blue / 255f, colour.alpha / 255f).next() + builder.vertex(matrix, box.maxX.toFloat(), box.maxY.toFloat(), box.minZ.toFloat()).color(colour.red / 255f, colour.green / 255f, colour.blue / 255f, colour.alpha / 255f).next() + builder.vertex(matrix, box.maxX.toFloat(), box.maxY.toFloat(), box.maxZ.toFloat()).color(colour.red / 255f, colour.green / 255f, colour.blue / 255f, colour.alpha / 255f).next() + builder.vertex(matrix, box.maxX.toFloat(), box.minY.toFloat(), box.minZ.toFloat()).color(colour.red / 255f, colour.green / 255f, colour.blue / 255f, colour.alpha / 255f).next() + builder.vertex(matrix, box.minX.toFloat(), box.minY.toFloat(), box.minZ.toFloat()).color(colour.red / 255f, colour.green / 255f, colour.blue / 255f, colour.alpha / 255f).next() + builder.vertex(matrix, box.minX.toFloat(), box.maxY.toFloat(), box.minZ.toFloat()).color(colour.red / 255f, colour.green / 255f, colour.blue / 255f, colour.alpha / 255f).next() + builder.vertex(matrix, box.maxX.toFloat(), box.maxY.toFloat(), box.minZ.toFloat()).color(colour.red / 255f, colour.green / 255f, colour.blue / 255f, colour.alpha / 255f).next() + builder.vertex(matrix, box.minX.toFloat(), box.minY.toFloat(), box.maxZ.toFloat()).color(colour.red / 255f, colour.green / 255f, colour.blue / 255f, colour.alpha / 255f).next() + builder.vertex(matrix, box.maxX.toFloat(), box.minY.toFloat(), box.maxZ.toFloat()).color(colour.red / 255f, colour.green / 255f, colour.blue / 255f, colour.alpha / 255f).next() + builder.vertex(matrix, box.maxX.toFloat(), box.maxY.toFloat(), box.maxZ.toFloat()).color(colour.red / 255f, colour.green / 255f, colour.blue / 255f, colour.alpha / 255f).next() + builder.vertex(matrix, box.minX.toFloat(), box.maxY.toFloat(), box.maxZ.toFloat()).color(colour.red / 255f, colour.green / 255f, colour.blue / 255f, colour.alpha / 255f).next() + builder.vertex(matrix, box.minX.toFloat(), box.maxY.toFloat(), box.maxZ.toFloat()).color(colour.red / 255f, colour.green / 255f, colour.blue / 255f, colour.alpha / 255f).next() + builder.vertex(matrix, box.maxX.toFloat(), box.maxY.toFloat(), box.maxZ.toFloat()).color(colour.red / 255f, colour.green / 255f, colour.blue / 255f, colour.alpha / 255f).next() + builder.vertex(matrix, box.maxX.toFloat(), box.maxY.toFloat(), box.minZ.toFloat()).color(colour.red / 255f, colour.green / 255f, colour.blue / 255f, colour.alpha / 255f).next() + builder.vertex(matrix, box.minX.toFloat(), box.maxY.toFloat(), box.minZ.toFloat()).color(colour.red / 255f, colour.green / 255f, colour.blue / 255f, colour.alpha / 255f).next() + } + + private fun outlineBBVertices(matrix: Matrix4f, builder: BufferBuilder, box: Box, colour: Colour) { + // the most comedic rendering + + builder.vertex(matrix, box.minX.toFloat(), box.minY.toFloat(), box.minZ.toFloat()).color(colour.rgb).next() + builder.vertex(matrix, box.maxX.toFloat(), box.minY.toFloat(), box.minZ.toFloat()).color(colour.rgb).next() + builder.vertex(matrix, box.maxX.toFloat(), box.minY.toFloat(), box.maxZ.toFloat()).color(colour.rgb).next() + builder.vertex(matrix, box.minX.toFloat(), box.minY.toFloat(), box.maxZ.toFloat()).color(colour.rgb).next() + builder.vertex(matrix, box.minX.toFloat(), box.minY.toFloat(), box.minZ.toFloat()).color(colour.rgb).next() + + builder.vertex(matrix, box.minX.toFloat(), box.maxY.toFloat(), box.minZ.toFloat()).color(colour.rgb).next() + builder.vertex(matrix, box.maxX.toFloat(), box.maxY.toFloat(), box.minZ.toFloat()).color(colour.rgb).next() + + builder.vertex(matrix, box.maxX.toFloat(), box.minY.toFloat(), box.minZ.toFloat()).color(colour.rgb).next() + builder.vertex(matrix, box.maxX.toFloat(), box.minY.toFloat(), box.minZ.toFloat()).color(0).next() + builder.vertex(matrix, box.maxX.toFloat(), box.minY.toFloat(), box.maxZ.toFloat()).color(0).next() + builder.vertex(matrix, box.maxX.toFloat(), box.minY.toFloat(), box.maxZ.toFloat()).color(colour.rgb).next() + builder.vertex(matrix, box.maxX.toFloat(), box.maxY.toFloat(), box.maxZ.toFloat()).color(colour.rgb).next() + + builder.vertex(matrix, box.maxX.toFloat(), box.maxY.toFloat(), box.minZ.toFloat()).color(colour.rgb).next() + builder.vertex(matrix, box.maxX.toFloat(), box.maxY.toFloat(), box.minZ.toFloat()).color(0).next() + builder.vertex(matrix, box.maxX.toFloat(), box.maxY.toFloat(), box.maxZ.toFloat()).color(0).next() + builder.vertex(matrix, box.maxX.toFloat(), box.maxY.toFloat(), box.maxZ.toFloat()).color(colour.rgb).next() + builder.vertex(matrix, box.minX.toFloat(), box.maxY.toFloat(), box.maxZ.toFloat()).color(colour.rgb).next() + + builder.vertex(matrix, box.minX.toFloat(), box.minY.toFloat(), box.maxZ.toFloat()).color(colour.rgb).next() + builder.vertex(matrix, box.minX.toFloat(), box.minY.toFloat(), box.maxZ.toFloat()).color(0).next() + builder.vertex(matrix, box.minX.toFloat(), box.maxY.toFloat(), box.maxZ.toFloat()).color(0).next() + builder.vertex(matrix, box.minX.toFloat(), box.maxY.toFloat(), box.maxZ.toFloat()).color(colour.rgb).next() + builder.vertex(matrix, box.minX.toFloat(), box.maxY.toFloat(), box.minZ.toFloat()).color(colour.rgb).next() + } + + private fun lineImplementation(matrices: MatrixStack, start: Vec3d, end: Vec3d, lineWidth: Float, colour: Colour, secondary: Colour) { + val camera: Vec3d = mc.gameRenderer.camera.pos + + val vecStart: Vec3d = start.subtract(camera) + val vecEnd: Vec3d = end.subtract(camera) + + val matrix: Matrix4f = matrices.peek().positionMatrix + val builder: BufferBuilder = Tessellator.getInstance().buffer + + RenderSystem.setShader { GameRenderer.getPositionColorProgram() } + RenderSystem.lineWidth(lineWidth) + RenderSystem.enableBlend() + RenderSystem.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) + + builder.begin(VertexFormat.DrawMode.DEBUG_LINES, VertexFormats.POSITION_COLOR) + + builder.vertex(matrix, vecStart.x.toFloat(), vecStart.y.toFloat(), vecStart.z.toFloat()).color(colour.rgb).next() + builder.vertex(matrix, vecEnd.x.toFloat(), vecEnd.y.toFloat(), vecEnd.z.toFloat()).color(secondary.rgb).next() + + BufferRenderer.drawWithGlobalProgram(builder.end()) + } + + private fun boxImplementation(matrices: MatrixStack, bb: Box, colour: Colour, mode: DrawMode) { + val matrix: Matrix4f = matrices.peek().positionMatrix + val builder: BufferBuilder = Tessellator.getInstance().buffer + val cameraPos = mc.gameRenderer.camera.pos + val box = bb.offset(-cameraPos.x, -cameraPos.y, -cameraPos.z) + + RenderSystem.depthFunc(GL_ALWAYS) + RenderSystem.enableBlend() + RenderSystem.setShader { GameRenderer.getPositionColorProgram() } + + builder.begin(mode.mode, VertexFormats.POSITION_COLOR) + + mode.vertices(matrix, builder, box, colour) + + BufferRenderer.drawWithGlobalProgram(builder.end()) + + RenderSystem.disableBlend() + RenderSystem.depthFunc(GL_LEQUAL) + } + + private fun polygonImplementation(matrices: MatrixStack, center: Vec3d, radius: Double, colour: Colour, mode: DrawMode, sides: Int, outsideOffset: Double = 0.0) { + val matrix: Matrix4f = matrices.peek().positionMatrix + val builder: BufferBuilder = Tessellator.getInstance().buffer + val cameraPos = mc.gameRenderer.camera.pos + val center = Vec3d(center.x - cameraPos.x, center.y - cameraPos.y, center.z - cameraPos.z) + + RenderSystem.setShader { GameRenderer.getPositionColorProgram() } + + RenderSystem.disableCull() + RenderSystem.depthFunc(GL_ALWAYS) + RenderSystem.enableBlend() + + builder.begin(mode.mode, VertexFormats.POSITION_COLOR) + + val angleIncrement = 2.0 * PI / sides + var angle = 0.0 + + /* for (i in 0 until sides) { + builder.vertex(matrix, (center.x + radius * cos(angle)).toFloat(), center.y.toFloat(), (center.z + radius * sin(angle)).toFloat()).color(colour.rgb).next() + + if (mode == DrawMode.FILL) { + builder.vertex(matrix, center.x.toFloat(), center.y.toFloat(), center.z.toFloat()).color(colour.rgb).next() + builder.vertex(matrix, (center.x + radius * cos(angle + angleIncrement)).toFloat(), center.y.toFloat(), (center.z + radius * sin(angle + angleIncrement)).toFloat()).color(colour.rgb).next() + builder.vertex(matrix, (center.x + radius * cos(angle)).toFloat(), center.y.toFloat(), (center.z + radius * sin(angle)).toFloat()).color(colour.rgb).next() + } + + angle += angleIncrement + } */ + + for (i in 0 until sides) { + builder.vertex(matrix, (center.x + radius * cos(angle)).toFloat(), center.y.toFloat() + outsideOffset.toFloat(), (center.z + radius * sin(angle)).toFloat()).color(colour.rgb).next() + + if (mode == DrawMode.FILL) { + builder.vertex(matrix, center.x.toFloat(), center.y.toFloat(), center.z.toFloat()).color(colour.rgb).next() + builder.vertex(matrix, (center.x + radius * cos(angle + angleIncrement)).toFloat(), center.y.toFloat() + outsideOffset.toFloat(), (center.z + radius * sin(angle + angleIncrement)).toFloat()).color(colour.rgb).next() + builder.vertex(matrix, (center.x + radius * cos(angle)).toFloat(), center.y.toFloat() + outsideOffset.toFloat(), (center.z + radius * sin(angle)).toFloat()).color(colour.rgb).next() + } + + angle += angleIncrement + } + + // Add final vertex to close the polygon + builder.vertex(matrix, (center.x + radius).toFloat(), center.y.toFloat() + outsideOffset.toFloat(), center.z.toFloat()).color(colour.rgb).next() + + BufferRenderer.drawWithGlobalProgram(builder.end()) + + RenderSystem.disableBlend() + RenderSystem.depthFunc(GL_LEQUAL) + RenderSystem.enableCull() + } + + fun crosshair(): Vec3d { + val camera: Camera = mc.gameRenderer.camera + + val yawRadius = Math.toRadians(-camera.yaw.toDouble()).toFloat() + val pitchRadius = Math.toRadians(-camera.pitch.toDouble()).toFloat() + val pitch: Float = -MathHelper.cos(pitchRadius) + + return Vec3d( + (MathHelper.sin((yawRadius - Math.PI).toFloat()) * pitch).toDouble(), + MathHelper.sin(pitchRadius).toDouble(), + (MathHelper.cos((yawRadius - Math.PI).toFloat()) * pitch).toDouble() + ).add(camera.pos) + } + + abstract class Action { + abstract fun draw() + } + + enum class DrawMode(val mode: VertexFormat.DrawMode, val vertices: (Matrix4f, BufferBuilder, Box, Colour) -> Unit) { + FILL(VertexFormat.DrawMode.QUADS, { matrix, builder, box, colour -> filledBBVertices(matrix, builder, box, colour) }), + LINES(VertexFormat.DrawMode.DEBUG_LINE_STRIP, { matrix, builder, box, colour -> outlineBBVertices(matrix, builder, box, colour) }) + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/paragon/util/rendering/ui/Element.kt b/src/main/kotlin/com/paragon/util/rendering/ui/Element.kt new file mode 100644 index 0000000..d8e56aa --- /dev/null +++ b/src/main/kotlin/com/paragon/util/rendering/ui/Element.kt @@ -0,0 +1,50 @@ +package com.paragon.util.rendering.ui + +import com.paragon.backend.setting.Colour +import com.paragon.util.rendering.NVGWrapper + +/** + * @author surge + * @since 11/02/2023 + */ +abstract class Element(var x: Float = 0.0f, var y: Float = 0.0f, var width: Float = 0.0f, var height: Float = 0.0f) { + + abstract fun render(nvg: NVGWrapper, mouseX: Int, mouseY: Int, mouseDelta: Float) + + open fun mouseClick(mouseX: Int, mouseY: Int, button: Int): Boolean { + return false + } + + open fun mouseRelease(mouseX: Int, mouseY: Int, button: Int): Boolean { + return false + } + + open fun scroll(mouseX: Int, mouseY: Int, amount: Double): Boolean { + return false + } + + open fun keyTyped(keyCode: Int, scanCode: Int, modifiers: Int) {} + open fun charTyped(char: Char, modifiers: Int) {} + + open fun getOffset(): Float { + return height + } + + fun position(x: Float, y: Float): Element { + this.x = x + this.y = y + return this + } + + fun hovered(mouseX: Int, mouseY: Int): Boolean { + return mouseX >= x && mouseX <= x + width && mouseY >= y && mouseY <= y + height + } + + fun hovered(mouseX: Int, mouseY: Int, w: Float = this.width, h: Float = this.height): Boolean { + return mouseX >= x && mouseX <= x + w && mouseY >= y && mouseY <= y + h + } + + protected val background = Colour(23, 23, 23, 255) + protected val hovered = Colour(26, 26, 26, 255) + +} \ No newline at end of file diff --git a/src/main/resources/assets/paragon/font/axiforma.ttf b/src/main/resources/assets/paragon/font/axiforma.ttf new file mode 100644 index 0000000..33267a1 Binary files /dev/null and b/src/main/resources/assets/paragon/font/axiforma.ttf differ diff --git a/src/main/resources/assets/paragon/font/inter.ttf b/src/main/resources/assets/paragon/font/inter.ttf new file mode 100644 index 0000000..8d4eebf Binary files /dev/null and b/src/main/resources/assets/paragon/font/inter.ttf differ diff --git a/src/main/resources/assets/paragon/textures/icon.png b/src/main/resources/assets/paragon/textures/icon.png new file mode 100644 index 0000000..ea0795d Binary files /dev/null and b/src/main/resources/assets/paragon/textures/icon.png differ diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json new file mode 100644 index 0000000..3c17a5c --- /dev/null +++ b/src/main/resources/fabric.mod.json @@ -0,0 +1,37 @@ +{ + "schemaVersion": 1, + "id": "paragon", + "version": "${version}", + + "name": "Paragon", + "description": "utility mod for minecraft 1.19", + "authors": [ + "surge", + "aesthetical", + "kassuk" + ], + "contact": { + "homepage": "https://fabricmc.net/", + "sources": "https://github.com/FabricMC/fabric-example-mod" + }, + + "license": "CC0-1.0", + "icon": "assets/paragon/textures/icon.png", + "accessWidener": "paragon.accesswidener", + + "environment": "client", + "entrypoints": { + "client": [ + "com.paragon.Paragon" + ] + }, + "mixins": [ + "paragon.mixins.json" + ], + + "depends": { + "fabricloader": ">=0.14.11", + "minecraft": "~1.19.3", + "java": ">=17" + } +} diff --git a/src/main/resources/paragon.accesswidener b/src/main/resources/paragon.accesswidener new file mode 100644 index 0000000..64fecde --- /dev/null +++ b/src/main/resources/paragon.accesswidener @@ -0,0 +1,6 @@ +accessWidener v1 named + +# PlayerInteractEntityC2SPacket I LOVE MOJANG!!!!! +accessible class net/minecraft/network/packet/c2s/play/PlayerInteractEntityC2SPacket$InteractType +accessible class net/minecraft/network/packet/c2s/play/PlayerInteractEntityC2SPacket$InteractAtHandler +accessible class net/minecraft/network/packet/c2s/play/PlayerInteractEntityC2SPacket$InteractTypeHandler \ No newline at end of file diff --git a/src/main/resources/paragon.mixins.json b/src/main/resources/paragon.mixins.json new file mode 100644 index 0000000..df95a53 --- /dev/null +++ b/src/main/resources/paragon.mixins.json @@ -0,0 +1,36 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "com.paragon.mixin.mixins", + "compatibilityLevel": "JAVA_17", + "client": [ + "MinecraftClientMixin", + "entity.MixinClientPlayerEntity", + "entity.MixinLivingEntity", + "input.MixinClientPlayerInteractionManager", + "input.MixinItemUsageContext", + "input.io.KeyboardMixin", + "input.io.MouseMixin", + "item.TridentItemMixin", + "math.MixinVec3d", + "net.MixinClientConnection", + "net.packet.c2s.IPlayerMoveC2SPacket", + "net.packet.c2s.MixinPlayerInteractEntityC2SPacket", + "net.packet.s2c.IEntityVelocityUpdateS2CPacket", + "net.packet.s2c.IExplosionS2CPacket", + "render.GameRendererMixin", + "render.MixinCamera", + "render.MixinLightmapTextureManager", + "render.MixinRenderTickCounter", + "render.WindowMixin", + "render.entity.MixinLivingEntityRenderer", + "render.entity.MixinPlayerEntityRenderer", + "render.gui.MixinInGameHud", + "render.gui.TitleScreenMixin", + "world.block.MixinAbstractBlockState", + "world.block.MixinBlock" + ], + "injectors": { + "defaultRequire": 1 + } +}