Initial commit

This commit is contained in:
RaphiMC 2023-01-04 20:58:09 +01:00
parent d1acd4fb31
commit 886fbd9c5e
72 changed files with 3804 additions and 0 deletions

9
.gitattributes vendored Normal file
View file

@ -0,0 +1,9 @@
#
# https://help.github.com/articles/dealing-with-line-endings/
#
# Linux start script should use lf
/gradlew text eol=lf
# These are Windows script files and should use crlf
*.bat text eol=crlf

6
.github/dependabot.yml vendored Normal file
View file

@ -0,0 +1,6 @@
version: 2
updates:
- package-ecosystem: "gradle"
directory: "/"
schedule:
interval: "daily"

16
.gitignore vendored Normal file
View file

@ -0,0 +1,16 @@
# Compiled class file
*.class
# Log file
*.log
*.log.gz
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
# Project files
/.idea/
/.gradle/
/build/
/out/
/run/

25
README.md Normal file
View file

@ -0,0 +1,25 @@
# ViaProxy
Standalone proxy which uses ViaVersion to translate between minecraft versions.
## Supported Server versions
- Classic (c0.0.15 - c0.30 including [CPE](https://wiki.vg/Classic_Protocol_Extension))
- Alpha (a1.0.15 - a1.2.6)
- Beta (b1.0 - b1.8.1)
- Release (1.0.0 - 1.19.3)
- April Fools (3D Shareware, 20w14infinite)
- Combat Snapshots (Combat Test 8c)
## Supported Client versions
- Release (1.7.2 - 1.19.3)
- April Fools (3D Shareware)
## Releases
### Gradle/Maven
To use ViaProxy with Gradle/Maven you can use this [Maven server](https://maven.lenni0451.net/#/releases/net/raphimc/ViaProxy) or [Jitpack](https://jitpack.io/#RaphiMC/ViaProxy).
You can also find instructions how to implement it into your build script there.
### Jar File
If you just want the latest jar file you can download it from this [Jenkins](https://build.lenni0451.net/job/ViaProxy/).
## Usage
TODO

110
build.gradle Normal file
View file

@ -0,0 +1,110 @@
plugins {
id "java"
id "maven-publish"
}
java.toolchain.languageVersion = JavaLanguageVersion.of(8)
compileJava.options.encoding = compileTestJava.options.encoding = javadoc.options.encoding = "UTF-8"
group = project.maven_group
archivesBaseName = project.maven_name
version = project.maven_version
configurations {
include
implementation.extendsFrom include
api.extendsFrom include
}
repositories {
mavenCentral()
maven {
name = "Jitpack"
url = "https://jitpack.io"
}
maven {
name = "Lenni0451"
url "https://maven.lenni0451.net/releases"
}
maven {
name = "ViaVersion"
url "https://repo.viaversion.com"
}
}
dependencies {
include "com.viaversion:viaversion:4.5.2-SNAPSHOT"
include("com.viaversion:viabackwards-common:4.5.2-SNAPSHOT") {
exclude group: "com.viaversion", module: "viaversion"
exclude group: "io.netty", module: "netty-all"
exclude group: "com.google.guava", module: "guava"
}
include "com.viaversion:viarewind-core:2.0.3-SNAPSHOT"
include "net.raphimc:ViaLegacy:2.0.3"
include("net.raphimc:ViaProtocolHack:2.0.1") {
exclude group: "org.slf4j", module: "slf4j-api"
}
include "com.formdev:flatlaf:3.0"
include "com.google.guava:guava:31.1-jre"
include "net.sf.jopt-simple:jopt-simple:5.0.4"
include "org.apache.logging.log4j:log4j-core:2.19.0"
include "org.apache.logging.log4j:log4j-slf4j-impl:2.19.0"
include "com.github.GeyserMC:MCAuthLib:1.4"
include "net.lenni0451.classtransform:mixinstranslator:1.7.5"
include "net.lenni0451.classtransform:mixinsdummy:1.7.5"
include "net.lenni0451.classtransform:additionalclassprovider:1.7.5"
include "net.lenni0451:Reflect:1.0.2"
include "net.lenni0451:LambdaEvents:2.0.3"
include "net.raphimc.netminecraft:all:2.2.2"
}
java {
withSourcesJar()
}
jar {
dependsOn configurations.include
from {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
configurations.include.collect {
zipTree(it)
}
} {
exclude "META-INF/*.RSA", "META-INF/*.SF", "META-INF/*.DSA"
}
manifest {
attributes(
"Main-Class": "net.raphimc.viaproxy.ViaProxy",
"Multi-Release": "true"
)
}
from("LICENSE") {
rename { "${it}_${project.archivesBaseName}" }
}
}
publishing {
repositories {
maven {
name = "reposilite"
url = "https://maven.lenni0451.net/releases"
credentials(PasswordCredentials)
authentication {
basic(BasicAuthentication)
}
}
}
publications {
maven(MavenPublication) {
groupId = project.maven_group
artifactId = project.maven_name
version = project.maven_version
from components.java
}
}
}

9
gradle.properties Normal file
View file

@ -0,0 +1,9 @@
# Gradle properties
org.gradle.daemon=true
org.gradle.parallel=true
org.gradle.configureondemand=true
# Project properties
maven_name=ViaProxy
maven_group=net.raphimc
maven_version=3.0.0

BIN
gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View file

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

240
gradlew vendored Normal file
View file

@ -0,0 +1,240 @@
#!/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/master/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
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
warn () {
echo "$*"
} >&2
die () {
echo
echo "$*"
echo
exit 1
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

91
gradlew.bat vendored Normal file
View file

@ -0,0 +1,91 @@
@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=.
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

8
settings.gradle Normal file
View file

@ -0,0 +1,8 @@
pluginManagement {
repositories {
mavenCentral()
gradlePluginPortal()
}
}
rootProject.name = "ViaProxy"

View file

@ -0,0 +1,114 @@
package net.raphimc.viaproxy;
import io.netty.channel.Channel;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.ResourceLeakDetector;
import io.netty.util.concurrent.GlobalEventExecutor;
import net.lenni0451.classtransform.TransformerManager;
import net.lenni0451.classtransform.additionalclassprovider.GuavaClassPathProvider;
import net.lenni0451.classtransform.mixinstranslator.MixinsTranslator;
import net.lenni0451.classtransform.utils.loader.EnumLoaderPriority;
import net.lenni0451.classtransform.utils.loader.InjectionClassLoader;
import net.lenni0451.reflect.ClassLoaders;
import net.raphimc.netminecraft.constants.MCPipeline;
import net.raphimc.netminecraft.netty.connection.NetServer;
import net.raphimc.viaproxy.cli.ConsoleHandler;
import net.raphimc.viaproxy.cli.options.Options;
import net.raphimc.viaproxy.plugins.PluginManager;
import net.raphimc.viaproxy.protocolhack.ProtocolHack;
import net.raphimc.viaproxy.proxy.ProxyConnection;
import net.raphimc.viaproxy.proxy.client2proxy.Client2ProxyChannelInitializer;
import net.raphimc.viaproxy.proxy.client2proxy.Client2ProxyHandler;
import net.raphimc.viaproxy.ui.ViaProxyUI;
import net.raphimc.viaproxy.util.logging.Logger;
import javax.swing.*;
import java.awt.*;
public class ViaProxy {
public static NetServer currentProxyServer;
public static Thread loaderThread;
public static ChannelGroup c2pChannels;
public static void main(String[] args) throws Throwable {
final TransformerManager transformerManager = new TransformerManager(new GuavaClassPathProvider());
transformerManager.addTransformerPreprocessor(new MixinsTranslator());
transformerManager.addTransformer("net.raphimc.viaproxy.injection.transformer.**");
transformerManager.addTransformer("net.raphimc.viaproxy.injection.mixins.**");
final InjectionClassLoader injectionClassLoader = new InjectionClassLoader(transformerManager, ClassLoaders.getSystemClassPath());
injectionClassLoader.setPriority(EnumLoaderPriority.PARENT_FIRST);
injectionClassLoader.executeMain(ViaProxy.class.getName(), "injectedMain", args);
}
public static void injectedMain(String[] args) throws InterruptedException {
Logger.setup();
ConsoleHandler.hookConsole();
Logger.LOGGER.info("Initializing ViaProxy...");
setNettyParameters();
MCPipeline.useOptimizedPipeline();
c2pChannels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
loaderThread = new Thread(() -> {
ProtocolHack.init();
PluginManager.loadPlugins();
}, "ViaProtocolHack-Loader");
if (args.length == 0 && !GraphicsEnvironment.isHeadless()) {
loaderThread.start();
final ViaProxyUI[] ui = new ViaProxyUI[1];
SwingUtilities.invokeLater(() -> ui[0] = new ViaProxyUI());
loaderThread.join();
ui[0].setReady();
Logger.LOGGER.info("ViaProxy started successfully!");
return;
}
try {
Options.parse(args);
} catch (Throwable t) {
Logger.LOGGER.fatal("[" + t.getClass().getSimpleName() + "] " + t.getMessage());
return;
}
loaderThread.start();
loaderThread.join();
Logger.LOGGER.info("ViaProxy started successfully!");
startProxy();
}
public static void startProxy() {
if (currentProxyServer != null) {
throw new IllegalStateException("Proxy is already running");
}
currentProxyServer = new NetServer(Client2ProxyHandler::new, Client2ProxyChannelInitializer::new);
Logger.LOGGER.info("Binding proxy server to " + Options.BIND_ADDRESS + ":" + Options.BIND_PORT);
currentProxyServer.bind(Options.BIND_ADDRESS, Options.BIND_PORT, false);
}
public static void stopProxy() {
if (currentProxyServer != null) {
Logger.LOGGER.info("Stopping proxy server");
currentProxyServer.getChannel().close();
currentProxyServer = null;
for (Channel channel : c2pChannels) {
try {
ProxyConnection.fromChannel(channel).kickClient("§cViaProxy has been stopped");
} catch (Throwable ignored) {
}
}
}
}
private static void setNettyParameters() {
ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.DISABLED);
if (System.getProperty("io.netty.allocator.maxOrder") == null) {
System.setProperty("io.netty.allocator.maxOrder", "9");
}
if (Options.NETTY_THREADS > 0) {
System.setProperty("io.netty.eventLoopThreads", Integer.toString(Options.NETTY_THREADS));
}
}
}

View file

@ -0,0 +1,87 @@
package net.raphimc.viaproxy.cli;
public class ConsoleFormatter {
private static final String PREFIX = "\033[";
private static final String SUFFIX = "m";
public static String convert(final String s) {
StringBuilder out = new StringBuilder();
char[] chars = s.toCharArray();
for (int i = 0; i < chars.length; i++) {
char c = chars[i];
char next = i + 1 < chars.length ? chars[i + 1] : '\0';
if (c == '§') {
if (next != '\0') {
if (isColor(next)) out.append(convertToAnsi('r'));
out.append(convertToAnsi(next));
i++;
}
} else {
out.append(c);
}
}
return out + convertToAnsi('r');
}
//The ANSI codes are an approximation. True color is used to get the exact color.
private static String convertToAnsi(final char color) {
switch (Character.toLowerCase(color)) {
case '0': //Black
return PREFIX + getColor("30", 0x00_00_00) + SUFFIX;
case '1': //Dark Blue
return PREFIX + getColor("34", 0x00_00_AA) + SUFFIX;
case '2': //Dark Green
return PREFIX + getColor("32", 0x00_AA_00) + SUFFIX;
case '3': //Dark Aqua
return PREFIX + getColor("36", 0x00_AA_AA) + SUFFIX;
case '4': //Dark Red
return PREFIX + getColor("31", 0xAA_00_00) + SUFFIX;
case '5': //Dark Purple
return PREFIX + getColor("35", 0xAA_00_AA) + SUFFIX;
case '6': //Gold
return PREFIX + getColor("33", 0xFF_AA_00) + SUFFIX;
case '7': //Gray
return PREFIX + getColor("37", 0xAA_AA_AA) + SUFFIX;
case '8': //Dark Gray
return PREFIX + getColor("90", 0x55_55_55) + SUFFIX;
case '9': //Blue
return PREFIX + getColor("94", 0x55_55_FF) + SUFFIX;
case 'a': //Green
return PREFIX + getColor("92", 0x55_FF_55) + SUFFIX;
case 'b': //Aqua
return PREFIX + getColor("96", 0x55_FF_FF) + SUFFIX;
case 'c': //Red
return PREFIX + getColor("91", 0xFF_55_55) + SUFFIX;
case 'd': //Light Purple
return PREFIX + getColor("95", 0xFF_55_FF) + SUFFIX;
case 'e': //Yellow
return PREFIX + getColor("93", 0xFF_FF_55) + SUFFIX;
case 'f': //White
return PREFIX + getColor("97", 0xFF_FF_FF) + SUFFIX;
case 'k': //Obfuscated
return ""; //Not supported in terminal
case 'l': //Bold
return PREFIX + "1" + SUFFIX;
case 'm': //Strikethrough
return PREFIX + "9" + SUFFIX;
case 'n': //Underline
return PREFIX + "4" + SUFFIX;
case 'o': //Italic
return PREFIX + "3" + SUFFIX;
case 'r': //Reset
default:
return PREFIX + 0 + SUFFIX;
}
}
private static boolean isColor(char color) {
color = Character.toLowerCase(color);
return color >= '0' && color <= '9' || color >= 'a' && color <= 'f';
}
private static String getColor(final String ansi, final int rgb) {
return String.format("38;2;%d;%d;%d", (rgb >> 16) & 255, (rgb >> 8) & 255, rgb & 255);
}
}

View file

@ -0,0 +1,42 @@
package net.raphimc.viaproxy.cli;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.connection.UserConnectionImpl;
import net.raphimc.viaprotocolhack.commands.UserCommandSender;
import net.raphimc.viaproxy.plugins.PluginManager;
import net.raphimc.viaproxy.plugins.events.ConsoleCommandEvent;
import net.raphimc.viaproxy.util.ArrayHelper;
import java.util.Arrays;
import java.util.Scanner;
public class ConsoleHandler {
public static void hookConsole() {
new Thread(ConsoleHandler::listen, "Console-Handler").start();
}
private static void listen() {
final Scanner scanner = new Scanner(System.in);
while (scanner.hasNextLine()) {
final String line = scanner.nextLine();
final String[] parts = line.split(" ");
if (parts.length == 0) continue;
final String command = parts[0];
final ArrayHelper args = new ArrayHelper(Arrays.copyOfRange(parts, 1, parts.length));
if (command.equalsIgnoreCase("gc")) {
System.gc();
System.out.println("GC Done");
} else if (command.equalsIgnoreCase("via")) {
Via.getManager().getCommandHandler().onCommand(new UserCommandSender(new UserConnectionImpl(null, true)), args.getAsArray());
} else {
if (PluginManager.EVENT_MANAGER.call(new ConsoleCommandEvent(command, args.getAsArray())).isCancelled()) continue;
System.out.println("Invalid Command!");
System.out.println(" via | Run a viaversion command");
System.out.println(" gc | Run the garbage collector");
}
}
}
}

View file

@ -0,0 +1,21 @@
package net.raphimc.viaproxy.cli.options;
import joptsimple.BuiltinHelpFormatter;
import joptsimple.OptionDescriptor;
import joptsimple.internal.Classes;
import joptsimple.internal.Strings;
public class BetterHelpFormatter extends BuiltinHelpFormatter {
public BetterHelpFormatter() {
super(250, 4);
}
@Override
protected String extractTypeIndicator(OptionDescriptor descriptor) {
String indicator = descriptor.argumentTypeIndicator();
if (indicator != null && indicator.startsWith("[")) return indicator.substring(1, indicator.length() - 1);
return !Strings.isNullOrEmpty(indicator) && !String.class.getName().equals(indicator) ? Classes.shortNameOf(indicator) : "String";
}
}

View file

@ -0,0 +1,72 @@
package net.raphimc.viaproxy.cli.options;
import joptsimple.*;
import net.raphimc.vialegacy.util.VersionEnum;
import net.raphimc.viaproxy.util.logging.Logger;
import java.io.IOException;
import static java.util.Arrays.asList;
public class Options {
public static String BIND_ADDRESS = "0.0.0.0";
public static int BIND_PORT = 25568;
public static boolean SRV_MODE; // Example: lenni0451.net_25565_1.8.x.viaproxy.127.0.0.1.nip.io
public static boolean INTERNAL_SRV_MODE; // Example: ip\7port\7version\7mppass
public static boolean ONLINE_MODE;
public static int NETTY_THREADS = 0;
public static int COMPRESSION_THRESHOLD = 256;
public static String CONNECT_ADDRESS;
public static int CONNECT_PORT;
public static VersionEnum PROTOCOL_VERSION;
public static boolean OPENAUTHMOD_AUTH;
public static boolean LOCAL_SOCKET_AUTH;
public static boolean BETACRAFT_AUTH;
public static void parse(final String[] args) throws IOException {
VersionEnum.init(); // We need to init the version list already here
final OptionParser parser = new OptionParser();
final OptionSpec<Void> help = parser.acceptsAll(asList("help", "h", "?"), "Get a list of all arguments").forHelp();
final OptionSpec<String> bindAddress = parser.acceptsAll(asList("bind_address", "bind_ip", "ba"), "The address the proxy should bind to").withRequiredArg().ofType(String.class).defaultsTo(BIND_ADDRESS);
final OptionSpec<Integer> bindPort = parser.acceptsAll(asList("bind_port", "bp"), "The port the proxy should bind to").withRequiredArg().ofType(Integer.class).defaultsTo(BIND_PORT);
final OptionSpec<Void> srvMode = parser.acceptsAll(asList("srv_mode", "srv", "s"), "Enable srv mode");
final OptionSpec<Void> iSrvMode = parser.acceptsAll(asList("internal_srv_mode", "isrv"), "Enable internal srv mode").availableUnless(srvMode);
final OptionSpec<Void> onlineMode = parser.acceptsAll(asList("online_mode", "om", "o"), "Enable online mode");
final OptionSpec<Integer> nettyThreads = parser.acceptsAll(asList("netty_threads", "t"), "The amount of netty threads to use").withRequiredArg().ofType(Integer.class).defaultsTo(NETTY_THREADS);
final OptionSpec<Integer> compressionThreshold = parser.acceptsAll(asList("compression_threshold", "ct", "c"), "The threshold for packet compression").withRequiredArg().ofType(Integer.class).defaultsTo(COMPRESSION_THRESHOLD);
final OptionSpec<String> connectAddress = parser.acceptsAll(asList("connect_address", "target_ip", "ca", "a"), "The address of the target server").withRequiredArg().ofType(String.class).required();
final OptionSpec<Integer> connectPort = parser.acceptsAll(asList("connect_port", "target_port", "cp", "p"), "The port of the target server").withRequiredArg().ofType(Integer.class).defaultsTo(CONNECT_PORT);
final OptionSpec<VersionEnum> version = parser.acceptsAll(asList("version", "v"), "The version of the target server").withRequiredArg().withValuesConvertedBy(new VersionEnumConverter()).required();
final OptionSpec<Void> openAuthModAuth = parser.acceptsAll(asList("openauthmod_auth", "oam_auth"), "Enable OpenAuthMod authentication");
final OptionSpec<Void> localSocketAuth = parser.accepts("local_socket_auth", "Enable authentication over a local socket");
final OptionSpec<Void> betaCraftAuth = parser.accepts("betacraft_auth", "Use BetaCraft authentication servers for classic");
final OptionSet options = parser.parse(args);
if (options.has(help)) {
parser.formatHelpWith(new BetterHelpFormatter());
parser.printHelpOn(Logger.SYSOUT);
System.exit(0);
}
BIND_ADDRESS = options.valueOf(bindAddress);
BIND_PORT = options.valueOf(bindPort);
SRV_MODE = options.has(srvMode);
INTERNAL_SRV_MODE = options.has(iSrvMode);
ONLINE_MODE = options.has(onlineMode);
NETTY_THREADS = options.valueOf(nettyThreads);
CONNECT_ADDRESS = options.valueOf(connectAddress);
CONNECT_PORT = options.valueOf(connectPort);
PROTOCOL_VERSION = options.valueOf(version);
COMPRESSION_THRESHOLD = options.valueOf(compressionThreshold);
OPENAUTHMOD_AUTH = options.has(openAuthModAuth);
LOCAL_SOCKET_AUTH = options.has(localSocketAuth);
BETACRAFT_AUTH = options.has(betaCraftAuth);
}
}

View file

@ -0,0 +1,31 @@
package net.raphimc.viaproxy.cli.options;
import joptsimple.ValueConversionException;
import joptsimple.ValueConverter;
import net.raphimc.vialegacy.util.VersionEnum;
public class VersionEnumConverter implements ValueConverter<VersionEnum> {
@Override
public VersionEnum convert(String s) {
for (VersionEnum version : VersionEnum.getAllVersions()) {
if (version.getName().equalsIgnoreCase(s)) return version;
}
throw new ValueConversionException("Unable to find version '" + s + "'");
}
@Override
public Class<VersionEnum> valueType() {
return VersionEnum.class;
}
@Override
public String valuePattern() {
StringBuilder s = new StringBuilder();
for (VersionEnum version : VersionEnum.getAllVersions()) {
s.append((s.length() == 0) ? "" : ", ").append(version.getName());
}
return "[" + s + "]";
}
}

View file

@ -0,0 +1,173 @@
package net.raphimc.viaproxy.injection;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.chunks.Chunk;
import com.viaversion.viaversion.api.minecraft.chunks.ChunkSection;
import com.viaversion.viaversion.api.protocol.remapper.PacketRemapper;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.*;
import com.viaversion.viaversion.protocols.protocol1_17to1_16_4.Protocol1_17To1_16_4;
import com.viaversion.viaversion.protocols.protocol1_17to1_16_4.types.Chunk1_17Type;
import net.raphimc.vialegacy.protocols.classic.protocola1_0_15toc0_28_30.model.ClassicLevel;
import net.raphimc.vialegacy.protocols.classic.protocola1_0_15toc0_28_30.providers.ClassicWorldHeightProvider;
import net.raphimc.vialegacy.protocols.classic.protocola1_0_15toc0_28_30.storage.ClassicLevelStorage;
import net.raphimc.vialegacy.util.VersionEnum;
import java.util.*;
public class ClassicWorldHeightInjection {
public static PacketRemapper handleJoinGame(final Protocol1_17To1_16_4 protocol, final PacketRemapper parentRemapper) {
return new PacketRemapper() {
@Override
public void registerMap() {
handler(wrapper -> {
parentRemapper.remap(wrapper);
if (wrapper.isCancelled()) return;
if (VersionEnum.fromUserConnection(wrapper.user()).isOlderThanOrEqualTo(VersionEnum.c0_28toc0_30)) {
for (Tag dimension : wrapper.get(Type.NBT, 0).<CompoundTag>get("minecraft:dimension_type").<ListTag>get("value")) {
changeDimensionTagHeight(wrapper.user(), ((CompoundTag) dimension).get("element"));
}
changeDimensionTagHeight(wrapper.user(), wrapper.get(Type.NBT, 1));
}
});
}
};
}
public static PacketRemapper handleRespawn(final Protocol1_17To1_16_4 protocol, final PacketRemapper parentRemapper) {
return new PacketRemapper() {
@Override
public void registerMap() {
handler(wrapper -> {
parentRemapper.remap(wrapper);
if (wrapper.isCancelled()) return;
if (VersionEnum.fromUserConnection(wrapper.user()).isOlderThanOrEqualTo(VersionEnum.c0_28toc0_30)) {
changeDimensionTagHeight(wrapper.user(), wrapper.get(Type.NBT, 0));
}
});
}
};
}
public static PacketRemapper handleChunkData(final Protocol1_17To1_16_4 protocol, final PacketRemapper parentRemapper) {
return new PacketRemapper() {
@Override
public void registerMap() {
handler(wrapper -> {
parentRemapper.remap(wrapper);
if (wrapper.isCancelled()) return;
if (VersionEnum.fromUserConnection(wrapper.user()).isOlderThanOrEqualTo(VersionEnum.c0_28toc0_30)) {
wrapper.resetReader();
final Chunk chunk = wrapper.read(new Chunk1_17Type(16));
wrapper.write(new Chunk1_17Type(chunk.getSections().length), chunk);
final ClassicWorldHeightProvider heightProvider = Via.getManager().getProviders().get(ClassicWorldHeightProvider.class);
if (chunk.getSections().length < heightProvider.getMaxChunkSectionCount(wrapper.user())) { // Increase available sections to match new world height
final ChunkSection[] newArray = new ChunkSection[heightProvider.getMaxChunkSectionCount(wrapper.user())];
System.arraycopy(chunk.getSections(), 0, newArray, 0, chunk.getSections().length);
chunk.setSections(newArray);
}
final BitSet chunkMask = new BitSet();
for (int i = 0; i < chunk.getSections().length; i++) {
if (chunk.getSections()[i] != null) chunkMask.set(i);
}
chunk.setChunkMask(chunkMask);
final int[] newBiomeData = new int[chunk.getSections().length * 4 * 4 * 4];
System.arraycopy(chunk.getBiomeData(), 0, newBiomeData, 0, chunk.getBiomeData().length);
for (int i = 64; i < chunk.getSections().length * 4; i++) { // copy top layer of old biome data all the way to max world height
System.arraycopy(chunk.getBiomeData(), chunk.getBiomeData().length - 16, newBiomeData, i * 16, 16);
}
chunk.setBiomeData(newBiomeData);
chunk.setHeightMap(new CompoundTag()); // rip heightmap :(
}
});
}
};
}
public static PacketRemapper handleUpdateLight(final Protocol1_17To1_16_4 protocol, final PacketRemapper parentRemapper) {
final PacketRemapper classicLightHandler = new PacketRemapper() {
@Override
public void registerMap() {
map(Type.VAR_INT); // x
map(Type.VAR_INT); // y
map(Type.BOOLEAN); // trust edges
handler(wrapper -> {
wrapper.read(Type.VAR_INT); // sky light mask
wrapper.read(Type.VAR_INT); // block light mask
final int emptySkyLightMask = wrapper.read(Type.VAR_INT); // empty sky light mask
final int emptyBlockLightMask = wrapper.read(Type.VAR_INT); // empty block light mask
final ClassicLevel level = wrapper.user().get(ClassicLevelStorage.class).getClassicLevel();
final ClassicWorldHeightProvider heightProvider = Via.getManager().getProviders().get(ClassicWorldHeightProvider.class);
int sectionYCount = level.getSizeY() >> 4;
if (level.getSizeY() % 16 != 0) sectionYCount++;
if (sectionYCount > heightProvider.getMaxChunkSectionCount(wrapper.user())) {
sectionYCount = heightProvider.getMaxChunkSectionCount(wrapper.user());
}
final List<byte[]> lightArrays = new ArrayList<>();
while (wrapper.isReadable(Type.BYTE_ARRAY_PRIMITIVE, 0)) {
lightArrays.add(wrapper.read(Type.BYTE_ARRAY_PRIMITIVE));
}
int skyLightCount = 16;
int blockLightCount = sectionYCount;
if (lightArrays.size() == 16 + 0 + 2) {
blockLightCount = 0;
} else if (lightArrays.size() == 16 + sectionYCount + 2) {
} else if (lightArrays.size() == sectionYCount + sectionYCount + 2) {
skyLightCount = sectionYCount;
}
skyLightCount += 2; // Chunk below 0 and above 255
final BitSet skyLightMask = new BitSet();
final BitSet blockLightMask = new BitSet();
skyLightMask.set(0, skyLightCount);
blockLightMask.set(0, blockLightCount);
wrapper.write(Type.LONG_ARRAY_PRIMITIVE, skyLightMask.toLongArray());
wrapper.write(Type.LONG_ARRAY_PRIMITIVE, blockLightMask.toLongArray());
wrapper.write(Type.LONG_ARRAY_PRIMITIVE, new long[emptySkyLightMask]);
wrapper.write(Type.LONG_ARRAY_PRIMITIVE, new long[emptyBlockLightMask]);
wrapper.write(Type.VAR_INT, skyLightCount);
for (int i = 0; i < skyLightCount; i++) {
wrapper.write(Type.BYTE_ARRAY_PRIMITIVE, lightArrays.remove(0));
}
wrapper.write(Type.VAR_INT, blockLightCount);
for (int i = 0; i < blockLightCount; i++) {
wrapper.write(Type.BYTE_ARRAY_PRIMITIVE, lightArrays.remove(0));
}
});
}
};
return new PacketRemapper() {
@Override
public void registerMap() {
handler(wrapper -> {
if (VersionEnum.fromUserConnection(wrapper.user()).isOlderThanOrEqualTo(VersionEnum.c0_28toc0_30)) {
classicLightHandler.remap(wrapper);
} else {
parentRemapper.remap(wrapper);
}
});
}
};
}
private static void changeDimensionTagHeight(final UserConnection user, final CompoundTag tag) {
tag.put("height", new IntTag(Via.getManager().getProviders().get(ClassicWorldHeightProvider.class).getMaxChunkSectionCount(user) << 4));
}
}

View file

@ -0,0 +1,34 @@
package net.raphimc.viaproxy.injection.mixins;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.BlockFace;
import com.viaversion.viaversion.api.minecraft.Position;
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.blockconnections.AbstractFenceConnectionHandler;
import net.raphimc.vialegacy.util.VersionEnum;
import org.spongepowered.asm.mixin.*;
@Mixin(value = AbstractFenceConnectionHandler.class, remap = false)
public abstract class MixinAbstractFenceConnectionHandler {
@Shadow
protected abstract boolean connects(BlockFace side, int blockState, boolean pre1_12);
@Shadow
public abstract int getBlockData(UserConnection user, Position position);
/**
* @author RK_01
* @reason Fixes version comparisons
*/
@Overwrite
public byte getStates(UserConnection user, Position position, int blockState) {
byte states = 0;
boolean pre1_12 = VersionEnum.fromUserConnection(user).isOlderThan(VersionEnum.r1_12);
if (connects(BlockFace.EAST, getBlockData(user, position.getRelative(BlockFace.EAST)), pre1_12)) states |= 1;
if (connects(BlockFace.NORTH, getBlockData(user, position.getRelative(BlockFace.NORTH)), pre1_12)) states |= 2;
if (connects(BlockFace.SOUTH, getBlockData(user, position.getRelative(BlockFace.SOUTH)), pre1_12)) states |= 4;
if (connects(BlockFace.WEST, getBlockData(user, position.getRelative(BlockFace.WEST)), pre1_12)) states |= 8;
return states;
}
}

View file

@ -0,0 +1,30 @@
package net.raphimc.viaproxy.injection.mixins;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.minecraft.nbt.BinaryTagIO;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag;
import com.viaversion.viaversion.protocols.protocol1_12to1_11_1.ChatItemRewriter;
import net.raphimc.vialegacy.util.ViaStringTagReader1_11_2;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
import java.util.logging.Level;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Mixin(value = ChatItemRewriter.class, remap = false)
public abstract class MixinChatItemRewriter {
@Redirect(method = "toClient", at = @At(value = "INVOKE", target = "Ljava/util/regex/Pattern;matcher(Ljava/lang/CharSequence;)Ljava/util/regex/Matcher;"))
private static Matcher rewriteShowItem(Pattern pattern, CharSequence input) {
try {
final CompoundTag tag = ViaStringTagReader1_11_2.getTagFromJson(input.toString());
input = BinaryTagIO.writeString(tag);
} catch (Throwable e) {
Via.getPlatform().getLogger().log(Level.WARNING, "Error converting 1.11.2 nbt to 1.12.2 nbt: '" + input + "'", e);
}
return Pattern.compile("$^").matcher(input);
}
}

View file

@ -0,0 +1,37 @@
package net.raphimc.viaproxy.injection.mixins;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.minecraft.chunks.*;
import com.viaversion.viaversion.protocols.protocol1_9to1_8.types.Chunk1_8Type;
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.Redirect;
import java.util.ArrayList;
import java.util.logging.Level;
@Mixin(value = Chunk1_8Type.class, remap = false)
public abstract class MixinChunk1_8Type {
@Shadow
public static Chunk deserialize(int chunkX, int chunkZ, boolean fullChunk, boolean skyLight, int bitmask, byte[] data) {
return null;
}
@Redirect(method = "read(Lio/netty/buffer/ByteBuf;Lcom/viaversion/viaversion/protocols/protocol1_9_3to1_9_1_2/storage/ClientWorld;)Lcom/viaversion/viaversion/api/minecraft/chunks/Chunk;", at = @At(value = "INVOKE", target = "Lcom/viaversion/viaversion/protocols/protocol1_9to1_8/types/Chunk1_8Type;deserialize(IIZZI[B)Lcom/viaversion/viaversion/api/minecraft/chunks/Chunk;"))
private Chunk fixAegis(int chunkX, int chunkZ, boolean fullChunk, boolean skyLight, int bitmask, byte[] data) {
try {
return deserialize(chunkX, chunkZ, fullChunk, skyLight, bitmask, data);
} catch (Throwable e) {
Via.getPlatform().getLogger().log(Level.WARNING, "The server sent an invalid chunk data packet, returning an empty chunk", e);
final ChunkSection[] airSections = new ChunkSection[16];
for (int i = 0; i < airSections.length; i++) {
airSections[i] = new ChunkSectionImpl(true);
airSections[i].palette(PaletteType.BLOCKS).addId(0);
}
return new BaseChunk(chunkX, chunkZ, fullChunk, false, 65535, airSections, new int[256], new ArrayList<>());
}
}
}

View file

@ -0,0 +1,16 @@
package net.raphimc.viaproxy.injection.mixins;
import com.viaversion.viaversion.protocols.protocol1_9to1_8.providers.CommandBlockProvider;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.Constant;
import org.spongepowered.asm.mixin.injection.ModifyConstant;
@Mixin(value = CommandBlockProvider.class, remap = false)
public abstract class MixinCommandBlockProvider {
@ModifyConstant(method = "sendPermission", constant = @Constant(intValue = 26))
private int modifyOpLevel() {
return 28; // Op Level 4
}
}

View file

@ -0,0 +1,15 @@
package net.raphimc.viaproxy.injection.mixins;
import com.viaversion.viaversion.legacy.bossbar.CommonBoss;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(value = CommonBoss.class, remap = false)
public abstract class MixinCommonBoss {
@Redirect(method = {"<init>", "setHealth"}, at = @At(value = "INVOKE", target = "Lcom/google/common/base/Preconditions;checkArgument(ZLjava/lang/Object;)V"))
private void removeBoundChecks(boolean expression, Object errorMessage) {
}
}

View file

@ -0,0 +1,25 @@
package net.raphimc.viaproxy.injection.mixins;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
import com.viaversion.viaversion.api.protocol.remapper.PacketRemapper;
import com.viaversion.viaversion.protocols.protocol1_16_2to1_16_1.ClientboundPackets1_16_2;
import com.viaversion.viaversion.protocols.protocol1_17to1_16_4.Protocol1_17To1_16_4;
import com.viaversion.viaversion.protocols.protocol1_17to1_16_4.packets.EntityPackets;
import net.raphimc.viaproxy.injection.ClassicWorldHeightInjection;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(value = EntityPackets.class, remap = false)
public abstract class MixinEntityPackets1_17 {
@Redirect(method = "registerPackets", at = @At(value = "INVOKE", target = "Lcom/viaversion/viaversion/protocols/protocol1_17to1_16_4/Protocol1_17To1_16_4;registerClientbound(Lcom/viaversion/viaversion/api/protocol/packet/ClientboundPacketType;Lcom/viaversion/viaversion/api/protocol/remapper/PacketRemapper;)V"))
private void handleClassicWorldHeight(Protocol1_17To1_16_4 instance, ClientboundPacketType packetType, PacketRemapper packetRemapper) {
if (packetType == ClientboundPackets1_16_2.JOIN_GAME) packetRemapper = ClassicWorldHeightInjection.handleJoinGame(instance, packetRemapper);
if (packetType == ClientboundPackets1_16_2.RESPAWN) packetRemapper = ClassicWorldHeightInjection.handleRespawn(instance, packetRemapper);
((Protocol) instance).registerClientbound(packetType, packetRemapper);
}
}

View file

@ -0,0 +1,25 @@
package net.raphimc.viaproxy.injection.mixins;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.protocols.protocol1_9to1_8.Protocol1_9To1_8;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(targets = "com.viaversion.viaversion.protocols.protocol1_9to1_8.packets.EntityPackets$6$1", remap = false)
public abstract class MixinEntityPackets_6_1 {
@SuppressWarnings({"UnresolvedMixinReference", "MixinAnnotationTarget"})
@Inject(method = "transform(Lcom/viaversion/viaversion/api/protocol/packet/PacketWrapper;Ljava/lang/Short;)Ljava/lang/Integer;", at = @At(value = "INVOKE", target = "Lcom/viaversion/viaversion/api/data/entity/EntityTracker;clientEntityId()I"), cancellable = true)
private void fixOutOfBoundsSlot(PacketWrapper wrapper, Short slot, CallbackInfoReturnable<Integer> cir) throws Exception {
final int entityId = wrapper.get(Type.VAR_INT, 0);
final int clientPlayerId = wrapper.user().getEntityTracker(Protocol1_9To1_8.class).clientEntityId();
if (slot < 0 || slot > 4 || (entityId == clientPlayerId && slot > 3)) {
wrapper.cancel();
cir.setReturnValue(0);
}
}
}

View file

@ -0,0 +1,30 @@
package net.raphimc.viaproxy.injection.mixins;
import com.viaversion.viaversion.api.minecraft.metadata.Metadata;
import com.viaversion.viaversion.protocols.protocol1_9to1_8.storage.EntityTracker1_9;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.*;
@Mixin(value = EntityTracker1_9.class, remap = false)
public abstract class MixinEntityTracker1_9 {
@Redirect(method = "handleMetadata", at = @At(value = "INVOKE", target = "Ljava/lang/Math;min(FF)F"), slice = @Slice(from = @At(value = "INVOKE", target = "Lcom/viaversion/viaversion/api/configuration/ViaVersionConfig;isBossbarAntiflicker()Z")))
private float removeMin(float a, float b) {
return a;
}
@Redirect(method = "handleMetadata", at = @At(value = "INVOKE", target = "Ljava/lang/Math;max(FF)F"), slice = @Slice(from = @At(value = "INVOKE", target = "Lcom/viaversion/viaversion/api/configuration/ViaVersionConfig;isBossbarAntiflicker()Z")))
private float removeMax(float a, float b) {
return b;
}
@Redirect(method = "handleMetadata", at = @At(value = "INVOKE", target = "Lcom/viaversion/viaversion/api/minecraft/metadata/Metadata;getValue()Ljava/lang/Object;"), slice = @Slice(from = @At(value = "INVOKE", target = "Lcom/viaversion/viaversion/api/configuration/ViaVersionConfig;isBossbarAntiflicker()Z")))
private Object remapNaNToZero(Metadata instance) {
if (instance.getValue() instanceof Float && ((Float) instance.getValue()).isNaN()) {
return 0F;
}
return instance.getValue();
}
}

View file

@ -0,0 +1,32 @@
package net.raphimc.viaproxy.injection.mixins;
import com.viaversion.viaversion.api.connection.ProtocolInfo;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.Position;
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.blockconnections.AbstractFenceConnectionHandler;
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.blockconnections.GlassConnectionHandler;
import net.raphimc.vialegacy.util.Ver