diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..37c5cf1 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2023 3arthqu4ke, alpha432, cattyn + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/README.md b/README.md index 78e0c04..d3d9c92 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,14 @@ -# fros.cc -A utility client for Minecraft 1.21.11. \ No newline at end of file +
+ +# oyvey-ported +Kosher client base ported to modern Minecraft by [@cattyngmd](https://github.com/cattyngmd) + + + +# Why +![](https://i.imgur.com/VYjIphG.png) + +# What +Add stuff to it like you would add stuff to your 1.12.2 OyVey paste + +
diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000..17301c7 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,111 @@ +import java.nio.file.Paths +import java.text.SimpleDateFormat +import java.util.Date + +plugins { + id("fabric-loom") + id("com.github.gmazzo.buildconfig") + java +} + +val mod_version: String by project +val maven_group: String by project +val mod_name: String by project +val archives_base_name: String by project +val minecraft_version: String by project +val loader_version: String by project +val fabric_version: String by project +val catformat_version: String by project + +val USING_GIT = Paths.get(rootDir.absolutePath).resolve(".git").toFile().exists() +val GIT_HASH = execute("git rev-parse --short HEAD") + +version = mod_version +group = maven_group + +buildConfig { + packageName("$group.util") + useJavaOutput() + generateAtSync.set(true) + + val typeString = String::class.java + val typeBool = Boolean::class.java + + val buildTime = SimpleDateFormat("MM/dd/yyyy HH:mm").format(Date()) + + buildConfigField(typeString, "NAME", mod_name) + buildConfigField(typeString, "GROUP", maven_group) + buildConfigField(typeString, "VERSION", mod_version) + buildConfigField(typeString, "BUILD_TIME", buildTime) + buildConfigField(typeBool, "USING_GIT", USING_GIT) + buildConfigField(typeString, "HASH", GIT_HASH) + buildConfigField(typeString, "BRANCH", execute("git branch --show-current")) +} + +sourceSets.main { + java.srcDirs("build/gen/buildconfig/src/main") +} + +base { + archivesName.set("$archives_base_name-$GIT_HASH") +} + +repositories { + mavenCentral() + maven { url = uri("https://jitpack.io") } +} + +loom { + accessWidenerPath.set(file("src/main/resources/oyvey.accesswidener")) +} + +dependencies { + minecraft("com.mojang:minecraft:$minecraft_version") + mappings(loom.officialMojangMappings()) + modImplementation("net.fabricmc:fabric-loader:$loader_version") + modImplementation("net.fabricmc.fabric-api:fabric-api:$fabric_version") + + include(implementation("com.github.cattyngmd.catformat:catformat-core:$catformat_version")!!) + include(modImplementation("com.github.cattyngmd.catformat:catformat-fabric:$catformat_version")!!) +} + +tasks.processResources { + inputs.property("version", version) + inputs.property("minecraft_version", minecraft_version) + inputs.property("loader_version", loader_version) + filteringCharset = "UTF-8" + + filesMatching("fabric.mod.json") { + expand( + "version" to version, + "minecraft_version" to minecraft_version, + "loader_version" to loader_version + ) + } +} + +tasks.withType().configureEach { + options.release = 21 + dependsOn("generateBuildConfig") +} + +java { + withSourcesJar() + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 +} + +tasks.named("sourcesJar") { + dependsOn("generateBuildConfig") +} + +tasks.jar { + from("LICENSE") { + rename { "${it}_$archives_base_name" } + } +} + +fun execute(cmd: String): String = providers.exec { + commandLine(cmd.split(" ")) + isIgnoreExitValue = true +}.standardOutput.asText.getOrElse("nogit").trim().replace("\n", "") diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..e7b8197 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,17 @@ +# Done to increase the memory available to gradle. +org.gradle.jvmargs=-Xmx1G +# Fabric Properties +# check these on https://modmuss50.me/fabric.html +minecraft_version=1.21.11 +loader_version=0.18.4 +loom_version=1.14-SNAPSHOT +# Mod Properties +maven_group=me.alpha432.oyvey +mod_version=1.0.0 +mod_name=OyVey +archives_base_name=oyvey +# Dependencies +# check this on https://modmuss50.me/fabric.html +fabric_version=0.141.1+1.21.11 +catformat_version=2.1.0 +buildconfig_version=5.3.5 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..c1962a7 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..bad7c24 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.0-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100644 index 0000000..6146088 --- /dev/null +++ b/gradlew @@ -0,0 +1,245 @@ +#!/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 + +# 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 + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, 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" "$@" \ No newline at end of file diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..2578005 --- /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 \ No newline at end of file diff --git a/images/ui.png b/images/ui.png new file mode 100644 index 0000000..a26d337 Binary files /dev/null and b/images/ui.png differ diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 0000000..854d175 --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,17 @@ +pluginManagement { + repositories { + maven { + name = "Fabric" + url = uri("https://maven.fabricmc.net/") + } + gradlePluginPortal() + } + + plugins { + id("fabric-loom") version providers.gradleProperty("loom_version") + id("com.github.gmazzo.buildconfig") version providers.gradleProperty("buildconfig_version") + java + } +} + +rootProject.name = "oyvey-ported" \ No newline at end of file diff --git a/src/main/java/me/alpha432/oyvey/OyVey.java b/src/main/java/me/alpha432/oyvey/OyVey.java new file mode 100644 index 0000000..f9a1154 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/OyVey.java @@ -0,0 +1,66 @@ +package me.alpha432.oyvey; + +import me.alpha432.oyvey.manager.*; +import me.alpha432.oyvey.util.BuildConfig; +import me.alpha432.oyvey.util.TextUtil; +import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.api.ModInitializer; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +public class OyVey implements ModInitializer, ClientModInitializer { + public static float TIMER = 1f; + + public static final Logger LOGGER = LogManager.getLogger("OyVey"); + public static ServerManager serverManager; + public static ColorManager colorManager; + public static RotationManager rotationManager; + public static PositionManager positionManager; + public static HoleManager holeManager; + public static EventManager eventManager; + public static SpeedManager speedManager; + public static CommandManager commandManager; + public static FriendManager friendManager; + public static ModuleManager moduleManager; + public static ConfigManager configManager; + + @Override + public void onInitialize() { + LOGGER.info("Pre-initializing {} v{}", + BuildConfig.NAME, BuildConfig.VERSION); + configManager = new ConfigManager(); + eventManager = new EventManager(); + serverManager = new ServerManager(); + rotationManager = new RotationManager(); + positionManager = new PositionManager(); + friendManager = new FriendManager(); + colorManager = new ColorManager(); + commandManager = new CommandManager(); + moduleManager = new ModuleManager(); + speedManager = new SpeedManager(); + holeManager = new HoleManager(); + + TextUtil.init(); + } + + @Override + public void onInitializeClient() { + LOGGER.info("Initializing {}", BuildConfig.NAME); + + long startTime = System.nanoTime(); + + eventManager.init(); + commandManager.init(); + moduleManager.init(); + friendManager.init(); + + configManager.load(); + colorManager.init(); + Runtime.getRuntime().addShutdownHook(new Thread(() -> configManager.save())); + + long endTime = System.nanoTime(); + + LOGGER.info("Initialized {} in {}ms", + BuildConfig.NAME, (endTime - startTime) / 1000000.0); + } +} diff --git a/src/main/java/me/alpha432/oyvey/ducks/render/IChatComponent.java b/src/main/java/me/alpha432/oyvey/ducks/render/IChatComponent.java new file mode 100644 index 0000000..282475e --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/ducks/render/IChatComponent.java @@ -0,0 +1,9 @@ +package me.alpha432.oyvey.ducks.render; + +import net.minecraft.client.GuiMessage; +import net.minecraft.network.chat.MessageSignature; + +public interface IChatComponent { + void oyvey$addMessage(GuiMessage message); + void oyvey$removeMessage(MessageSignature signature); +} \ No newline at end of file diff --git a/src/main/java/me/alpha432/oyvey/event/Event.java b/src/main/java/me/alpha432/oyvey/event/Event.java new file mode 100644 index 0000000..68fac19 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/event/Event.java @@ -0,0 +1,13 @@ +package me.alpha432.oyvey.event; + +public class Event { + private boolean cancelled; + + public boolean isCancelled() { + return cancelled; + } + + public void cancel() { + cancelled = true; + } +} diff --git a/src/main/java/me/alpha432/oyvey/event/Stage.java b/src/main/java/me/alpha432/oyvey/event/Stage.java new file mode 100644 index 0000000..861daf8 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/event/Stage.java @@ -0,0 +1,6 @@ +package me.alpha432.oyvey.event; + +public enum Stage { + PRE, + POST +} diff --git a/src/main/java/me/alpha432/oyvey/event/impl/ClientEvent.java b/src/main/java/me/alpha432/oyvey/event/impl/ClientEvent.java new file mode 100644 index 0000000..6722b27 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/event/impl/ClientEvent.java @@ -0,0 +1,38 @@ +package me.alpha432.oyvey.event.impl; + +import me.alpha432.oyvey.event.Event; +import me.alpha432.oyvey.features.Feature; +import me.alpha432.oyvey.features.settings.Setting; + +public class ClientEvent extends Event { + private final Type type; + private final Feature feature; + private Setting setting; + + public ClientEvent(Type type, Feature feature) { + this.type = type; + this.feature = feature; + } + + public ClientEvent(Setting setting) { + this(Type.SETTING_UPDATE, setting.getFeature()); + this.setting = setting; + } + + public Type getType() { + return type; + } + + public Feature getFeature() { + return this.feature; + } + + public Setting getSetting() { + return this.setting; + } + + public enum Type { + TOGGLE_MODULE, + SETTING_UPDATE + } +} diff --git a/src/main/java/me/alpha432/oyvey/event/impl/entity/DeathEvent.java b/src/main/java/me/alpha432/oyvey/event/impl/entity/DeathEvent.java new file mode 100644 index 0000000..5bdb8d2 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/event/impl/entity/DeathEvent.java @@ -0,0 +1,16 @@ +package me.alpha432.oyvey.event.impl.entity; + +import me.alpha432.oyvey.event.Event; +import net.minecraft.world.entity.LivingEntity; + +public class DeathEvent extends Event { + private final LivingEntity entity; + + public DeathEvent(LivingEntity entity) { + this.entity = entity; + } + + public LivingEntity getEntity() { + return entity; + } +} diff --git a/src/main/java/me/alpha432/oyvey/event/impl/entity/player/MoveEvent.java b/src/main/java/me/alpha432/oyvey/event/impl/entity/player/MoveEvent.java new file mode 100644 index 0000000..48a9429 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/event/impl/entity/player/MoveEvent.java @@ -0,0 +1,31 @@ +package me.alpha432.oyvey.event.impl.entity.player; + +import me.alpha432.oyvey.event.Event; +import net.minecraft.world.entity.MoverType; +import net.minecraft.world.phys.Vec3; + +public class MoveEvent extends Event { + private final MoverType type; + private Vec3 movement; + + public MoveEvent(MoverType type, Vec3 movement) { + this.type = type; + this.movement = movement; + } + + public MoverType getType() { + return type; + } + + public Vec3 getMovement() { + return movement; + } + + public void setMovement(Vec3 movement) { + this.movement = movement; + } + + public void setMovement(double x, double y, double z) { + this.movement = new Vec3(x, y, z); + } +} diff --git a/src/main/java/me/alpha432/oyvey/event/impl/entity/player/TickEvent.java b/src/main/java/me/alpha432/oyvey/event/impl/entity/player/TickEvent.java new file mode 100644 index 0000000..4311f08 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/event/impl/entity/player/TickEvent.java @@ -0,0 +1,9 @@ +package me.alpha432.oyvey.event.impl.entity.player; + +import me.alpha432.oyvey.event.Event; + +public class TickEvent extends Event { + public static class Post extends TickEvent { } + + public static class Pre extends TickEvent { } +} diff --git a/src/main/java/me/alpha432/oyvey/event/impl/entity/player/TravelEvent.java b/src/main/java/me/alpha432/oyvey/event/impl/entity/player/TravelEvent.java new file mode 100644 index 0000000..557d293 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/event/impl/entity/player/TravelEvent.java @@ -0,0 +1,9 @@ +package me.alpha432.oyvey.event.impl.entity.player; + +import me.alpha432.oyvey.event.Event; + +public class TravelEvent extends Event { + public static class Post extends TravelEvent { } + + public static class Pre extends TravelEvent { } +} diff --git a/src/main/java/me/alpha432/oyvey/event/impl/entity/player/UpdateWalkingPlayerEvent.java b/src/main/java/me/alpha432/oyvey/event/impl/entity/player/UpdateWalkingPlayerEvent.java new file mode 100644 index 0000000..ba82bc8 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/event/impl/entity/player/UpdateWalkingPlayerEvent.java @@ -0,0 +1,16 @@ +package me.alpha432.oyvey.event.impl.entity.player; + +import me.alpha432.oyvey.event.Event; +import me.alpha432.oyvey.event.Stage; + +public class UpdateWalkingPlayerEvent extends Event { + private final Stage stage; + + public UpdateWalkingPlayerEvent(Stage stage) { + this.stage = stage; + } + + public Stage getStage() { + return stage; + } +} diff --git a/src/main/java/me/alpha432/oyvey/event/impl/input/KeyInputEvent.java b/src/main/java/me/alpha432/oyvey/event/impl/input/KeyInputEvent.java new file mode 100644 index 0000000..8bdee21 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/event/impl/input/KeyInputEvent.java @@ -0,0 +1,15 @@ +package me.alpha432.oyvey.event.impl.input; + +import me.alpha432.oyvey.event.Event; + +public class KeyInputEvent extends Event { + private final int key; + + public KeyInputEvent(int key) { + this.key = key; + } + + public int getKey() { + return key; + } +} diff --git a/src/main/java/me/alpha432/oyvey/event/impl/input/MouseInputEvent.java b/src/main/java/me/alpha432/oyvey/event/impl/input/MouseInputEvent.java new file mode 100644 index 0000000..b17c7c4 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/event/impl/input/MouseInputEvent.java @@ -0,0 +1,22 @@ +package me.alpha432.oyvey.event.impl.input; + +import me.alpha432.oyvey.event.Event; + +public class MouseInputEvent extends Event { + private final int button; + private final int action; + + public MouseInputEvent(int button, int action) { + this.button = button; + this.action = action; + } + + public int getButton() { + return button; + } + + public int getAction() { + return action; + } +} + diff --git a/src/main/java/me/alpha432/oyvey/event/impl/network/ChatEvent.java b/src/main/java/me/alpha432/oyvey/event/impl/network/ChatEvent.java new file mode 100644 index 0000000..65291a1 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/event/impl/network/ChatEvent.java @@ -0,0 +1,15 @@ +package me.alpha432.oyvey.event.impl.network; + +import me.alpha432.oyvey.event.Event; + +public class ChatEvent extends Event { + private final String content; + + public ChatEvent(String content) { + this.content = content; + } + + public String getMessage() { + return content; + } +} diff --git a/src/main/java/me/alpha432/oyvey/event/impl/network/PacketEvent.java b/src/main/java/me/alpha432/oyvey/event/impl/network/PacketEvent.java new file mode 100644 index 0000000..8f9d7b5 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/event/impl/network/PacketEvent.java @@ -0,0 +1,30 @@ +package me.alpha432.oyvey.event.impl.network; + +import me.alpha432.oyvey.event.Event; +import net.minecraft.network.protocol.Packet; + +public abstract class PacketEvent extends Event { + + private final Packet packet; + + public PacketEvent(Packet packet) { + this.packet = packet; + } + + public Packet getPacket() { + return packet; + } + + public static class Receive extends PacketEvent { + public Receive(Packet packet) { + super(packet); + } + } + + public static class Send extends PacketEvent { + public Send(Packet packet) { + super(packet); + } + } + +} \ No newline at end of file diff --git a/src/main/java/me/alpha432/oyvey/event/impl/render/Render2DEvent.java b/src/main/java/me/alpha432/oyvey/event/impl/render/Render2DEvent.java new file mode 100644 index 0000000..37da00a --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/event/impl/render/Render2DEvent.java @@ -0,0 +1,22 @@ +package me.alpha432.oyvey.event.impl.render; + +import me.alpha432.oyvey.event.Event; +import net.minecraft.client.gui.GuiGraphics; + +public class Render2DEvent extends Event { + private final GuiGraphics context; + private final float delta; + + public Render2DEvent(GuiGraphics context, float delta) { + this.context = context; + this.delta = delta; + } + + public GuiGraphics getContext() { + return context; + } + + public float getDelta() { + return delta; + } +} diff --git a/src/main/java/me/alpha432/oyvey/event/impl/render/Render3DEvent.java b/src/main/java/me/alpha432/oyvey/event/impl/render/Render3DEvent.java new file mode 100644 index 0000000..adf8786 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/event/impl/render/Render3DEvent.java @@ -0,0 +1,22 @@ +package me.alpha432.oyvey.event.impl.render; + +import com.mojang.blaze3d.vertex.PoseStack; +import me.alpha432.oyvey.event.Event; + +public class Render3DEvent extends Event { + private final PoseStack matrix; + private final float delta; + + public Render3DEvent(PoseStack matrix, float delta) { + this.matrix = matrix; + this.delta = delta; + } + + public PoseStack getMatrix() { + return matrix; + } + + public float getDelta() { + return delta; + } +} diff --git a/src/main/java/me/alpha432/oyvey/event/impl/render/RenderBlockOutlineEvent.java b/src/main/java/me/alpha432/oyvey/event/impl/render/RenderBlockOutlineEvent.java new file mode 100644 index 0000000..e259b64 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/event/impl/render/RenderBlockOutlineEvent.java @@ -0,0 +1,6 @@ +package me.alpha432.oyvey.event.impl.render; + +import me.alpha432.oyvey.event.Event; + +public class RenderBlockOutlineEvent extends Event { +} diff --git a/src/main/java/me/alpha432/oyvey/event/system/EventBus.java b/src/main/java/me/alpha432/oyvey/event/system/EventBus.java new file mode 100644 index 0000000..baea470 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/event/system/EventBus.java @@ -0,0 +1,74 @@ +package me.alpha432.oyvey.event.system; + +import me.alpha432.oyvey.event.Event; + +import java.lang.reflect.Method; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; + +public class EventBus { + private final Map, CopyOnWriteArrayList> listeners = new ConcurrentHashMap<>(); + + public void register(Object host) { + register(host, host.getClass()); + } + + public void unregister(Object host) { + for (CopyOnWriteArrayList list : listeners.values()) { + list.removeIf(listener -> listener.getHost().equals(host)); + } + } + + public boolean post(Event event) { + List list = listeners.get(event.getClass()); + if (list == null) return false; + + for (Listener listener : list) { + listener.invoke(event); + + if (event.isCancelled()) + return true; + } + + return false; + } + + private void register(Object host, Class klass) { + for (Method method : klass.getDeclaredMethods()) { + Subscribe subscribe = method.getAnnotation(Subscribe.class); + if (subscribe == null) continue; + + Class[] params = method.getParameterTypes(); + if (params.length == 1) { + Class eventType = params[0]; + + Listener listener = Listener.of(host, subscribe.priority(), method); + List registry = listeners.computeIfAbsent( + eventType, + k -> new CopyOnWriteArrayList<>() + ); + + register(registry, listener); + } + } + + if (klass.getSuperclass() != null) + register(host, klass.getSuperclass()); + } + + private void register(List registry, Listener target) { + int i = 0; + + for (Listener listener : registry) { + if (target.priority() > listener.priority()) { + break; + } + + i++; + } + + registry.add(i, target); + } +} diff --git a/src/main/java/me/alpha432/oyvey/event/system/Listener.java b/src/main/java/me/alpha432/oyvey/event/system/Listener.java new file mode 100644 index 0000000..196e968 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/event/system/Listener.java @@ -0,0 +1,38 @@ +package me.alpha432.oyvey.event.system; + +import java.lang.invoke.*; +import java.lang.reflect.Method; +import java.util.function.Consumer; + +public record Listener(Object host, int priority, Consumer consumer) { + public static Listener of(Object host, int priority, Method method) { + return new Listener(host, priority, buildLambdaMetafactory(host, method)); + } + + public void invoke(Object event) { + consumer.accept(event); + } + + public Object getHost() { + return host; + } + + @SuppressWarnings("unchecked") + private static Consumer buildLambdaMetafactory(Object host, Method method) { + try { + MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(method.getDeclaringClass(), MethodHandles.lookup()); + CallSite site = LambdaMetafactory.metafactory( + lookup, + "accept", + MethodType.methodType(Consumer.class, method.getDeclaringClass()), + MethodType.methodType(void.class, Object.class), + lookup.unreflect(method), + MethodType.methodType(void.class, method.getParameterTypes()[0]) + ); + MethodHandle target = site.getTarget(); + return (Consumer) (target.invoke(host)); + } catch (Throwable e) { + throw new RuntimeException("Failed to build lambda from %s method".formatted(method.getName()), e); + } + } +} diff --git a/src/main/java/me/alpha432/oyvey/event/system/Subscribe.java b/src/main/java/me/alpha432/oyvey/event/system/Subscribe.java new file mode 100644 index 0000000..241042d --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/event/system/Subscribe.java @@ -0,0 +1,13 @@ +package me.alpha432.oyvey.event.system; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface Subscribe { + int priority() default 0; +} + diff --git a/src/main/java/me/alpha432/oyvey/features/Feature.java b/src/main/java/me/alpha432/oyvey/features/Feature.java new file mode 100644 index 0000000..322443b --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/Feature.java @@ -0,0 +1,65 @@ +package me.alpha432.oyvey.features; + +import me.alpha432.oyvey.features.settings.Setting; +import me.alpha432.oyvey.features.settings.SettingFactory; +import me.alpha432.oyvey.util.traits.Util; + +import java.util.ArrayList; +import java.util.List; + +public class Feature + implements Util, SettingFactory { + public List> settings = new ArrayList<>(); + private String name; + + public Feature() { + } + + public Feature(String name) { + this.name = name; + } + + public static boolean nullCheck() { + return Feature.mc.player == null || Feature.mc.level == null; + } + + public String getName() { + return this.name; + } + + public List> getSettings() { + return this.settings; + } + + public boolean hasSettings() { + return !this.settings.isEmpty(); + } + + public boolean isEnabled() { + return false; + } + + public boolean isDisabled() { + return !this.isEnabled(); + } + + public > T register(T setting) { + setting.setFeature(this); + this.settings.add(setting); + return setting; + } + + public Setting getSettingByName(String name) { + for (Setting setting : this.settings) { + if (!setting.getName().equalsIgnoreCase(name)) continue; + return setting; + } + return null; + } + + public void reset() { + for (Setting setting : this.settings) { + setting.reset(); + } + } +} \ No newline at end of file diff --git a/src/main/java/me/alpha432/oyvey/features/commands/ArgumentSuggestions.java b/src/main/java/me/alpha432/oyvey/features/commands/ArgumentSuggestions.java new file mode 100644 index 0000000..df39a4a --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/commands/ArgumentSuggestions.java @@ -0,0 +1,37 @@ +package me.alpha432.oyvey.features.commands; + +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; + +import java.util.Locale; +import java.util.concurrent.CompletableFuture; +import java.util.function.Function; +import java.util.stream.Stream; + +public final class ArgumentSuggestions { + public static CompletableFuture suggest(Stream stream, SuggestionsBuilder builder) { + return suggest(stream.toList(), x -> x, builder); + } + + public static CompletableFuture suggest(Iterable iterable, SuggestionsBuilder builder) { + return suggest(iterable, x -> x, builder); + } + + public static CompletableFuture suggest(Iterable iterable, Function map, SuggestionsBuilder builder) { + String remaining = builder.getRemainingLowerCase(); + for (T t : iterable) { + String target = map.apply(t).toLowerCase(Locale.ROOT); + if (target.equals(remaining)) { + builder.suggest(target); + return builder.buildFuture(); + } + } + + for (T t : iterable) { + String target = map.apply(t).toLowerCase(Locale.ROOT); + if (target.contains(remaining)) builder.suggest(target); + } + + return builder.buildFuture(); + } +} diff --git a/src/main/java/me/alpha432/oyvey/features/commands/Command.java b/src/main/java/me/alpha432/oyvey/features/commands/Command.java new file mode 100644 index 0000000..c654be1 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/commands/Command.java @@ -0,0 +1,81 @@ +package me.alpha432.oyvey.features.commands; + +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.builder.RequiredArgumentBuilder; +import me.alpha432.oyvey.features.Feature; +import me.alpha432.oyvey.manager.CommandManager; +import me.alpha432.oyvey.util.TextUtil; +import me.alpha432.oyvey.util.chat.ChatUtil; +import me.alpha432.oyvey.util.chat.Signature; + +import static com.mojang.brigadier.Command.SINGLE_SUCCESS; +import static me.alpha432.oyvey.features.commands.MessageSignatures.FAIL; +import static me.alpha432.oyvey.features.commands.MessageSignatures.SUCCESS; + +public abstract class Command extends Feature { + public static final int NO_OP = -1; + public static final int SINGLE_FAILURE = 0; + + private final String[] aliases; + private String description = "No description was provided for this command."; + + public Command(String... aliases) { + super(aliases[0]); + this.aliases = aliases; + } + + public abstract void createArgumentBuilder(LiteralArgumentBuilder builder); + + protected int success(String message, Object... format) { + sendMessage(message, SUCCESS, format); + return NO_OP; + } + + protected int success() { + return SINGLE_SUCCESS; + } + + protected int fail(String message, Object... format) { + sendMessage("{red} " + message, FAIL, format); + return NO_OP; + } + + protected int fail() { + return SINGLE_FAILURE; + } + + public String[] getAliases() { + return aliases; + } + + protected void setDescription(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } + + public boolean isShown() { + return true; + } + + public static void sendMessage(String message, Signature identifier) { + if (message == null) return; + ChatUtil.sendMessage(TextUtil.text(message), identifier); + } + + public static void sendMessage(String message, Signature identifier, Object... format) { + if (message == null) return; + ChatUtil.sendMessage(TextUtil.text(message, format), identifier); + } + + public static LiteralArgumentBuilder literal(String literal) { + return LiteralArgumentBuilder.literal(literal); + } + + public static RequiredArgumentBuilder argument(String name, ArgumentType type) { + return RequiredArgumentBuilder.argument(name, type); + } +} \ No newline at end of file diff --git a/src/main/java/me/alpha432/oyvey/features/commands/CommandExceptions.java b/src/main/java/me/alpha432/oyvey/features/commands/CommandExceptions.java new file mode 100644 index 0000000..f728abc --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/commands/CommandExceptions.java @@ -0,0 +1,10 @@ +package me.alpha432.oyvey.features.commands; + +import com.mojang.brigadier.LiteralMessage; +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; + +public class CommandExceptions { + public static SimpleCommandExceptionType invalidArgument(String message, Object... format) { + return new SimpleCommandExceptionType(new LiteralMessage(String.format(message, format))); + } +} diff --git a/src/main/java/me/alpha432/oyvey/features/commands/MessageSignatures.java b/src/main/java/me/alpha432/oyvey/features/commands/MessageSignatures.java new file mode 100644 index 0000000..ca8782a --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/commands/MessageSignatures.java @@ -0,0 +1,10 @@ +package me.alpha432.oyvey.features.commands; + +import me.alpha432.oyvey.util.chat.Signature; +import me.alpha432.oyvey.util.chat.SimpleSignature; + +public class MessageSignatures { + public static final Signature GENERAL = SimpleSignature.fromLong(-1L); + public static final Signature SUCCESS = SimpleSignature.fromLong(0L); + public static final Signature FAIL = SimpleSignature.fromLong(1L); +} \ No newline at end of file diff --git a/src/main/java/me/alpha432/oyvey/features/commands/ModuleCommand.java b/src/main/java/me/alpha432/oyvey/features/commands/ModuleCommand.java new file mode 100644 index 0000000..1960918 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/commands/ModuleCommand.java @@ -0,0 +1,160 @@ +package me.alpha432.oyvey.features.commands; + +import com.mojang.brigadier.arguments.BoolArgumentType; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import me.alpha432.oyvey.OyVey; +import me.alpha432.oyvey.features.commands.argument.ColorArgumentType; +import me.alpha432.oyvey.features.modules.Module; +import me.alpha432.oyvey.features.settings.Setting; +import me.alpha432.oyvey.manager.CommandManager; +import me.alpha432.oyvey.util.chat.ChatUtil; +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.ClickEvent; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.Style; + +import java.awt.*; + +import static com.mojang.brigadier.arguments.BoolArgumentType.getBool; +import static com.mojang.brigadier.arguments.StringArgumentType.getString; +import static com.mojang.brigadier.arguments.StringArgumentType.greedyString; +import static me.alpha432.oyvey.features.commands.argument.ColorArgumentType.getColor; +import static me.alpha432.oyvey.features.commands.argument.EnumArgumentType._enum; +import static me.alpha432.oyvey.features.commands.argument.EnumArgumentType.getEnum; +import static me.alpha432.oyvey.features.commands.argument.NumberArgumentType.*; + +public class ModuleCommand extends Command { + private final Module module; + + public ModuleCommand(Module module) { + super(module.getName().toLowerCase()); + setDescription("Command line configuration implementation for \"" + module.getName() + "\""); + this.module = module; + } + + @SuppressWarnings("unchecked") + @Override + public void createArgumentBuilder(LiteralArgumentBuilder builder) { + registerDefault(builder); + for (Setting setting : module.getSettings()) { + Class type = setting.getDefaultValue().getClass(); + + if (Boolean.class.isAssignableFrom(type)) { + registerBooleanArgument(builder, (Setting) setting); + } else if (Number.class.isAssignableFrom(type)) { + registerNumberArgument(builder, (Setting) setting); + } else if (Enum.class.isAssignableFrom(type)) { + registerEnumArgument(builder, (Setting>) setting); + } else if (String.class.isAssignableFrom(type)) { + registerStringArgument(builder, (Setting) setting); + } else if (Color.class.isAssignableFrom(type)) { + registerColorArgument(builder, (Setting) setting); + } + } + } + + private void registerDefault(LiteralArgumentBuilder builder) { + builder.executes(ctx -> { + var message = Component.empty(); + + message.append("[ "); + message.append(Component.literal(module.getName()) + .withStyle(s -> s.withColor(module.isToggled() ? ChatFormatting.GREEN : ChatFormatting.RED)) + .withStyle(s -> s.withClickEvent(suggestCommand("toggle " + module.getName()))) + ); + message.append(" ]"); + + for (Setting setting : module.getSettings()) { + message.append("\n"); + message.append(Component.literal(setting.getName() + ": ").withStyle(ChatFormatting.GRAY)); + message.append(Component.literal(setting.getValueAsString()).withStyle(s -> styledValue(setting, s))); + } + + ChatUtil.sendMessage(message, MessageSignatures.SUCCESS); + + return success(); + }); + } + + private void registerColorArgument(LiteralArgumentBuilder builder, + Setting setting) { + builder.then(literal(setting.getName().toLowerCase()) + .then(argument("value", ColorArgumentType.color()) + .executes((ctx) -> { + setting.setValue(getColor(ctx, "value")); + Color value = setting.getValue(); + return success("Set %s.%s to RGB(%s, %s, %s)", + module.getName(), + setting.getName(), + value.getRed(), + value.getGreen(), + value.getBlue()); + }))); + } + + private void registerStringArgument(LiteralArgumentBuilder builder, + Setting setting) { + builder.then(literal(setting.getName().toLowerCase()) + .then(argument("value", greedyString()) + .executes((ctx) -> { + setting.setValue(getString(ctx, "value")); + return settingChangeReturn(setting); + }))); + } + + @SuppressWarnings("unchecked") + private void registerEnumArgument(LiteralArgumentBuilder builder, + Setting> setting) { + Class> type = (Class>) setting.getDefaultValue().getClass(); + builder.then(literal(setting.getName().toLowerCase()) + .then(argument("value", _enum(type)) + .executes((ctx) -> { + setting.setValue(getEnum(ctx, "value")); + return settingChangeReturn(setting); + }))); + } + + @SuppressWarnings("unchecked") + private void registerNumberArgument(LiteralArgumentBuilder builder, + Setting setting) { + Class type = (Class) setting.getDefaultValue().getClass(); + builder.then(literal(setting.getName().toLowerCase()) + .then(argument("value", number(type, minMax(setting.getMin(), setting.getMax()))) + .executes((ctx) -> { + setting.setValue(get(type, ctx, "value")); + return settingChangeReturn(setting); + }))); + } + + private void registerBooleanArgument(LiteralArgumentBuilder builder, + Setting setting) { + builder.then(literal(setting.getName().toLowerCase()) + .then(argument("value", BoolArgumentType.bool()) + .executes((ctx) -> { + setting.setValue(getBool(ctx, "value")); + return settingChangeReturn(setting); + }))); + } + + private int settingChangeReturn(final Setting setting) { + return success("Set %s.%s to %s", module.getName(), setting.getName(), setting.getValue()); + } + + private static ClickEvent suggestCommand(String command) { + return new ClickEvent.SuggestCommand(OyVey.commandManager.getCommandPrefix() + command); + } + + private static Style styledValue(Setting setting, Style style) { + return switch (setting.getValue()) { + case Boolean value -> style.withColor(value ? ChatFormatting.GREEN : ChatFormatting.RED); + case Color value -> style.withColor(value.getRGB()); + case Enum ignored -> style.withColor(ChatFormatting.YELLOW); + default -> style.withColor(ChatFormatting.WHITE); + }; + } + + @Override + public boolean isShown() { + return false; + } +} diff --git a/src/main/java/me/alpha432/oyvey/features/commands/argument/ColorArgumentType.java b/src/main/java/me/alpha432/oyvey/features/commands/argument/ColorArgumentType.java new file mode 100644 index 0000000..e4ebe92 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/commands/argument/ColorArgumentType.java @@ -0,0 +1,148 @@ +package me.alpha432.oyvey.features.commands.argument; + +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import me.alpha432.oyvey.features.commands.CommandExceptions; +import net.minecraft.ChatFormatting; + +import java.awt.*; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +import static me.alpha432.oyvey.features.commands.ArgumentSuggestions.suggest; + +public final class ColorArgumentType implements ArgumentType { + private static final List EXAMPLES = List.of("hsb:55,100,100", "255,0,255", "0,255,255,80"); + private static final String[] RGBA_VALUES = {"Red", "Green", "Blue", "Alpha"}; + + @Override + public Color parse(StringReader reader) throws CommandSyntaxException { + String value = reader.getRemaining(); + reader.setCursor(reader.getTotalLength()); + + // if input begins with "#" its a hex color + if (value.startsWith("#")) { + int color; + if (value.length() == 4) { + char[] c = value.toCharArray(); + String hex = "" + c[1] + c[1] + c[2] + c[2] + c[3] + c[3]; + color = Integer.parseInt(hex, 16); + } else { + color = Integer.parseInt(value.substring(1), 16); + } + + return new Color(color); + } + + if (value.startsWith("hsb:")) { + int[] elements = parseColorElements(reader, value.substring(4)); + + int hue = elements[0]; + if (hue < 0 || hue > 360) { + throw CommandExceptions.invalidArgument("Hue value must be between 0-360") + .createWithContext(reader); + } + + int saturation = elements[1]; + if (saturation < 0 || saturation > 100) { + throw CommandExceptions.invalidArgument("Saturation value must be between 0-100") + .createWithContext(reader); + } + + int brightness = elements[2]; + if (brightness < 0 || brightness > 100) { + throw CommandExceptions.invalidArgument("Brightness value must be between 0-100") + .createWithContext(reader); + } + + return Color.getHSBColor((float) hue / 360.0f, + (float) saturation / 100.0f, + (float) brightness / 100.0f); + } + + ChatFormatting format = parseFormatting(value); + if (format != null) { + return new Color(format.getColor(), false); + } + + int[] elements = parseColorElements(reader, value); + for (int i = 0; i < elements.length; ++i) { + int element = elements[i]; + if (element < 0 || element > 255) { + throw CommandExceptions.invalidArgument("%s value must be between 0-255", RGBA_VALUES[i]) + .createWithContext(reader); + } + } + + return new Color(elements[0], + elements[1], + elements[2], + elements.length == 4 ? elements[3] : 255); + } + + @Override + public CompletableFuture listSuggestions(CommandContext context, SuggestionsBuilder builder) { + String input = builder.getRemainingLowerCase(); + if (input.isEmpty()) { + builder.suggest("#"); + builder.suggest("hsb:"); + return builder.buildFuture(); + } + + if (input.startsWith("#")) { + builder.suggest(input); + } else if (input.startsWith("h")) { + if (input.startsWith("hsb:")) builder.suggest(input); + else builder.suggest("hsb:"); + } else if (!Character.isDigit(input.charAt(0))){ + return suggest(Arrays.stream(ChatFormatting.values()) + .filter(ChatFormatting::isColor) + .map(ChatFormatting::getName), builder); + } + + return builder.buildFuture(); + } + + private int[] parseColorElements(StringReader reader, String value) throws CommandSyntaxException { + String[] parts = value.split(","); + if (parts.length < 3) { + throw CommandExceptions.invalidArgument("Color element must have three values (with optional alpha value), either RGB(A) or hsb:HSB") + .createWithContext(reader); + } + + int[] elements = new int[parts.length]; + for (int i = 0; i < parts.length; ++i) { + elements[i] = Integer.parseInt(parts[i]); + } + return elements; + } + + private ChatFormatting parseFormatting(String value) { + for (ChatFormatting format : ChatFormatting.values()) { + if (!format.isColor()) continue; + if (value.equalsIgnoreCase(format.getName())) { + return format; + } + } + return null; + } + + @Override + public Collection getExamples() { + return EXAMPLES; + } + + public static Color getColor(CommandContext ctx, String name) { + return ctx.getArgument(name, Color.class); + } + + public static ColorArgumentType color() { + return new ColorArgumentType(); + } +} diff --git a/src/main/java/me/alpha432/oyvey/features/commands/argument/CommandArgumentType.java b/src/main/java/me/alpha432/oyvey/features/commands/argument/CommandArgumentType.java new file mode 100644 index 0000000..bb358e8 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/commands/argument/CommandArgumentType.java @@ -0,0 +1,44 @@ +package me.alpha432.oyvey.features.commands.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.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import me.alpha432.oyvey.OyVey; +import me.alpha432.oyvey.features.commands.Command; +import me.alpha432.oyvey.features.commands.CommandExceptions; + +import java.util.concurrent.CompletableFuture; + +import static me.alpha432.oyvey.features.commands.ArgumentSuggestions.suggest; + +public final class CommandArgumentType implements ArgumentType, CommandExceptionType { + @Override + public Command parse(StringReader reader) throws CommandSyntaxException { + String value = reader.readString().toLowerCase(); + + for (String alias : OyVey.commandManager.getCommandAliases()) { + if (value.equalsIgnoreCase(alias)) { + return OyVey.commandManager.getCommand(alias); + } + } + + throw CommandExceptions.invalidArgument("Invalid command").createWithContext(reader); + } + + @Override + public CompletableFuture listSuggestions(CommandContext context, SuggestionsBuilder builder) { + return suggest(OyVey.commandManager.getCommandAliases(), builder); + } + + public static Command getCommand(CommandContext ctx, String name) { + return ctx.getArgument(name, Command.class); + } + + public static CommandArgumentType command() { + return new CommandArgumentType(); + } +} diff --git a/src/main/java/me/alpha432/oyvey/features/commands/argument/EnumArgumentType.java b/src/main/java/me/alpha432/oyvey/features/commands/argument/EnumArgumentType.java new file mode 100644 index 0000000..663a167 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/commands/argument/EnumArgumentType.java @@ -0,0 +1,62 @@ +package me.alpha432.oyvey.features.commands.argument; + +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import me.alpha432.oyvey.features.commands.CommandExceptions; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CompletableFuture; + +import static me.alpha432.oyvey.features.commands.ArgumentSuggestions.suggest; + +public final class EnumArgumentType> implements ArgumentType { + private final Map enumNameMap = new HashMap<>(); + private final T defaultValue; + + public EnumArgumentType(Class clazz, T defaultValue) { + this.defaultValue = defaultValue; + + for (T constant : clazz.getEnumConstants()) { + enumNameMap.put(constant.toString(), constant); + } + } + + @Override + public T parse(StringReader reader) throws CommandSyntaxException { + String value = reader.readString(); + for (String name : enumNameMap.keySet()) { + if (value.equalsIgnoreCase(name)) { + return enumNameMap.get(name); + } + } + + if (defaultValue != null) { + return defaultValue; + } + + throw CommandExceptions.invalidArgument("Invalid enum type").createWithContext(reader); + } + + @Override + public CompletableFuture listSuggestions(CommandContext context, SuggestionsBuilder builder) { + return suggest(enumNameMap.keySet(), builder); + } + + @SuppressWarnings("unchecked") + public static > T getEnum(CommandContext ctx, String name) { + return (T) ctx.getArgument(name, Object.class); + } + + public static > EnumArgumentType _enum(Class clazz) { + return _enum(clazz, null); + } + + public static > EnumArgumentType _enum(Class clazz, T defaultValue) { + return new EnumArgumentType<>(clazz, defaultValue); + } +} diff --git a/src/main/java/me/alpha432/oyvey/features/commands/argument/GreedyArgumentType.java b/src/main/java/me/alpha432/oyvey/features/commands/argument/GreedyArgumentType.java new file mode 100644 index 0000000..b0a4366 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/commands/argument/GreedyArgumentType.java @@ -0,0 +1,40 @@ +package me.alpha432.oyvey.features.commands.argument; + +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; + +import java.lang.reflect.Array; +import java.util.concurrent.CompletableFuture; + +public record GreedyArgumentType(ArgumentType parent, Class type) implements ArgumentType { + @Override + @SuppressWarnings("unchecked") + public T[] parse(StringReader reader) throws CommandSyntaxException { + String input = reader.getRemaining(); + reader.setCursor(reader.getTotalLength()); + String[] split = input.split(" "); + T[] values = (T[]) Array.newInstance(type, split.length); + for (int i = 0; i < split.length; i++) { + values[i] = parent.parse(new StringReader(split[i])); + } + return values; + } + + @Override public CompletableFuture listSuggestions(CommandContext context, SuggestionsBuilder builder) { + String[] s = builder.getRemaining().split(" ", -1); + if (s.length == 0) { + return parent.listSuggestions(context, builder); + } + + int st = builder.getStart() + builder.getRemaining().length() - s[s.length - 1].length(); + return parent.listSuggestions(context, new SuggestionsBuilder(builder.getInput(), st)); + } + + public static GreedyArgumentType greedy(ArgumentType parent, Class type) { + return new GreedyArgumentType<>(parent, type); + } +} diff --git a/src/main/java/me/alpha432/oyvey/features/commands/argument/KeybindArgumentType.java b/src/main/java/me/alpha432/oyvey/features/commands/argument/KeybindArgumentType.java new file mode 100644 index 0000000..96f41e4 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/commands/argument/KeybindArgumentType.java @@ -0,0 +1,45 @@ +package me.alpha432.oyvey.features.commands.argument; + +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import me.alpha432.oyvey.features.commands.CommandExceptions; +import me.alpha432.oyvey.features.settings.Bind; +import me.alpha432.oyvey.util.KeyboardUtil; + +import java.util.Collection; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +import static me.alpha432.oyvey.features.commands.ArgumentSuggestions.suggest; + +public final class KeybindArgumentType implements ArgumentType { + private static final List EXAMPLES = List.of("A", "RIGHT_SHIFT", "MOUSE0"); + + @Override + public Bind parse(StringReader reader) throws CommandSyntaxException { + String input = reader.readString(); + Bind bind = KeyboardUtil.getBind(input); + if (bind == null) { + throw CommandExceptions.invalidArgument("Invalid key name").createWithContext(reader); + } + return bind; + } + + @Override + public CompletableFuture listSuggestions(CommandContext context, SuggestionsBuilder builder) { + return suggest(KeyboardUtil.iterateKeys(), builder); + } + + @Override + public Collection getExamples() { + return EXAMPLES; + } + + public static KeybindArgumentType keybind() { + return new KeybindArgumentType(); + } +} diff --git a/src/main/java/me/alpha432/oyvey/features/commands/argument/ModuleArgumentType.java b/src/main/java/me/alpha432/oyvey/features/commands/argument/ModuleArgumentType.java new file mode 100644 index 0000000..08bffec --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/commands/argument/ModuleArgumentType.java @@ -0,0 +1,57 @@ +package me.alpha432.oyvey.features.commands.argument; + +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import me.alpha432.oyvey.OyVey; +import me.alpha432.oyvey.features.Feature; +import me.alpha432.oyvey.features.commands.CommandExceptions; +import me.alpha432.oyvey.features.modules.Module; + +import java.util.Locale; +import java.util.concurrent.CompletableFuture; + +import static me.alpha432.oyvey.features.commands.ArgumentSuggestions.suggest; + +public record ModuleArgumentType(boolean fullName) implements ArgumentType { + @Override + public Module parse(StringReader reader) throws CommandSyntaxException { + String value = reader.readString().toLowerCase(Locale.ROOT); + + for (Module module : OyVey.moduleManager.getModules()) { + if (value.equalsIgnoreCase(module.getName())) { + return module; + } + } + + if (!fullName) { + for (Module module : OyVey.moduleManager.getModules()) { + if (module.getName().toLowerCase(Locale.ROOT).startsWith(value)) { + return module; + } + } + } + + throw CommandExceptions.invalidArgument("Invalid module").createWithContext(reader); + } + + @Override + public CompletableFuture listSuggestions(CommandContext context, SuggestionsBuilder builder) { + return suggest(OyVey.moduleManager.getModules(), Feature::getName, builder); + } + + public static ModuleArgumentType module() { + return module(false); + } + + public static ModuleArgumentType module(boolean fullName) { + return new ModuleArgumentType(fullName); + } + + public static Module getModule(CommandContext ctx, String name) { + return ctx.getArgument(name, Module.class); + } +} diff --git a/src/main/java/me/alpha432/oyvey/features/commands/argument/NumberArgumentType.java b/src/main/java/me/alpha432/oyvey/features/commands/argument/NumberArgumentType.java new file mode 100644 index 0000000..01c7ea8 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/commands/argument/NumberArgumentType.java @@ -0,0 +1,70 @@ +package me.alpha432.oyvey.features.commands.argument; + +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import me.alpha432.oyvey.features.commands.CommandExceptions; + +public record NumberArgumentType(Class type, Constraint constraint) implements ArgumentType { + @SuppressWarnings("unchecked") + @Override + public T parse(StringReader reader) throws CommandSyntaxException { + String input = reader.readString(); + + T value = null; + try { + if (type.isAssignableFrom(Integer.class)) { + value = (T) Integer.valueOf(input); + } else if (type.isAssignableFrom(Double.class)) { + value = (T) Double.valueOf(input); + } else if (type.isAssignableFrom(Float.class)) { + value = (T) Float.valueOf(input); + } else if (type.isAssignableFrom(Long.class)) { + value = (T) Long.valueOf(input); + } + } catch (NumberFormatException ignored) { + } + + if (value == null) { + throw CommandExceptions.invalidArgument("Could not parse \"%s\"", input) + .createWithContext(reader); + } + + if (constraint != null) { + constraint.validate(reader, value); + } + + return value; + } + + public static Constraint minMax(T min, T max) { + return (reader, input) -> { + double value = input.doubleValue(); + if (min.doubleValue() > value) { + throw CommandExceptions.invalidArgument("Value is less than minimum(%s)", min.toString()) + .createWithContext(reader); + } + if (max.doubleValue() < value) { + throw CommandExceptions.invalidArgument("Value is more than maximum(%s)", max.toString()) + .createWithContext(reader); + } + }; + } + + public static T get(Class type, CommandContext ctx, String name) { + return ctx.getArgument(name, type); + } + + public static NumberArgumentType number(Class type) { + return number(type, null); + } + + public static NumberArgumentType number(Class type, Constraint constraint) { + return new NumberArgumentType<>(type, constraint); + } + + public interface Constraint { + void validate(StringReader reader, T input) throws CommandSyntaxException; + } +} diff --git a/src/main/java/me/alpha432/oyvey/features/commands/impl/BindCommand.java b/src/main/java/me/alpha432/oyvey/features/commands/impl/BindCommand.java new file mode 100644 index 0000000..8294664 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/commands/impl/BindCommand.java @@ -0,0 +1,64 @@ +package me.alpha432.oyvey.features.commands.impl; + +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import me.alpha432.oyvey.event.impl.input.KeyInputEvent; +import me.alpha432.oyvey.event.system.Subscribe; +import me.alpha432.oyvey.features.commands.Command; +import me.alpha432.oyvey.features.modules.Module; +import me.alpha432.oyvey.features.settings.Bind; +import me.alpha432.oyvey.manager.CommandManager; +import me.alpha432.oyvey.util.KeyboardUtil; + +import static me.alpha432.oyvey.features.commands.argument.KeybindArgumentType.keybind; +import static me.alpha432.oyvey.features.commands.argument.ModuleArgumentType.module; +import static org.lwjgl.glfw.GLFW.GLFW_KEY_ESCAPE; +import static org.lwjgl.glfw.GLFW.GLFW_KEY_UNKNOWN; + +public class BindCommand extends Command { + private Module module; + + public BindCommand() { + super("bind", "setbind"); + setDescription("Sets a key bind for a module"); + EVENT_BUS.register(this); + } + + @Override + public void createArgumentBuilder(LiteralArgumentBuilder builder) { + builder.then(argument("module", module(true)).then( + argument("keybind", keybind()).executes(ctx -> { + Module module = ctx.getArgument("module", Module.class); + Bind bind = ctx.getArgument("keybind", Bind.class); + module.bind.setValue(bind); + return success("Bind for {green} %s {} set to {green} %s", + module.getName(), + KeyboardUtil.getKeyName(bind) + ); + }) + ).executes((ctx) -> { + module = ctx.getArgument("module", Module.class); + return success("Press any key..."); + })); + } + + @Subscribe + public void onKey(final KeyInputEvent event) { + if (nullCheck() || module == null || event.getKey() == GLFW_KEY_UNKNOWN) { + return; + } + + if (event.getKey() == GLFW_KEY_ESCAPE) { + module = null; + fail("Operation canceled."); + return; + } + + module.bind.setValue(Bind.keyboard(event.getKey())); + success("Bind for {green} %s {} set to {green} %s", + module.getName(), + KeyboardUtil.getKeyName(module.getBind()) + ); + + module = null; + } +} diff --git a/src/main/java/me/alpha432/oyvey/features/commands/impl/DrawnCommand.java b/src/main/java/me/alpha432/oyvey/features/commands/impl/DrawnCommand.java new file mode 100644 index 0000000..93ae5cd --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/commands/impl/DrawnCommand.java @@ -0,0 +1,30 @@ +package me.alpha432.oyvey.features.commands.impl; + +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import me.alpha432.oyvey.features.commands.Command; +import me.alpha432.oyvey.features.modules.Module; +import me.alpha432.oyvey.manager.CommandManager; + +import static me.alpha432.oyvey.features.commands.argument.ModuleArgumentType.getModule; +import static me.alpha432.oyvey.features.commands.argument.ModuleArgumentType.module; + +public class DrawnCommand extends Command { + public DrawnCommand() { + super("drawn"); + setDescription("Sets a module to be drawn to the arraylist or not"); + } + + @Override + public void createArgumentBuilder(LiteralArgumentBuilder builder) { + builder.then(argument("module", module()) + .executes((ctx) -> { + Module module = getModule(ctx, "module"); + module.setDrawn(!module.isDrawn()); + boolean drawn = module.isDrawn(); + return success("{gray} %s {reset} is now %s %s", + module.getDisplayName(), + drawn ? "{green}" : "{red}", + drawn ? "drawn" : "hidden"); + })); + } +} diff --git a/src/main/java/me/alpha432/oyvey/features/commands/impl/FriendCommand.java b/src/main/java/me/alpha432/oyvey/features/commands/impl/FriendCommand.java new file mode 100644 index 0000000..3f95668 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/commands/impl/FriendCommand.java @@ -0,0 +1,58 @@ +package me.alpha432.oyvey.features.commands.impl; + +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import me.alpha432.oyvey.OyVey; +import me.alpha432.oyvey.features.commands.Command; +import me.alpha432.oyvey.manager.CommandManager; + +import java.util.List; +import java.util.StringJoiner; + +import static com.mojang.brigadier.arguments.StringArgumentType.getString; +import static com.mojang.brigadier.arguments.StringArgumentType.word; + +public class FriendCommand extends Command { + public FriendCommand() { + super("friend", "friends", "f"); + setDescription("Manages your friends list"); + } + + @Override + public void createArgumentBuilder(LiteralArgumentBuilder builder) { + builder.then(literal("list") + .executes((ctx) -> { + List friends = OyVey.friendManager.getFriends(); + if (friends.isEmpty()) { + return success("You have no friends :("); + } + StringJoiner joiner = new StringJoiner(","); + friends.forEach(joiner::add); + return success("Friends (%s): %s", friends.size(), joiner); + })) + .then(literal("clear") + .executes((ctx) -> { + OyVey.friendManager.getFriends().clear(); + return success("Cleared friends list"); + })) + .then(literal("add") + .then(argument("username", word()) + .executes((ctx) -> { + String username = getString(ctx, "username"); + if (OyVey.friendManager.isFriend(username)) { + return success("{green} %s {reset} is already on your friends list.", username); + } + OyVey.friendManager.addFriend(username); + return success("Added {green} %s {reset} to your friends list", username); + }))) + .then(literal("remove") + .then(argument("username", word()) + .executes((ctx) -> { + String username = getString(ctx, "username"); + if (!OyVey.friendManager.isFriend(username)) { + return success("{green} %s {reset} is not on your friends list.", username); + } + OyVey.friendManager.removeFriend(username); + return success("Removed {green} %s {reset} from your friends list", username); + }))); + } +} diff --git a/src/main/java/me/alpha432/oyvey/features/commands/impl/HelpCommand.java b/src/main/java/me/alpha432/oyvey/features/commands/impl/HelpCommand.java new file mode 100644 index 0000000..3ddc5ab --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/commands/impl/HelpCommand.java @@ -0,0 +1,118 @@ +package me.alpha432.oyvey.features.commands.impl; + +import com.google.common.collect.Iterables; +import com.mojang.brigadier.ParseResults; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.tree.CommandNode; +import me.alpha432.oyvey.OyVey; +import me.alpha432.oyvey.features.commands.Command; +import me.alpha432.oyvey.manager.CommandManager; +import me.alpha432.oyvey.util.chat.ChatUtil; +import net.minecraft.network.chat.ClickEvent; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.ComponentUtils; +import net.minecraft.network.chat.MutableComponent; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import static me.alpha432.oyvey.features.commands.MessageSignatures.GENERAL; +import static me.alpha432.oyvey.features.commands.argument.CommandArgumentType.command; +import static me.alpha432.oyvey.features.commands.argument.CommandArgumentType.getCommand; +import static me.alpha432.oyvey.features.commands.argument.NumberArgumentType.get; +import static me.alpha432.oyvey.features.commands.argument.NumberArgumentType.number; +import static me.alpha432.oyvey.util.TextUtil.text; +import static me.alpha432.oyvey.util.chat.ChatUtil.prefix; +import static me.alpha432.oyvey.util.chat.ChatUtil.withPrefix; + +public class HelpCommand extends Command { + private static final int ITEMS_PER_PAGE = 5; + + public HelpCommand() { + super("help", "commands", "h", "cmds"); + setDescription("Displays all executable commands and additional information"); + } + + @Override + public void createArgumentBuilder(LiteralArgumentBuilder builder) { + builder.then(argument("page", number(Integer.class)) + .executes((ctx) -> helpCommands(ctx, get(Integer.class, ctx, "page")))) + .then(argument("command_name", command()) + .executes(this::helpSpecific)) + .executes((ctx) -> helpCommands(ctx, 1)); + } + + private int helpSpecific(CommandContext ctx) { + Command command = getCommand(ctx, "command_name"); + + MutableComponent text = Component.empty(); + text.append(withPrefix("Usages for %s:\n", command.getName())); + + ParseResults results = ctx.getSource().getDispatcher() + .parse(command.getName(), ctx.getSource()); + + if (results.getContext().getNodes().isEmpty()) { + text.append(withPrefix("No usages available")); + } else { + Map, String> smartUsages = ctx.getSource().getDispatcher().getSmartUsage( + Iterables.getLast(results.getContext().getNodes()).getNode(), ctx.getSource()); + List usages = new ArrayList<>(); + + for (String usage : smartUsages.values()) { + usages.add(text(" {gray}%s%s %s", ctx.getSource().getCommandPrefix(), command.getName(), usage)); + } + + text.append(ComponentUtils.formatList(usages, Component.literal("\n"))); + } + + ChatUtil.sendClientSideMessage(text, GENERAL); + return success(); + } + + private int helpCommands(CommandContext ctx, int page) { + List commands = ctx.getSource().getCommands() + .stream().filter(Command::isShown).toList(); + + int pages = Math.max(1, (int) Math.ceil((double) commands.size() / ITEMS_PER_PAGE)); + int pageIndex = page < 1 || page > pages ? 1 : page; + + List paginated = commands.subList((pageIndex - 1) * ITEMS_PER_PAGE, + Math.min(commands.size(), pageIndex * ITEMS_PER_PAGE)); + + MutableComponent text = Component.empty(); + text.append(withPrefix("Commands (%s): \n", commands.size())); + + for (Command command : paginated) { + String aliases = String.join(", ", command.getAliases()); + String description = command.getDescription(); + text.append(withPrefix("{dark_gray} %s: {reset}\n %s\n", aliases, description)); + } + + text.append(buildPages(pageIndex, pages)); + + ChatUtil.sendClientSideMessage(text, GENERAL); + return success(); + } + + private static Component buildPages(int index, int pages) { + String command = OyVey.commandManager.getCommandPrefix() + "help "; + MutableComponent text = prefix(); + boolean hasPages = pages > 1; + + if (hasPages && index != 1) + text.append(suggest(Component.literal(" <"), command + (index - 1))); + + text.append(text(" Page %d/%d", index, pages)); + + if (hasPages && index != pages) + text.append(suggest(Component.literal(" > "), command + (index + 1))); + + return text; + } + + private static Component suggest(MutableComponent component, String command) { + return component.withStyle(s -> s.withClickEvent(new ClickEvent.SuggestCommand(command.formatted()))); + } +} diff --git a/src/main/java/me/alpha432/oyvey/features/commands/impl/PrefixCommand.java b/src/main/java/me/alpha432/oyvey/features/commands/impl/PrefixCommand.java new file mode 100644 index 0000000..bc2ed9f --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/commands/impl/PrefixCommand.java @@ -0,0 +1,28 @@ +package me.alpha432.oyvey.features.commands.impl; + +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import me.alpha432.oyvey.features.commands.Command; +import me.alpha432.oyvey.manager.CommandManager; + +import static com.mojang.brigadier.arguments.StringArgumentType.getString; +import static com.mojang.brigadier.arguments.StringArgumentType.greedyString; + +public class PrefixCommand extends Command { + public PrefixCommand() { + super("prefix", "setprefix"); + setDescription("Sets the command prefix"); + } + + @Override + public void createArgumentBuilder(LiteralArgumentBuilder builder) { + builder.then(argument("prefix", greedyString()) + .executes((ctx) -> { + String prefix = getString(ctx, "prefix").trim(); + if (prefix.isBlank()) { + return fail("Prefix must contain at least one character"); + } + ctx.getSource().setCommandPrefix(prefix); + return success("Prefix changed to {green} %s", prefix); + })); + } +} diff --git a/src/main/java/me/alpha432/oyvey/features/commands/impl/ToggleCommand.java b/src/main/java/me/alpha432/oyvey/features/commands/impl/ToggleCommand.java new file mode 100644 index 0000000..67493c5 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/commands/impl/ToggleCommand.java @@ -0,0 +1,30 @@ +package me.alpha432.oyvey.features.commands.impl; + +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import me.alpha432.oyvey.features.commands.Command; +import me.alpha432.oyvey.features.modules.Module; +import me.alpha432.oyvey.manager.CommandManager; + +import static me.alpha432.oyvey.features.commands.argument.ModuleArgumentType.getModule; +import static me.alpha432.oyvey.features.commands.argument.ModuleArgumentType.module; + +public class ToggleCommand extends Command { + public ToggleCommand() { + super("toggle", "t"); + setDescription("Toggles a module"); + } + + @Override + public void createArgumentBuilder(LiteralArgumentBuilder builder) { + builder.then(argument("module", module(true)) + .executes((ctx) -> { + Module module = getModule(ctx, "module"); + module.toggle(); + boolean toggled = module.isEnabled(); + return success("{gray} %s {reset} is now %s %s", + module.getDisplayName(), + toggled ? "{green}" : "{red}", + toggled ? "enabled" : "disabled"); + })); + } +} diff --git a/src/main/java/me/alpha432/oyvey/features/gui/HudEditorScreen.java b/src/main/java/me/alpha432/oyvey/features/gui/HudEditorScreen.java new file mode 100644 index 0000000..b1ceff6 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/gui/HudEditorScreen.java @@ -0,0 +1,100 @@ +package me.alpha432.oyvey.features.gui; + +import me.alpha432.oyvey.OyVey; +import me.alpha432.oyvey.features.Feature; +import me.alpha432.oyvey.features.gui.items.buttons.ModuleButton; +import me.alpha432.oyvey.features.modules.Module; +import me.alpha432.oyvey.features.modules.client.HudModule; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.input.CharacterEvent; +import net.minecraft.client.input.KeyEvent; +import net.minecraft.client.input.MouseButtonEvent; +import net.minecraft.network.chat.Component; + +import java.util.ArrayList; +import java.util.Comparator; + +public class HudEditorScreen extends Screen { + private static HudEditorScreen INSTANCE; + + private final ArrayList components = new ArrayList<>(); + public HudModule currentDragging; + public boolean anyHover; + + private HudEditorScreen() { + super(Component.literal("oyvey-hudeditor")); + load(); + } + + private void load() { + Widget hud = new Widget("Hud", 50, 50, true); + OyVey.moduleManager.stream() + .filter(m -> m.getCategory() == Module.Category.HUD && !m.hidden) + .map(ModuleButton::new) + .forEach(hud::addButton); + this.components.add(hud); + this.components.forEach(component -> component.getItems().sort(Comparator.comparing(Feature::getName))); + } + + @Override + public void render(GuiGraphics context, int mouseX, int mouseY, float delta) { + anyHover = false; + this.components.forEach(component -> component.drawScreen(context, mouseX, mouseY, delta)); + } + + @Override + public boolean mouseClicked(MouseButtonEvent click, boolean doubled) { + this.components.forEach(component -> component.mouseClicked((int) click.x(), (int) click.y(), click.button())); + return super.mouseClicked(click, doubled); + } + + @Override + public boolean mouseReleased(MouseButtonEvent click) { + this.components.forEach(component -> component.mouseReleased((int) click.x(), (int) click.y(), click.button())); + return super.mouseReleased(click); + } + + @Override + public boolean mouseScrolled(double mouseX, double mouseY, double horizontalAmount, double verticalAmount) { + if (verticalAmount < 0) { + this.components.forEach(component -> component.setY(component.getY() - 10)); + } else if (verticalAmount > 0) { + this.components.forEach(component -> component.setY(component.getY() + 10)); + } + return super.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount); + } + + @Override + public boolean keyPressed(KeyEvent input) { + this.components.forEach(component -> component.onKeyPressed(input.input())); + return super.keyPressed(input); + } + + @Override + public boolean charTyped(CharacterEvent input) { + this.components.forEach(component -> component.onKeyTyped(input.codepointAsString(), input.modifiers())); + return super.charTyped(input); + } + + @Override + public boolean isPauseScreen() { + return false; + } + + @Override // ignore 1.21.8 menu blur thing + public void renderBackground(GuiGraphics context, int mouseX, int mouseY, float delta) { + } + + public ArrayList getComponents() { + return components; + } + + public static HudEditorScreen getInstance() { + if (INSTANCE == null) { + INSTANCE = new HudEditorScreen(); + } + return INSTANCE; + } +} + diff --git a/src/main/java/me/alpha432/oyvey/features/gui/OyVeyGui.java b/src/main/java/me/alpha432/oyvey/features/gui/OyVeyGui.java new file mode 100644 index 0000000..6b3ebb9 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/gui/OyVeyGui.java @@ -0,0 +1,147 @@ +package me.alpha432.oyvey.features.gui; + +import me.alpha432.oyvey.OyVey; +import me.alpha432.oyvey.features.Feature; +import me.alpha432.oyvey.features.gui.items.buttons.ModuleButton; +import me.alpha432.oyvey.features.modules.Module; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.input.CharacterEvent; +import net.minecraft.client.input.KeyEvent; +import net.minecraft.client.input.MouseButtonEvent; +import net.minecraft.network.chat.Component; + +import java.awt.*; +import java.util.ArrayList; +import java.util.Comparator; + +public class OyVeyGui extends Screen { + private static OyVeyGui INSTANCE; + private static Color colorClipboard = null; + + static { + INSTANCE = new OyVeyGui(); + } + + private Screen lastScreen; + private final ArrayList widgets = new ArrayList<>(); + + public OyVeyGui() { + super(Component.literal("OyVey")); + setInstance(); + load(); + } + + public static OyVeyGui getInstance() { + if (INSTANCE == null) { + INSTANCE = new OyVeyGui(); + } + return INSTANCE; + } + + public static OyVeyGui getClickGui() { + return OyVeyGui.getInstance(); + } + + public static void open(Screen previous) { + OyVeyGui gui = getInstance(); + gui.lastScreen = previous; + Minecraft.getInstance().setScreen(gui); + } + + @Override + public void onClose() { + Screen previous = this.lastScreen; + this.lastScreen = null; + this.minecraft.setScreen(previous); + } + + private void setInstance() { + INSTANCE = this; + } + + private void load() { + int x = -84; + for (Module.Category category : OyVey.moduleManager.getCategories()) { + if (category == Module.Category.HUD) continue; + Widget panel = new Widget(category.getName(), x += 90, 4, true); + OyVey.moduleManager.stream() + .filter(m -> m.getCategory() == category && !m.hidden) + .map(ModuleButton::new) + .forEach(panel::addButton); + this.widgets.add(panel); + } + this.widgets.forEach(components -> components.getItems().sort(Comparator.comparing(Feature::getName))); + } + + @Override + public void render(GuiGraphics context, int mouseX, int mouseY, float delta) { + if (lastScreen != null) { + lastScreen.renderBackground(context, Integer.MIN_VALUE, Integer.MIN_VALUE, delta); + lastScreen.render(context, Integer.MIN_VALUE, Integer.MIN_VALUE, delta); + context.nextStratum(); + } + + context.fill(0, 0, context.guiWidth(), context.guiHeight(), new Color(0, 0, 0, 120).hashCode()); + this.widgets.forEach(components -> components.drawScreen(context, mouseX, mouseY, delta)); + } + + @Override + public boolean mouseClicked(MouseButtonEvent click, boolean doubled) { + this.widgets.forEach(components -> components.mouseClicked((int) click.x(), (int) click.y(), click.button())); + return super.mouseClicked(click, doubled); + } + + @Override + public boolean mouseReleased(MouseButtonEvent click) { + this.widgets.forEach(components -> components.mouseReleased((int) click.x(), (int) click.y(), click.button())); + return super.mouseReleased(click); + } + + @Override + public boolean mouseScrolled(double mouseX, double mouseY, double horizontalAmount, double verticalAmount) { + if (verticalAmount < 0) { + this.widgets.forEach(component -> component.setY(component.getY() - 10)); + } else if (verticalAmount > 0) { + this.widgets.forEach(component -> component.setY(component.getY() + 10)); + } + return super.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount); + } + + @Override + public boolean keyPressed(KeyEvent input) { + this.widgets.forEach(component -> component.onKeyPressed(input.input())); + return super.keyPressed(input); + } + + @Override + public boolean charTyped(CharacterEvent input) { + this.widgets.forEach(component -> component.onKeyTyped(input.codepointAsString(), input.modifiers())); + return super.charTyped(input); + } + + @Override + public boolean isPauseScreen() { + return false; + } + @Override + public void renderBackground(GuiGraphics context, int mouseX, int mouseY, float delta) { + }//ignore 1.21.8 blur thing + + public final ArrayList getComponents() { + return this.widgets; + } + + public int getTextOffset() { + return -6; + } + + public static Color getColorClipboard() { + return colorClipboard; + } + + public static void setColorClipboard(Color color) { + colorClipboard = color; + } +} diff --git a/src/main/java/me/alpha432/oyvey/features/gui/Widget.java b/src/main/java/me/alpha432/oyvey/features/gui/Widget.java new file mode 100644 index 0000000..d321f1b --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/gui/Widget.java @@ -0,0 +1,198 @@ +package me.alpha432.oyvey.features.gui; + +import me.alpha432.oyvey.features.Feature; +import me.alpha432.oyvey.features.gui.items.Item; +import me.alpha432.oyvey.features.gui.items.buttons.Button; +import me.alpha432.oyvey.features.modules.client.ClickGuiModule; +import me.alpha432.oyvey.util.ColorUtil; +import me.alpha432.oyvey.util.render.RenderUtil; +import me.alpha432.oyvey.util.render.ScissorUtil; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.resources.sounds.SimpleSoundInstance; +import net.minecraft.sounds.SoundEvents; + +import java.awt.*; +import java.util.ArrayList; +import java.util.List; + +public class Widget + extends Feature { + protected GuiGraphics context; + private final List items = new ArrayList<>(); + public boolean drag; + private int x; + private int y; + private int x2; + private int y2; + private int width; + private int height; + private boolean open; + private boolean hidden = false; + + public Widget(String name, int x, int y, boolean open) { + super(name); + this.x = x; + this.y = y; + this.width = 88; + this.height = 18; + this.open = open; + } + + private void drag(int mouseX, int mouseY) { + if (!this.drag) { + return; + } + this.x = this.x2 + mouseX; + this.y = this.y2 + mouseY; + } + + public void drawScreen(GuiGraphics context, int mouseX, int mouseY, float partialTicks) { + this.context = context; + this.drag(mouseX, mouseY); + float totalItemHeight = this.open ? this.getTotalItemHeight() - 2.0f : 0.0f; + int color = ClickGuiModule.getInstance().topColor.getValue().getRGB(); + context.fill(this.x, this.y - 1, this.x + this.width, this.y + this.height - 6, ClickGuiModule.getInstance().rainbow.getValue() ? ColorUtil.rainbow(ClickGuiModule.getInstance().rainbowHue.getValue()).getRGB() : color); + if (this.open) { + RenderUtil.rect(context, this.x, (float) this.y + 12.5f, this.x + this.width, (float) (this.y + this.height) + totalItemHeight, 0x77000000); + } + drawString(this.getName(), (float) this.x + 3.0f, (float) this.y - 4.0f - (float) OyVeyGui.getClickGui().getTextOffset(), -1); + ScissorUtil.enable(context, x, 0, x + width, mc.getWindow().getGuiScaledHeight()); + + if (this.open) { + float y = (float) (this.getY() + this.getHeight()) - 3.0f; + for (Item item : this.getItems()) { + if (item.isHidden()) continue; + item.setLocation((float) this.x + 2.0f, y); + item.setWidth(this.getWidth() - 4); + if (item.isHovering(mouseX, mouseY)) { + ScissorUtil.disable(context); + } + item.drawScreen(context, mouseX, mouseY, partialTicks); + + if (item.isHovering(mouseX, mouseY)) { + ScissorUtil.enable(context); + } + y += (float) item.getHeight() + 2f; + } + } + + ScissorUtil.disable(context); + } + + public void mouseClicked(int mouseX, int mouseY, int mouseButton) { + if (mouseButton == 0 && this.isHovering(mouseX, mouseY)) { + this.x2 = this.x - mouseX; + this.y2 = this.y - mouseY; + OyVeyGui.getClickGui().getComponents().forEach(component -> { + if (component.drag) { + component.drag = false; + } + }); + this.drag = true; + return; + } + if (mouseButton == 1 && this.isHovering(mouseX, mouseY)) { + this.open = !this.open; + mc.getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1f)); + return; + } + if (!this.open) { + return; + } + this.getItems().forEach(item -> item.mouseClicked(mouseX, mouseY, mouseButton)); + } + + public void mouseReleased(int mouseX, int mouseY, int releaseButton) { + if (releaseButton == 0) { + this.drag = false; + } + if (!this.open) { + return; + } + this.getItems().forEach(item -> item.mouseReleased(mouseX, mouseY, releaseButton)); + } + + public void onKeyTyped(String typedChar, int keyCode) { + if (!this.open) { + return; + } + this.getItems().forEach(item -> item.onKeyTyped(typedChar, keyCode)); + } + + public void onKeyPressed(int key) { + if (!open) return; + this.getItems().forEach(item -> item.onKeyPressed(key)); + } + + public void addButton(Button button) { + this.items.add(button); + } + + public int getX() { + return this.x; + } + + public void setX(int x) { + this.x = x; + } + + public int getY() { + return this.y; + } + + public void setY(int y) { + this.y = y; + } + + public int getWidth() { + return this.width; + } + + public void setWidth(int width) { + this.width = width; + } + + public int getHeight() { + return this.height; + } + + public void setHeight(int height) { + this.height = height; + } + + public boolean isHidden() { + return this.hidden; + } + + public void setHidden(boolean hidden) { + this.hidden = hidden; + } + + public boolean isOpen() { + return this.open; + } + + public final List getItems() { + return this.items; + } + + public boolean isHovering(int mouseX, int mouseY) { + return mouseX >= this.getX() && mouseX <= this.getX() + this.getWidth() && mouseY >= this.getY() && mouseY <= this.getY() + this.getHeight() - (this.open ? 2 : 0); + } + + private float getTotalItemHeight() { + float height = 0.0f; + for (Item item : this.getItems()) { + height += (float) item.getHeight() + 2; + } + return height; + } + + protected void drawString(String text, double x, double y, Color color) { + drawString(text, x, y, color.hashCode()); + } + + protected void drawString(String text, double x, double y, int color) { + context.drawString(mc.font, text, (int) x, (int) y, color); + } +} \ No newline at end of file diff --git a/src/main/java/me/alpha432/oyvey/features/gui/items/Item.java b/src/main/java/me/alpha432/oyvey/features/gui/items/Item.java new file mode 100644 index 0000000..bf35c1b --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/gui/items/Item.java @@ -0,0 +1,87 @@ +package me.alpha432.oyvey.features.gui.items; + +import me.alpha432.oyvey.features.Feature; +import net.minecraft.client.gui.GuiGraphics; + +import java.awt.*; + +public class Item + extends Feature { + protected float x; + protected float y; + protected int width; + protected int height; + private boolean hidden; + + public Item(String name) { + super(name); + } + + public void setLocation(float x, float y) { + this.x = x; + this.y = y; + } + + public void drawScreen(GuiGraphics context, int mouseX, int mouseY, float partialTicks) { + } + + public void mouseClicked(int mouseX, int mouseY, int mouseButton) { + } + + public void mouseReleased(int mouseX, int mouseY, int releaseButton) { + } + + public void update() { + } + + public void onKeyTyped(String typedChar, int keyCode) { + } + + public void onKeyPressed(int key) { + } + + public float getX() { + return this.x; + } + + public float getY() { + return this.y; + } + + public int getWidth() { + return this.width; + } + + public void setWidth(int width) { + this.width = width; + } + + public int getHeight() { + return this.height; + } + + public void setHeight(int height) { + this.height = height; + } + + public boolean isHidden() { + return this.hidden; + } + + public boolean setHidden(boolean hidden) { + this.hidden = hidden; + return this.hidden; + } + + protected void drawString(GuiGraphics context, String text, double x, double y, Color color) { + drawString(context, text, x, y, color.getRGB()); + } + + protected void drawString(GuiGraphics context, String text, double x, double y, int color) { + context.drawString(mc.font, text, (int) x, (int) y, color); + } + + public boolean isHovering(int mouseX, int mouseY) { + return false; + } +} \ No newline at end of file diff --git a/src/main/java/me/alpha432/oyvey/features/gui/items/buttons/BindButton.java b/src/main/java/me/alpha432/oyvey/features/gui/items/buttons/BindButton.java new file mode 100644 index 0000000..2c81276 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/gui/items/buttons/BindButton.java @@ -0,0 +1,80 @@ +package me.alpha432.oyvey.features.gui.items.buttons; + +import me.alpha432.oyvey.OyVey; +import me.alpha432.oyvey.features.gui.OyVeyGui; +import me.alpha432.oyvey.features.modules.client.ClickGuiModule; +import me.alpha432.oyvey.features.settings.Bind; +import me.alpha432.oyvey.features.settings.Setting; +import me.alpha432.oyvey.util.KeyboardUtil; +import me.alpha432.oyvey.util.render.RenderUtil; +import net.minecraft.ChatFormatting; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.resources.sounds.SimpleSoundInstance; +import net.minecraft.sounds.SoundEvents; +import org.lwjgl.glfw.GLFW; + +public class BindButton + extends Button { + private final Setting setting; + public boolean isListening; + + public BindButton(Setting setting) { + super(setting.getName()); + this.setting = setting; + this.width = 15; + } + + @Override + public void drawScreen(GuiGraphics context, int mouseX, int mouseY, float partialTicks) { + int color = ClickGuiModule.getInstance().color.getValue().getRGB(); + RenderUtil.rect(context, this.x, this.y, this.x + (float) this.width + 7.4f, this.y + (float) this.height - 0.5f, this.getState() ? (!this.isHovering(mouseX, mouseY) ? 0x11555555 : -2007673515) : (!this.isHovering(mouseX, mouseY) ? OyVey.colorManager.getColorWithAlpha(y, ClickGuiModule.getInstance().color.getValue().getAlpha()) : OyVey.colorManager.getColorWithAlpha(y, ClickGuiModule.getInstance().topColor.getValue().getAlpha()))); + if (this.isListening) { + drawString(context, "Press a Key...", this.x + 2.3f, this.y - 1.7f - (float) OyVeyGui.getClickGui().getTextOffset(), -1); + } else { + String str = KeyboardUtil.getKeyName(setting.getValue()); + drawString(context, this.setting.getName() + " " + ChatFormatting.GRAY + str, this.x + 2.3f, this.y - 1.7f - (float) OyVeyGui.getClickGui().getTextOffset(), this.getState() ? -1 : -5592406); + } + } + + @Override + public void update() { + this.setHidden(!this.setting.isVisible()); + } + + @Override + public void mouseClicked(int mouseX, int mouseY, int mouseButton) { + super.mouseClicked(mouseX, mouseY, mouseButton); + if (this.isListening) { + if (mouseButton != 0 && mouseButton != 1) { + this.setting.setValue(new Bind(-mouseButton - 2)); + this.onMouseClick(); + } + } else if (this.isHovering(mouseX, mouseY)) { + mc.getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1f)); + } + } + + @Override + public void onKeyPressed(int key) { + if (this.isListening) { + Bind bind = new Bind(key); + if (key == GLFW.GLFW_KEY_DELETE + || key == GLFW.GLFW_KEY_BACKSPACE + || key == GLFW.GLFW_KEY_ESCAPE) { + bind = new Bind(-1); + } + this.setting.setValue(bind); + this.onMouseClick(); + } + } + + @Override + public void toggle() { + this.isListening = !this.isListening; + } + + @Override + public boolean getState() { + return !this.isListening; + } +} \ No newline at end of file diff --git a/src/main/java/me/alpha432/oyvey/features/gui/items/buttons/BooleanButton.java b/src/main/java/me/alpha432/oyvey/features/gui/items/buttons/BooleanButton.java new file mode 100644 index 0000000..358ffad --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/gui/items/buttons/BooleanButton.java @@ -0,0 +1,51 @@ +package me.alpha432.oyvey.features.gui.items.buttons; + + +import me.alpha432.oyvey.OyVey; +import me.alpha432.oyvey.features.gui.OyVeyGui; +import me.alpha432.oyvey.features.modules.client.ClickGuiModule; +import me.alpha432.oyvey.features.settings.Setting; +import me.alpha432.oyvey.util.render.RenderUtil; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.resources.sounds.SimpleSoundInstance; +import net.minecraft.sounds.SoundEvents; + +public class BooleanButton + extends Button { + private final Setting setting; + + public BooleanButton(Setting setting) { + super(setting.getName()); + this.setting = setting; + this.width = 15; + } + + @Override + public void drawScreen(GuiGraphics context, int mouseX, int mouseY, float partialTicks) { + RenderUtil.rect(context, this.x, this.y, this.x + (float) this.width + 7.4f, this.y + (float) this.height - 0.5f, this.getState() ? (!this.isHovering(mouseX, mouseY) ? OyVey.colorManager.getColorWithAlpha(y, ClickGuiModule.getInstance().color.getValue().getAlpha()) : OyVey.colorManager.getColorWithAlpha(y, ClickGuiModule.getInstance().topColor.getValue().getAlpha())) : (!this.isHovering(mouseX, mouseY) ? 0x11555555 : -2007673515)); + drawString(context, this.getName(), this.x + 2.3f, this.y - 1.7f - (float) OyVeyGui.getClickGui().getTextOffset(), this.getState() ? -1 : -5592406); + } + + @Override + public void update() { + this.setHidden(!this.setting.isVisible()); + } + + @Override + public void mouseClicked(int mouseX, int mouseY, int mouseButton) { + super.mouseClicked(mouseX, mouseY, mouseButton); + if (this.isHovering(mouseX, mouseY)) { + mc.getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1f)); + } + } + + @Override + public void toggle() { + this.setting.setValue(!this.setting.getValue()); + } + + @Override + public boolean getState() { + return this.setting.getValue(); + } +} \ No newline at end of file diff --git a/src/main/java/me/alpha432/oyvey/features/gui/items/buttons/Button.java b/src/main/java/me/alpha432/oyvey/features/gui/items/buttons/Button.java new file mode 100644 index 0000000..583e853 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/gui/items/buttons/Button.java @@ -0,0 +1,60 @@ +package me.alpha432.oyvey.features.gui.items.buttons; + +import me.alpha432.oyvey.OyVey; +import me.alpha432.oyvey.features.gui.OyVeyGui; +import me.alpha432.oyvey.features.gui.Widget; +import me.alpha432.oyvey.features.gui.items.Item; +import me.alpha432.oyvey.features.modules.client.ClickGuiModule; +import me.alpha432.oyvey.util.render.RenderUtil; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.resources.sounds.SimpleSoundInstance; +import net.minecraft.sounds.SoundEvents; + +public class Button + extends Item { + private boolean state; + + public Button(String name) { + super(name); + this.height = 15; + } + + @Override + public void drawScreen(GuiGraphics context, int mouseX, int mouseY, float partialTicks) { + RenderUtil.rect(context, this.x, this.y, this.x + (float) this.width, this.y + (float) this.height - 0.5f, this.getState() ? (!this.isHovering(mouseX, mouseY) ? OyVey.colorManager.getColorWithAlpha(y, ClickGuiModule.getInstance().color.getValue().getAlpha()) : OyVey.colorManager.getColorWithAlpha(y, ClickGuiModule.getInstance().topColor.getValue().getAlpha())) : (!this.isHovering(mouseX, mouseY) ? 0x11555555 : -2007673515)); + drawString(context, this.getName(), this.x + 2.3f, this.y - 2.0f - (float) OyVeyGui.getClickGui().getTextOffset(), this.getState() ? -1 : -5592406); + } + + @Override + public void mouseClicked(int mouseX, int mouseY, int mouseButton) { + if (mouseButton == 0 && this.isHovering(mouseX, mouseY)) { + this.onMouseClick(); + } + } + + public void onMouseClick() { + this.state = !this.state; + this.toggle(); + mc.getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1f)); + } + + public void toggle() { + } + + public boolean getState() { + return this.state; + } + + @Override + public int getHeight() { + return 14; + } + + public boolean isHovering(int mouseX, int mouseY) { + for (Widget widget : OyVeyGui.getClickGui().getComponents()) { + if (!widget.drag) continue; + return false; + } + return (float) mouseX >= this.getX() && (float) mouseX <= this.getX() + (float) this.getWidth() && (float) mouseY >= this.getY() && (float) mouseY < this.getY() + (float) this.height; + } +} \ No newline at end of file diff --git a/src/main/java/me/alpha432/oyvey/features/gui/items/buttons/ColorButton.java b/src/main/java/me/alpha432/oyvey/features/gui/items/buttons/ColorButton.java new file mode 100644 index 0000000..9489ea5 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/gui/items/buttons/ColorButton.java @@ -0,0 +1,201 @@ +package me.alpha432.oyvey.features.gui.items.buttons; + +import me.alpha432.oyvey.OyVey; +import me.alpha432.oyvey.features.gui.OyVeyGui; +import me.alpha432.oyvey.features.gui.Widget; +import me.alpha432.oyvey.features.modules.client.ClickGuiModule; +import me.alpha432.oyvey.features.settings.Setting; +import me.alpha432.oyvey.util.render.RenderUtil; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.resources.sounds.SimpleSoundInstance; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.util.Mth; + +import java.awt.*; + +public class ColorButton extends Button { + private static final int PICKER_SIZE = 84; + + private final Setting setting; + private boolean open = false; + private boolean hoveringHue = false, hoveringColor = false, hoveringAlpha = false, hoveringCopy = false, hoveringPaste = false; + private boolean draggingHue = false, draggingColor = false, draggingAlpha = false; + private float[] hsb; + + public ColorButton(Setting setting) { + super(setting.getName()); + this.setting = setting; + this.width = 15; + hsb = Color.RGBtoHSB(setting.getValue().getRed(), setting.getValue().getGreen(), setting.getValue().getBlue(), null); + } + + @Override + public void drawScreen(GuiGraphics context, int mouseX, int mouseY, float partialTicks) { + Color currentColor = setting.getValue(); + Color outlineColor = Color.BLACK; + Color realColor = Color.getHSBColor(hsb[0], 1, 1); + + RenderUtil.rect(context, this.x, this.y, this.x + (float) this.width + 7.4f, this.y + (float) this.height - 0.5f, + !this.isHovering(mouseX, mouseY) ? 0x11555555 : -2007673515); + + RenderUtil.rect(context, this.x + (float) this.width - 4f, this.y + 3f, + this.x + (float) this.width + 5.0f, this.y + (float) this.height - 2.5f, + new Color(currentColor.getRGB(), false).getRGB()); + + drawString(context, this.getName(), this.x + 2.3f, this.y - 1.7f - (float) OyVeyGui.getClickGui().getTextOffset(), -1); + + if (open) { + float yOffset = this.height + 1; + int availableWidth = this.width + 3; + int pickerWidth = Math.min(PICKER_SIZE, availableWidth); + float pickerX = this.x + 2.0f; + + int dragX = Mth.clamp(mouseX - (int) pickerX, 0, pickerWidth); + int dragY = Mth.clamp(mouseY - (int) (getY() + yOffset), 0, pickerWidth); + float dragHue = Math.max(pickerWidth * hsb[0] - .5f, 1); + float dragSaturation = Math.max(pickerWidth * hsb[1] - 1, 2); + float dragBrightness = Math.max(pickerWidth * (1.0f - hsb[2]) - 1, 2); + float dragAlpha = Math.max(pickerWidth * (currentColor.getAlpha() / 255.0f) - .5f, 1); + + RenderUtil.horizontalGradient(context, pickerX, this.y + yOffset, pickerX + pickerWidth, this.y + yOffset + pickerWidth, Color.WHITE, realColor); + RenderUtil.verticalGradient(context, pickerX, this.y + yOffset, pickerX + pickerWidth, this.y + yOffset + pickerWidth, new Color(0, 0, 0, 0), Color.BLACK); + RenderUtil.rect(context, pickerX, this.y + yOffset, pickerX + pickerWidth, this.y + yOffset + pickerWidth, outlineColor.getRGB(), 1.0f); + + hoveringColor = isHoveringArea(mouseX, mouseY, pickerX, this.y + yOffset, pickerX + pickerWidth, this.y + yOffset + pickerWidth); + + if (dragSaturation < pickerWidth && dragBrightness < pickerWidth) { + RenderUtil.rect(context, pickerX + dragSaturation - 2.5f, this.y + yOffset + dragBrightness - 2.5f, + pickerX + dragSaturation + 0.5f, this.y + yOffset + dragBrightness + 0.5f, outlineColor.getRGB()); + RenderUtil.rect(context, pickerX + dragSaturation - 1.5f, this.y + yOffset + dragBrightness - 1.5f, + pickerX + dragSaturation - 0.5f, this.y + yOffset + dragBrightness - 0.5f, Color.WHITE.getRGB()); + } + + if (draggingColor) { + hsb[1] = (float) dragX / pickerWidth; + hsb[2] = 1.0f - (float) dragY / pickerWidth; + setColor(hsb); + } + + yOffset += pickerWidth + 2; + + RenderUtil.horizontalGradient(context, pickerX, this.y + yOffset, pickerX + pickerWidth, this.y + yOffset + 8, + new Color(currentColor.getRed(), currentColor.getGreen(), currentColor.getBlue(), 0), + new Color(currentColor.getRed(), currentColor.getGreen(), currentColor.getBlue(), 255)); + RenderUtil.rect(context, pickerX, this.y + yOffset, pickerX + pickerWidth, this.y + yOffset + 8, outlineColor.getRGB(), 1.0f); + hoveringAlpha = isHoveringArea(mouseX, mouseY, pickerX, this.y + yOffset, pickerX + pickerWidth, this.y + yOffset + 8); + + RenderUtil.rect(context, pickerX + dragAlpha - 1.5f, this.y + yOffset - 1, + pickerX + dragAlpha + 1.5f, this.y + yOffset + 9, outlineColor.getRGB()); + RenderUtil.rect(context, pickerX + dragAlpha - 0.5f, this.y + yOffset, + pickerX + dragAlpha + 0.5f, this.y + yOffset + 8, Color.WHITE.getRGB()); + + if (draggingAlpha) { + setColor(hsb, (int) (255 * (float) dragX / pickerWidth)); + } + + yOffset += 10; + + for (float i = 0; i < pickerWidth; i += 0.5f) { + RenderUtil.rect(context, pickerX + i, this.y + yOffset, pickerX + i + 0.5f, this.y + yOffset + 8, + Color.getHSBColor(i / pickerWidth, 1.0f, 1.0f).getRGB()); + } + RenderUtil.rect(context, pickerX, this.y + yOffset, pickerX + pickerWidth, this.y + yOffset + 8, outlineColor.getRGB(), 1.0f); + hoveringHue = isHoveringArea(mouseX, mouseY, pickerX, this.y + yOffset, pickerX + pickerWidth, this.y + yOffset + 8); + + if (dragHue < pickerWidth) { + RenderUtil.rect(context, pickerX + dragHue - 1.5f, this.y + yOffset - 1, + pickerX + dragHue + 1.5f, this.y + yOffset + 9, outlineColor.getRGB()); + RenderUtil.rect(context, pickerX + dragHue - 0.5f, this.y + yOffset, + pickerX + dragHue + 0.5f, this.y + yOffset + 8, Color.WHITE.getRGB()); + } + + if (draggingHue) { + hsb[0] = (float) dragX / pickerWidth; + setColor(hsb); + } + + yOffset += 10; + + int buttonWidth = availableWidth / 2; + RenderUtil.rect(context, pickerX, this.y + yOffset, pickerX + buttonWidth, this.y + yOffset + 14, + hoveringCopy ? OyVey.colorManager.getColorWithAlpha(y, ClickGuiModule.getInstance().topColor.getValue().getAlpha()) : 0x11555555); + drawString(context, "Copy", pickerX + buttonWidth / 2.0 - mc.font.width("Copy") / 2.0, this.y + yOffset + 3, -1); + hoveringCopy = isHoveringArea(mouseX, mouseY, pickerX, this.y + yOffset, pickerX + buttonWidth, this.y + yOffset + 14); + + RenderUtil.rect(context, pickerX + buttonWidth + 1, this.y + yOffset, pickerX + buttonWidth * 2 + 1, this.y + yOffset + 14, + hoveringPaste ? OyVey.colorManager.getColorWithAlpha(y, ClickGuiModule.getInstance().topColor.getValue().getAlpha()) : 0x11555555); + drawString(context, "Paste", pickerX + buttonWidth + buttonWidth / 2.0 - mc.font.width("Paste") / 2.0 + 1, this.y + yOffset + 3, -1); + hoveringPaste = isHoveringArea(mouseX, mouseY, pickerX + buttonWidth + 1, this.y + yOffset, pickerX + buttonWidth * 2 + 1, this.y + yOffset + 14); + } + } + + @Override + public void mouseClicked(int mouseX, int mouseY, int mouseButton) { + if (this.isHovering(mouseX, mouseY) && mouseButton == 1) { + open = !open; + mc.getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1f)); + } + + if (mouseButton == 0) { + if (hoveringHue) draggingHue = true; + if (hoveringColor) draggingColor = true; + if (hoveringAlpha) draggingAlpha = true; + + if (hoveringCopy) { + OyVeyGui.setColorClipboard(setting.getValue()); + mc.getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1f)); + } + if (hoveringPaste && OyVeyGui.getColorClipboard() != null) { + setting.setValue(OyVeyGui.getColorClipboard()); + hsb = Color.RGBtoHSB(setting.getValue().getRed(), setting.getValue().getGreen(), setting.getValue().getBlue(), null); + mc.getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1f)); + } + } + } + + @Override + public void mouseReleased(int mouseX, int mouseY, int releaseButton) { + if (releaseButton == 0) { + draggingHue = false; + draggingColor = false; + draggingAlpha = false; + } + } + + @Override + public void update() { + this.setHidden(!this.setting.isVisible()); + } + + @Override + public int getHeight() { + if (!open) return 14; + int pickerWidth = Math.min(PICKER_SIZE, this.width + 3); + return 14 + pickerWidth + 8 + 8 + 14 + 8; + } + + @Override + public boolean isHovering(int mouseX, int mouseY) { + for (Widget widget : OyVeyGui.getClickGui().getComponents()) { + if (widget.drag) return false; + } + return (float) mouseX >= this.getX() && (float) mouseX <= this.getX() + (float) this.getWidth() + 8.0f + && (float) mouseY >= this.getY() && (float) mouseY < this.getY() + (float) this.height; + } + + private boolean isHoveringArea(int mouseX, int mouseY, float left, float top, float right, float bottom) { + for (Widget widget : OyVeyGui.getClickGui().getComponents()) { + if (widget.drag) return false; + } + return left <= mouseX && top <= mouseY && right > mouseX && bottom > mouseY; + } + + private void setColor(float[] hsb) { + setColor(hsb, setting.getValue().getAlpha()); + } + + private void setColor(float[] hsb, int alpha) { + Color color = new Color(Color.HSBtoRGB(hsb[0], hsb[1], hsb[2])); + setting.setValue(new Color(color.getRed(), color.getGreen(), color.getBlue(), alpha)); + } +} diff --git a/src/main/java/me/alpha432/oyvey/features/gui/items/buttons/EnumButton.java b/src/main/java/me/alpha432/oyvey/features/gui/items/buttons/EnumButton.java new file mode 100644 index 0000000..0e22751 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/gui/items/buttons/EnumButton.java @@ -0,0 +1,52 @@ +package me.alpha432.oyvey.features.gui.items.buttons; + + +import me.alpha432.oyvey.OyVey; +import me.alpha432.oyvey.features.gui.OyVeyGui; +import me.alpha432.oyvey.features.modules.client.ClickGuiModule; +import me.alpha432.oyvey.features.settings.Setting; +import me.alpha432.oyvey.util.render.RenderUtil; +import net.minecraft.ChatFormatting; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.resources.sounds.SimpleSoundInstance; +import net.minecraft.sounds.SoundEvents; + +public class EnumButton + extends Button { + public Setting> setting; + + public EnumButton(Setting> setting) { + super(setting.getName()); + this.setting = setting; + this.width = 15; + } + + @Override + public void drawScreen(GuiGraphics context, int mouseX, int mouseY, float partialTicks) { + RenderUtil.rect(context, this.x, this.y, this.x + (float) this.width + 7.4f, this.y + (float) this.height - 0.5f, this.getState() ? (!this.isHovering(mouseX, mouseY) ? OyVey.colorManager.getColorWithAlpha(y, ClickGuiModule.getInstance().color.getValue().getAlpha()) : OyVey.colorManager.getColorWithAlpha(y, ClickGuiModule.getInstance().topColor.getValue().getAlpha())) : (!this.isHovering(mouseX, mouseY) ? 0x11555555 : -2007673515)); + drawString(context, this.setting.getName() + " " + ChatFormatting.GRAY + (this.setting.currentEnumName().equalsIgnoreCase("ABC") ? "ABC" : this.setting.currentEnumName()), this.x + 2.3f, this.y - 1.7f - (float) OyVeyGui.getClickGui().getTextOffset(), this.getState() ? -1 : -5592406); + } + + @Override + public void update() { + this.setHidden(!this.setting.isVisible()); + } + + @Override + public void mouseClicked(int mouseX, int mouseY, int mouseButton) { + super.mouseClicked(mouseX, mouseY, mouseButton); + if (this.isHovering(mouseX, mouseY)) { + mc.getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1f)); + } + } + + @Override + public void toggle() { + this.setting.increaseEnum(); + } + + @Override + public boolean getState() { + return true; + } +} \ No newline at end of file diff --git a/src/main/java/me/alpha432/oyvey/features/gui/items/buttons/ModuleButton.java b/src/main/java/me/alpha432/oyvey/features/gui/items/buttons/ModuleButton.java new file mode 100644 index 0000000..ff84f69 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/gui/items/buttons/ModuleButton.java @@ -0,0 +1,151 @@ +package me.alpha432.oyvey.features.gui.items.buttons; + +import me.alpha432.oyvey.features.gui.items.Item; +import me.alpha432.oyvey.features.modules.Module; +import me.alpha432.oyvey.features.settings.Bind; +import me.alpha432.oyvey.features.settings.Setting; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.resources.sounds.SimpleSoundInstance; +import net.minecraft.sounds.SoundEvents; + +import java.util.ArrayList; +import java.util.List; + +public class ModuleButton + extends Button { + private final Module module; + private List items = new ArrayList<>(); + private boolean subOpen; + + public ModuleButton(Module module) { + super(module.getName()); + this.module = module; + this.initSettings(); + } + + @SuppressWarnings("unchecked") + public void initSettings() { + ArrayList newItems = new ArrayList<>(); + if (!this.module.getSettings().isEmpty()) { + for (Setting setting : this.module.getSettings()) { + if (setting.getValue() instanceof Boolean && !setting.getName().equals("Enabled")) { + newItems.add(new BooleanButton((Setting) setting)); + } + if (setting.getValue() instanceof Bind && !setting.getName().equalsIgnoreCase("Keybind") && !this.module.getName().equalsIgnoreCase("Hud")) { + newItems.add(new BindButton((Setting) setting)); + } + if ((setting.getValue() instanceof String || setting.getValue() instanceof Character) && !setting.getName().equalsIgnoreCase("displayName")) { + newItems.add(new StringButton((Setting) setting)); + } + if (setting.isColorSetting()) { + newItems.add(new ColorButton((Setting) setting)); + continue; + } + if (setting.isNumberSetting() && setting.hasRestriction()) { + newItems.add(new Slider((Setting) setting)); + continue; + } + if (!setting.isEnumSetting()) continue; + newItems.add(new EnumButton((Setting>) setting)); + } + } + newItems.add(new BindButton((Setting) this.module.getSettingByName("Keybind"))); + this.items = newItems; + } + + @Override + public void drawScreen(GuiGraphics context, int mouseX, int mouseY, float partialTicks) { + super.drawScreen(context, mouseX, mouseY, partialTicks); + if (!this.items.isEmpty()) { + if (this.subOpen) { + float height = 16.0f; + for (Item item : this.items) { + if (!item.isHidden()) { + item.setLocation(this.x + 1.0f, this.y + height); + item.setWidth(this.width - 9); + item.drawScreen(context, mouseX, mouseY, partialTicks); + height += item.getHeight() + 1f; + } + item.update(); + } + } + } + } + + @Override + public void mouseClicked(int mouseX, int mouseY, int mouseButton) { + super.mouseClicked(mouseX, mouseY, mouseButton); + if (!this.items.isEmpty()) { + if (mouseButton == 1 && this.isHovering(mouseX, mouseY)) { + this.subOpen = !this.subOpen; + mc.getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1f)); + } + if (this.subOpen) { + for (Item item : this.items) { + if (item.isHidden()) continue; + item.mouseClicked(mouseX, mouseY, mouseButton); + } + } + } + } + + @Override + public void mouseReleased(int mouseX, int mouseY, int releaseButton) { + super.mouseReleased(mouseX, mouseY, releaseButton); + if (!this.items.isEmpty() && this.subOpen) { + for (Item item : this.items) { + if (item.isHidden()) continue; + item.mouseReleased(mouseX, mouseY, releaseButton); + } + } + } + + @Override + public void onKeyTyped(String typedChar, int keyCode) { + super.onKeyTyped(typedChar, keyCode); + if (!this.items.isEmpty() && this.subOpen) { + for (Item item : this.items) { + if (item.isHidden()) continue; + item.onKeyTyped(typedChar, keyCode); + } + } + } + + @Override + public void onKeyPressed(int key) { + super.onKeyPressed(key); + if (!this.items.isEmpty() && this.subOpen) { + for (Item item : this.items) { + if (item.isHidden()) continue; + item.onKeyPressed(key); + } + } + } + + @Override + public int getHeight() { + if (this.subOpen) { + int height = 16; + for (Item item : this.items) { + if (item.isHidden()) continue; + height += item.getHeight() + 1; + } + return height; + } + return 14; + } + + public Module getModule() { + return this.module; + } + + @Override + public void toggle() { + this.module.toggle(); + } + + @Override + public boolean getState() { + return this.module.isEnabled(); + } +} \ No newline at end of file diff --git a/src/main/java/me/alpha432/oyvey/features/gui/items/buttons/Slider.java b/src/main/java/me/alpha432/oyvey/features/gui/items/buttons/Slider.java new file mode 100644 index 0000000..b6c36a9 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/gui/items/buttons/Slider.java @@ -0,0 +1,95 @@ +package me.alpha432.oyvey.features.gui.items.buttons; + +import me.alpha432.oyvey.OyVey; +import me.alpha432.oyvey.features.gui.OyVeyGui; +import me.alpha432.oyvey.features.gui.Widget; +import me.alpha432.oyvey.features.modules.client.ClickGuiModule; +import me.alpha432.oyvey.features.settings.Setting; +import me.alpha432.oyvey.util.render.RenderUtil; +import net.minecraft.ChatFormatting; +import net.minecraft.client.gui.GuiGraphics; +import org.lwjgl.glfw.GLFW; + +public class Slider + extends Button { + private final Number min; + private final Number max; + private final double difference; + public Setting setting; + private boolean dragging; + + public Slider(Setting setting) { + super(setting.getName()); + this.setting = setting; + this.min = setting.getMin(); + this.max = setting.getMax(); + this.difference = this.max.doubleValue() - this.min.doubleValue(); + this.width = 15; + } + + @Override + public void drawScreen(GuiGraphics context, int mouseX, int mouseY, float partialTicks) { + this.dragSetting(mouseX, mouseY); + RenderUtil.rect(context, this.x, this.y, this.x + (float) this.width + 7.4f, this.y + (float) this.height - 0.5f, !(this.dragging || this.isHovering(mouseX, mouseY)) ? 0x11555555 : -2007673515); + RenderUtil.rect(context, this.x, this.y, (this.setting.getValue()).floatValue() <= this.min.floatValue() ? this.x : this.x + ((float) this.width + 7.4f) * this.partialMultiplier(), this.y + (float) this.height - 0.5f, !(this.dragging || this.isHovering(mouseX, mouseY)) ? OyVey.colorManager.getColorWithAlpha(y, ClickGuiModule.getInstance().color.getValue().getAlpha()) : OyVey.colorManager.getColorWithAlpha(y, ClickGuiModule.getInstance().topColor.getValue().getAlpha())); + drawString(context, this.getName() + " " + ChatFormatting.GRAY + (this.setting.getValue() instanceof Float ? this.setting.getValue() : Double.valueOf((this.setting.getValue()).doubleValue())), this.x + 2.3f, this.y - 1.7f - (float) OyVeyGui.getClickGui().getTextOffset(), -1); + } + + @Override + public void mouseClicked(int mouseX, int mouseY, int mouseButton) { + super.mouseClicked(mouseX, mouseY, mouseButton); + if (mouseButton == 0 && this.isHovering(mouseX, mouseY)) { + this.dragging = true; + this.setSettingFromX(mouseX); + } + } + + @Override + public boolean isHovering(int mouseX, int mouseY) { + for (Widget widget : OyVeyGui.getClickGui().getComponents()) { + if (!widget.drag) continue; + return false; + } + return (float) mouseX >= this.getX() && (float) mouseX <= this.getX() + (float) this.getWidth() + 8.0f && (float) mouseY >= this.getY() && (float) mouseY < this.getY() + (float) this.height; + } + + @Override + public void update() { + this.setHidden(!this.setting.isVisible()); + } + + private void dragSetting(int mouseX, int mouseY) { + if (GLFW.glfwGetMouseButton(mc.getWindow().handle(), 0) != 1) { + this.dragging = false; + return; + } + if (this.dragging) { + this.setSettingFromX(mouseX); + } + } + + private void setSettingFromX(int mouseX) { + float percent = Math.clamp(((float) mouseX - this.x) / ((float) this.width + 7.4f), 0.0f, 1.0f); + if (this.setting.getValue() instanceof Double) { + double result = this.setting.getMin().doubleValue() + this.difference * percent; + this.setting.setValue((double) Math.round(10.0 * result) / 10.0); + } else if (this.setting.getValue() instanceof Float) { + float result = this.setting.getMin().floatValue() + (float) (this.difference * percent); + this.setting.setValue((float) Math.round(10.0f * result) / 10.0f); + } else if (this.setting.getValue() instanceof Integer) { + this.setting.setValue(this.setting.getMin().intValue() + (int) Math.round(this.difference * percent)); + } + } + + private float middle() { + return this.max.floatValue() - this.min.floatValue(); + } + + private float part() { + return (this.setting.getValue()).floatValue() - this.min.floatValue(); + } + + private float partialMultiplier() { + return this.part() / this.middle(); + } +} \ No newline at end of file diff --git a/src/main/java/me/alpha432/oyvey/features/gui/items/buttons/StringButton.java b/src/main/java/me/alpha432/oyvey/features/gui/items/buttons/StringButton.java new file mode 100644 index 0000000..27c167f --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/gui/items/buttons/StringButton.java @@ -0,0 +1,117 @@ +package me.alpha432.oyvey.features.gui.items.buttons; + +import me.alpha432.oyvey.OyVey; +import me.alpha432.oyvey.features.gui.OyVeyGui; +import me.alpha432.oyvey.features.modules.client.ClickGuiModule; +import me.alpha432.oyvey.features.settings.Setting; +import me.alpha432.oyvey.util.models.Timer; +import me.alpha432.oyvey.util.render.RenderUtil; +import net.minecraft.ChatFormatting; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.resources.sounds.SimpleSoundInstance; +import net.minecraft.sounds.SoundEvents; +import org.lwjgl.glfw.GLFW; + +public class StringButton + extends Button { + private static final Timer idleTimer = new Timer(); + private static boolean idle; + private final Setting setting; + public boolean isListening; + private CurrentString currentString = new CurrentString(""); + + public StringButton(Setting setting) { + super(setting.getName()); + this.setting = setting; + this.width = 15; + } + + public static String removeLastChar(String str) { + String output = ""; + if (str != null && !str.isEmpty()) { + output = str.substring(0, str.length() - 1); + } + return output; + } + + @Override + public void drawScreen(GuiGraphics context, int mouseX, int mouseY, float partialTicks) { + RenderUtil.rect(context, this.x, this.y, this.x + (float) this.width + 7.4f, this.y + (float) this.height - 0.5f, this.getState() ? (!this.isHovering(mouseX, mouseY) ? OyVey.colorManager.getColorWithAlpha(y, ClickGuiModule.getInstance().color.getValue().getAlpha()) : OyVey.colorManager.getColorWithAlpha(y, ClickGuiModule.getInstance().topColor.getValue().getAlpha())) : (!this.isHovering(mouseX, mouseY) ? 0x11555555 : -2007673515)); + if (this.isListening) { + drawString(context, this.currentString.string() + getIdleSign(), this.x + 2.3f, this.y - 1.7f - (float) OyVeyGui.getClickGui().getTextOffset(), this.getState() ? -1 : -5592406); + } else { + drawString(context, (this.setting.getName().equals("Buttons") ? "Buttons " : (this.setting.getName().equals("Prefix") ? "Prefix " + ChatFormatting.GRAY : "")) + this.setting.getValue(), this.x + 2.3f, this.y - 1.7f - (float) OyVeyGui.getClickGui().getTextOffset(), this.getState() ? -1 : -5592406); + } + } + + @Override + public void mouseClicked(int mouseX, int mouseY, int mouseButton) { + super.mouseClicked(mouseX, mouseY, mouseButton); + if (this.isHovering(mouseX, mouseY)) { + mc.getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1f)); + } + } + + @Override + public void onKeyTyped(String typedChar, int keyCode) { + if (this.isListening) { + this.setString(this.currentString.string() + typedChar); + } + } + + @Override + public void onKeyPressed(int key) { + if (isListening) { + switch (key) { + case GLFW.GLFW_KEY_ENTER: { + this.enterString(); + break; + } + case GLFW.GLFW_KEY_BACKSPACE: { + this.setString(StringButton.removeLastChar(this.currentString.string())); + } + } + } + } + + @Override + public void update() { + this.setHidden(!this.setting.isVisible()); + } + + private void enterString() { + if (this.currentString.string().isEmpty()) { + this.setting.setValue(this.setting.getDefaultValue()); + } else { + this.setting.setValue(this.currentString.string()); + } + this.setString(""); + this.onMouseClick(); + } + + @Override + public void toggle() { + this.isListening = !this.isListening; + } + + @Override + public boolean getState() { + return !this.isListening; + } + + public void setString(String newString) { + this.currentString = new CurrentString(newString); + } + + public static String getIdleSign() { + if (idleTimer.passedMs(500)) { + idle = !idle; + idleTimer.reset(); + } + if (idle) return "_"; + return ""; + } + + public record CurrentString(String string) { + } +} \ No newline at end of file diff --git a/src/main/java/me/alpha432/oyvey/features/modules/Module.java b/src/main/java/me/alpha432/oyvey/features/modules/Module.java new file mode 100644 index 0000000..fe9ff80 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/modules/Module.java @@ -0,0 +1,204 @@ +package me.alpha432.oyvey.features.modules; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import me.alpha432.oyvey.OyVey; +import me.alpha432.oyvey.event.impl.ClientEvent; +import me.alpha432.oyvey.event.impl.render.Render2DEvent; +import me.alpha432.oyvey.event.impl.render.Render3DEvent; +import me.alpha432.oyvey.features.Feature; +import me.alpha432.oyvey.features.commands.Command; +import me.alpha432.oyvey.features.commands.MessageSignatures; +import me.alpha432.oyvey.features.settings.Bind; +import me.alpha432.oyvey.features.settings.Setting; +import me.alpha432.oyvey.manager.ConfigManager; +import me.alpha432.oyvey.util.traits.Jsonable; +import me.alpha432.oyvey.util.traits.Toggleable; +import net.minecraft.ChatFormatting; +import org.joml.Vector2f; + +import static org.lwjgl.glfw.GLFW.GLFW_KEY_UNKNOWN; + +public class Module extends Feature implements Jsonable, Toggleable { + private final String description; + private final Category category; + + public final Setting enabled = bool("Enabled", false); + public final Setting drawn = bool("Drawn", true); + public final Setting bind = key("Keybind", new Bind(GLFW_KEY_UNKNOWN)); + public final Setting displayName; + + public boolean hidden; + + public Module(String name, String description, Category category) { + super(name); + this.displayName = str("DisplayName", name); + this.description = description; + this.category = category; + } + + public void onEnable() { + } + + public void onDisable() { + } + + public void onToggle() { + } + + public void onLoad() { + } + + public void onTick() { + } + + public void onRender2D(Render2DEvent event) { + } + + public void onRender3D(Render3DEvent event) { + } + + public void onUnload() { + } + + public String getDisplayInfo() { + return null; + } + + public void enable() { + this.enabled.setValue(true); + EVENT_BUS.register(this); + EVENT_BUS.post(new ClientEvent(ClientEvent.Type.TOGGLE_MODULE, this)); + this.onToggle(); + this.onEnable(); + } + + public void disable() { + this.enabled.setValue(false); + EVENT_BUS.unregister(this); + EVENT_BUS.post(new ClientEvent(ClientEvent.Type.TOGGLE_MODULE, this)); + this.onToggle(); + this.onDisable(); + } + + public String getDisplayName() { + return this.displayName.getValue(); + } + + public void setDisplayName(String name) { + Module module = OyVey.moduleManager.getModuleByDisplayName(name); + Module originalModule = OyVey.moduleManager.getModuleByName(name); + if (module == null && originalModule == null) { + Command.sendMessage("%s, name: %s, has been renamed to: %s", MessageSignatures.GENERAL, + getDisplayName(), getName(), name); + this.displayName.setValue(name); + return; + } + + Command.sendMessage("{red} A module of this name already exists.", MessageSignatures.GENERAL); + } + + @Override + public boolean isEnabled() { + return enabled.getValue(); + } + + @Override + public boolean isToggled() { + return isEnabled(); + } + + public String getDescription() { + return this.description; + } + + public boolean isDrawn() { + return this.drawn.getValue(); + } + + public void setDrawn(boolean drawn) { + this.drawn.setValue(drawn); + } + + public Category getCategory() { + return this.category; + } + + public String getInfo() { + return null; + } + + public Bind getBind() { + return this.bind.getValue(); + } + + public void setBind(int key) { + this.bind.setValue(new Bind(key)); + } + + public String getFullArrayString() { + return this.getDisplayName() + ChatFormatting.GRAY + (this.getDisplayInfo() != null ? " [" + ChatFormatting.WHITE + this.getDisplayInfo() + ChatFormatting.GRAY + "]" : ""); + } + + @Override + public JsonElement toJson() { + JsonObject object = new JsonObject(); + for (Setting setting : getSettings()) { + try { + if (setting.getValue() instanceof Bind keyBind) { + object.addProperty(setting.getName(), keyBind.getKey()); + } else if (setting.getValue() instanceof java.awt.Color color) { + object.addProperty(setting.getName(), color.getRed() + "," + color.getGreen() + "," + color.getBlue() + "," + color.getAlpha()); + } else if (setting.getValue() instanceof Vector2f pos) { + object.addProperty(setting.getName(), pos.x() + "," + pos.y()); + } else { + object.addProperty(setting.getName(), setting.getValueAsString()); + } + } catch (Throwable e) { + OyVey.LOGGER.error("Failed to create JSON field", e); + } + } + return object; + } + + @Override + public void fromJson(JsonElement element) { + if (element == null || element.isJsonNull()) return; + JsonObject object = element.getAsJsonObject(); + if (object.has("Enabled")) { + boolean enabled = Boolean.parseBoolean(object.get("Enabled").getAsString()); + if (enabled != isEnabled()) toggle(); + } + for (Setting setting : getSettings()) { + if (setting == this.enabled) continue; + try { + JsonElement settingElement = object.get(setting.getName()); + if (settingElement != null && !settingElement.isJsonNull()) { + ConfigManager.setValueFromJson(this, setting, settingElement); + } + } catch (Throwable throwable) { + OyVey.LOGGER.error("Failed to load from JSON", throwable); + } + } + } + + public enum Category { + COMBAT("Combat"), + MISC("Misc"), + RENDER("Render"), + MOVEMENT("Movement"), + PLAYER("Player"), + CLIENT("Client"), + HUD("Hud"); + + private final String name; + + Category(String name) { + this.name = name; + } + + public String getName() { + return this.name; + } + } +} diff --git a/src/main/java/me/alpha432/oyvey/features/modules/client/ClickGuiModule.java b/src/main/java/me/alpha432/oyvey/features/modules/client/ClickGuiModule.java new file mode 100644 index 0000000..d065657 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/modules/client/ClickGuiModule.java @@ -0,0 +1,73 @@ +package me.alpha432.oyvey.features.modules.client; + +import me.alpha432.oyvey.OyVey; +import me.alpha432.oyvey.event.impl.ClientEvent; +import me.alpha432.oyvey.event.system.Subscribe; +import me.alpha432.oyvey.features.commands.Command; +import me.alpha432.oyvey.features.gui.OyVeyGui; +import me.alpha432.oyvey.features.modules.Module; +import me.alpha432.oyvey.features.settings.Setting; +import org.lwjgl.glfw.GLFW; + +import java.awt.*; + +import static me.alpha432.oyvey.features.commands.MessageSignatures.GENERAL; + +public class ClickGuiModule extends Module { + private static ClickGuiModule INSTANCE; + + public final Setting prefix = str("Prefix", "."); + public final Setting color = color("Color", 0, 0, 255, 180); + public final Setting topColor = color("TopColor", 0, 0, 150, 240); + public final Setting rainbow = bool("Rainbow", false); + public final Setting rainbowHue = num("Delay", 240, 0, 600); + public final Setting rainbowBrightness = num("Brightness", 150.0f, 1.0f, 255.0f); + public final Setting rainbowSaturation = num("Saturation", 150.0f, 1.0f, 255.0f); + + public ClickGuiModule() { + super("ClickGui", "Opens the ClickGui", Module.Category.CLIENT); + setBind(GLFW.GLFW_KEY_RIGHT_SHIFT); + rainbowHue.setVisibility(v -> rainbow.getValue()); + rainbowBrightness.setVisibility(v -> rainbow.getValue()); + rainbowSaturation.setVisibility(v -> rainbow.getValue()); + INSTANCE = this; + } + + @Subscribe + public void onSettingChange(ClientEvent event) { + if (event.getType() == ClientEvent.Type.SETTING_UPDATE && event.getSetting().getFeature().equals(this)) { + if (event.getSetting().equals(this.prefix)) { + OyVey.commandManager.setCommandPrefix(this.prefix.getPlannedValue()); + Command.sendMessage("Prefix set to {global} %s", GENERAL, OyVey.commandManager.getCommandPrefix()); + } + if (event.getSetting().equals(this.color)) { + OyVey.colorManager.setColor(this.color.getPlannedValue()); + } + } + } + + @Override + public void onEnable() { + if (nullCheck()) { + return; + } + mc.setScreen(OyVeyGui.getClickGui()); + } + + @Override + public void onLoad() { + OyVey.colorManager.setColor(this.color.getValue()); + OyVey.commandManager.setCommandPrefix(this.prefix.getValue()); + } + + @Override + public void onTick() { + if (!(ClickGuiModule.mc.screen instanceof OyVeyGui)) { + this.disable(); + } + } + + public static ClickGuiModule getInstance() { + return INSTANCE; + } +} \ No newline at end of file diff --git a/src/main/java/me/alpha432/oyvey/features/modules/client/HudEditorModule.java b/src/main/java/me/alpha432/oyvey/features/modules/client/HudEditorModule.java new file mode 100644 index 0000000..7771fb2 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/modules/client/HudEditorModule.java @@ -0,0 +1,21 @@ +package me.alpha432.oyvey.features.modules.client; + +import me.alpha432.oyvey.features.gui.HudEditorScreen; +import me.alpha432.oyvey.features.modules.Module; + +public class HudEditorModule extends Module { + public HudEditorModule() { + super("HudEditor", "Edit HUD element positions", Category.CLIENT); + } + + @Override + public void onEnable() { + if (nullCheck()) { + disable(); + return; + } + mc.setScreen(HudEditorScreen.getInstance()); + disable(); + } +} + diff --git a/src/main/java/me/alpha432/oyvey/features/modules/client/HudModule.java b/src/main/java/me/alpha432/oyvey/features/modules/client/HudModule.java new file mode 100644 index 0000000..7dfa8b1 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/modules/client/HudModule.java @@ -0,0 +1,150 @@ +package me.alpha432.oyvey.features.modules.client; + +import me.alpha432.oyvey.OyVey; +import me.alpha432.oyvey.event.impl.input.MouseInputEvent; +import me.alpha432.oyvey.event.impl.render.Render2DEvent; +import me.alpha432.oyvey.event.system.Subscribe; +import me.alpha432.oyvey.features.gui.HudEditorScreen; +import me.alpha432.oyvey.features.modules.Module; +import me.alpha432.oyvey.features.settings.Setting; +import me.alpha432.oyvey.util.render.RenderUtil; +import net.minecraft.client.gui.screens.ChatScreen; +import org.joml.Vector2f; + +public abstract class HudModule extends Module { + public final Setting pos = vec2f("Position", 0.5f, 0.5f); + + private float dragX, dragY, width, height; + private boolean dragging, button; + + public HudModule(String name, String description, float width, float height) { + super(name, description, Category.HUD); + this.width = width; + this.height = height; + } + + public float getX() { + return mc.getWindow().getGuiScaledWidth() * pos.getValue().x(); + } + + public float getY() { + float heightWithChat = mc.getWindow().getGuiScaledHeight() - 14; + float baseY = mc.getWindow().getGuiScaledHeight() * pos.getValue().y(); + float combined = baseY + getHeight(); + + if (mc.screen instanceof ChatScreen) { + baseY = Math.min(combined, heightWithChat) - getHeight(); + } + return baseY; + } + + @Subscribe + public void onRender2DHud(Render2DEvent e) { + render(e); + } + + @Subscribe + public void onMouse(MouseInputEvent e) { + if (!(mc.screen instanceof HudEditorScreen) || nullCheck()) return; + + if (e.getAction() == 0) { + button = false; + dragging = false; + HudEditorScreen.getInstance().currentDragging = null; + } + + if (e.getAction() == 1 && isHovering()) { + button = true; + } + } + + protected void render(Render2DEvent e) { + if (!(mc.screen instanceof HudEditorScreen) || nullCheck()) return; + + float x = getX(); + float y = getY(); + + if (button) { + if (!dragging && isHovering() && HudEditorScreen.getInstance().currentDragging == null) { + dragX = getMouseX() - x; + dragY = getMouseY() - y; + dragging = true; + HudEditorScreen.getInstance().currentDragging = this; + } + + if (dragging) { + float finalX = Math.min(Math.max(getMouseX() - dragX, 0), + mc.getWindow().getGuiScaledWidth() - width); + float finalY = Math.min(Math.max(getMouseY() - dragY, 0), + mc.getWindow().getGuiScaledHeight() - height); + + pos.setValue(new Vector2f(finalX, finalY) + .div(mc.getWindow().getGuiScaledWidth(), mc.getWindow().getGuiScaledHeight())); + } + } else { + dragging = false; + } + + boolean shouldDrawDescription = isHovering() && !HudEditorScreen.getInstance().anyHover; + if (HudEditorScreen.getInstance().currentDragging != null) { + shouldDrawDescription = HudEditorScreen.getInstance().currentDragging == this; + } + + if (shouldDrawDescription) { + int textWidth = mc.font.width(getName()); + int textHeight = mc.font.lineHeight; + float textX = x + width + 5; + if (textX + textWidth > mc.getWindow().getGuiScaledWidth()) { + textX = x - 5 - textWidth; + } + e.getContext().drawString(mc.font, getName(), + (int) textX, (int) (y + height / 2f - textHeight / 2f), -1); + HudEditorScreen.getInstance().anyHover = true; + } + + RenderUtil.rect(e.getContext(), + x - 1, y - 1, x + width + 1, y + height + 1, + OyVey.colorManager.getColor().getRGB(), 1.0f); + } + + public int getMouseX() { + return (int) (mc.mouseHandler.xpos() / mc.getWindow().getGuiScale()); + } + + public int getMouseY() { + return (int) (mc.mouseHandler.ypos() / mc.getWindow().getGuiScale()); + } + + public void setBounds(float x, float y, float width, float height) { + this.width = width; + this.height = height; + pos.setValue(new Vector2f(x, y) + .div(mc.getWindow().getGuiScaledWidth(), mc.getWindow().getGuiScaledHeight())); + } + + public boolean isHovering() { + float x = getX(); + float y = getY(); + int mouseX = getMouseX(); + int mouseY = getMouseY(); + + return mouseX >= x - 1 && mouseX <= x + width + 1 && + mouseY >= y - 1 && mouseY <= y + height + 1; + } + + public float getWidth() { + return width; + } + + public float getHeight() { + return height; + } + + public void setWidth(float width) { + this.width = width; + } + + public void setHeight(float height) { + this.height = height; + } +} diff --git a/src/main/java/me/alpha432/oyvey/features/modules/client/NotificationsModule.java b/src/main/java/me/alpha432/oyvey/features/modules/client/NotificationsModule.java new file mode 100644 index 0000000..4bdbbba --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/modules/client/NotificationsModule.java @@ -0,0 +1,39 @@ +package me.alpha432.oyvey.features.modules.client; + +import me.alpha432.oyvey.event.impl.ClientEvent; +import me.alpha432.oyvey.event.system.Subscribe; +import me.alpha432.oyvey.features.modules.Module; +import me.alpha432.oyvey.features.settings.Setting; +import me.alpha432.oyvey.util.TextUtil; +import me.alpha432.oyvey.util.chat.ChatUtil; + +import static me.alpha432.oyvey.util.chat.SimpleSignature.from; + +public class NotificationsModule extends Module { + private static final String MODULE_FORMAT = "{gray} %s %s%s"; + + public final Setting moduleToggle = bool("ModuleToggle", true); + + public NotificationsModule() { + super("Notifications", "Displays notifications for various client events", Category.CLIENT); + } + + @Subscribe + public void onClient(ClientEvent event) { + if (!moduleToggle.getValue() + || event.getType() != ClientEvent.Type.TOGGLE_MODULE + || event.getFeature() instanceof ClickGuiModule) { + return; + } + + boolean moduleState = event.getFeature().isEnabled(); + String name = event.getFeature() instanceof Module module + ? module.getDisplayName() + : event.getFeature().getName(); + + ChatUtil.sendMessage(TextUtil.text(MODULE_FORMAT, + name, + moduleState ? "{green}" : "{red}", + moduleState ? "on" : "off"), from(event.getFeature().getName())); + } +} diff --git a/src/main/java/me/alpha432/oyvey/features/modules/combat/CriticalsModule.java b/src/main/java/me/alpha432/oyvey/features/modules/combat/CriticalsModule.java new file mode 100644 index 0000000..eaadfee --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/modules/combat/CriticalsModule.java @@ -0,0 +1,37 @@ +package me.alpha432.oyvey.features.modules.combat; + +import me.alpha432.oyvey.event.impl.network.PacketEvent; +import me.alpha432.oyvey.event.system.Subscribe; +import me.alpha432.oyvey.features.modules.Module; +import net.minecraft.network.protocol.game.ServerboundInteractPacket; +import net.minecraft.network.protocol.game.ServerboundMovePlayerPacket; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.boss.enderdragon.EndCrystal; + +public class CriticalsModule extends Module { + public CriticalsModule() { + super("Criticals", "Makes you do critical hits", Category.COMBAT); + } + + @Subscribe + private void onPacketSend(PacketEvent.Send event) { + if (event.getPacket() instanceof ServerboundInteractPacket packet && packet.action.getType() == ServerboundInteractPacket.ActionType.ATTACK) { + Entity entity = mc.level.getEntity(packet.entityId); + if (entity == null + || entity instanceof EndCrystal + || !mc.player.onGround() + || !(entity instanceof LivingEntity)) return; + + boolean bl = mc.player.horizontalCollision; + mc.player.connection.send(new ServerboundMovePlayerPacket.Pos(mc.player.getX(), mc.player.getY() + 0.1f, mc.player.getZ(), false, bl)); + mc.player.connection.send(new ServerboundMovePlayerPacket.Pos(mc.player.getX(), mc.player.getY(), mc.player.getZ(), false, bl)); + mc.player.crit(entity); + } + } + + @Override + public String getDisplayInfo() { + return "Packet"; + } +} diff --git a/src/main/java/me/alpha432/oyvey/features/modules/combat/KeyPearlModule.java b/src/main/java/me/alpha432/oyvey/features/modules/combat/KeyPearlModule.java new file mode 100644 index 0000000..8c7ee44 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/modules/combat/KeyPearlModule.java @@ -0,0 +1,28 @@ +package me.alpha432.oyvey.features.modules.combat; + +import me.alpha432.oyvey.features.modules.Module; +import me.alpha432.oyvey.features.settings.Setting; +import me.alpha432.oyvey.util.inventory.InventoryUtil; +import me.alpha432.oyvey.util.inventory.Result; +import net.minecraft.world.item.Items; + +import static me.alpha432.oyvey.util.inventory.InventoryUtil.FULL_SCOPE; +import static me.alpha432.oyvey.util.inventory.InventoryUtil.HOTBAR_SCOPE; + +public class KeyPearlModule extends Module { + private final Setting inventory = bool("Inventory", false); + + public KeyPearlModule() { + super("KeyPearl", "Throws a pearl when enabled.", Category.COMBAT); + } + + @Override + public void onEnable() { + disable(); + + if (nullCheck()) return; + + Result result = InventoryUtil.find(Items.ENDER_PEARL, inventory.getValue() ? FULL_SCOPE : HOTBAR_SCOPE); + InventoryUtil.withSwap(result, () -> mc.gameMode.useItem(mc.player, result.hand())); + } +} diff --git a/src/main/java/me/alpha432/oyvey/features/modules/combat/KillAuraModule.java b/src/main/java/me/alpha432/oyvey/features/modules/combat/KillAuraModule.java new file mode 100644 index 0000000..bbf8cee --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/modules/combat/KillAuraModule.java @@ -0,0 +1,77 @@ +package me.alpha432.oyvey.features.modules.combat; + +import me.alpha432.oyvey.OyVey; +import me.alpha432.oyvey.event.impl.entity.player.TickEvent; +import me.alpha432.oyvey.event.system.Subscribe; +import me.alpha432.oyvey.features.modules.Module; +import me.alpha432.oyvey.features.settings.Setting; +import me.alpha432.oyvey.util.models.Angles; +import net.minecraft.tags.ItemTags; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; + +public class KillAuraModule extends Module { + private final Setting delay = num("Delay", 1f, 0f, 1f); + private final Setting range = num("Range", 3f, 1f, 6f); + private final Setting onlyWeapon = bool("OnlyWeapon", false); + private final Setting sync = bool("MovementSync", false); + + public KillAuraModule() { + super("KillAura", "Attacks nearby players.", Category.COMBAT); + } + + @Subscribe public void onPreTick(TickEvent.Pre event) { + if (isOnCooldown()) + return; + + if (onlyWeapon.getValue() && !isHoldingWeapon()) + return; + + Player target = findPlayerTarget(); + if (target == null) + return; + + Angles angles = Angles.entity(target); + int priority = 0; + + if (sync.getValue()) { + OyVey.rotationManager.sync(angles, priority, () -> attack(target)); + } else { + OyVey.rotationManager.motion(angles, priority, () -> attack(target)); + } + } + + private void attack(Entity entity) { + if (nullCheck() || !entity.isAlive() || entity.isRemoved() || entity.distanceTo(mc.player) > range.getValue()) + return; + mc.gameMode.attack(mc.player, entity); + mc.player.swing(InteractionHand.MAIN_HAND); + } + + private boolean isOnCooldown() { + float attackDelay = sync.getValue() ? 1 : 0; + return mc.player.getAttackStrengthScale(attackDelay) < delay.getValue(); + } + + private boolean isHoldingWeapon() { + ItemStack stack = mc.player.getMainHandItem(); + return stack.is(ItemTags.SWORDS) || stack.is(ItemTags.AXES) || stack.is(ItemTags.SPEARS) + || stack.is(Items.MACE) || stack.is(Items.TRIDENT); + } + + private Player findPlayerTarget() { + Player target = null; + float min = range.getValue(); + for (Player entity : mc.level.players()) { + float dist = entity.distanceTo(mc.player); + if (entity == mc.player || dist > min) continue; + if (OyVey.friendManager.isFriend(entity)) continue; + target = entity; + min = dist; + } + return target; + } +} diff --git a/src/main/java/me/alpha432/oyvey/features/modules/hud/CoordinatesHudModule.java b/src/main/java/me/alpha432/oyvey/features/modules/hud/CoordinatesHudModule.java new file mode 100644 index 0000000..668b342 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/modules/hud/CoordinatesHudModule.java @@ -0,0 +1,43 @@ +package me.alpha432.oyvey.features.modules.hud; + +import me.alpha432.oyvey.event.impl.render.Render2DEvent; +import me.alpha432.oyvey.features.modules.client.HudModule; +import me.alpha432.oyvey.features.settings.Setting; +import net.minecraft.resources.ResourceKey; +import net.minecraft.world.level.Level; + +public class CoordinatesHudModule extends HudModule { + public final Setting nether = bool("Nether", false); + + public CoordinatesHudModule() { + super("Coordinates", "Display coordinates", 150, 20); + } + + @Override + protected void render(Render2DEvent e) { + super.render(e); + + if (nullCheck()) return; + + String coordsStr = String.format("X: %d Y: %d Z: %d", + mc.player.getBlockX(), + mc.player.getBlockY(), + mc.player.getBlockZ()); + + if (nether.getValue()) { + ResourceKey dimension = mc.player.level().dimension(); + if (dimension == Level.NETHER) { + coordsStr += String.format(" [%d, %d]", mc.player.getBlockX() * 8, mc.player.getBlockZ() * 8); + } else if (dimension == Level.OVERWORLD) { + coordsStr += String.format(" [%d, %d]", Math.floorDiv(mc.player.getBlockX(), 8), Math.floorDiv(mc.player.getBlockZ(), 8)); + } + } + + e.getContext().drawString(mc.font, coordsStr, + (int) getX(), (int) getY(), -1); + + setWidth(mc.font.width(coordsStr)); + setHeight(mc.font.lineHeight); + } +} + diff --git a/src/main/java/me/alpha432/oyvey/features/modules/hud/WatermarkHudModule.java b/src/main/java/me/alpha432/oyvey/features/modules/hud/WatermarkHudModule.java new file mode 100644 index 0000000..34841ab --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/modules/hud/WatermarkHudModule.java @@ -0,0 +1,36 @@ +package me.alpha432.oyvey.features.modules.hud; + +import me.alpha432.oyvey.event.impl.render.Render2DEvent; +import me.alpha432.oyvey.features.modules.client.HudModule; +import me.alpha432.oyvey.features.settings.Setting; +import me.alpha432.oyvey.util.BuildConfig; +import me.alpha432.oyvey.util.TextUtil; +import net.minecraft.network.chat.Component; + +public class WatermarkHudModule extends HudModule { + public final Setting text = str("Text", BuildConfig.NAME); + public final Setting fullVersion = new Setting<>("FullVersion", false); + + public WatermarkHudModule() { + super("Watermark", "Display watermark", 100, 10); + if (BuildConfig.USING_GIT) { + register(fullVersion); + } + } + + @Override + protected void render(Render2DEvent e) { + super.render(e); + String watermarkString = "{global} %s {} %s"; + if (fullVersion.getValue() && BuildConfig.USING_GIT) { + watermarkString += "/" + BuildConfig.BRANCH + "-" + BuildConfig.HASH; + } + + Component component = TextUtil.text(watermarkString, text.getValue(), BuildConfig.VERSION); + e.getContext().drawString(mc.font, component, (int) getX(), (int) getY(), -1); + + setWidth(mc.font.width(component)); + setHeight(mc.font.lineHeight); + } +} + diff --git a/src/main/java/me/alpha432/oyvey/features/modules/misc/MCFModule.java b/src/main/java/me/alpha432/oyvey/features/modules/misc/MCFModule.java new file mode 100644 index 0000000..5cdc6cf --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/modules/misc/MCFModule.java @@ -0,0 +1,48 @@ +package me.alpha432.oyvey.features.modules.misc; + +import me.alpha432.oyvey.OyVey; +import me.alpha432.oyvey.features.commands.Command; +import me.alpha432.oyvey.features.modules.Module; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import org.lwjgl.glfw.GLFW; + +import static me.alpha432.oyvey.util.chat.SimpleSignature.from; + +public class MCFModule extends Module { + private boolean pressed; + + public MCFModule() { + super("MCF", "Middle click friend", Category.MISC); + } + + @Override + public void onTick() { + if (mc.screen != null) { + pressed = false; + return; + } + + if (GLFW.glfwGetMouseButton(mc.getWindow().handle(), 2) == 1) { + if (!pressed) click(); + pressed = true; + } else { + pressed = false; + } + } + + private void click() { + Entity targetedEntity = mc.crosshairPickEntity; + if (!(targetedEntity instanceof Player)) return; + String name = ((Player) targetedEntity).getGameProfile().name(); + + if (OyVey.friendManager.isFriend(name)) { + OyVey.friendManager.removeFriend(name); + + Command.sendMessage("{red} %s has been unfriended.", from(getName()), name); + } else { + OyVey.friendManager.addFriend(name); + Command.sendMessage("{aqua} %s has been friended.", from(getName()), name); + } + } +} diff --git a/src/main/java/me/alpha432/oyvey/features/modules/movement/FastAccelModule.java b/src/main/java/me/alpha432/oyvey/features/modules/movement/FastAccelModule.java new file mode 100644 index 0000000..3d694ee --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/modules/movement/FastAccelModule.java @@ -0,0 +1,34 @@ +package me.alpha432.oyvey.features.modules.movement; + +import me.alpha432.oyvey.event.impl.entity.player.MoveEvent; +import me.alpha432.oyvey.event.system.Subscribe; +import me.alpha432.oyvey.features.modules.Module; +import me.alpha432.oyvey.features.settings.Setting; +import me.alpha432.oyvey.util.MovementUtil; +import net.minecraft.world.entity.MoverType; +import org.joml.Vector2f; + +public class FastAccelModule extends Module { + private final Setting speed = num("Speed", 1f, 0.5f, 2f); + private final Setting slowness = bool("Slowness", true); + + public FastAccelModule() { + super("FastAccel", "Makes the player accelerate faster while walking", Category.MOVEMENT); + } + + @Subscribe + private void onMove(MoveEvent event) { + if (nullCheck() || event.getType() != MoverType.SELF) return; + if (mc.player.isInLiquid() || mc.player.isFallFlying() + || mc.player.getAbilities().flying || mc.player.isSpectator()) return; + + double speed = MovementUtil.SPRINT_SPEED * this.speed.getValue() * MovementUtil.getSpeedFactor(true, slowness.getValue()); + + if (event.getMovement().horizontalDistance() > speed) { + speed = event.getMovement().horizontalDistance(); + } + + Vector2f motion = MovementUtil.calcMoveVector(mc.player.getYRot(), speed); + event.setMovement(motion.x, event.getMovement().y, motion.y); + } +} diff --git a/src/main/java/me/alpha432/oyvey/features/modules/movement/ReverseStepModule.java b/src/main/java/me/alpha432/oyvey/features/modules/movement/ReverseStepModule.java new file mode 100644 index 0000000..c79c47d --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/modules/movement/ReverseStepModule.java @@ -0,0 +1,16 @@ +package me.alpha432.oyvey.features.modules.movement; + +import me.alpha432.oyvey.features.modules.Module; + +public class ReverseStepModule extends Module { + public ReverseStepModule() { + super("ReverseStep", "step but reversed..", Category.MOVEMENT); + } + + @Override + public void onTick() { + if (nullCheck()) return; + if (mc.player.isInLava() || mc.player.isInWater() || !mc.player.onGround()) return; + mc.player.push(0, -1, 0); + } +} diff --git a/src/main/java/me/alpha432/oyvey/features/modules/movement/StepModule.java b/src/main/java/me/alpha432/oyvey/features/modules/movement/StepModule.java new file mode 100644 index 0000000..bccb3ad --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/modules/movement/StepModule.java @@ -0,0 +1,36 @@ +package me.alpha432.oyvey.features.modules.movement; + +import me.alpha432.oyvey.features.modules.Module; +import me.alpha432.oyvey.features.settings.Setting; +import net.minecraft.world.entity.ai.attributes.Attributes; + +public class StepModule extends Module { + private final Setting height = num("Height", 2f, 1f, 3f); + + public StepModule() { + super("Step", "step..", Category.MOVEMENT); + } + + private float prev; + + @Override + public void onEnable() { + if (nullCheck()) { + prev = 0.6f; + return; + } + prev = mc.player.maxUpStep(); + } + + @Override + public void onDisable() { + if (nullCheck()) return; + mc.player.getAttribute(Attributes.STEP_HEIGHT).setBaseValue(prev); + } + + @Override + public void onTick() { + if (nullCheck()) return; + mc.player.getAttribute(Attributes.STEP_HEIGHT).setBaseValue(height.getValue()); + } +} diff --git a/src/main/java/me/alpha432/oyvey/features/modules/player/FastPlaceModule.java b/src/main/java/me/alpha432/oyvey/features/modules/player/FastPlaceModule.java new file mode 100644 index 0000000..8bddd01 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/modules/player/FastPlaceModule.java @@ -0,0 +1,19 @@ +package me.alpha432.oyvey.features.modules.player; + +import me.alpha432.oyvey.features.modules.Module; +import net.minecraft.world.item.Items; + +public class FastPlaceModule extends Module { + public FastPlaceModule() { + super("FastPlace", "Makes you throw exp faster", Category.PLAYER); + } + + @Override + public void onTick() { + if (nullCheck()) return; + + if (mc.player.isHolding(Items.EXPERIENCE_BOTTLE)) { + mc.rightClickDelay = 0; + } + } +} diff --git a/src/main/java/me/alpha432/oyvey/features/modules/player/NoFallModule.java b/src/main/java/me/alpha432/oyvey/features/modules/player/NoFallModule.java new file mode 100644 index 0000000..889bfc7 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/modules/player/NoFallModule.java @@ -0,0 +1,21 @@ +package me.alpha432.oyvey.features.modules.player; + +import me.alpha432.oyvey.OyVey; +import me.alpha432.oyvey.features.modules.Module; +import net.minecraft.network.protocol.game.ServerboundMovePlayerPacket; + +public class NoFallModule extends Module { + public NoFallModule() { + super("NoFall", "Removes fall damage", Category.PLAYER); + } + + @Override + public void onTick() { + if (!mc.player.onGround() && OyVey.positionManager.getFallDistance() > 3) { + boolean bl = mc.player.horizontalCollision; + ServerboundMovePlayerPacket.PosRot packet = new ServerboundMovePlayerPacket.PosRot(mc.player.getX(), mc.player.getY() + 0.000000001, mc.player.getZ(), + mc.player.getYRot(), mc.player.getXRot(), false, bl); + mc.player.connection.send(packet); + } + } +} diff --git a/src/main/java/me/alpha432/oyvey/features/modules/player/VelocityModule.java b/src/main/java/me/alpha432/oyvey/features/modules/player/VelocityModule.java new file mode 100644 index 0000000..8901e92 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/modules/player/VelocityModule.java @@ -0,0 +1,24 @@ +package me.alpha432.oyvey.features.modules.player; + +import me.alpha432.oyvey.event.impl.network.PacketEvent; +import me.alpha432.oyvey.event.system.Subscribe; +import me.alpha432.oyvey.features.modules.Module; +import net.minecraft.network.protocol.game.ClientboundExplodePacket; +import net.minecraft.network.protocol.game.ClientboundSetEntityMotionPacket; + +public class VelocityModule extends Module { + public VelocityModule() { + super("Velocity", "Removes velocity from explosions and entities", Category.PLAYER); + } + + @Subscribe + private void onPacketReceive(PacketEvent.Receive event) { + if (nullCheck()) + return; + + if (event.getPacket() instanceof ClientboundSetEntityMotionPacket packet && packet.getId() == mc.player.getId() + || event.getPacket() instanceof ClientboundExplodePacket) { + event.cancel(); + } + } +} diff --git a/src/main/java/me/alpha432/oyvey/features/modules/render/BlockHighlightModule.java b/src/main/java/me/alpha432/oyvey/features/modules/render/BlockHighlightModule.java new file mode 100644 index 0000000..9a25af8 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/modules/render/BlockHighlightModule.java @@ -0,0 +1,39 @@ +package me.alpha432.oyvey.features.modules.render; + +import me.alpha432.oyvey.event.impl.render.Render3DEvent; +import me.alpha432.oyvey.event.impl.render.RenderBlockOutlineEvent; +import me.alpha432.oyvey.event.system.Subscribe; +import me.alpha432.oyvey.features.modules.Module; +import me.alpha432.oyvey.features.settings.Setting; +import me.alpha432.oyvey.util.render.RenderUtil; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.shapes.VoxelShape; + +import java.awt.*; + +public class BlockHighlightModule extends Module { + public final Setting color = color("Color", 255, 0, 0, 255); + public final Setting lineWidth = num("LineWidth", 1.0f, 0.1f, 5.0f); + + public BlockHighlightModule() { + super("BlockHighlight", "Draws box at the block that you are looking at", Category.RENDER); + } + + @Override + public void onRender3D(Render3DEvent event) { + if (mc.hitResult instanceof BlockHitResult result) { + VoxelShape shape = mc.level.getBlockState(result.getBlockPos()).getShape(mc.level, result.getBlockPos()); + if (shape.isEmpty() || result.getType() == HitResult.Type.MISS) return; + AABB aabb = shape.bounds(); + aabb = aabb.move(result.getBlockPos()); + RenderUtil.drawBox(event.getMatrix(), aabb, color.getValue(), lineWidth.getValue()); + } + } + + @Subscribe + public void onRenderBlockOutline(RenderBlockOutlineEvent event) { + event.cancel(); + } +} diff --git a/src/main/java/me/alpha432/oyvey/features/settings/Bind.java b/src/main/java/me/alpha432/oyvey/features/settings/Bind.java new file mode 100644 index 0000000..a6507b8 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/settings/Bind.java @@ -0,0 +1,61 @@ +package me.alpha432.oyvey.features.settings; + +import com.mojang.blaze3d.platform.InputConstants; +import me.alpha432.oyvey.util.traits.Util; +import net.minecraft.client.input.KeyEvent; +import org.lwjgl.glfw.GLFW; + +public class Bind implements Util { + private int key; + + public Bind(int key) { + this.key = key; + } + + public static Bind keyboard(int key) { + return new Bind(key); + } + + public static Bind mouse(int key) { + return new Bind(-key - 2); + } + + public static Bind none() { + return new Bind(-1); + } + + public int getKey() { + return this.key; + } + + public void setKey(int key) { + this.key = key; + } + + public boolean isEmpty() { + return this.key == -1; + } + + public boolean isMouse() { + return key < -1; + } + + public String toString() { + if (this.isEmpty()) return "None"; + if (this.key < -1) return "Mouse " + (-this.key - 1); + return this.capitalise(InputConstants.getKey(new KeyEvent(this.key, 0, 0)).getName().replace("key.keyboard.", "")); + } + + public boolean isDown() { + if (this.isEmpty()) return false; + if (this.key < -1) return GLFW.glfwGetMouseButton(mc.getWindow().handle(), -this.key - 2) == 1; + return GLFW.glfwGetKey(mc.getWindow().handle(), this.getKey()) == 1; + } + + private String capitalise(String str) { + if (str.isEmpty()) { + return ""; + } + return Character.toUpperCase(str.charAt(0)) + (str.length() != 1 ? str.substring(1).toLowerCase() : ""); + } +} \ No newline at end of file diff --git a/src/main/java/me/alpha432/oyvey/features/settings/EnumConverter.java b/src/main/java/me/alpha432/oyvey/features/settings/EnumConverter.java new file mode 100644 index 0000000..2b05c8d --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/settings/EnumConverter.java @@ -0,0 +1,51 @@ +package me.alpha432.oyvey.features.settings; + +import com.google.common.base.Converter; +import com.google.gson.JsonElement; +import com.google.gson.JsonPrimitive; + +@SuppressWarnings("unchecked") +public class EnumConverter> extends Converter { + private final Class clazz; + + public EnumConverter(Class clazz) { + this.clazz = clazz; + } + + public static > int currentEnum(T clazz) { + for (int i = 0; i < clazz.getDeclaringClass().getEnumConstants().length; ++i) { + T e = (T) clazz.getDeclaringClass().getEnumConstants()[i]; + if (!e.name().equalsIgnoreCase(clazz.name())) continue; + return i; + } + return -1; + } + + public static > T increaseEnum(T clazz) { + int index = EnumConverter.currentEnum(clazz); + for (int i = 0; i < clazz.getDeclaringClass().getEnumConstants().length; ++i) { + T e = (T) clazz.getDeclaringClass().getEnumConstants()[i]; + if (i != index + 1) continue; + return e; + } + return (T) clazz.getDeclaringClass().getEnumConstants()[0]; + } + + public static > String getProperName(T clazz) { + return Character.toUpperCase(clazz.name().charAt(0)) + clazz.name().toLowerCase().substring(1); + } + + public JsonElement doForward(Enum anEnum) { + return new JsonPrimitive(anEnum.name()); + } + + public T doBackward(JsonElement jsonElement) { + String name = jsonElement.getAsString(); + for (T constant : this.clazz.getEnumConstants()) { + if (constant.name().equalsIgnoreCase(name) || constant.toString().equalsIgnoreCase(name)) { + return constant; + } + } + return null; + } +} \ No newline at end of file diff --git a/src/main/java/me/alpha432/oyvey/features/settings/Setting.java b/src/main/java/me/alpha432/oyvey/features/settings/Setting.java new file mode 100644 index 0000000..6ffef74 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/settings/Setting.java @@ -0,0 +1,287 @@ +package me.alpha432.oyvey.features.settings; + +import me.alpha432.oyvey.event.impl.ClientEvent; +import me.alpha432.oyvey.features.Feature; +import org.joml.Vector2f; + +import java.awt.*; +import java.util.Objects; +import java.util.function.Predicate; + +import static me.alpha432.oyvey.util.traits.Util.EVENT_BUS; + +public class Setting { + private final String name; + private final T defaultValue; + private T value; + private T plannedValue; + private T min; + private T max; + private boolean hasRestriction; + private Predicate visibility; + private String description; + private Feature feature; + + public Setting(String name, T defaultValue) { + this.name = name; + this.defaultValue = defaultValue; + this.value = copy(defaultValue); + this.plannedValue = this.value; + this.description = ""; + } + + public Setting(String name, T defaultValue, String description) { + this.name = name; + this.defaultValue = defaultValue; + this.value = copy(defaultValue); + this.plannedValue = this.value; + this.description = description; + } + + public Setting(String name, T defaultValue, T min, T max, String description) { + this.name = name; + this.defaultValue = defaultValue; + this.value = copy(defaultValue); + this.min = min; + this.max = max; + this.plannedValue = this.value; + this.description = description; + this.hasRestriction = true; + } + + public Setting(String name, T defaultValue, T min, T max) { + this.name = name; + this.defaultValue = defaultValue; + this.value = copy(defaultValue); + this.min = min; + this.max = max; + this.plannedValue = this.value; + this.description = ""; + this.hasRestriction = true; + } + + public Setting(String name, T defaultValue, T min, T max, Predicate visibility, String description) { + this.name = name; + this.defaultValue = defaultValue; + this.value = copy(defaultValue); + this.min = min; + this.max = max; + this.plannedValue = this.value; + this.visibility = visibility; + this.description = description; + this.hasRestriction = true; + } + + public Setting(String name, T defaultValue, T min, T max, Predicate visibility) { + this.name = name; + this.defaultValue = defaultValue; + this.value = copy(defaultValue); + this.min = min; + this.max = max; + this.plannedValue = this.value; + this.visibility = visibility; + this.description = ""; + this.hasRestriction = true; + } + + public Setting(String name, T defaultValue, Predicate visibility) { + this.name = name; + this.defaultValue = defaultValue; + this.value = copy(defaultValue); + this.visibility = visibility; + this.plannedValue = this.value; + } + + public String getName() { + return this.name; + } + + public T getValue() { + return this.value; + } + + public void setValue(T value) { + this.setPlannedValue(value); + if (this.hasRestriction) { + if (((Number) this.min).floatValue() > ((Number) value).floatValue()) { + this.setPlannedValue(this.min); + } + if (((Number) this.max).floatValue() < ((Number) value).floatValue()) { + this.setPlannedValue(this.max); + } + } + ClientEvent event = new ClientEvent(this); + EVENT_BUS.post(event); + if (!event.isCancelled()) { + this.value = this.plannedValue; + } else { + this.plannedValue = this.value; + } + } + + public void reset() { + setValue(copy(getDefaultValue())); + } + + @SuppressWarnings("unchecked") + private static T copy(T value) { + if (value instanceof Vector2f vector) { + return (T) new Vector2f(vector); + } + return value; + } + + public T getPlannedValue() { + return this.plannedValue; + } + + public void setPlannedValue(T value) { + this.plannedValue = value; + } + + public T getMin() { + return this.min; + } + + public void setMin(T min) { + this.min = min; + } + + public T getMax() { + return this.max; + } + + public void setMax(T max) { + this.max = max; + } + + public void setValueNoEvent(T value) { + this.setPlannedValue(value); + if (this.hasRestriction) { + if (((Number) this.min).floatValue() > ((Number) value).floatValue()) { + this.setPlannedValue(this.min); + } + if (((Number) this.max).floatValue() < ((Number) value).floatValue()) { + this.setPlannedValue(this.max); + } + } + this.value = this.plannedValue; + } + + public Feature getFeature() { + return this.feature; + } + + public void setFeature(Feature feature) { + this.feature = feature; + } + + public int getEnum(String input) { + for (int i = 0; i < this.value.getClass().getEnumConstants().length; ++i) { + Enum e = (Enum) this.value.getClass().getEnumConstants()[i]; + if (!e.name().equalsIgnoreCase(input)) continue; + return i; + } + return -1; + } + + @SuppressWarnings("unchecked") + public void setEnumValue(String value) { + for (Enum e : ((Enum) this.value).getClass().getEnumConstants()) { + if (!e.name().equalsIgnoreCase(value)) continue; + this.value = (T) e; + } + } + + public String currentEnumName() { + return EnumConverter.getProperName((Enum) this.value); + } + + public int currentEnum() { + return EnumConverter.currentEnum((Enum) this.value); + } + + @SuppressWarnings("unchecked") + public void increaseEnum() { + this.plannedValue = (T) EnumConverter.increaseEnum((Enum) this.value); + ClientEvent event = new ClientEvent(this); + EVENT_BUS.post(event); + if (!event.isCancelled()) { + this.value = this.plannedValue; + } else { + this.plannedValue = this.value; + } + } + + @SuppressWarnings("unchecked") + public void increaseEnumNoEvent() { + this.value = (T) EnumConverter.increaseEnum((Enum) this.value); + } + + public String getType() { + if (this.isEnumSetting()) { + return "Enum"; + } + if (this.isColorSetting()) { + return "Color"; + } + if (this.isVec2fSetting()) { + return "Pos"; + } + return this.getClassName(this.defaultValue); + } + + public String getClassName(K value) { + return value.getClass().getSimpleName(); + } + + public String getDescription() { + return Objects.requireNonNullElse(this.description, ""); + } + + public boolean isNumberSetting() { + return this.value instanceof Number; + } + + public boolean isEnumSetting() { + return this.value instanceof Enum; + } + + public boolean isStringSetting() { + return this.value instanceof String; + } + + public boolean isColorSetting() { + return this.value instanceof java.awt.Color; + } + + public boolean isVec2fSetting() { + return this.value instanceof Vector2f; + } + + public T getDefaultValue() { + return this.defaultValue; + } + + public String getValueAsString() { + if (value instanceof Color color) { + return "%d, %d, %d, %d".formatted(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()); + } + if (value instanceof Enum e) { + return e.name(); + } + return this.value.toString(); + } + + public boolean hasRestriction() { + return this.hasRestriction; + } + + public void setVisibility(Predicate visibility) { + this.visibility = visibility; + } + + public boolean isVisible() { + return this.visibility == null || this.visibility.test(this.getValue()); + } +} \ No newline at end of file diff --git a/src/main/java/me/alpha432/oyvey/features/settings/SettingFactory.java b/src/main/java/me/alpha432/oyvey/features/settings/SettingFactory.java new file mode 100644 index 0000000..8c612f6 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/features/settings/SettingFactory.java @@ -0,0 +1,46 @@ +package me.alpha432.oyvey.features.settings; + +import org.joml.Vector2f; + +import java.awt.*; + +public interface SettingFactory { + > T register(T setting); + + default Setting bool(String name, boolean value) { + return register(new Setting<>(name, value)); + } + + default Setting num(String name, T value, T min, T max) { + return register(new Setting<>(name, value, min, max)); + } + + default Setting str(String name, String value) { + return register(new Setting<>(name, value)); + } + + default > Setting mode(String name, T value) { + return register(new Setting<>(name, value)); + } + + default Setting key(String name, Bind bind) { + return register(new Setting<>(name, bind)); + } + + default Setting color(String name, Color value) { + return register(new Setting<>(name, value)); + } + + default Setting color(String name, int r, int g, int b, int a) { + return register(new Setting<>(name, new Color(r, g, b, a))); + } + + default Setting vec2f(String name, Vector2f value) { + return register(new Setting<>(name, value)); + } + + default Setting vec2f(String name, float x, float y) { + return register(new Setting<>(name, new Vector2f(x, y))); + } + +} diff --git a/src/main/java/me/alpha432/oyvey/manager/ColorManager.java b/src/main/java/me/alpha432/oyvey/manager/ColorManager.java new file mode 100644 index 0000000..c85624c --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/manager/ColorManager.java @@ -0,0 +1,39 @@ +package me.alpha432.oyvey.manager; + +import me.alpha432.oyvey.features.modules.client.ClickGuiModule; +import me.alpha432.oyvey.util.ColorUtil; + +import java.awt.*; + +public class ColorManager { + private Color color = new Color(0, 0, 255, 180); + + public void init() { + ClickGuiModule ui = ClickGuiModule.getInstance(); + setColor(ui.color.getValue()); + } + + public Color getColor() { + return this.color; + } + + public void setColor(Color color) { + this.color = color; + } + + public int getColorAsInt() { + return this.color.getRGB(); + } + + public int getColorAsIntFullAlpha() { + return new Color(this.color.getRed(), this.color.getGreen(), this.color.getBlue(), 255).getRGB(); + } + + public int getColorWithAlpha(float offset, int alpha) { + if (ClickGuiModule.getInstance().rainbow.getValue()) { + int rgb = ColorUtil.rainbow((int) (offset / 10f * ClickGuiModule.getInstance().rainbowHue.getValue())).getRGB(); + return (rgb & 0xFFFFFF) | ((alpha & 0xFF) << 24); + } + return new Color(this.color.getRed(), this.color.getGreen(), this.color.getBlue(), alpha).getRGB(); + } +} diff --git a/src/main/java/me/alpha432/oyvey/manager/CommandManager.java b/src/main/java/me/alpha432/oyvey/manager/CommandManager.java new file mode 100644 index 0000000..fa1727b --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/manager/CommandManager.java @@ -0,0 +1,114 @@ +package me.alpha432.oyvey.manager; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import me.alpha432.oyvey.OyVey; +import me.alpha432.oyvey.features.Feature; +import me.alpha432.oyvey.features.commands.Command; +import me.alpha432.oyvey.features.commands.impl.*; +import me.alpha432.oyvey.util.traits.Jsonable; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.*; + +import static me.alpha432.oyvey.features.commands.Command.SINGLE_FAILURE; +import static me.alpha432.oyvey.features.commands.MessageSignatures.GENERAL; +import static me.alpha432.oyvey.features.commands.MessageSignatures.SUCCESS; + +public class CommandManager extends Feature implements Jsonable { + private static final Logger LOGGER = LogManager.getLogger("Commands"); + + private final CommandDispatcher dispatcher = new CommandDispatcher<>(); + private final Map commandAliasMap = new LinkedHashMap<>(); + private final List commandList = new LinkedList<>(); + + private String commandPrefix = "."; + + public CommandManager() { + super("Commands"); + } + + public void init() { + register(new BindCommand()); + register(new DrawnCommand()); + register(new FriendCommand()); + register(new HelpCommand()); + register(new PrefixCommand()); + register(new ToggleCommand()); + + LOGGER.info("Registered {} commands", commandList.size()); + OyVey.configManager.addConfig(this); + } + + public void onChatSent(String message) { + try { + int result = dispatcher.execute(message.substring(getCommandPrefix().length()).trim(), this); + + if (result == SINGLE_FAILURE) { + Command.sendMessage("{red} Failed to execute command", SUCCESS); + } + } catch (CommandSyntaxException e) { + LOGGER.error("Failed to execute command", e); + Command.sendMessage("{red} %s", GENERAL, e.getMessage()); + } catch (RuntimeException e) { + LOGGER.error("Unexpected error while executing command", e); + Command.sendMessage("{red} Failed to execute command", GENERAL); + } + } + + public void register(Command command) { + commandList.add(command); + for (String alias : command.getAliases()) { + commandAliasMap.put(alias, command); + LiteralArgumentBuilder builder = Command.literal(alias); + command.createArgumentBuilder(builder); + dispatcher.register(builder); + } + } + + public void setCommandPrefix(String commandPrefix) { + this.commandPrefix = commandPrefix; + } + + public String getCommandPrefix() { + return commandPrefix; + } + + public Command getCommand(String alias) { + return commandAliasMap.get(alias); + } + + public Set getCommandAliases() { + return commandAliasMap.keySet(); + } + + public List getCommands() { + return commandList; + } + + public CommandDispatcher getDispatcher() { + return dispatcher; + } + + @Override + public JsonElement toJson() { + JsonObject object = new JsonObject(); + object.addProperty("prefix", commandPrefix); + return object; + } + + @Override + public void fromJson(JsonElement element) { + if (element == null || !element.isJsonObject()) return; + + JsonObject object = element.getAsJsonObject(); + + if (object.has("prefix")) { + setCommandPrefix(object.get("prefix").getAsString()); + } + } +} diff --git a/src/main/java/me/alpha432/oyvey/manager/ConfigManager.java b/src/main/java/me/alpha432/oyvey/manager/ConfigManager.java new file mode 100644 index 0000000..5c291d5 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/manager/ConfigManager.java @@ -0,0 +1,120 @@ +package me.alpha432.oyvey.manager; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; +import me.alpha432.oyvey.features.Feature; +import me.alpha432.oyvey.features.settings.Bind; +import me.alpha432.oyvey.features.settings.EnumConverter; +import me.alpha432.oyvey.features.settings.Setting; +import me.alpha432.oyvey.util.traits.Jsonable; +import net.fabricmc.loader.api.FabricLoader; +import org.joml.Vector2f; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.awt.*; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.LinkedList; +import java.util.List; + +public class ConfigManager { + private static final Logger LOGGER = LoggerFactory.getLogger("ConfigManager"); + private static final Path OYVEY_PATH = FabricLoader.getInstance().getGameDir().resolve("oyvey"); + private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); + + private final List jsonables = new LinkedList<>(); + + public void addConfig(Jsonable jsonable) { + jsonables.add(jsonable); + } + + public void load() { + mkdirs(); + for (Jsonable jsonable : jsonables) { + Path path = OYVEY_PATH.resolve(jsonable.getFileName()); + if (!Files.exists(path)) continue; + try { + String read = Files.readString(path); + jsonable.fromJson(JsonParser.parseString(read)); + } catch (Throwable e) { + LOGGER.error("Failed to load", e); + } + } + } + + public synchronized void save() { + mkdirs(); + for (Jsonable jsonable : jsonables) { + try { + JsonElement json = jsonable.toJson(); + Path path = OYVEY_PATH.resolve(jsonable.getFileName()); + Files.writeString(path, GSON.toJson(json)); + } catch (Throwable e) { + LOGGER.error("Failed to write to file", e); + } + } + } + + private void mkdirs() { + if (!OYVEY_PATH.toFile().exists()) { + boolean success = OYVEY_PATH.toFile().mkdirs(); + if (!success) { + throw new RuntimeException("Failed to create needed directories!"); + } + } + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + public static void setValueFromJson(Feature feature, Setting setting, JsonElement element) { + if (element == null || element.isJsonNull()) return; + switch (setting.getType()) { + case "Boolean" -> setting.setValue(element.getAsBoolean()); + case "Double" -> setting.setValue(element.getAsDouble()); + case "Float" -> setting.setValue(element.getAsFloat()); + case "Integer" -> setting.setValue(element.getAsInt()); + case "String" -> setting.setValue(element.getAsString()); + case "Bind" -> setting.setValue(new Bind(element.getAsInt())); + case "Color" -> { + try { + String colorStr = element.getAsString(); + String[] parts = colorStr.split(","); + if (parts.length == 4) { + int r = Integer.parseInt(parts[0]); + int g = Integer.parseInt(parts[1]); + int b = Integer.parseInt(parts[2]); + int a = Integer.parseInt(parts[3]); + setting.setValue(new Color(r, g, b, a)); + } + } catch (Exception exception) { + LOGGER.error("Error parsing color for: {} : {}", feature.getName(), setting.getName()); + } + } + case "Pos" -> { + try { + String posStr = element.getAsString(); + String[] parts = posStr.split(","); + if (parts.length == 2) { + float x = Float.parseFloat(parts[0]); + float y = Float.parseFloat(parts[1]); + setting.setValue(new Vector2f(x, y)); + } + } catch (Exception exception) { + LOGGER.error("Error parsing position for: {} : {}", feature.getName(), setting.getName()); + } + } + case "Enum" -> { + try { + EnumConverter converter = new EnumConverter(((Enum) setting.getValue()).getDeclaringClass()); + Enum value = converter.doBackward(element); + setting.setValue(value); + } catch (Exception exception) { + LOGGER.error("Error parsing enum for {}.{}: {}", feature.getName(), setting.getName(), exception); + } + } + default -> LOGGER.error("Unknown Setting type for: {} : {}", feature.getName(), setting.getName()); + } + } +} diff --git a/src/main/java/me/alpha432/oyvey/manager/EventManager.java b/src/main/java/me/alpha432/oyvey/manager/EventManager.java new file mode 100644 index 0000000..4421774 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/manager/EventManager.java @@ -0,0 +1,96 @@ +package me.alpha432.oyvey.manager; + +import me.alpha432.oyvey.OyVey; +import me.alpha432.oyvey.event.Stage; +import me.alpha432.oyvey.event.impl.entity.DeathEvent; +import me.alpha432.oyvey.event.impl.entity.player.TickEvent; +import me.alpha432.oyvey.event.impl.entity.player.UpdateWalkingPlayerEvent; +import me.alpha432.oyvey.event.impl.input.KeyInputEvent; +import me.alpha432.oyvey.event.impl.input.MouseInputEvent; +import me.alpha432.oyvey.event.impl.network.ChatEvent; +import me.alpha432.oyvey.event.impl.network.PacketEvent; +import me.alpha432.oyvey.event.impl.render.Render2DEvent; +import me.alpha432.oyvey.event.impl.render.Render3DEvent; +import me.alpha432.oyvey.event.system.Subscribe; +import me.alpha432.oyvey.features.Feature; +import net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket; +import net.minecraft.network.protocol.common.custom.BrandPayload; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.network.protocol.game.ClientboundSetTimePacket; +import net.minecraft.world.entity.player.Player; + +import java.util.HashSet; +import java.util.Set; + +public class EventManager extends Feature { + private final Set deadPlayers = new HashSet<>(); + + public void init() { + EVENT_BUS.register(this); + } + + public void onUnload() { + EVENT_BUS.unregister(this); + } + + @Subscribe + public void onTick(TickEvent.Post event) { + if (nullCheck()) + return; + OyVey.speedManager.update(); + OyVey.moduleManager.onTick(); + Set dead = new HashSet<>(); + for (Player player : mc.level.players()) { + if (player == null || player.getHealth() > 0.0F) + continue; + dead.add(player.getId()); + if (!deadPlayers.contains(player.getId())) + EVENT_BUS.post(new DeathEvent(player)); + } + deadPlayers.clear(); + deadPlayers.addAll(dead); + } + + @Subscribe + public void onPacketReceive(PacketEvent.Receive event) { + OyVey.serverManager.onPacketReceived(); + if (event.getPacket() instanceof ClientboundSetTimePacket) + OyVey.serverManager.update(); + if (event.getPacket() instanceof ClientboundCustomPayloadPacket(CustomPacketPayload payload) + && payload instanceof BrandPayload(String brand)) { + OyVey.serverManager.setServerBrand(brand); + } + } + + @Subscribe + public void onWorldRender(Render3DEvent event) { + OyVey.moduleManager.onRender3D(event); + } + + @Subscribe + public void onRenderGameOverlayEvent(Render2DEvent event) { + OyVey.moduleManager.onRender2D(event); + } + + @Subscribe + public void onKeyInput(KeyInputEvent event) { + OyVey.moduleManager.onKeyPressed(event.getKey()); + } + + @Subscribe + public void onMouseInput(MouseInputEvent event) { + if (event.getAction() == 1) { + OyVey.moduleManager.onMouseClicked(event.getButton()); + } + } + + @Subscribe + public void onChatSent(ChatEvent event) { + String message = event.getMessage(); + if (!message.startsWith(OyVey.commandManager.getCommandPrefix())) { + return; + } + event.cancel(); + OyVey.commandManager.onChatSent(message); + } +} \ No newline at end of file diff --git a/src/main/java/me/alpha432/oyvey/manager/FriendManager.java b/src/main/java/me/alpha432/oyvey/manager/FriendManager.java new file mode 100644 index 0000000..ed10435 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/manager/FriendManager.java @@ -0,0 +1,67 @@ +package me.alpha432.oyvey.manager; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import me.alpha432.oyvey.OyVey; +import me.alpha432.oyvey.util.traits.Jsonable; +import net.minecraft.world.entity.player.Player; + +import java.util.ArrayList; +import java.util.List; + +public class FriendManager implements Jsonable { + private final List friends = new ArrayList<>(); + + public void init() { + OyVey.configManager.addConfig(this); + } + + public boolean isFriend(String name) { + return this.friends.stream().anyMatch(friend -> friend.equalsIgnoreCase(name)); + } + + public boolean isFriend(Player player) { + return this.isFriend(player.getGameProfile().name()); + } + + public void addFriend(String name) { + this.friends.add(name); + } + + public void removeFriend(String name) { + friends.removeIf(s -> s.equalsIgnoreCase(name)); + } + + public List getFriends() { + return this.friends; + } + + @Override + public JsonElement toJson() { + JsonObject object = new JsonObject(); + JsonArray array = new JsonArray(); + for (String friend : friends) { + array.add(friend); + } + object.add("friends", array); + return object; + } + + @Override + public void fromJson(JsonElement element) { + friends.clear(); + if (element == null || !element.isJsonObject()) return; + JsonElement array = element.getAsJsonObject().get("friends"); + if (array == null || !array.isJsonArray()) return; + for (JsonElement e : array.getAsJsonArray()) { + String name = e.getAsString(); + if (!friends.contains(name)) friends.add(name); + } + } + + @Override + public String getFileName() { + return "friends.json"; + } +} \ No newline at end of file diff --git a/src/main/java/me/alpha432/oyvey/manager/HoleManager.java b/src/main/java/me/alpha432/oyvey/manager/HoleManager.java new file mode 100644 index 0000000..5bbe0ca --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/manager/HoleManager.java @@ -0,0 +1,68 @@ +package me.alpha432.oyvey.manager; + +import me.alpha432.oyvey.event.impl.entity.player.TickEvent; +import me.alpha432.oyvey.event.system.Subscribe; +import me.alpha432.oyvey.features.Feature; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +public class HoleManager extends Feature { + private static final int RANGE = 8; + + private final List holes = new ArrayList<>(); + private final BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(); + + public HoleManager() { + EVENT_BUS.register(this); + } + + @Subscribe + private void onTick(TickEvent.Pre event) { + holes.clear(); + for (int x = -RANGE; x < RANGE; x++) { + for (int y = -RANGE; y < RANGE; y++) { + for (int z = -RANGE; z < RANGE; z++) { + pos.set(mc.player.getX() + x, mc.player.getY() + y, mc.player.getZ() + z); + Hole hole = getHole(pos); + if (hole == null) continue; + holes.add(hole); + } + } + } + } + + @Nullable + public Hole getHole(BlockPos pos) { + if (mc.level.getBlockState(pos).getBlock() != Blocks.AIR) + return null; + HoleType type = HoleType.BEDROCK; + for (Direction direction : Direction.Plane.HORIZONTAL) { + Block block = mc.level.getBlockState(pos.relative(direction)).getBlock(); + if (block == Blocks.OBSIDIAN) type = HoleType.UNSAFE; + else if (block != Blocks.BEDROCK) return null; + } + return new Hole(pos.immutable(), type); + } + + public List getHoles() { + return holes; + } + + public boolean isHole(BlockPos pos) { + return holes.stream().anyMatch(hole -> hole.pos().equals(pos)); + } + + public record Hole(BlockPos pos, HoleType holeType) { + } + + private enum HoleType { + BEDROCK, + UNSAFE + } +} diff --git a/src/main/java/me/alpha432/oyvey/manager/ModuleManager.java b/src/main/java/me/alpha432/oyvey/manager/ModuleManager.java new file mode 100644 index 0000000..28c1bf2 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/manager/ModuleManager.java @@ -0,0 +1,165 @@ +package me.alpha432.oyvey.manager; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import me.alpha432.oyvey.OyVey; +import me.alpha432.oyvey.event.impl.render.Render2DEvent; +import me.alpha432.oyvey.features.gui.OyVeyGui; +import net.minecraft.client.gui.screens.TitleScreen; +import net.minecraft.client.gui.screens.multiplayer.JoinMultiplayerScreen; +import me.alpha432.oyvey.event.impl.render.Render3DEvent; +import me.alpha432.oyvey.features.Feature; +import me.alpha432.oyvey.features.commands.ModuleCommand; +import me.alpha432.oyvey.features.modules.Module; +import me.alpha432.oyvey.features.modules.client.ClickGuiModule; +import me.alpha432.oyvey.features.modules.client.HudEditorModule; +import me.alpha432.oyvey.features.modules.client.NotificationsModule; +import me.alpha432.oyvey.features.modules.combat.KillAuraModule; +import me.alpha432.oyvey.features.modules.combat.CriticalsModule; +import me.alpha432.oyvey.features.modules.combat.KeyPearlModule; +import me.alpha432.oyvey.features.modules.hud.CoordinatesHudModule; +import me.alpha432.oyvey.features.modules.hud.WatermarkHudModule; +import me.alpha432.oyvey.features.modules.misc.MCFModule; +import me.alpha432.oyvey.features.modules.movement.FastAccelModule; +import me.alpha432.oyvey.features.modules.movement.ReverseStepModule; +import me.alpha432.oyvey.features.modules.movement.StepModule; +import me.alpha432.oyvey.features.modules.player.FastPlaceModule; +import me.alpha432.oyvey.features.modules.player.NoFallModule; +import me.alpha432.oyvey.features.modules.player.VelocityModule; +import me.alpha432.oyvey.features.modules.render.BlockHighlightModule; +import me.alpha432.oyvey.util.traits.Jsonable; +import me.alpha432.oyvey.util.traits.Util; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; +import java.util.stream.Stream; + +public class ModuleManager implements Jsonable, Util { + private static final Logger LOGGER = LoggerFactory.getLogger("ModuleManager"); + + private final Map, Module> fastRegistry = new HashMap<>(); + private final List modules = new ArrayList<>(); + + public void init() { + register(new WatermarkHudModule()); + register(new CoordinatesHudModule()); + register(new HudEditorModule()); + register(new ClickGuiModule()); + register(new NotificationsModule()); + register(new CriticalsModule()); + register(new MCFModule()); + register(new StepModule()); + register(new ReverseStepModule()); + register(new FastPlaceModule()); + register(new VelocityModule()); + register(new BlockHighlightModule()); + register(new NoFallModule()); + register(new KeyPearlModule()); + register(new KillAuraModule()); + register(new FastAccelModule()); + + LOGGER.info("Registered {} modules", modules.size()); + + // Create a command for each module for modules to be configurable via command line + for (Module module : modules) { + OyVey.commandManager.register(new ModuleCommand(module)); + } + + OyVey.configManager.addConfig(this); + } + + public void register(Module module) { + getModules().add(module); + fastRegistry.put(module.getClass(), module); + } + + public List getModules() { + return modules; + } + + public Stream stream() { + return getModules().stream(); + } + + @SuppressWarnings("unchecked") + public T getModuleByClass(Class clazz) { + return (T) fastRegistry.get(clazz); + } + + public Module getModuleByName(String name) { + return stream().filter(m -> m.getName().equalsIgnoreCase(name)).findFirst().orElse(null); + } + + public Module getModuleByDisplayName(String display) { + return stream().filter(m -> m.getDisplayName().equalsIgnoreCase(display)).findFirst().orElse(null); + } + + public List getModulesByCategory(Module.Category category) { + return stream().filter(m -> m.getCategory() == category).toList(); + } + + public List getCategories() { + return Arrays.asList(Module.Category.values()); + } + + public void onLoad() { + getModules().forEach(Module::onLoad); + } + + public void onTick() { + stream().filter(Feature::isEnabled).forEach(Module::onTick); + } + + public void onRender2D(Render2DEvent event) { + stream().filter(Feature::isEnabled).forEach(module -> module.onRender2D(event)); + } + + public void onRender3D(Render3DEvent event) { + stream().filter(Feature::isEnabled).forEach(module -> module.onRender3D(event)); + } + + public void onUnload() { + getModules().forEach(EVENT_BUS::unregister); + getModules().forEach(Module::onUnload); + } + + public void onKeyPressed(int key) { + if (key <= 0) return; + if (mc.screen instanceof TitleScreen || mc.screen instanceof JoinMultiplayerScreen) { + if (ClickGuiModule.getInstance().getBind().getKey() == key) { + OyVeyGui.open(mc.screen); + } + return; + } + if (mc.screen != null) return; + stream().filter(module -> module.getBind().getKey() == key).forEach(Module::toggle); + } + + public void onMouseClicked(int button) { + if (mc.screen != null) return; + int key = -button - 2; + stream().filter(module -> module.getBind().getKey() == key).forEach(Module::toggle); + } + + @Override + public JsonElement toJson() { + JsonObject object = new JsonObject(); + for (Module module : getModules()) { + object.add(module.getName(), module.toJson()); + } + return object; + } + + @Override + public void fromJson(JsonElement element) { + for (Module module : getModules()) { + module.fromJson(element.getAsJsonObject().get(module.getName())); + } + } + + @Override + public String getFileName() { + return "modules.json"; + } +} diff --git a/src/main/java/me/alpha432/oyvey/manager/PositionManager.java b/src/main/java/me/alpha432/oyvey/manager/PositionManager.java new file mode 100644 index 0000000..c041c4c --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/manager/PositionManager.java @@ -0,0 +1,92 @@ +package me.alpha432.oyvey.manager; + +import me.alpha432.oyvey.event.Stage; +import me.alpha432.oyvey.event.impl.entity.player.UpdateWalkingPlayerEvent; +import me.alpha432.oyvey.event.system.Subscribe; +import me.alpha432.oyvey.features.Feature; +import net.minecraft.network.protocol.game.ServerboundMovePlayerPacket; + +public class PositionManager + extends Feature { + private double x; + private double y; + private double z; + private boolean onground; + private double fallDistance; + + public PositionManager() { + EVENT_BUS.register(this); + } + + @Subscribe + public void onUpdateWalkingPlayer(UpdateWalkingPlayerEvent event) { + if (event.getStage() == Stage.POST) return; + + double diff = mc.player.yo - mc.player.getY(); + if (mc.player.onGround() || diff <= 0) { + fallDistance = 0; + } else { + fallDistance += diff; + } + } + + public void updatePosition() { + this.x = mc.player.getX(); + this.y = mc.player.getY(); + this.z = mc.player.getZ(); + this.onground = mc.player.onGround(); + } + + public void restorePosition() { + mc.player.setPos(x, y, z); + mc.player.setOnGround(onground); + } + + public void setPlayerPosition(double x, double y, double z) { + mc.player.setPos(x, y, z); + } + + public void setPlayerPosition(double x, double y, double z, boolean onground) { + mc.player.setPos(x, y, z); + mc.player.setOnGround(onground); + } + + public void setPositionPacket(double x, double y, double z, boolean onGround, boolean setPos, boolean noLagBack) { + boolean bl = mc.player.horizontalCollision; + mc.player.connection.send(new ServerboundMovePlayerPacket.Pos(x, y, z, onGround, bl)); + if (setPos) { + mc.player.setPos(x, y, z); + if (noLagBack) { + this.updatePosition(); + } + } + } + + public double getX() { + return this.x; + } + + public void setX(double x) { + this.x = x; + } + + public double getY() { + return this.y; + } + + public void setY(double y) { + this.y = y; + } + + public double getZ() { + return this.z; + } + + public void setZ(double z) { + this.z = z; + } + + public double getFallDistance() { + return fallDistance; + } +} \ No newline at end of file diff --git a/src/main/java/me/alpha432/oyvey/manager/RotationManager.java b/src/main/java/me/alpha432/oyvey/manager/RotationManager.java new file mode 100644 index 0000000..b9ab07a --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/manager/RotationManager.java @@ -0,0 +1,162 @@ +package me.alpha432.oyvey.manager; + +import me.alpha432.oyvey.event.Stage; +import me.alpha432.oyvey.event.impl.entity.player.TickEvent; +import me.alpha432.oyvey.event.impl.entity.player.TravelEvent; +import me.alpha432.oyvey.event.impl.entity.player.UpdateWalkingPlayerEvent; +import me.alpha432.oyvey.event.system.Subscribe; +import me.alpha432.oyvey.util.models.Angles; +import me.alpha432.oyvey.util.traits.Util; +import net.minecraft.network.protocol.game.ServerboundMovePlayerPacket; +import net.minecraft.util.Mth; + +import java.util.*; +import java.util.function.Predicate; + +public class RotationManager implements Util { + private final List callbacks = new ArrayList<>(); + + private boolean updateRender; + private Angles renderSnapshot, renderSnapshot0; + + private Angles snapshot; + private Angles travelSnapshot; + + public RotationManager() { + EVENT_BUS.register(this); + } + + @Subscribe(priority = 1000) + public void onTickPre(TickEvent.Pre event) { + executeCallbacks(callback -> callback.type() == Type.SYNC); + } + + @Subscribe + public void onTravelPre(TravelEvent.Pre event) { + if (callbacks.isEmpty()) + return; + + Callback highest = callbacks.stream().max(Comparator.comparing(Callback::priority)).orElseThrow(); + if (highest.type() == Type.SYNC) { + travelSnapshot = new Angles(mc.player.getYRot(), mc.player.getXRot()); + mc.player.setYRot(highest.angles().yRot()); + mc.player.setXRot(highest.angles().xRot()); + } + } + + @Subscribe + public void onTravelPost(TravelEvent.Post event) { + if (travelSnapshot != null) { + mc.player.setYRot(travelSnapshot.yRot()); + mc.player.setXRot(travelSnapshot.xRot()); + travelSnapshot = null; + } + } + + @Subscribe + public void onUpdateWalking(UpdateWalkingPlayerEvent event) { + if (event.getStage() == Stage.PRE) { + if (callbacks.isEmpty()) { + updateRenderSnapshot(new Angles(mc.player.getYRot(), mc.player.getXRot()), false); + return; + } + Callback highest = callbacks.stream().max(Comparator.comparing(Callback::priority)).orElseThrow(); + + updateRenderSnapshot(highest.angles(), true); + + snapshot = new Angles(mc.player.getYRot(), mc.player.getXRot()); + mc.player.setYRot(highest.angles().yRot()); + mc.player.setXRot(highest.angles().xRot()); + } else if (snapshot != null) { + executeCallbacks(callback -> callback.type() == Type.MOTION); + + mc.player.setYRot(snapshot.yRot()); + mc.player.setXRot(snapshot.xRot()); + snapshot = null; + } + } + + public void sync(Angles angles, Runnable runnable) { + sync(angles, 0, runnable); + } + + public void sync(Angles angles, int priority, Runnable runnable) { + request(Type.SYNC, angles, priority, runnable); + } + + public void motion(Angles angles, Runnable runnable) { + motion(angles, 0, runnable); + } + + public void motion(Angles angles, int priority, Runnable runnable) { + request(Type.MOTION, angles, priority, runnable); + } + + public void silent(Angles angles, Runnable runnable) { + request(Type.SILENT, angles, 0, runnable); + } + + public Angles getLerpRenderSnapshot(float lerp) { + if (!updateRender) return null; + return new Angles( + Mth.lerp(lerp, renderSnapshot0.yRot(), renderSnapshot.yRot()), + Mth.lerp(lerp, renderSnapshot0.xRot(), renderSnapshot.xRot()) + ); + } + + public void sendDuplicate(float yaw, float pitch) { + mc.player.positionReminder = 20; + mc.player.yRotLast = yaw; + mc.player.xRotLast = pitch; + mc.player.connection.send(new ServerboundMovePlayerPacket.PosRot( + mc.player.getX(), mc.player.getY(), mc.player.getZ(), + yaw, pitch, + mc.player.onGround(), mc.player.horizontalCollision + )); + } + + private void request(Type type, Angles angles, int priority, Runnable runnable) { + Callback callback = new Callback(type, angles, priority, runnable); + if (type == Type.SILENT) { + sendDuplicate(angles.yRot(), angles.xRot()); + callback.execute(); + } else { + callbacks.add(callback); + } + } + + private void executeCallbacks(Predicate filter) { + callbacks.removeIf(callback -> { + if (filter.test(callback)) { + callback.execute(); + return true; + } + return false; + }); + } + + private void updateRenderSnapshot(Angles angles, boolean update) { + this.renderSnapshot0 = this.renderSnapshot; + this.renderSnapshot = angles; + this.updateRender = update; + + if (renderSnapshot0 == null || renderSnapshot == null) + return; + + if (Mth.abs(renderSnapshot.yRot() - renderSnapshot0.yRot()) > 320) { + this.renderSnapshot0 = this.renderSnapshot; + } + } + + record Callback(Type type, Angles angles, int priority, Runnable action) { + public void execute() { + if (action != null) action.run(); + } + } + + public enum Type { + MOTION, + SYNC, + SILENT + } +} diff --git a/src/main/java/me/alpha432/oyvey/manager/ServerManager.java b/src/main/java/me/alpha432/oyvey/manager/ServerManager.java new file mode 100644 index 0000000..63a0a30 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/manager/ServerManager.java @@ -0,0 +1,88 @@ +package me.alpha432.oyvey.manager; + +import me.alpha432.oyvey.features.Feature; +import me.alpha432.oyvey.util.models.Timer; + +import java.util.Arrays; + +public class ServerManager + extends Feature { + private final float[] tpsCounts = new float[10]; + private final Timer timer = new Timer(); + private float tps = 20.0f; + private long lastUpdate = -1L; + private String serverBrand = ""; + + public void onPacketReceived() { + this.timer.reset(); + } + + public void update() { + float tps; + long currentTime = System.currentTimeMillis(); + if (this.lastUpdate == -1L) { + this.lastUpdate = currentTime; + return; + } + long timeDiff = currentTime - this.lastUpdate; + float tickTime = (float) timeDiff / 20.0f; + if (tickTime == 0.0f) { + tickTime = 50.0f; + } + if ((tps = 1000.0f / tickTime) > 20.0f) { + tps = 20.0f; + } + System.arraycopy(this.tpsCounts, 0, this.tpsCounts, 1, this.tpsCounts.length - 1); + this.tpsCounts[0] = tps; + double total = 0.0; + for (float f : this.tpsCounts) { + total += f; + } + if ((total /= this.tpsCounts.length) > 20.0) { + total = 20.0; + } + this.tps = (float) total; + this.lastUpdate = currentTime; + } + + @Override + public void reset() { + Arrays.fill(this.tpsCounts, 20.0f); + this.tps = 20.0f; + } + + public boolean isServerNotResponding() { + return this.timer.passedMs(2000); + } + + public long serverRespondingTime() { + return this.timer.getPassedTimeMs(); + } + + public float getTpsFactor() { + return 20.0f / this.tps; + } + + public float getTps() { + return this.tps; + } + + public String getServerBrand() { + return this.serverBrand; + } + + public void setServerBrand(String brand) { + this.serverBrand = brand; + } + + public int getPing() { + if (ServerManager.nullCheck()) { + return 0; + } + try { + return mc.getConnection().getPlayerInfo(mc.player.getGameProfile().name()).getLatency(); + } catch (Throwable e) { + return 0; + } + } +} \ No newline at end of file diff --git a/src/main/java/me/alpha432/oyvey/manager/SpeedManager.java b/src/main/java/me/alpha432/oyvey/manager/SpeedManager.java new file mode 100644 index 0000000..de7094e --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/manager/SpeedManager.java @@ -0,0 +1,47 @@ +package me.alpha432.oyvey.manager; + +import me.alpha432.oyvey.features.Feature; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; + +import java.util.ArrayList; +import java.util.List; + +public class SpeedManager extends Feature { + private static final int SPEED_NORMALIZATION = 20; + + private final List localSpeed = new ArrayList<>(); + private float localSpeedNormal = 0f; + + public void update() { + localSpeed.add(getCurrentSpeed(mc.player)); + while (localSpeed.size() > SPEED_NORMALIZATION) localSpeed.removeFirst(); + + localSpeedNormal = localSpeed.stream().reduce(0f, Float::sum) / localSpeed.size(); + } + + public double getSpeed(Player player) { + if (mc.player == player) return localSpeedNormal; + return getCurrentSpeed(player); + } + + public double getSpeedBpS(Player player) { + return getSpeed(player) * 20; + } + + public double getSpeedKmH(Player player) { + return getSpeedBpS(player) * 3.6; + } + + public float getCurrentSpeed(Entity entity) { + Entity vehicle = entity.getVehicle(); + double distTraveledX = entity.getX() - entity.xo; + double distTraveledZ = entity.getZ() - entity.zo; + if (vehicle != null) { + distTraveledX = vehicle.getX() - vehicle.xo; + distTraveledZ = vehicle.getZ() - vehicle.zo; + } + + return (float) Math.hypot(distTraveledX, distTraveledZ); + } +} \ No newline at end of file diff --git a/src/main/java/me/alpha432/oyvey/mixin/entity/MixinAbstractClientPlayer.java b/src/main/java/me/alpha432/oyvey/mixin/entity/MixinAbstractClientPlayer.java new file mode 100644 index 0000000..9c9bc56 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/mixin/entity/MixinAbstractClientPlayer.java @@ -0,0 +1,28 @@ +package me.alpha432.oyvey.mixin.entity; + +import me.alpha432.oyvey.event.impl.entity.player.TravelEvent; +import net.minecraft.client.player.AbstractClientPlayer; +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; + +import static me.alpha432.oyvey.util.traits.Util.EVENT_BUS; +import static me.alpha432.oyvey.util.traits.Util.isLocalPlayer; + +@Mixin(AbstractClientPlayer.class) +public class MixinAbstractClientPlayer { + @Inject(method = "tick", at = @At("HEAD")) + private void travelPreHook(CallbackInfo ci) { + if (isLocalPlayer(this)) { + EVENT_BUS.post(new TravelEvent.Pre()); + } + } + + @Inject(method = "tick", at = @At("TAIL")) + private void travelPostHook(CallbackInfo ci) { + if (isLocalPlayer(this)) { + EVENT_BUS.post(new TravelEvent.Post()); + } + } +} diff --git a/src/main/java/me/alpha432/oyvey/mixin/entity/MixinClientPlayerEntity.java b/src/main/java/me/alpha432/oyvey/mixin/entity/MixinClientPlayerEntity.java new file mode 100644 index 0000000..8a0cdcb --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/mixin/entity/MixinClientPlayerEntity.java @@ -0,0 +1,48 @@ +package me.alpha432.oyvey.mixin.entity; + +import me.alpha432.oyvey.event.Stage; +import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import me.alpha432.oyvey.event.impl.entity.player.MoveEvent; +import me.alpha432.oyvey.event.impl.entity.player.TickEvent; +import me.alpha432.oyvey.event.impl.entity.player.UpdateWalkingPlayerEvent; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.world.entity.MoverType; +import net.minecraft.world.phys.Vec3; +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; + +import static me.alpha432.oyvey.util.traits.Util.EVENT_BUS; + +@Mixin(LocalPlayer.class) +public class MixinClientPlayerEntity { + @Inject(method = "tick", at = @At("HEAD")) + private void tickPreHook(CallbackInfo ci) { + EVENT_BUS.post(new TickEvent.Pre()); + } + + @Inject(method = "tick", at = @At("TAIL")) + private void tickHook(CallbackInfo ci) { + EVENT_BUS.post(new TickEvent.Post()); + } + + @Inject(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/player/AbstractClientPlayer;tick()V", shift = At.Shift.AFTER)) + private void tickHook2(CallbackInfo ci) { + EVENT_BUS.post(new UpdateWalkingPlayerEvent(Stage.PRE)); + } + + @Inject(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/player/LocalPlayer;sendPosition()V", shift = At.Shift.AFTER)) + private void tickHook3(CallbackInfo ci) { + EVENT_BUS.post(new UpdateWalkingPlayerEvent(Stage.POST)); + } + + @WrapMethod(method = "move") + private void moveHook(MoverType type, Vec3 movement, Operation original) { + MoveEvent event = new MoveEvent(type, movement); + EVENT_BUS.post(event); + if (event.isCancelled()) return; + original.call(type, event.getMovement()); + } +} diff --git a/src/main/java/me/alpha432/oyvey/mixin/input/MixinKeyboardHandler.java b/src/main/java/me/alpha432/oyvey/mixin/input/MixinKeyboardHandler.java new file mode 100644 index 0000000..930e3a4 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/mixin/input/MixinKeyboardHandler.java @@ -0,0 +1,21 @@ +package me.alpha432.oyvey.mixin.input; + +import me.alpha432.oyvey.event.impl.input.KeyInputEvent; +import net.minecraft.client.KeyboardHandler; +import net.minecraft.client.input.KeyEvent; +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; + +import static me.alpha432.oyvey.util.traits.Util.EVENT_BUS; + +@Mixin(KeyboardHandler.class) +public class MixinKeyboardHandler { + @Inject(method = "keyPress", at = @At("TAIL")) + private void keyPress(long l, int i, KeyEvent keyEvent, CallbackInfo ci) { + if (i != 1) return; + + EVENT_BUS.post(new KeyInputEvent(keyEvent.key())); + } +} diff --git a/src/main/java/me/alpha432/oyvey/mixin/input/MixinMouseHandler.java b/src/main/java/me/alpha432/oyvey/mixin/input/MixinMouseHandler.java new file mode 100644 index 0000000..a92cc48 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/mixin/input/MixinMouseHandler.java @@ -0,0 +1,22 @@ +package me.alpha432.oyvey.mixin.input; + +import me.alpha432.oyvey.event.impl.input.MouseInputEvent; +import net.minecraft.client.MouseHandler; +import net.minecraft.client.input.MouseButtonInfo; +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; + +import static me.alpha432.oyvey.util.traits.Util.EVENT_BUS; + +@Mixin(MouseHandler.class) +public class MixinMouseHandler { + @Inject(method = "onButton", at = @At("HEAD"), cancellable = true) + private void onButton(long window, MouseButtonInfo input, int action, CallbackInfo ci) { + if (EVENT_BUS.post(new MouseInputEvent(input.button(), action))) { + ci.cancel(); + } + } +} + diff --git a/src/main/java/me/alpha432/oyvey/mixin/network/MixinClientPacketListener.java b/src/main/java/me/alpha432/oyvey/mixin/network/MixinClientPacketListener.java new file mode 100644 index 0000000..26b357a --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/mixin/network/MixinClientPacketListener.java @@ -0,0 +1,20 @@ +package me.alpha432.oyvey.mixin.network; + +import me.alpha432.oyvey.event.impl.network.ChatEvent; +import net.minecraft.client.multiplayer.ClientPacketListener; +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; + +import static me.alpha432.oyvey.util.traits.Util.EVENT_BUS; + +@Mixin(ClientPacketListener.class) +public class MixinClientPacketListener { + @Inject(method = "sendChat", at = @At("HEAD"), cancellable = true) + private void sendChat(String content, CallbackInfo ci) { + if (EVENT_BUS.post(new ChatEvent(content))) { + ci.cancel(); + } + } +} \ No newline at end of file diff --git a/src/main/java/me/alpha432/oyvey/mixin/network/MixinConnection.java b/src/main/java/me/alpha432/oyvey/mixin/network/MixinConnection.java new file mode 100644 index 0000000..68f0647 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/mixin/network/MixinConnection.java @@ -0,0 +1,59 @@ +package me.alpha432.oyvey.mixin.network; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import me.alpha432.oyvey.event.impl.network.PacketEvent; +import net.minecraft.network.Connection; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.PacketFlow; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import static me.alpha432.oyvey.util.traits.Util.EVENT_BUS; + +@Mixin(Connection.class) +public class MixinConnection { + @Unique + private static final Logger LOGGER = LoggerFactory.getLogger("PacketEvent"); + + @Shadow + private Channel channel; + @Shadow + @Final + private PacketFlow receiving; + + @Inject(method = "channelRead0*", at = @At("HEAD"), cancellable = true) + public void channelRead0(ChannelHandlerContext chc, Packet packet, CallbackInfo ci) { + if (this.channel.isOpen() && packet != null) { + try { + if (EVENT_BUS.post(new PacketEvent.Receive(packet))) { + ci.cancel(); + } + } catch (Exception e) { + LOGGER.error("Failed to post packet event for {}", packet.getClass().getSimpleName(), e); + } + } + } + + @Inject(method = "sendPacket", at = @At("HEAD"), cancellable = true) + private void sendPacket(Packet packet, ChannelFutureListener callbacks, boolean flush, CallbackInfo ci) { + if (this.receiving != PacketFlow.CLIENTBOUND) return; + try { + if (EVENT_BUS.post(new PacketEvent.Send(packet))) { + ci.cancel(); + } + } catch (Exception e) { + LOGGER.error("Failed to post packet event for {}", packet.getClass().getSimpleName(), e); + } + } + + +} \ No newline at end of file diff --git a/src/main/java/me/alpha432/oyvey/mixin/render/MixinAvatarRenderer.java b/src/main/java/me/alpha432/oyvey/mixin/render/MixinAvatarRenderer.java new file mode 100644 index 0000000..59d2ee3 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/mixin/render/MixinAvatarRenderer.java @@ -0,0 +1,26 @@ +package me.alpha432.oyvey.mixin.render; + +import me.alpha432.oyvey.OyVey; +import me.alpha432.oyvey.util.models.Angles; +import net.minecraft.client.renderer.entity.player.AvatarRenderer; +import net.minecraft.client.renderer.entity.state.AvatarRenderState; +import net.minecraft.world.entity.Avatar; +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; + +import static me.alpha432.oyvey.util.traits.Util.mc; + +@Mixin(AvatarRenderer.class) +public class MixinAvatarRenderer { + @Inject(method = "extractRenderState(Lnet/minecraft/world/entity/Avatar;Lnet/minecraft/client/renderer/entity/state/AvatarRenderState;F)V", at = @At("TAIL")) + private void extractRenderStateHook(T avatar, AvatarRenderState state, float f, CallbackInfo ci) { + if (mc.player != avatar) return; + Angles lerped = OyVey.rotationManager.getLerpRenderSnapshot(f); + if (lerped == null) return; + state.xRot = lerped.xRot(); + state.yRot = 0; + state.bodyRot = lerped.yRot(); + } +} diff --git a/src/main/java/me/alpha432/oyvey/mixin/render/MixinChatComponent.java b/src/main/java/me/alpha432/oyvey/mixin/render/MixinChatComponent.java new file mode 100644 index 0000000..5e1fcb8 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/mixin/render/MixinChatComponent.java @@ -0,0 +1,32 @@ +package me.alpha432.oyvey.mixin.render; + +import me.alpha432.oyvey.ducks.render.IChatComponent; +import net.minecraft.client.GuiMessage; +import net.minecraft.client.gui.components.ChatComponent; +import net.minecraft.network.chat.MessageSignature; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import java.util.List; + +@Mixin(ChatComponent.class) +public abstract class MixinChatComponent implements IChatComponent { + @Final @Shadow + private List allMessages; + + @Shadow + private void refreshTrimmedMessages() {} + + @Override + public void oyvey$addMessage(GuiMessage message) { + this.allMessages.addFirst(message); + this.refreshTrimmedMessages(); + } + + @Override + public void oyvey$removeMessage(MessageSignature signature) { + this.allMessages.removeIf(message -> signature.equals(message.signature())); + this.refreshTrimmedMessages(); + } +} \ No newline at end of file diff --git a/src/main/java/me/alpha432/oyvey/mixin/render/MixinDeltaTrackerTimer.java b/src/main/java/me/alpha432/oyvey/mixin/render/MixinDeltaTrackerTimer.java new file mode 100644 index 0000000..92e85cd --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/mixin/render/MixinDeltaTrackerTimer.java @@ -0,0 +1,21 @@ +package me.alpha432.oyvey.mixin.render; + +import me.alpha432.oyvey.OyVey; +import net.minecraft.client.DeltaTracker; +import org.objectweb.asm.Opcodes; +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.CallbackInfoReturnable; + +@Mixin(DeltaTracker.Timer.class) +public class MixinDeltaTrackerTimer { + @Shadow + private float deltaTicks; + + @Inject(method = "advanceGameTime(J)I", at = @At(value = "FIELD", target = "Lnet/minecraft/client/DeltaTracker$Timer;lastMs:J", opcode = Opcodes.PUTFIELD)) + public void advanceGameTime(long timeMillis, CallbackInfoReturnable cir) { + this.deltaTicks *= OyVey.TIMER; + } +} \ No newline at end of file diff --git a/src/main/java/me/alpha432/oyvey/mixin/render/MixinLevelRenderer.java b/src/main/java/me/alpha432/oyvey/mixin/render/MixinLevelRenderer.java new file mode 100644 index 0000000..6558184 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/mixin/render/MixinLevelRenderer.java @@ -0,0 +1,53 @@ +package me.alpha432.oyvey.mixin.render; + +import com.llamalad7.mixinextras.sugar.Local; +import com.mojang.blaze3d.buffers.GpuBufferSlice; +import com.mojang.blaze3d.resource.GraphicsResourceAllocator; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Axis; +import me.alpha432.oyvey.event.impl.render.Render3DEvent; +import me.alpha432.oyvey.event.impl.render.RenderBlockOutlineEvent; +import net.minecraft.client.Camera; +import net.minecraft.client.DeltaTracker; +import net.minecraft.client.renderer.LevelRenderer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.state.LevelRenderState; +import net.minecraft.util.profiling.ProfilerFiller; +import org.joml.Matrix4f; +import org.joml.Vector4f; +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; + +import static me.alpha432.oyvey.util.traits.Util.EVENT_BUS; +import static me.alpha432.oyvey.util.traits.Util.mc; + +@Mixin(LevelRenderer.class) +public class MixinLevelRenderer { + @Inject(method = "renderBlockOutline", at = @At("HEAD"), cancellable = true) + public void renderBlockOutline(MultiBufferSource.BufferSource bufferSource, PoseStack poseStack, boolean bl, LevelRenderState levelRenderState, CallbackInfo ci) { + if (EVENT_BUS.post(new RenderBlockOutlineEvent())) { + ci.cancel(); + } + } + + @Inject(method = "renderLevel", at = @At("RETURN")) + private void render(GraphicsResourceAllocator allocator, DeltaTracker tickCounter, boolean renderBlockOutline, + Camera camera, Matrix4f positionMatrix, Matrix4f matrix4f, Matrix4f projectionMatrix, + GpuBufferSlice fogBuffer, Vector4f fogColor, boolean renderSky, CallbackInfo ci, @Local ProfilerFiller profiler) { + + PoseStack stack = new PoseStack(); + stack.pushPose(); + stack.mulPose(Axis.XP.rotationDegrees(mc.gameRenderer.getMainCamera().xRot())); + stack.mulPose(Axis.YP.rotationDegrees(mc.gameRenderer.getMainCamera().yRot() + 180f)); + + profiler.push("oyvey-render-3d"); + + Render3DEvent event = new Render3DEvent(stack, tickCounter.getGameTimeDeltaPartialTick(true)); + EVENT_BUS.post(event); + stack.popPose(); + profiler.pop(); + } + +} diff --git a/src/main/java/me/alpha432/oyvey/mixin/render/gui/MixinCommandSuggestions.java b/src/main/java/me/alpha432/oyvey/mixin/render/gui/MixinCommandSuggestions.java new file mode 100644 index 0000000..cace0c0 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/mixin/render/gui/MixinCommandSuggestions.java @@ -0,0 +1,61 @@ +package me.alpha432.oyvey.mixin.render.gui; + +import com.llamalad7.mixinextras.sugar.Local; +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.ParseResults; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.suggestion.Suggestions; +import me.alpha432.oyvey.OyVey; +import me.alpha432.oyvey.manager.CommandManager; +import net.minecraft.client.gui.components.CommandSuggestions; +import net.minecraft.client.gui.components.EditBox; +import net.minecraft.client.multiplayer.ClientSuggestionProvider; +import org.jspecify.annotations.Nullable; +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.callback.CallbackInfo; + +import java.util.concurrent.CompletableFuture; + +@Mixin(CommandSuggestions.class) +public abstract class MixinCommandSuggestions { + @Shadow + private CommandSuggestions.SuggestionsList suggestions; + @Shadow + private @Nullable CompletableFuture pendingSuggestions; + @Shadow + private @Nullable ParseResults currentParse; + @Shadow + boolean keepSuggestions; + @Shadow + @Final + EditBox input; + + @Shadow + protected abstract void updateUsageInfo(); + + @SuppressWarnings("unchecked") + @Inject(method = "updateCommandInfo", at = @At("RETURN")) + public void updateCommandInfo(CallbackInfo ci, @Local StringReader stringReader) { + String prefix = OyVey.commandManager.getCommandPrefix(); + if (!stringReader.canRead() || !stringReader.getString().startsWith(prefix)) { + return; + } + stringReader.setCursor(prefix.length()); + + CommandDispatcher dispatcher = OyVey.commandManager.getDispatcher(); + ParseResults parse = dispatcher.parse(stringReader, OyVey.commandManager); + currentParse = (ParseResults) (Object) parse; + if (suggestions == null || !keepSuggestions) { + pendingSuggestions = dispatcher.getCompletionSuggestions(parse, input.getCursorPosition()); + pendingSuggestions.thenRun(() -> { + if (pendingSuggestions.isDone()) { + updateUsageInfo(); + } + }); + } + } +} diff --git a/src/main/java/me/alpha432/oyvey/mixin/render/gui/MixinGui.java b/src/main/java/me/alpha432/oyvey/mixin/render/gui/MixinGui.java new file mode 100644 index 0000000..44aadc8 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/mixin/render/gui/MixinGui.java @@ -0,0 +1,29 @@ +package me.alpha432.oyvey.mixin.render.gui; + +import me.alpha432.oyvey.event.impl.render.Render2DEvent; +import net.minecraft.client.DeltaTracker; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.GuiGraphics; +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; + +import static me.alpha432.oyvey.util.traits.Util.EVENT_BUS; +import static me.alpha432.oyvey.util.traits.Util.mc; + +@Mixin(Gui.class) +public class MixinGui { + + @Inject(method = "render", at = @At("RETURN")) + public void render(GuiGraphics context, DeltaTracker tickCounter, CallbackInfo ci) { + boolean debugOpen = mc.debugEntries.isOverlayVisible(); + + if (debugOpen) return; + + Render2DEvent event = new Render2DEvent(context, tickCounter.getGameTimeDeltaPartialTick(true)); + EVENT_BUS.post(event); + } + +} diff --git a/src/main/java/me/alpha432/oyvey/util/ColorUtil.java b/src/main/java/me/alpha432/oyvey/util/ColorUtil.java new file mode 100644 index 0000000..29c4870 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/util/ColorUtil.java @@ -0,0 +1,12 @@ +package me.alpha432.oyvey.util; + +import me.alpha432.oyvey.features.modules.client.ClickGuiModule; + +import java.awt.*; + +public class ColorUtil { + public static Color rainbow(int delay) { + double rainbowState = Math.ceil((double) (System.currentTimeMillis() + (long) delay) / 20.0); + return Color.getHSBColor((float) ((rainbowState % 360.0) / 360.0), ClickGuiModule.getInstance().rainbowSaturation.getValue() / 255.0f, ClickGuiModule.getInstance().rainbowBrightness.getValue() / 255.0f); + } +} \ No newline at end of file diff --git a/src/main/java/me/alpha432/oyvey/util/EnchantmentUtil.java b/src/main/java/me/alpha432/oyvey/util/EnchantmentUtil.java new file mode 100644 index 0000000..d453332 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/util/EnchantmentUtil.java @@ -0,0 +1,44 @@ +package me.alpha432.oyvey.util; + +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import me.alpha432.oyvey.util.traits.Util; +import net.minecraft.core.Holder; +import net.minecraft.resources.ResourceKey; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.enchantment.Enchantment; + +public final class EnchantmentUtil implements Util { + private EnchantmentUtil() { + throw new IllegalArgumentException(); + } + + public static int getLevel(ResourceKey key, ItemStack stack) { + if (stack.isEmpty()) return 0; + for (Object2IntMap.Entry> enchantment : stack.getEnchantments().entrySet()) { + if (enchantment.getKey().is(key)) return enchantment.getIntValue(); + } + return 0; + } + + public static int getLevel(ResourceKey key, EquipmentSlot slot, LivingEntity entity) { + return getLevel(key, entity.getItemBySlot(slot)); + } + + public static int getLevel(ResourceKey key, EquipmentSlot slot) { + return getLevel(key, slot, mc.player); + } + + public static boolean has(ResourceKey key, ItemStack stack) { + return getLevel(key, stack) > 0; + } + + public static boolean has(ResourceKey key, EquipmentSlot slot, LivingEntity entity) { + return getLevel(key, slot, entity) > 0; + } + + public static boolean has(ResourceKey key, EquipmentSlot slot) { + return getLevel(key, slot) > 0; + } +} diff --git a/src/main/java/me/alpha432/oyvey/util/InteractionUtil.java b/src/main/java/me/alpha432/oyvey/util/InteractionUtil.java new file mode 100644 index 0000000..2ab1cde --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/util/InteractionUtil.java @@ -0,0 +1,167 @@ +package me.alpha432.oyvey.util; + +import me.alpha432.oyvey.util.traits.Util; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.network.protocol.game.ServerboundPlayerActionPacket; +import net.minecraft.network.protocol.game.ServerboundSwingPacket; +import net.minecraft.tags.FluidTags; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.effect.MobEffectUtil; +import net.minecraft.world.effect.MobEffects; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.ExperienceOrb; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.entity.projectile.throwableitemprojectile.ThrownExperienceBottle; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.enchantment.Enchantments; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; +import net.minecraft.world.phys.shapes.Shapes; + +public class InteractionUtil implements Util { + public static boolean canBreak(BlockPos blockPos, BlockState state) { + if (!mc.player.isCreative() && state.getDestroySpeed(mc.level, blockPos) < 0) return false; + return state.getShape(mc.level, blockPos) != Shapes.empty(); + } + + public static boolean isPlaceable(BlockPos pos, boolean entityCheck) { + if (!mc.level.getBlockState(pos).canBeReplaced()) return false; + for (Entity e : mc.level.getEntitiesOfClass(Entity.class, new AABB(pos), e -> !(e instanceof ThrownExperienceBottle || e instanceof ItemEntity || e instanceof ExperienceOrb))) { + if (e instanceof Player) return false; + return !entityCheck; + } + return true; + } + + public static boolean breakBlock(BlockPos pos) { + if (!canBreak(pos, mc.level.getBlockState(pos))) return false; + BlockPos bp = pos instanceof BlockPos.MutableBlockPos ? new BlockPos(pos) : pos; + + mc.getConnection().send(new ServerboundPlayerActionPacket(ServerboundPlayerActionPacket.Action.START_DESTROY_BLOCK, bp, Direction.UP)); + mc.player.swing(InteractionHand.MAIN_HAND); + mc.getConnection().send(new ServerboundPlayerActionPacket(ServerboundPlayerActionPacket.Action.STOP_DESTROY_BLOCK, bp, Direction.UP)); + + mc.getConnection().send(new ServerboundSwingPacket(InteractionHand.MAIN_HAND)); + + return true; + } + + public static void useItem(BlockPos pos) { + useItem(pos, InteractionHand.MAIN_HAND); + } + + public static void useItem(BlockPos pos, InteractionHand hand) { + if (mc.level == null || mc.player == null || mc.gameMode == null) return; + Direction direction = mc.hitResult != null ? ((BlockHitResult) mc.hitResult).getDirection() : Direction.DOWN; + InteractionResult result = mc.gameMode.useItemOn(mc.player, hand, new BlockHitResult( + Vec3.atCenterOf(pos), direction, pos, false + )); + if (result instanceof InteractionResult.Success success && success.swingSource() != InteractionResult.SwingSource.NONE) { + mc.player.connection.send(new ServerboundSwingPacket(hand)); + } + } + + public static boolean place(BlockPos pos, boolean airPlace) { + return place(pos, airPlace, InteractionHand.MAIN_HAND); + } + + public static boolean place(BlockPos pos, boolean airPlace, InteractionHand hand) { + if (mc.level == null || mc.player == null || mc.gameMode == null) return false; + if (!isPlaceable(pos, false)) return false; + Direction direction = calcSide(pos); + if (direction == null) { + if (airPlace) + direction = mc.hitResult != null ? ((BlockHitResult) mc.hitResult).getDirection() : Direction.DOWN; + else return false; + } + BlockPos bp = airPlace ? pos : pos.relative(direction); + InteractionResult result = mc.gameMode.useItemOn(mc.player, hand, new BlockHitResult( + airPlace ? Vec3.atCenterOf(pos) : Vec3.atCenterOf(bp).relative(direction.getOpposite(), 0.5), + airPlace ? direction : direction.getOpposite(), bp, false + )); + if (result instanceof InteractionResult.Success success && success.swingSource() != InteractionResult.SwingSource.NONE) { + mc.player.connection.send(new ServerboundSwingPacket(hand)); + } + return true; + } + + public static Direction calcSide(BlockPos pos) { + for (Direction d : Direction.values()) + if (!mc.level.getBlockState(pos.offset(d.getUnitVec3i())).canBeReplaced()) return d; + return null; + } + + public static double getBlockBreakingSpeed(int slot, BlockPos pos) { + return getBlockBreakingSpeed(slot, mc.level.getBlockState(pos)); + } + + public static double getBlockBreakingSpeed(int slot, BlockState block) { + double speed = mc.player.getInventory().getNonEquipmentItems().get(slot).getDestroySpeed(block); + + if (speed > 1) { + ItemStack tool = mc.player.getInventory().getItem(slot); + + int efficiency = EnchantmentUtil.getLevel(Enchantments.EFFICIENCY, tool); + + if (efficiency > 0 && !tool.isEmpty()) speed += efficiency * efficiency + 1; + } + + if (MobEffectUtil.hasDigSpeed(mc.player)) { + speed *= 1 + (MobEffectUtil.getDigSpeedAmplification(mc.player) + 1) * 0.2F; + } + + if (mc.player.hasEffect(MobEffects.MINING_FATIGUE)) { + float k = switch (mc.player.getEffect(MobEffects.MINING_FATIGUE).getAmplifier()) { + case 0 -> 0.3F; + case 1 -> 0.09F; + case 2 -> 0.0027F; + default -> 8.1E-4F; + }; + + speed *= k; + } + + if (mc.player.isEyeInFluid(FluidTags.WATER) && EnchantmentUtil.has(Enchantments.AQUA_AFFINITY, EquipmentSlot.HEAD)) { + speed /= 5.0F; + } + + if (!mc.player.onGround()) { + speed /= 5.0F; + } + + float hardness = block.getDestroySpeed(null, null); + if (hardness == -1) return 0; + + speed /= hardness / (!block.requiresCorrectToolForDrops() || mc.player.getInventory().getNonEquipmentItems().get(slot).isCorrectToolForDrops(block) ? 30 : 100); + + float ticks = (float) (Math.floor(1.0f / speed) + 1.0f); + + return (long) ((ticks / 20.0f) * 1000); + } + + public static Direction right(Direction direction) { + return switch (direction) { + case EAST -> Direction.SOUTH; + case SOUTH -> Direction.WEST; + case WEST -> Direction.NORTH; + case NORTH -> Direction.EAST; + default -> throw new IllegalStateException("Unexpected value: " + direction); + }; + } + + public static Direction left(Direction direction) { + return switch (direction) { + case EAST -> Direction.NORTH; + case NORTH -> Direction.WEST; + case WEST -> Direction.SOUTH; + case SOUTH -> Direction.EAST; + default -> throw new IllegalStateException("Unexpected value: " + direction); + }; + } +} diff --git a/src/main/java/me/alpha432/oyvey/util/KeyboardUtil.java b/src/main/java/me/alpha432/oyvey/util/KeyboardUtil.java new file mode 100644 index 0000000..989abd9 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/util/KeyboardUtil.java @@ -0,0 +1,59 @@ +package me.alpha432.oyvey.util; + +import com.mojang.blaze3d.platform.InputConstants; +import me.alpha432.oyvey.features.settings.Bind; +import net.minecraft.client.input.KeyEvent; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +public class KeyboardUtil { + public static String getKeyName(int key, boolean mouse) { + return getKeyName(mouse ? Bind.mouse(key) : Bind.keyboard(key)); + } + + public static String getKeyName(Bind bind) { + if (bind.isEmpty()) return "NONE"; + if (bind.isMouse()) return "MOUSE" + (-bind.getKey() - 1); + return getKeyName(InputConstants.getKey(new KeyEvent(bind.getKey(), 0, 0))); + } + + public static String getKeyName(InputConstants.Key key) { + return key.getName() + .replace("key.mouse.", "") + .replace("key.keyboard.", "") + .replace(".", "_") + .toUpperCase(Locale.ROOT); + } + + public static Bind getBind(String name) { + String lowercaseName = name.toLowerCase(Locale.ROOT).replace("_", "."); + if (lowercaseName.startsWith("mouse")) { + try { + int button = Integer.parseInt(lowercaseName.substring(5)); + if (button < 1) return null; + return new Bind(-button - 1); + } catch (Exception e) { + return null; + } + } + + try { + InputConstants.Key key = InputConstants.getKey("key.keyboard." + lowercaseName); + return new Bind(key.getValue()); + } catch (IllegalArgumentException exception) { + return null; + } + } + + public static Iterable iterateKeys() { + List keys = new ArrayList<>(); + for (InputConstants.Key key : InputConstants.Type.KEYSYM.map.values()) + keys.add(getKeyName(key)); + for (int i = 1; i <= 9; i++) { + keys.add("MOUSE" + i); + } + return keys; + } +} diff --git a/src/main/java/me/alpha432/oyvey/util/MathUtil.java b/src/main/java/me/alpha432/oyvey/util/MathUtil.java new file mode 100644 index 0000000..e267dbb --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/util/MathUtil.java @@ -0,0 +1,215 @@ +package me.alpha432.oyvey.util; + +import me.alpha432.oyvey.util.traits.Util; +import net.minecraft.core.BlockPos; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.*; + +public class MathUtil + implements Util { + private static final Random random = new Random(); + + public static int getRandom(int min, int max) { + return min + random.nextInt(max - min + 1); + } + + public static double getRandom(double min, double max) { + return Mth.clamp(min + random.nextDouble() * (max - min), min, max); + } + + public static float getRandom(float min, float max) { + return Mth.clamp(min + random.nextFloat() * (max - min), min, max); + } + + public static int clamp(int num, int min, int max) { + return num < min ? min : Math.min(num, max); + } + + public static float clamp(float num, float min, float max) { + return num < min ? min : Math.min(num, max); + } + + public static double clamp(double num, double min, double max) { + return num < min ? min : Math.min(num, max); + } + + public static float sin(float value) { + return Mth.sin(value); + } + + public static float cos(float value) { + return Mth.cos(value); + } + + public static float wrapDegrees(float value) { + return Mth.wrapDegrees(value); + } + + public static double wrapDegrees(double value) { + return Mth.wrapDegrees(value); + } + + public static Vec3 roundVec(Vec3 vec3d, int places) { + return new Vec3(MathUtil.round(vec3d.x, places), MathUtil.round(vec3d.y, places), MathUtil.round(vec3d.z, places)); + } + + public static double square(double input) { + return input * input; + } + + public static double round(double value, int places) { + if (places < 0) { + throw new IllegalArgumentException(); + } + BigDecimal bd = BigDecimal.valueOf(value); + bd = bd.setScale(places, RoundingMode.FLOOR); + return bd.doubleValue(); + } + + public static float wrap(float valI) { + float val = valI % 360.0f; + if (val >= 180.0f) { + val -= 360.0f; + } + if (val < -180.0f) { + val += 360.0f; + } + return val; + } + + public static Vec3 direction(float yaw) { + return new Vec3(Math.cos(MathUtil.degToRad(yaw + 90.0f)), 0.0, Math.sin(MathUtil.degToRad(yaw + 90.0f))); + } + + public static float round(float value, int places) { + if (places < 0) { + throw new IllegalArgumentException(); + } + BigDecimal bd = BigDecimal.valueOf(value); + bd = bd.setScale(places, RoundingMode.FLOOR); + return bd.floatValue(); + } + + public static > Map sortByValue(Map map, boolean descending) { + LinkedList> list = new LinkedList<>(map.entrySet()); + if (descending) { + list.sort(Map.Entry.comparingByValue(Comparator.reverseOrder())); + } else { + list.sort(Map.Entry.comparingByValue()); + } + LinkedHashMap result = new LinkedHashMap<>(); + for (Map.Entry entry : list) { + result.put(entry.getKey(), entry.getValue()); + } + return result; + } + + public static String getTimeOfDay() { + Calendar c = Calendar.getInstance(); + int timeOfDay = c.get(Calendar.HOUR_OF_DAY); + if (timeOfDay < 12) { + return "Good Morning "; + } + if (timeOfDay < 16) { + return "Good Afternoon "; + } + if (timeOfDay < 21) { + return "Good Evening "; + } + return "Good Night "; + } + + public static double radToDeg(double rad) { + return rad * (double) 57.29578f; + } + + public static double degToRad(double deg) { + return deg * 0.01745329238474369; + } + + public static double getIncremental(double val, double inc) { + double one = 1.0 / inc; + return (double) Math.round(val * one) / one; + } + + public static double[] directionSpeed(double speed) { + float forward = MathUtil.mc.player.input.getMoveVector().y; + float side = MathUtil.mc.player.input.getMoveVector().x; + float yaw = MathUtil.mc.player.yRotO + (MathUtil.mc.player.getYRot() - MathUtil.mc.player.yRotO) * mc.getDeltaTracker().getGameTimeDeltaPartialTick(false); + if (forward != 0.0f) { + if (side > 0.0f) { + yaw += (float) (forward > 0.0f ? -45 : 45); + } else if (side < 0.0f) { + yaw += (float) (forward > 0.0f ? 45 : -45); + } + side = 0.0f; + if (forward > 0.0f) { + forward = 1.0f; + } else if (forward < 0.0f) { + forward = -1.0f; + } + } + double sin = Math.sin(Math.toRadians(yaw + 90.0f)); + double cos = Math.cos(Math.toRadians(yaw + 90.0f)); + double posX = (double) forward * speed * cos + (double) side * speed * sin; + double posZ = (double) forward * speed * sin - (double) side * speed * cos; + return new double[]{posX, posZ}; + } + + public static List getBlockBlocks(Entity entity) { + ArrayList vec3ds = new ArrayList<>(); + AABB bb = entity.getBoundingBox(); + double y = entity.getY(); + double minX = MathUtil.round(bb.minX, 0); + double minZ = MathUtil.round(bb.minZ, 0); + double maxX = MathUtil.round(bb.maxX, 0); + double maxZ = MathUtil.round(bb.maxZ, 0); + if (minX != maxX) { + vec3ds.add(new Vec3(minX, y, minZ)); + vec3ds.add(new Vec3(maxX, y, minZ)); + if (minZ != maxZ) { + vec3ds.add(new Vec3(minX, y, maxZ)); + vec3ds.add(new Vec3(maxX, y, maxZ)); + return vec3ds; + } + } else if (minZ != maxZ) { + vec3ds.add(new Vec3(minX, y, minZ)); + vec3ds.add(new Vec3(minX, y, maxZ)); + return vec3ds; + } + vec3ds.add(entity.position()); + return vec3ds; + } + + public static boolean areVec3dsAligned(Vec3 vec3d1, Vec3 vec3d2) { + return MathUtil.areVec3dsAlignedRetarded(vec3d1, vec3d2); + } + + public static boolean areVec3dsAlignedRetarded(Vec3 vec3d1, Vec3 vec3d2) { + BlockPos pos1 = BlockPos.containing(vec3d1); + BlockPos pos2 = BlockPos.containing(vec3d2.x, vec3d1.y, vec3d2.z); + return pos1.equals(pos2); + } + + public static float[] calcAngle(Vec3 from, Vec3 to) { + double difX = to.x - from.x; + double difY = (to.y - from.y) * -1.0; + double difZ = to.z - from.z; + double dist = Math.sqrt(difX * difX + difZ * difZ); + return new float[]{(float) Mth.wrapDegrees(Math.toDegrees(Math.atan2(difZ, difX)) - 90.0), (float) Mth.wrapDegrees(Math.toDegrees(Math.atan2(difY, dist)))}; + } + + public static Vec3 clamp(Vec3 vec3d, AABB aabb) { + return new Vec3( + clamp(vec3d.x, aabb.minX, aabb.maxX), + clamp(vec3d.y, aabb.minY, aabb.maxY), + clamp(vec3d.z, aabb.minZ, aabb.maxZ) + ); + } +} \ No newline at end of file diff --git a/src/main/java/me/alpha432/oyvey/util/MovementUtil.java b/src/main/java/me/alpha432/oyvey/util/MovementUtil.java new file mode 100644 index 0000000..a4e569d --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/util/MovementUtil.java @@ -0,0 +1,76 @@ +package me.alpha432.oyvey.util; + +import me.alpha432.oyvey.util.traits.Util; +import net.minecraft.client.player.ClientInput; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.effect.MobEffects; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.ai.attributes.Attributes; +import net.minecraft.world.level.block.state.BlockState; +import org.joml.Vector2f; + +public class MovementUtil implements Util { + public static final double SPRINT_SPEED = 0.2873; + + public static Vector2f calcMoveVector(float yaw, Vector2f input, double speed) { + Vector2f direction = new Vector2f(input); + + if (direction.lengthSquared() < 1.0E-8f) { + return direction.zero(); + } + + direction.normalize(); + + float rad = (float) Math.toRadians(yaw); + float sin = (float) Math.sin(rad); + float cos = (float) Math.cos(rad); + + float x = (direction.x * cos - direction.y * sin) * (float) speed; + float z = (direction.y * cos + direction.x * sin) * (float) speed; + + return direction.set(x, z); + } + + public static Vector2f calcMoveVector(float yaw, ClientInput input, double speed) { + return calcMoveVector(yaw, new Vector2f(input.getMoveVector().x, input.getMoveVector().y), speed); + } + + public static Vector2f calcMoveVector(float yaw, double speed) { + return calcMoveVector(yaw, mc.player.input, speed); + } + + public static double getSpeedFactor(boolean swiftness, boolean slowness) { + double factor = 1.0; + + MobEffectInstance speedEffect = mc.player.getEffect(MobEffects.SPEED); + if (swiftness && speedEffect != null) { + factor *= 1.0 + 0.2 * (speedEffect.getAmplifier() + 1); + } + + MobEffectInstance slowEffect = mc.player.getEffect(MobEffects.SLOWNESS); + if (slowness && slowEffect != null) { + factor *= Math.max(0.0, 1.0 - 0.15 * (slowEffect.getAmplifier() + 1)); + } + + return factor; + } + + public static double getJumpBoost() { + return mc.player.getJumpBoostPower(); + } + + public static double getJumpSpeed() { + return mc.player.getAttributeValue(Attributes.JUMP_STRENGTH) * getBlockJumpFactor(mc.player) + getJumpBoost(); + } + + public static double getJumpHeight() { + return mc.player.getAttributeValue(Attributes.JUMP_STRENGTH) + getJumpBoost(); + } + + private static float getBlockJumpFactor(LivingEntity entity) { + BlockState inside = entity.level().getBlockState(entity.blockPosition()); + float factor = inside.getBlock().getJumpFactor(); + if (factor != 1.0f) return factor; + return entity.level().getBlockState(entity.getBlockPosBelowThatAffectsMyMovement()).getBlock().getJumpFactor(); + } +} diff --git a/src/main/java/me/alpha432/oyvey/util/TextUtil.java b/src/main/java/me/alpha432/oyvey/util/TextUtil.java new file mode 100644 index 0000000..46796b0 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/util/TextUtil.java @@ -0,0 +1,35 @@ +package me.alpha432.oyvey.util; + +import dev.cattyn.catformat.CatFormat; +import dev.cattyn.catformat.fabric.FabricCatFormat; +import me.alpha432.oyvey.OyVey; +import net.minecraft.network.chat.MutableComponent; + +public final class TextUtil { + private static CatFormat formatter; + + private TextUtil() { + throw new AssertionError("Can't create an instance of utility class"); + } + + public static void init() { + if (formatter != null) throw new IllegalStateException("Formatter is already initialized"); + formatter = new FabricCatFormat(true); + initColors(); + } + + public static MutableComponent text(String content, Object... obj) { + if (obj == null || obj.length == 0) { + return formatter.format(content); + } + return formatter.format(content, obj); + } + + public static CatFormat getFormatter() { + return formatter; + } + + private static void initColors() { + formatter.add("global", () -> OyVey.colorManager.getColorAsInt()); + } +} diff --git a/src/main/java/me/alpha432/oyvey/util/chat/ChatUtil.java b/src/main/java/me/alpha432/oyvey/util/chat/ChatUtil.java new file mode 100644 index 0000000..3ee3730 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/util/chat/ChatUtil.java @@ -0,0 +1,60 @@ +package me.alpha432.oyvey.util.chat; + +import me.alpha432.oyvey.OyVey; +import me.alpha432.oyvey.ducks.render.IChatComponent; +import me.alpha432.oyvey.features.commands.Command; +import me.alpha432.oyvey.util.TextUtil; +import net.minecraft.ChatFormatting; +import net.minecraft.client.GuiMessage; +import net.minecraft.client.GuiMessageTag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MessageSignature; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.network.chat.Style; + +import static me.alpha432.oyvey.util.traits.Util.mc; + +public class ChatUtil { + public static MutableComponent prefix() { + return withPrefix((Component) null); + } + + public static MutableComponent withPrefix(String string) { + return withPrefix(string, new Object[0]); + } + + public static MutableComponent withPrefix(String string, Object... o) { + return withPrefix(TextUtil.text(string, o)); + } + + public static MutableComponent withPrefix(Component component) { + MutableComponent text = Component.empty() + .setStyle(Style.EMPTY.withColor(ChatFormatting.GRAY)) + .append(Component.literal("<")) + .append(getClientNameComponent()) + .append(Component.literal(">")); + if (component != null) text.append(" ").append(component); + return text; + } + + public static void sendMessage(Component message, Signature identifier) { + sendClientSideMessage(withPrefix(message), identifier); + } + + public static void sendClientSideMessage(Component message, Signature sig) { + if (Command.nullCheck()) return; + + IChatComponent chat = (IChatComponent) mc.gui.getChat(); + MessageSignature signature = new MessageSignature(sig.getByteSignature()); + chat.oyvey$removeMessage(signature); + chat.oyvey$addMessage(new GuiMessage(mc.gui.getGuiTicks(), message, signature, getMessageTag())); + } + + public static Component getClientNameComponent() { + return Component.empty().withColor(OyVey.colorManager.getColorAsInt()).append("OyVey"); + } + + private static GuiMessageTag getMessageTag() { + return new GuiMessageTag(OyVey.colorManager.getColorAsInt(), null, null, null); + } +} \ No newline at end of file diff --git a/src/main/java/me/alpha432/oyvey/util/chat/Signature.java b/src/main/java/me/alpha432/oyvey/util/chat/Signature.java new file mode 100644 index 0000000..3cf50d2 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/util/chat/Signature.java @@ -0,0 +1,5 @@ +package me.alpha432.oyvey.util.chat; + +public interface Signature { + byte[] getByteSignature(); +} diff --git a/src/main/java/me/alpha432/oyvey/util/chat/SimpleSignature.java b/src/main/java/me/alpha432/oyvey/util/chat/SimpleSignature.java new file mode 100644 index 0000000..da2b671 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/util/chat/SimpleSignature.java @@ -0,0 +1,61 @@ +package me.alpha432.oyvey.util.chat; + +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +public class SimpleSignature implements Signature { + private static final MessageDigest MESSAGE_DIGEST; + + private final byte[] signature; + + SimpleSignature(byte[] signature) { + this.signature = signature; + } + + public static SimpleSignature from(String content) { + byte[] sig = allocateBuf() + .put((byte) 1) + .put(sha256(content)) + .array(); + return new SimpleSignature(sig); + } + + public static SimpleSignature fromInt(int id) { + byte[] sig = allocateBuf() + .put((byte) 2) + .putInt(id) + .array(); + return new SimpleSignature(sig); + } + + public static SimpleSignature fromLong(long id) { + byte[] sig = allocateBuf() + .put((byte) 3) + .putLong(id) + .array(); + return new SimpleSignature(sig); + } + + @Override + public byte[] getByteSignature() { + return signature; + } + + private static byte[] sha256(String content) { + return MESSAGE_DIGEST.digest(content.getBytes(StandardCharsets.UTF_8)); + } + + private static ByteBuffer allocateBuf() { + return ByteBuffer.allocate(256); + } + + static { + try { + MESSAGE_DIGEST = MessageDigest.getInstance("SHA-512"); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/main/java/me/alpha432/oyvey/util/inventory/InventoryUtil.java b/src/main/java/me/alpha432/oyvey/util/inventory/InventoryUtil.java new file mode 100644 index 0000000..4e076a1 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/util/inventory/InventoryUtil.java @@ -0,0 +1,107 @@ +package me.alpha432.oyvey.util.inventory; + +import me.alpha432.oyvey.util.inventory.strategy.HoldingStrategy; +import me.alpha432.oyvey.util.inventory.strategy.HotbarStrategy; +import me.alpha432.oyvey.util.inventory.strategy.InventoryStrategy; +import me.alpha432.oyvey.util.inventory.strategy.SwapStrategy; +import me.alpha432.oyvey.util.traits.Util; +import net.minecraft.world.inventory.ClickType; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; + +import java.util.EnumSet; +import java.util.List; +import java.util.function.BiPredicate; +import java.util.function.Consumer; +import java.util.function.Predicate; + +public final class InventoryUtil implements Util { + static final Result NONE = new Result(-1, ItemStack.EMPTY, ResultType.NONE); + + public static final EnumSet HOTBAR_SCOPE = EnumSet.of(ResultType.OFFHAND, ResultType.HOTBAR); + public static final EnumSet INVENTORY_SCOPE = EnumSet.of(ResultType.OFFHAND, ResultType.INVENTORY); + public static final EnumSet FULL_SCOPE = EnumSet.of(ResultType.OFFHAND, ResultType.HOTBAR, ResultType.INVENTORY); + + private static final List STRATEGIES = List.of( + HoldingStrategy.INSTANCE, + HotbarStrategy.INSTANCE, + InventoryStrategy.INSTANCE + ); + + + private InventoryUtil() { + throw new AssertionError(); + } + + public static ItemStack cursor() { + return mc.player.containerMenu.getCarried(); + } + + public static int selected() { + return mc.player.getInventory().getSelectedSlot(); + } + + public static void click(int slot, int button, ClickType type) { + int id = mc.player.containerMenu.containerId; + mc.gameMode.handleInventoryMouseClick(id, slot, button, type, mc.player); + } + + public static void withSwap(Result result, Runnable action) { + withSwap(result, r -> action.run()); + } + + public static void withSwap(Result result, Consumer action) { + int lastSlot = selected(); + if (InventoryUtil.swap(result)) { + action.accept(result); + InventoryUtil.swapBack(result, lastSlot); + } + } + + public static void swap(int to) { + if (to < 0 || to > 8) return; + mc.player.getInventory().setSelectedSlot(to); + mc.gameMode.ensureHasSentCarriedItem(); + } + + public static boolean swap(Result result) { + for (SwapStrategy strategy : STRATEGIES) { + if (strategy.swap(result)) + return true; + } + return false; + } + + public static boolean swapBack(Result result, int last) { + for (SwapStrategy strategy : STRATEGIES) { + if (strategy.swapBack(last, result)) + return true; + } + return false; + } + + public static Result find(Item target, EnumSet scopes) { + return find(stack -> stack.is(target), scopes); + } + + public static Result find(Predicate predicate, EnumSet scopes) { + return find((item, scope) -> scopes.contains(scope) && predicate.test(item)); + } + + public static Result find(BiPredicate predicate) { + ItemStack offhand = mc.player.getOffhandItem(); + if (predicate.test(offhand, ResultType.OFFHAND)) { + return Result.fromOffhand(offhand); + } + + for (int i = 0; i < 36; i++) { + ItemStack item = mc.player.getInventory().getItem(i); + ResultType type = i < 9 ? ResultType.HOTBAR : ResultType.INVENTORY; + if (predicate.test(item, type)) { + return new Result(i, item, type); + } + } + + return NONE; + } +} diff --git a/src/main/java/me/alpha432/oyvey/util/inventory/Result.java b/src/main/java/me/alpha432/oyvey/util/inventory/Result.java new file mode 100644 index 0000000..a16a159 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/util/inventory/Result.java @@ -0,0 +1,26 @@ +package me.alpha432.oyvey.util.inventory; + +import net.minecraft.world.InteractionHand; +import net.minecraft.world.item.ItemStack; + +public record Result(int slot, ItemStack stack, ResultType type, boolean holding) { + public Result(int slot, ItemStack stack, ResultType type) { + this(slot, stack, type, isHolding(type, slot)); + } + + static Result fromOffhand(ItemStack stack) { + return new Result(-1, stack, ResultType.OFFHAND); + } + + public InteractionHand hand() { + return type == ResultType.OFFHAND ? InteractionHand.OFF_HAND : InteractionHand.MAIN_HAND; + } + + public boolean found() { + return type != ResultType.NONE; + } + + private static boolean isHolding(ResultType type, int slot) { + return type == ResultType.OFFHAND || type == ResultType.HOTBAR && slot == InventoryUtil.selected(); + } +} diff --git a/src/main/java/me/alpha432/oyvey/util/inventory/ResultType.java b/src/main/java/me/alpha432/oyvey/util/inventory/ResultType.java new file mode 100644 index 0000000..f73c447 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/util/inventory/ResultType.java @@ -0,0 +1,8 @@ +package me.alpha432.oyvey.util.inventory; + +public enum ResultType { + HOTBAR, + INVENTORY, + OFFHAND, + NONE +} diff --git a/src/main/java/me/alpha432/oyvey/util/inventory/strategy/HoldingStrategy.java b/src/main/java/me/alpha432/oyvey/util/inventory/strategy/HoldingStrategy.java new file mode 100644 index 0000000..63ff6a0 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/util/inventory/strategy/HoldingStrategy.java @@ -0,0 +1,20 @@ +package me.alpha432.oyvey.util.inventory.strategy; + +import me.alpha432.oyvey.util.inventory.Result; + +public final class HoldingStrategy implements SwapStrategy{ + public static final HoldingStrategy INSTANCE = new HoldingStrategy(); + + private HoldingStrategy() { + } + + @Override + public boolean swap(Result result) { + return result.holding(); + } + + @Override + public boolean swapBack(int last, Result result) { + return result.holding(); + } +} diff --git a/src/main/java/me/alpha432/oyvey/util/inventory/strategy/HotbarStrategy.java b/src/main/java/me/alpha432/oyvey/util/inventory/strategy/HotbarStrategy.java new file mode 100644 index 0000000..ef29c0e --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/util/inventory/strategy/HotbarStrategy.java @@ -0,0 +1,30 @@ +package me.alpha432.oyvey.util.inventory.strategy; + +import me.alpha432.oyvey.util.inventory.InventoryUtil; +import me.alpha432.oyvey.util.inventory.Result; +import me.alpha432.oyvey.util.inventory.ResultType; + +public final class HotbarStrategy implements SwapStrategy { + public static final HotbarStrategy INSTANCE = new HotbarStrategy(); + + private HotbarStrategy() { + } + + @Override + public boolean swap(Result result) { + if (result.type() == ResultType.HOTBAR) { + InventoryUtil.swap(result.slot()); + return true; + } + return false; + } + + @Override + public boolean swapBack(int last, Result result) { + if (result.type() == ResultType.HOTBAR) { + InventoryUtil.swap(last); + return true; + } + return false; + } +} diff --git a/src/main/java/me/alpha432/oyvey/util/inventory/strategy/InventoryStrategy.java b/src/main/java/me/alpha432/oyvey/util/inventory/strategy/InventoryStrategy.java new file mode 100644 index 0000000..431b155 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/util/inventory/strategy/InventoryStrategy.java @@ -0,0 +1,31 @@ +package me.alpha432.oyvey.util.inventory.strategy; + +import me.alpha432.oyvey.util.inventory.InventoryUtil; +import me.alpha432.oyvey.util.inventory.Result; +import me.alpha432.oyvey.util.inventory.ResultType; +import net.minecraft.world.inventory.ClickType; + +public final class InventoryStrategy implements SwapStrategy { + public static final InventoryStrategy INSTANCE = new InventoryStrategy(); + + private InventoryStrategy() { + } + + @Override + public boolean swap(Result result) { + if (result.type() != ResultType.INVENTORY && result.type() != ResultType.HOTBAR) + return false; + int slot = inventorySlot(result); + InventoryUtil.click(slot, InventoryUtil.selected(), ClickType.SWAP); + return true; + } + + @Override + public boolean swapBack(int last, Result result) { + return swap(result); + } + + private static int inventorySlot(Result result) { + return result.type() == ResultType.HOTBAR ? result.slot() + 36 : result.slot(); + } +} diff --git a/src/main/java/me/alpha432/oyvey/util/inventory/strategy/SwapStrategy.java b/src/main/java/me/alpha432/oyvey/util/inventory/strategy/SwapStrategy.java new file mode 100644 index 0000000..3f571c3 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/util/inventory/strategy/SwapStrategy.java @@ -0,0 +1,9 @@ +package me.alpha432.oyvey.util.inventory.strategy; + +import me.alpha432.oyvey.util.inventory.Result; + +public interface SwapStrategy { + boolean swap(Result result); + + boolean swapBack(int last, Result result); +} diff --git a/src/main/java/me/alpha432/oyvey/util/models/Angles.java b/src/main/java/me/alpha432/oyvey/util/models/Angles.java new file mode 100644 index 0000000..67bf7a7 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/util/models/Angles.java @@ -0,0 +1,21 @@ +package me.alpha432.oyvey.util.models; + +import me.alpha432.oyvey.util.MathUtil; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.phys.Vec3; + +import static me.alpha432.oyvey.util.traits.Util.mc; + +public record Angles(float yRot, float xRot) { + public Angles(float[] rot) { + this(rot[0], rot[1]); + } + + public static Angles pos(Vec3 pos) { + return new Angles(MathUtil.calcAngle(mc.player.getEyePosition(), pos)); + } + + public static Angles entity(Entity entity) { + return pos(MathUtil.clamp(mc.player.getEyePosition(), entity.getBoundingBox())); + } +} diff --git a/src/main/java/me/alpha432/oyvey/util/models/Timer.java b/src/main/java/me/alpha432/oyvey/util/models/Timer.java new file mode 100644 index 0000000..75276ac --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/util/models/Timer.java @@ -0,0 +1,45 @@ +package me.alpha432.oyvey.util.models; + +public class Timer { + private long time = -1L; + + public boolean passedS(double s) { + return this.getMs(System.nanoTime() - this.time) >= (long) (s * 1000.0); + } + + public boolean passedM(double m) { + return this.getMs(System.nanoTime() - this.time) >= (long) (m * 1000.0 * 60.0); + } + + public boolean passedDms(double dms) { + return this.getMs(System.nanoTime() - this.time) >= (long) (dms * 10.0); + } + + public boolean passedDs(double ds) { + return this.getMs(System.nanoTime() - this.time) >= (long) (ds * 100.0); + } + + public boolean passedMs(long ms) { + return this.getMs(System.nanoTime() - this.time) >= ms; + } + + public boolean passedNS(long ns) { + return System.nanoTime() - this.time >= ns; + } + + public void setMs(long ms) { + this.time = System.nanoTime() - ms * 1000000L; + } + + public long getPassedTimeMs() { + return this.getMs(System.nanoTime() - this.time); + } + + public void reset() { + this.time = System.nanoTime(); + } + + public long getMs(long time) { + return time / 1000000L; + } +} \ No newline at end of file diff --git a/src/main/java/me/alpha432/oyvey/util/render/Layers.java b/src/main/java/me/alpha432/oyvey/util/render/Layers.java new file mode 100644 index 0000000..98a7628 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/util/render/Layers.java @@ -0,0 +1,22 @@ +package me.alpha432.oyvey.util.render; + +import net.minecraft.client.renderer.rendertype.RenderSetup; +import net.minecraft.client.renderer.rendertype.RenderType; + +import static me.alpha432.oyvey.util.render.Pipelines.GLOBAL_LINES_PIPELINE; +import static me.alpha432.oyvey.util.render.Pipelines.GLOBAL_QUADS_PIPELINE; + +public class Layers { + private static final RenderType GLOBAL_QUADS = RenderType.create("global_fill", + RenderSetup.builder(GLOBAL_QUADS_PIPELINE).createRenderSetup()); + private static final RenderType GLOBAL_LINES = RenderType.create("global_lines", + RenderSetup.builder(GLOBAL_LINES_PIPELINE).createRenderSetup()); + + public static RenderType quads() { + return GLOBAL_QUADS; + } + + public static RenderType lines() { + return GLOBAL_LINES; + } +} diff --git a/src/main/java/me/alpha432/oyvey/util/render/Pipelines.java b/src/main/java/me/alpha432/oyvey/util/render/Pipelines.java new file mode 100644 index 0000000..d11911d --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/util/render/Pipelines.java @@ -0,0 +1,36 @@ +package me.alpha432.oyvey.util.render; + +import com.mojang.blaze3d.pipeline.BlendFunction; +import com.mojang.blaze3d.pipeline.RenderPipeline; +import com.mojang.blaze3d.platform.DepthTestFunction; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.VertexFormat; +import net.minecraft.resources.Identifier; + +import static net.minecraft.client.renderer.RenderPipelines.*; + +class Pipelines { + static final RenderPipeline.Snippet GLOBAL_LINES_SNIPPET = RenderPipeline.builder(MATRICES_FOG_SNIPPET, GLOBALS_SNIPPET) + .withVertexShader(Identifier.fromNamespaceAndPath("oyvey", "core/rendertype_lines_smooth")) + .withFragmentShader(Identifier.fromNamespaceAndPath("oyvey", "core/rendertype_lines_smooth")) + .withVertexFormat(DefaultVertexFormat.POSITION_COLOR_NORMAL_LINE_WIDTH, VertexFormat.Mode.LINES) + .withBlend(BlendFunction.TRANSLUCENT) + .withCull(false) + .buildSnippet(); + + + static final RenderPipeline GLOBAL_QUADS_PIPELINE = RenderPipeline.builder(DEBUG_FILLED_SNIPPET) + .withLocation("pipeline/global_fill_pipeline") + .withVertexFormat(DefaultVertexFormat.POSITION_COLOR, VertexFormat.Mode.QUADS) + .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) + .withBlend(BlendFunction.TRANSLUCENT) + .withDepthWrite(false) + .withCull(false) + .build(); + + static final RenderPipeline GLOBAL_LINES_PIPELINE = RenderPipeline.builder(GLOBAL_LINES_SNIPPET) + .withLocation("pipeline/global_lines_pipeline") + .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) + .withDepthWrite(false) + .build(); +} diff --git a/src/main/java/me/alpha432/oyvey/util/render/RenderUtil.java b/src/main/java/me/alpha432/oyvey/util/render/RenderUtil.java new file mode 100644 index 0000000..eaf5779 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/util/render/RenderUtil.java @@ -0,0 +1,270 @@ +package me.alpha432.oyvey.util.render; + +import com.mojang.blaze3d.vertex.*; +import com.mojang.math.Axis; +import me.alpha432.oyvey.util.render.state.RectRenderState; +import me.alpha432.oyvey.util.traits.Util; +import net.minecraft.client.Camera; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.render.TextureSetup; +import net.minecraft.client.renderer.RenderPipelines; +import net.minecraft.core.BlockPos; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; +import net.minecraft.world.phys.shapes.Shapes; +import net.minecraft.world.phys.shapes.VoxelShape; +import org.joml.Matrix3x2f; + +import java.awt.*; + +public class RenderUtil implements Util { + + public static void rect(GuiGraphics context, float x1, float y1, float x2, float y2, int color) { + int ix1 = Math.round(x1); + int iy1 = Math.round(y1); + int ix2 = Math.round(x2); + int iy2 = Math.round(y2); + context.fill(ix1, iy1, ix2, iy2, color); + } + + public static void rect(GuiGraphics context, float x1, float y1, float x2, float y2, int color, float width) { + int w = Math.max(1, Math.round(width)); + context.fill(Math.round(x1), Math.round(y1), Math.round(x2), Math.round(y1) + w, color); + context.fill(Math.round(x2) - w, Math.round(y1), Math.round(x2), Math.round(y2), color); + context.fill(Math.round(x1), Math.round(y2) - w, Math.round(x2), Math.round(y2), color); + context.fill(Math.round(x1), Math.round(y1), Math.round(x1) + w, Math.round(y2), color); + } + + public static void horizontalGradient(GuiGraphics context, float x1, float y1, float x2, float y2, Color left, Color right) { + int ix1 = Math.round(x1); + int iy1 = Math.round(y1); + int ix2 = Math.round(x2); + int iy2 = Math.round(y2); + + gradient(context, ix1, iy1, ix2, iy2, left.hashCode(), left.hashCode(), right.hashCode(), right.hashCode()); + } + + public static void verticalGradient(GuiGraphics context, float x1, float y1, float x2, float y2, Color top, Color bottom) { + int ix1 = Math.round(x1); + int iy1 = Math.round(y1); + int ix2 = Math.round(x2); + int iy2 = Math.round(y2); + + gradient(context, ix1, iy1, ix2, iy2, top.hashCode(), bottom.hashCode(), bottom.hashCode(), top.hashCode()); + } + + public static void gradient(GuiGraphics graphics, + int x1, int y1, int x2, int y2, + int topLeft, int bottomLeft, int bottomRight, int topRight) { + graphics.guiRenderState.submitGuiElement(new RectRenderState( + RenderPipelines.GUI, TextureSetup.noTexture(), new Matrix3x2f(graphics.pose()), + x1, y1, x2, y2, + topLeft, bottomLeft, bottomRight, topRight, + graphics.scissorStack.peek() + )); + } + + public static void rect(PoseStack stack, float x1, float y1, float x2, float y2, int color) { + rectFilled(stack, x1, y1, x2, y2, color); + } + + public static void rect(PoseStack stack, float x1, float y1, float x2, float y2, int color, float width) { + drawHorizontalLine(stack, x1, x2, y1, color, width); + drawVerticalLine(stack, x2, y1, y2, color, width); + drawHorizontalLine(stack, x1, x2, y2, color, width); + drawVerticalLine(stack, x1, y1, y2, color, width); + } + + protected static void drawHorizontalLine(PoseStack matrices, float x1, float x2, float y, int color) { + if (x2 < x1) { + float i = x1; + x1 = x2; + x2 = i; + } + + rectFilled(matrices, x1, y, x2 + 1, y + 1, color); + } + + protected static void drawVerticalLine(PoseStack matrices, float x, float y1, float y2, int color) { + if (y2 < y1) { + float i = y1; + y1 = y2; + y2 = i; + } + + rectFilled(matrices, x, y1 + 1, x + 1, y2, color); + } + + protected static void drawHorizontalLine(PoseStack matrices, float x1, float x2, float y, int color, float width) { + if (x2 < x1) { + float i = x1; + x1 = x2; + x2 = i; + } + + rectFilled(matrices, x1, y, x2 + width, y + width, color); + } + + protected static void drawVerticalLine(PoseStack matrices, float x, float y1, float y2, int color, float width) { + if (y2 < y1) { + float i = y1; + y1 = y2; + y2 = i; + } + + rectFilled(matrices, x, y1 + width, x + width, y2, color); + } + + public static void rectFilled(PoseStack matrix, float x1, float y1, float x2, float y2, int color) { + float i; + if (x1 < x2) { + i = x1; + x1 = x2; + x2 = i; + } + + if (y1 < y2) { + i = y1; + y1 = y2; + y2 = i; + } + + float f = (float) (color >> 24 & 255) / 255.0F; + float g = (float) (color >> 16 & 255) / 255.0F; + float h = (float) (color >> 8 & 255) / 255.0F; + float j = (float) (color & 255) / 255.0F; + + BufferBuilder bufferBuilder = Tesselator.getInstance() + .begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); + bufferBuilder.addVertex(matrix.last().pose(), x1, y2, 0.0F).setColor(g, h, j, f); + bufferBuilder.addVertex(matrix.last().pose(), x2, y2, 0.0F).setColor(g, h, j, f); + bufferBuilder.addVertex(matrix.last().pose(), x2, y1, 0.0F).setColor(g, h, j, f); + bufferBuilder.addVertex(matrix.last().pose(), x1, y1, 0.0F).setColor(g, h, j, f); + + Layers.quads().draw(bufferBuilder.buildOrThrow()); + } + + public static void horizontalGradient(PoseStack matrix, float x1, float y1, float x2, float y2, Color left, Color right) { + BufferBuilder bufferBuilder = Tesselator.getInstance() + .begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); + bufferBuilder.addVertex(matrix.last().pose(), x1, y1, 0.0F).setColor(left.getRed() / 255.0F, left.getGreen() / 255.0F, left.getBlue() / 255.0F, left.getAlpha() / 255.0F); + bufferBuilder.addVertex(matrix.last().pose(), x1, y2, 0.0F).setColor(left.getRed() / 255.0F, left.getGreen() / 255.0F, left.getBlue() / 255.0F, left.getAlpha() / 255.0F); + bufferBuilder.addVertex(matrix.last().pose(), x2, y2, 0.0F).setColor(right.getRed() / 255.0F, right.getGreen() / 255.0F, right.getBlue() / 255.0F, right.getAlpha() / 255.0F); + bufferBuilder.addVertex(matrix.last().pose(), x2, y1, 0.0F).setColor(right.getRed() / 255.0F, right.getGreen() / 255.0F, right.getBlue() / 255.0F, right.getAlpha() / 255.0F); + + Layers.quads().draw(bufferBuilder.buildOrThrow()); + } + + public static void verticalGradient(PoseStack matrix, float x1, float y1, float x2, float y2, Color top, Color bottom) { + BufferBuilder bufferBuilder = Tesselator.getInstance() + .begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); + bufferBuilder.addVertex(matrix.last().pose(), x1, y1, 0.0F).setColor(top.getRed() / 255.0F, top.getGreen() / 255.0F, top.getBlue() / 255.0F, top.getAlpha() / 255.0F); + bufferBuilder.addVertex(matrix.last().pose(), x1, y2, 0.0F).setColor(bottom.getRed() / 255.0F, bottom.getGreen() / 255.0F, bottom.getBlue() / 255.0F, bottom.getAlpha() / 255.0F); + bufferBuilder.addVertex(matrix.last().pose(), x2, y2, 0.0F).setColor(bottom.getRed() / 255.0F, bottom.getGreen() / 255.0F, bottom.getBlue() / 255.0F, bottom.getAlpha() / 255.0F); + bufferBuilder.addVertex(matrix.last().pose(), x2, y1, 0.0F).setColor(top.getRed() / 255.0F, top.getGreen() / 255.0F, top.getBlue() / 255.0F, top.getAlpha() / 255.0F); + + Layers.quads().draw(bufferBuilder.buildOrThrow()); + } + + // 3d + public static void drawBoxFilled(PoseStack stack, AABB box, Color c) { + float minX = (float) (box.minX - mc.getEntityRenderDispatcher().camera.position().x()); + float minY = (float) (box.minY - mc.getEntityRenderDispatcher().camera.position().y()); + float minZ = (float) (box.minZ - mc.getEntityRenderDispatcher().camera.position().z()); + float maxX = (float) (box.maxX - mc.getEntityRenderDispatcher().camera.position().x()); + float maxY = (float) (box.maxY - mc.getEntityRenderDispatcher().camera.position().y()); + float maxZ = (float) (box.maxZ - mc.getEntityRenderDispatcher().camera.position().z()); + + BufferBuilder bufferBuilder = Tesselator.getInstance() + .begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); + bufferBuilder.addVertex(stack.last().pose(), minX, minY, minZ).setColor(c.getRGB()); + bufferBuilder.addVertex(stack.last().pose(), maxX, minY, minZ).setColor(c.getRGB()); + bufferBuilder.addVertex(stack.last().pose(), maxX, minY, maxZ).setColor(c.getRGB()); + bufferBuilder.addVertex(stack.last().pose(), minX, minY, maxZ).setColor(c.getRGB()); + + bufferBuilder.addVertex(stack.last().pose(), minX, maxY, minZ).setColor(c.getRGB()); + bufferBuilder.addVertex(stack.last().pose(), minX, maxY, maxZ).setColor(c.getRGB()); + bufferBuilder.addVertex(stack.last().pose(), maxX, maxY, maxZ).setColor(c.getRGB()); + bufferBuilder.addVertex(stack.last().pose(), maxX, maxY, minZ).setColor(c.getRGB()); + + bufferBuilder.addVertex(stack.last().pose(), minX, minY, minZ).setColor(c.getRGB()); + bufferBuilder.addVertex(stack.last().pose(), minX, maxY, minZ).setColor(c.getRGB()); + bufferBuilder.addVertex(stack.last().pose(), maxX, maxY, minZ).setColor(c.getRGB()); + bufferBuilder.addVertex(stack.last().pose(), maxX, minY, minZ).setColor(c.getRGB()); + + bufferBuilder.addVertex(stack.last().pose(), maxX, minY, minZ).setColor(c.getRGB()); + bufferBuilder.addVertex(stack.last().pose(), maxX, maxY, minZ).setColor(c.getRGB()); + bufferBuilder.addVertex(stack.last().pose(), maxX, maxY, maxZ).setColor(c.getRGB()); + bufferBuilder.addVertex(stack.last().pose(), maxX, minY, maxZ).setColor(c.getRGB()); + + bufferBuilder.addVertex(stack.last().pose(), minX, minY, maxZ).setColor(c.getRGB()); + bufferBuilder.addVertex(stack.last().pose(), maxX, minY, maxZ).setColor(c.getRGB()); + bufferBuilder.addVertex(stack.last().pose(), maxX, maxY, maxZ).setColor(c.getRGB()); + bufferBuilder.addVertex(stack.last().pose(), minX, maxY, maxZ).setColor(c.getRGB()); + + bufferBuilder.addVertex(stack.last().pose(), minX, minY, minZ).setColor(c.getRGB()); + bufferBuilder.addVertex(stack.last().pose(), minX, minY, maxZ).setColor(c.getRGB()); + bufferBuilder.addVertex(stack.last().pose(), minX, maxY, maxZ).setColor(c.getRGB()); + bufferBuilder.addVertex(stack.last().pose(), minX, maxY, minZ).setColor(c.getRGB()); + + Layers.quads().draw(bufferBuilder.buildOrThrow()); + } + + public static void drawBoxFilled(PoseStack stack, Vec3 vec, Color c) { + drawBoxFilled(stack, AABB.unitCubeFromLowerCorner(vec), c); + } + + public static void drawBoxFilled(PoseStack stack, BlockPos bp, Color c) { + drawBoxFilled(stack, new AABB(bp), c); + } + + public static void drawBox(PoseStack stack, AABB box, Color c, float lineWidth) { + drawBox(stack, Shapes.create(box), c, lineWidth); + } + + public static void drawBox(PoseStack stack, VoxelShape shape, Color c, float lineWidth) { + Vec3 camera = mc.getEntityRenderDispatcher().camera.position(); + + BufferBuilder bufferBuilder = Tesselator.getInstance() + .begin(VertexFormat.Mode.LINES, DefaultVertexFormat.POSITION_COLOR_NORMAL_LINE_WIDTH); + PoseStack.Pose pose = stack.last(); + int color = c.getRGB(); + + shape.forAllEdges((x1, y1, z1, x2, y2, z2) -> { + addLine(bufferBuilder, pose, color, lineWidth, + x1 - camera.x, y1 - camera.y, z1 - camera.z, + x2 - camera.x, y2 - camera.y, z2 - camera.z + ); + }); + + Layers.lines().draw(bufferBuilder.buildOrThrow()); + } + + private static void addLine(BufferBuilder buf, PoseStack.Pose pose, int color, float lineWidth, + double x1, double y1, double z1, double x2, double y2, double z2) { + float nx = (float) (x2 - x1); + float ny = (float) (y2 - y1); + float nz = (float) (z2 - z1); + buf.addVertex(pose, (float) x1, (float) y1, (float) z1) + .setColor(color).setNormal(pose, nx, ny, nz).setLineWidth(lineWidth); + buf.addVertex(pose, (float) x2, (float) y2, (float) z2) + .setColor(color).setNormal(pose, nx, ny, nz).setLineWidth(lineWidth); + } + + public static void drawBox(PoseStack stack, Vec3 vec, Color c, float lineWidth) { + drawBox(stack, AABB.unitCubeFromLowerCorner(vec), c, lineWidth); + } + + public static void drawBox(PoseStack stack, BlockPos bp, Color c, float lineWidth) { + drawBox(stack, new AABB(bp), c, lineWidth); + } + + public static PoseStack matrixFrom(Vec3 pos) { + PoseStack matrices = new PoseStack(); + Camera camera = mc.gameRenderer.getMainCamera(); + matrices.mulPose(Axis.XP.rotationDegrees(camera.xRot())); + matrices.mulPose(Axis.YP.rotationDegrees(camera.yRot() + 180.0F)); + matrices.translate(pos.x() - camera.position().x, pos.y() - camera.position().y, pos.z() - camera.position().z); + return matrices; + } +} diff --git a/src/main/java/me/alpha432/oyvey/util/render/ScissorUtil.java b/src/main/java/me/alpha432/oyvey/util/render/ScissorUtil.java new file mode 100644 index 0000000..0bd3a66 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/util/render/ScissorUtil.java @@ -0,0 +1,26 @@ +package me.alpha432.oyvey.util.render; + +import net.minecraft.client.gui.GuiGraphics; + +public class ScissorUtil { + private static int X_1; + private static int Y_1; + private static int X_2; + private static int Y_2; + + public static void enable(GuiGraphics context, int x1, int y1, int x2, int y2) { + context.enableScissor(x1, y1, x2, y2); + X_1 = x1; + Y_1 = y1; + X_2 = x2; + Y_2 = y2; + } + + public static void disable(GuiGraphics context) { + context.disableScissor(); + } + + public static void enable(GuiGraphics context) { + context.enableScissor(X_1, Y_1, X_2, Y_2); + } +} diff --git a/src/main/java/me/alpha432/oyvey/util/render/state/RectRenderState.java b/src/main/java/me/alpha432/oyvey/util/render/state/RectRenderState.java new file mode 100644 index 0000000..3b80927 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/util/render/state/RectRenderState.java @@ -0,0 +1,28 @@ +package me.alpha432.oyvey.util.render.state; + +import com.mojang.blaze3d.pipeline.RenderPipeline; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.gui.navigation.ScreenRectangle; +import net.minecraft.client.gui.render.TextureSetup; +import net.minecraft.client.gui.render.state.GuiElementRenderState; +import org.jetbrains.annotations.Nullable; +import org.joml.Matrix3x2f; + +public record RectRenderState(RenderPipeline pipeline, TextureSetup textureSetup, Matrix3x2f pose, int x0, int y0, int x1, int y1, int topLeft, int bottomLeft, int bottomRight, int topRight, @Nullable ScreenRectangle scissorArea, @Nullable ScreenRectangle bounds) implements GuiElementRenderState { + public RectRenderState(RenderPipeline renderPipeline, TextureSetup textureSetup, Matrix3x2f matrix3x2f, int x0, int y0, int x1, int y1, int topLeft, int bottomLeft, int bottomRight, int topRight, @Nullable ScreenRectangle screenRectangle) { + this(renderPipeline, textureSetup, matrix3x2f, x0, y0, x1, y1, topLeft, bottomLeft, bottomRight, topRight, screenRectangle, getBounds(x0, y0, x1, y1, matrix3x2f, screenRectangle)); + } + + public void buildVertices(VertexConsumer vertexConsumer) { + vertexConsumer.addVertexWith2DPose(this.pose(), (float)this.x0(), (float)this.y0()).setColor(this.topLeft()); + vertexConsumer.addVertexWith2DPose(this.pose(), (float)this.x0(), (float)this.y1()).setColor(this.bottomLeft()); + vertexConsumer.addVertexWith2DPose(this.pose(), (float)this.x1(), (float)this.y1()).setColor(this.bottomRight()); + vertexConsumer.addVertexWith2DPose(this.pose(), (float)this.x1(), (float)this.y0()).setColor(this.topRight()); + } + + @Nullable + private static ScreenRectangle getBounds(int i, int j, int k, int l, Matrix3x2f matrix3x2f, @Nullable ScreenRectangle screenRectangle) { + ScreenRectangle screenRectangle2 = (new ScreenRectangle(i, j, k - i, l - j)).transformMaxBounds(matrix3x2f); + return screenRectangle != null ? screenRectangle.intersection(screenRectangle2) : screenRectangle2; + } +} diff --git a/src/main/java/me/alpha432/oyvey/util/traits/Jsonable.java b/src/main/java/me/alpha432/oyvey/util/traits/Jsonable.java new file mode 100644 index 0000000..209754a --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/util/traits/Jsonable.java @@ -0,0 +1,13 @@ +package me.alpha432.oyvey.util.traits; + +import com.google.gson.JsonElement; + +public interface Jsonable { + JsonElement toJson(); + + void fromJson(JsonElement element); + + default String getFileName() { + return ""; + } +} diff --git a/src/main/java/me/alpha432/oyvey/util/traits/Toggleable.java b/src/main/java/me/alpha432/oyvey/util/traits/Toggleable.java new file mode 100644 index 0000000..5be2bef --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/util/traits/Toggleable.java @@ -0,0 +1,18 @@ +package me.alpha432.oyvey.util.traits; + +public interface Toggleable { + boolean isToggled(); + + void enable(); + + void disable(); + + default void toggle() { + if (isToggled()) disable(); + else enable(); + } + + default void setToggled(boolean toggled) { + if(isToggled() != toggled) toggle(); + } +} diff --git a/src/main/java/me/alpha432/oyvey/util/traits/Util.java b/src/main/java/me/alpha432/oyvey/util/traits/Util.java new file mode 100644 index 0000000..59fb273 --- /dev/null +++ b/src/main/java/me/alpha432/oyvey/util/traits/Util.java @@ -0,0 +1,13 @@ +package me.alpha432.oyvey.util.traits; + +import me.alpha432.oyvey.event.system.EventBus; +import net.minecraft.client.Minecraft; + +public interface Util { + Minecraft mc = Minecraft.getInstance(); + EventBus EVENT_BUS = new EventBus(); + + static boolean isLocalPlayer(Object o) { + return o == mc.player; + } +} diff --git a/src/main/resources/assets/oyvey/shaders/core/rendertype_lines_smooth.fsh b/src/main/resources/assets/oyvey/shaders/core/rendertype_lines_smooth.fsh new file mode 100644 index 0000000..99c5eed --- /dev/null +++ b/src/main/resources/assets/oyvey/shaders/core/rendertype_lines_smooth.fsh @@ -0,0 +1,20 @@ +#version 330 + +#moj_import +#moj_import + +in float sphericalVertexDistance; +in float cylindricalVertexDistance; +in vec4 vertexColor; +in float lineEdge; + +out vec4 fragColor; + +void main() { + vec4 color = vertexColor * ColorModulator; + color.a *= exp(-4.0 * lineEdge * lineEdge); + + if (color.a < 0.001) discard; + + fragColor = apply_fog(color, sphericalVertexDistance, cylindricalVertexDistance, FogEnvironmentalStart, FogEnvironmentalEnd, FogRenderDistanceStart, FogRenderDistanceEnd, FogColor); +} \ No newline at end of file diff --git a/src/main/resources/assets/oyvey/shaders/core/rendertype_lines_smooth.vsh b/src/main/resources/assets/oyvey/shaders/core/rendertype_lines_smooth.vsh new file mode 100644 index 0000000..72918a8 --- /dev/null +++ b/src/main/resources/assets/oyvey/shaders/core/rendertype_lines_smooth.vsh @@ -0,0 +1,51 @@ +#version 330 + +#moj_import +#moj_import +#moj_import +#moj_import + +in vec3 Position; +in vec4 Color; +in vec3 Normal; +in float LineWidth; + +out float sphericalVertexDistance; +out float cylindricalVertexDistance; +out vec4 vertexColor; +out float lineEdge; + +const float VIEW_SHRINK = 1.0 - (1.0 / 256.0); +const mat4 VIEW_SCALE = mat4( + VIEW_SHRINK, 0.0, 0.0, 0.0, + 0.0, VIEW_SHRINK, 0.0, 0.0, + 0.0, 0.0, VIEW_SHRINK, 0.0, + 0.0, 0.0, 0.0, 1.0 +); + +void main() { + vec4 linePosStart = ProjMat * VIEW_SCALE * ModelViewMat * vec4(Position, 1.0); + vec4 linePosEnd = ProjMat * VIEW_SCALE * ModelViewMat * vec4(Position + Normal, 1.0); + + vec3 ndc1 = linePosStart.xyz / linePosStart.w; + vec3 ndc2 = linePosEnd.xyz / linePosEnd.w; + + vec2 lineScreenDirection = normalize((ndc2.xy - ndc1.xy) * ScreenSize); + vec2 lineOffset = vec2(-lineScreenDirection.y, lineScreenDirection.x) * LineWidth * 2 / ScreenSize; + + if (lineOffset.x < 0.0) { + lineOffset *= -1.0; + } + + if (gl_VertexID % 2 == 0) { + gl_Position = vec4((ndc1 + vec3(lineOffset, 0.0)) * linePosStart.w, linePosStart.w); + lineEdge = 1.0; + } else { + gl_Position = vec4((ndc1 - vec3(lineOffset, 0.0)) * linePosStart.w, linePosStart.w); + lineEdge = -1.0; + } + + sphericalVertexDistance = fog_spherical_distance(Position); + cylindricalVertexDistance = fog_cylindrical_distance(Position); + vertexColor = Color; +} \ No newline at end of file diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json new file mode 100644 index 0000000..d4977fc --- /dev/null +++ b/src/main/resources/fabric.mod.json @@ -0,0 +1,34 @@ +{ + "schemaVersion": 1, + "id": "oyvey", + "version": "${version}", + "name": "oyvey-ported", + "description": "free and opensource client base", + "authors": [ + "3arthqu4ke", + "alpha432", + "cattyn" + ], + "contact": { + "repo": "https://github.com/mioclient/oyvey-ported" + }, + "license": "MIT", + "environment": "client", + "accessWidener": "oyvey.accesswidener", + "entrypoints": { + "client": [ + "me.alpha432.oyvey.OyVey" + ], + "main": [ + "me.alpha432.oyvey.OyVey" + ] + }, + "mixins": [ + "oyvey.mixins.json" + ], + "depends": { + "fabricloader": ">=${loader_version}", + "fabric": "*", + "minecraft": "${minecraft_version}" + } +} diff --git a/src/main/resources/oyvey.accesswidener b/src/main/resources/oyvey.accesswidener new file mode 100644 index 0000000..32453a4 --- /dev/null +++ b/src/main/resources/oyvey.accesswidener @@ -0,0 +1,13 @@ +accessWidener v2 named + +accessible field net/minecraft/client/Minecraft rightClickDelay I +accessible field net/minecraft/network/protocol/game/ServerboundInteractPacket entityId I +accessible method net/minecraft/network/protocol/game/ServerboundInteractPacket$Action getType ()Lnet/minecraft/network/protocol/game/ServerboundInteractPacket$ActionType; +accessible class net/minecraft/network/protocol/game/ServerboundInteractPacket$ActionType +accessible field net/minecraft/network/protocol/game/ServerboundInteractPacket action Lnet/minecraft/network/protocol/game/ServerboundInteractPacket$Action; +accessible method net/minecraft/client/multiplayer/MultiPlayerGameMode ensureHasSentCarriedItem ()V +accessible field com/mojang/blaze3d/platform/InputConstants$Type map Lit/unimi/dsi/fastutil/ints/Int2ObjectMap; + +accessible field net/minecraft/client/player/LocalPlayer positionReminder I +accessible field net/minecraft/client/player/LocalPlayer yRotLast F +accessible field net/minecraft/client/player/LocalPlayer xRotLast F \ No newline at end of file diff --git a/src/main/resources/oyvey.mixins.json b/src/main/resources/oyvey.mixins.json new file mode 100644 index 0000000..88a27b0 --- /dev/null +++ b/src/main/resources/oyvey.mixins.json @@ -0,0 +1,25 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "me.alpha432.oyvey.mixin", + "compatibilityLevel": "JAVA_21", + "mixins": [ + "network.MixinConnection" + ], + "client": [ + "entity.MixinAbstractClientPlayer", + "entity.MixinClientPlayerEntity", + "input.MixinKeyboardHandler", + "input.MixinMouseHandler", + "network.MixinClientPacketListener", + "render.MixinAvatarRenderer", + "render.MixinChatComponent", + "render.MixinDeltaTrackerTimer", + "render.MixinLevelRenderer", + "render.gui.MixinCommandSuggestions", + "render.gui.MixinGui" + ], + "injectors": { + "defaultRequire": 1 + } +}