mirror of
https://github.com/ViaVersion/ViaFabric.git
synced 2024-11-25 12:15:14 +01:00
subprojects part 2
This commit is contained in:
parent
e49f1539ed
commit
c09d6f0a74
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
@ -1 +1 @@
|
|||||||
custom: ['https://viaversion.com/donate', 'https://viaversion.com/backwards', 'https://viaversion.com/rewind', 'https://creeper123123321.keybase.pub/#donate']
|
custom: ['https://viaversion.com/donate', 'https://viaversion.com/backwards', 'https://viaversion.com/rewind', 'https://creeper123123321.github.io/#donate']
|
||||||
|
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@ -18,7 +18,7 @@ jobs:
|
|||||||
java-version: 11
|
java-version: 11
|
||||||
- name: build
|
- name: build
|
||||||
env:
|
env:
|
||||||
curse_api_key: ${{ secrets.CREEPER_CF }}
|
CURSEFORGE_API_KEY: ${{ secrets.CREEPER_CF }}
|
||||||
run: ./gradlew
|
run: ./gradlew
|
||||||
- name: capture build artifacts
|
- name: capture build artifacts
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v2
|
||||||
|
26
build.gradle
26
build.gradle
@ -16,7 +16,6 @@ class Globals {
|
|||||||
version = Globals.baseVersion + "+" + (ENV.GITHUB_RUN_NUMBER ? "" : "local-") + getBranch()
|
version = Globals.baseVersion + "+" + (ENV.GITHUB_RUN_NUMBER ? "" : "local-") + getBranch()
|
||||||
logger.lifecycle("Building ViaFabric: " + version)
|
logger.lifecycle("Building ViaFabric: " + version)
|
||||||
|
|
||||||
import org.apache.commons.codec.digest.DigestUtils
|
|
||||||
import net.fabricmc.loom.task.RunClientTask
|
import net.fabricmc.loom.task.RunClientTask
|
||||||
import net.fabricmc.loom.task.RunServerTask
|
import net.fabricmc.loom.task.RunServerTask
|
||||||
|
|
||||||
@ -118,13 +117,13 @@ allprojects {
|
|||||||
}
|
}
|
||||||
|
|
||||||
jar {
|
jar {
|
||||||
classifier = "dev"
|
archiveClassifier = "dev"
|
||||||
}
|
}
|
||||||
|
|
||||||
afterEvaluate {
|
afterEvaluate {
|
||||||
remapJar {
|
remapJar {
|
||||||
input = file("${project.buildDir}/libs/$archivesBaseName-${version}-dev.jar")
|
input = file("${project.buildDir}/libs/$archivesBaseName-${version}-dev.jar")
|
||||||
archiveName = "${archivesBaseName}-${version}.jar"
|
archiveFileName = "${archivesBaseName}-${version}.jar"
|
||||||
}
|
}
|
||||||
|
|
||||||
artifacts {
|
artifacts {
|
||||||
@ -220,7 +219,7 @@ subprojects {
|
|||||||
task remapMavenJar(type: net.fabricmc.loom.task.RemapJarTask, dependsOn: jar) {
|
task remapMavenJar(type: net.fabricmc.loom.task.RemapJarTask, dependsOn: jar) {
|
||||||
afterEvaluate {
|
afterEvaluate {
|
||||||
input = file("${project.buildDir}/libs/${archivesBaseName}-${version}-dev.jar")
|
input = file("${project.buildDir}/libs/${archivesBaseName}-${version}-dev.jar")
|
||||||
archiveName = "${archivesBaseName}-${version}-maven.jar"
|
archiveFileName = "${archivesBaseName}-${version}-maven.jar"
|
||||||
addNestedDependencies = false
|
addNestedDependencies = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -279,6 +278,10 @@ dependencies {
|
|||||||
mappings("net.fabricmc:yarn:1.8.9+build.202103291533:v2")
|
mappings("net.fabricmc:yarn:1.8.9+build.202103291533:v2")
|
||||||
modCompile("net.fabricmc:fabric-loader:0.10.5+build.213")
|
modCompile("net.fabricmc:fabric-loader:0.10.5+build.213")
|
||||||
|
|
||||||
|
include("com.viaversion:viaversion:4.0.0-21w17a")
|
||||||
|
include("org.yaml:snakeyaml:1.28")
|
||||||
|
include("io.github.cottonmc:cotton-client-commands:1.0.0+1.15.2")
|
||||||
|
|
||||||
afterEvaluate {
|
afterEvaluate {
|
||||||
subprojects.each {
|
subprojects.each {
|
||||||
compile project(path: ":${it.name}", configuration: "dev")
|
compile project(path: ":${it.name}", configuration: "dev")
|
||||||
@ -298,11 +301,16 @@ curseforge {
|
|||||||
id = "391298"
|
id = "391298"
|
||||||
changelog = "A changelog can be found at https://github.com/ViaVersion/ViaFabric/commits"
|
changelog = "A changelog can be found at https://github.com/ViaVersion/ViaFabric/commits"
|
||||||
releaseType = "alpha"
|
releaseType = "alpha"
|
||||||
addGameVersion "1.17"
|
Arrays.<String> asList("1.17", "1.16.5", "1.15.2", "1.14.4", "1.8.9", "Java 8", "Java 9", "Java 10", "Fabric")
|
||||||
addGameVersion "Fabric"
|
.forEach { ver -> addGameVersion(ver) }
|
||||||
|
|
||||||
mainArtifact(file("${project.buildDir}/libs/${archivesBaseName}-${version}.jar")) {
|
mainArtifact(file("${project.buildDir}/libs/${archivesBaseName}-${version}.jar")) {
|
||||||
displayName = "[${getBranch()}] ViaFabric $Globals.baseVersion"
|
displayName = "[${getBranch()}] ViaFabric $Globals.baseVersion"
|
||||||
|
relations {
|
||||||
|
requiredDependency("fabric-api")
|
||||||
|
requiredDependency("legacy-fabric-api")
|
||||||
|
embeddedLibrary("cotton-client-commands")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
afterEvaluate {
|
afterEvaluate {
|
||||||
@ -314,3 +322,9 @@ curseforge {
|
|||||||
forgeGradleIntegration = false
|
forgeGradleIntegration = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (getBranch() == "master" && ENV.CURSEFORGE_API_KEY && !ENV.CURSEFORGE_API_KEY.isEmpty()) {
|
||||||
|
defaultTasks("clean", "build", "curseforge")
|
||||||
|
} else {
|
||||||
|
defaultTasks("clean", "build")
|
||||||
|
}
|
@ -12,4 +12,6 @@ rootProject.name = "viafabric"
|
|||||||
|
|
||||||
include "viafabric-mc18"
|
include "viafabric-mc18"
|
||||||
include "viafabric-mc114"
|
include "viafabric-mc114"
|
||||||
|
include "viafabric-mc115"
|
||||||
|
include "viafabric-mc116"
|
||||||
include "viafabric-mc117"
|
include "viafabric-mc117"
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"schemaVersion": 1,
|
"schemaVersion": 1,
|
||||||
"id": "viafabric-impl",
|
"id": "viafabric-mc114",
|
||||||
"name": "ViaFabric",
|
"name": "ViaFabric",
|
||||||
"version": "@version@",
|
"version": "@version@",
|
||||||
"description": "@description@",
|
"description": "@description@",
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
{
|
{
|
||||||
"required": true,
|
"required": true,
|
||||||
"compatibilityLevel": "JAVA_8",
|
"compatibilityLevel": "JAVA_8",
|
||||||
"package": "com.viaversion.fabric.mc114.mixin.address",
|
|
||||||
"mixins": [
|
"mixins": [
|
||||||
],
|
],
|
||||||
"client": [
|
"client": [
|
||||||
"client.MixinConnectScreenThread",
|
"com.viaversion.fabric.mc114.mixin.address.client.MixinConnectScreenThread",
|
||||||
"client.MixinServerAddress",
|
"com.viaversion.fabric.mc114.mixin.address.client.MixinServerAddress",
|
||||||
"client.MixinServerPinger"
|
"com.viaversion.fabric.mc114.mixin.address.client.MixinServerPinger"
|
||||||
],
|
],
|
||||||
"injectors": {
|
"injectors": {
|
||||||
"defaultRequire": 1
|
"defaultRequire": 1
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
{
|
{
|
||||||
"required": true,
|
"required": true,
|
||||||
"compatibilityLevel": "JAVA_8",
|
"compatibilityLevel": "JAVA_8",
|
||||||
"package": "com.viaversion.fabric.mc114.mixin.debug",
|
|
||||||
"mixins": [
|
"mixins": [
|
||||||
],
|
],
|
||||||
"client": [
|
"client": [
|
||||||
"client.MixinClientConnectionAccessor",
|
"com.viaversion.fabric.mc114.mixin.debug.client.MixinClientConnectionAccessor",
|
||||||
"client.MixinDebugHud"
|
"com.viaversion.fabric.mc114.mixin.debug.client.MixinDebugHud"
|
||||||
],
|
],
|
||||||
"injectors": {
|
"injectors": {
|
||||||
"defaultRequire": 0
|
"defaultRequire": 0
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
{
|
{
|
||||||
"required": true,
|
"required": true,
|
||||||
"compatibilityLevel": "JAVA_8",
|
"compatibilityLevel": "JAVA_8",
|
||||||
"package": "com.viaversion.fabric.mc114.mixin.gui",
|
|
||||||
"mixins": [
|
"mixins": [
|
||||||
],
|
],
|
||||||
"client": [
|
"client": [
|
||||||
"client.MixinMultiplayerScreen"
|
"com.viaversion.fabric.mc114.mixin.gui.client.MixinMultiplayerScreen"
|
||||||
],
|
],
|
||||||
"injectors": {
|
"injectors": {
|
||||||
"defaultRequire": 0
|
"defaultRequire": 0
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
{
|
{
|
||||||
"required": true,
|
"required": true,
|
||||||
"compatibilityLevel": "JAVA_8",
|
"compatibilityLevel": "JAVA_8",
|
||||||
"package": "com.viaversion.fabric.mc114.mixin.pipeline",
|
|
||||||
"mixins": [
|
"mixins": [
|
||||||
"MixinClientConnection",
|
"com.viaversion.fabric.mc114.mixin.pipeline.MixinClientConnection",
|
||||||
"MixinServerNetworkIoChInit"
|
"com.viaversion.fabric.mc114.mixin.pipeline.MixinServerNetworkIoChInit"
|
||||||
],
|
],
|
||||||
"client": [
|
"client": [
|
||||||
"client.MixinClientConnectionChInit"
|
"com.viaversion.fabric.mc114.mixin.pipeline.client.MixinClientConnectionChInit"
|
||||||
],
|
],
|
||||||
"injectors": {
|
"injectors": {
|
||||||
"defaultRequire": 1
|
"defaultRequire": 1
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
version = rootProject.version
|
version = rootProject.version
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
minecraft("com.mojang:minecraft:1.14.4")
|
minecraft("com.mojang:minecraft:1.15.2")
|
||||||
mappings("net.fabricmc:yarn:1.14.4+build.16:v2")
|
mappings("net.fabricmc:yarn:1.15.2+build.17:v2")
|
||||||
modImplementation("net.fabricmc:fabric-loader:0.8.2+build.194")
|
modImplementation("net.fabricmc:fabric-loader:0.9.3+build.207")
|
||||||
|
|
||||||
modImplementation("net.fabricmc.fabric-api:fabric-api:0.13.1+build.257-1.14")
|
modImplementation("net.fabricmc.fabric-api:fabric-api:0.19.0+build.325-1.15")
|
||||||
modImplementation("io.github.prospector:modmenu:1.7.16.1.14.4+build.128")
|
modImplementation("io.github.prospector:modmenu:1.10.2+build.32")
|
||||||
modImplementation("io.github.cottonmc:cotton-client-commands:1.0.0+1.15.2")
|
|
||||||
}
|
}
|
@ -0,0 +1,110 @@
|
|||||||
|
package com.viaversion.fabric.mc115;
|
||||||
|
|
||||||
|
import com.viaversion.fabric.mc115.commands.VRCommandHandler;
|
||||||
|
import com.viaversion.fabric.mc115.config.VRConfig;
|
||||||
|
import com.viaversion.fabric.mc115.platform.VRInjector;
|
||||||
|
import com.viaversion.fabric.mc115.platform.VRLoader;
|
||||||
|
import com.viaversion.fabric.mc115.platform.VRPlatform;
|
||||||
|
import com.viaversion.fabric.mc115.protocol.ViaFabricHostnameProtocol;
|
||||||
|
import com.viaversion.fabric.mc115.util.JLoggerToLog4j;
|
||||||
|
import com.google.common.collect.Range;
|
||||||
|
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||||
|
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||||
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||||
|
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
|
||||||
|
import io.netty.channel.DefaultEventLoop;
|
||||||
|
import io.netty.channel.EventLoop;
|
||||||
|
import net.fabricmc.api.ModInitializer;
|
||||||
|
import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback;
|
||||||
|
import net.fabricmc.fabric.api.registry.CommandRegistry;
|
||||||
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
|
import net.minecraft.server.command.CommandSource;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import com.viaversion.viaversion.ViaManagerImpl;
|
||||||
|
import com.viaversion.viaversion.api.Via;
|
||||||
|
import com.viaversion.viaversion.api.data.MappingDataLoader;
|
||||||
|
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||||
|
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ThreadFactory;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
public class ViaFabric implements ModInitializer {
|
||||||
|
public static final Logger JLOGGER = new JLoggerToLog4j(LogManager.getLogger("ViaFabric"));
|
||||||
|
public static final ExecutorService ASYNC_EXECUTOR;
|
||||||
|
public static final EventLoop EVENT_LOOP;
|
||||||
|
public static CompletableFuture<Void> INIT_FUTURE = new CompletableFuture<>();
|
||||||
|
public static VRConfig config;
|
||||||
|
|
||||||
|
static {
|
||||||
|
ThreadFactory factory = new ThreadFactoryBuilder().setDaemon(true).setNameFormat("ViaFabric-%d").build();
|
||||||
|
ASYNC_EXECUTOR = Executors.newFixedThreadPool(8, factory);
|
||||||
|
EVENT_LOOP = new DefaultEventLoop(factory);
|
||||||
|
EVENT_LOOP.submit(INIT_FUTURE::join); // https://github.com/ViaVersion/ViaFabric/issues/53 ugly workaround code but works tm
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getVersion() {
|
||||||
|
return FabricLoader.getInstance().getModContainer("viafabric")
|
||||||
|
.get().getMetadata().getVersion().getFriendlyString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <S extends CommandSource> LiteralArgumentBuilder<S> command(String commandName) {
|
||||||
|
return LiteralArgumentBuilder.<S>literal(commandName)
|
||||||
|
.then(
|
||||||
|
RequiredArgumentBuilder
|
||||||
|
.<S, String>argument("args", StringArgumentType.greedyString())
|
||||||
|
.executes(((VRCommandHandler) Via.getManager().getCommandHandler())::execute)
|
||||||
|
.suggests(((VRCommandHandler) Via.getManager().getCommandHandler())::suggestion)
|
||||||
|
)
|
||||||
|
.executes(((VRCommandHandler) Via.getManager().getCommandHandler())::execute);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInitialize() {
|
||||||
|
Via.init(ViaManagerImpl.builder()
|
||||||
|
.injector(new VRInjector())
|
||||||
|
.loader(new VRLoader())
|
||||||
|
.commandHandler(new VRCommandHandler())
|
||||||
|
.platform(new VRPlatform()).build());
|
||||||
|
|
||||||
|
FabricLoader.getInstance().getModContainer("viabackwards").ifPresent(mod -> MappingDataLoader.enableMappingsCache());
|
||||||
|
|
||||||
|
((ViaManagerImpl) Via.getManager()).init();
|
||||||
|
|
||||||
|
Via.getManager().getProtocolManager().registerBaseProtocol(ViaFabricHostnameProtocol.INSTANCE, Range.lessThan(Integer.MIN_VALUE));
|
||||||
|
ProtocolVersion.register(-2, "AUTO");
|
||||||
|
|
||||||
|
FabricLoader.getInstance().getEntrypoints("viafabric:via_api_initialized", Runnable.class).forEach(Runnable::run);
|
||||||
|
|
||||||
|
try {
|
||||||
|
registerCommandsV1();
|
||||||
|
} catch (NoClassDefFoundError ignored) {
|
||||||
|
try {
|
||||||
|
registerCommandsV0();
|
||||||
|
JLOGGER.info("Using Fabric Commands V0");
|
||||||
|
} catch (NoClassDefFoundError ignored2) {
|
||||||
|
JLOGGER.info("Couldn't register command as Fabric Commands isn't installed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
config = new VRConfig(FabricLoader.getInstance().getConfigDir().resolve("ViaFabric")
|
||||||
|
.resolve("viafabric.yml").toFile());
|
||||||
|
|
||||||
|
INIT_FUTURE.complete(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerCommandsV1() {
|
||||||
|
CommandRegistrationCallback.EVENT.register((dispatcher, dedicated) -> dispatcher.register(command("viaversion")));
|
||||||
|
CommandRegistrationCallback.EVENT.register((dispatcher, dedicated) -> dispatcher.register(command("viaver")));
|
||||||
|
CommandRegistrationCallback.EVENT.register((dispatcher, dedicated) -> dispatcher.register(command("vvfabric")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
private void registerCommandsV0() {
|
||||||
|
CommandRegistry.INSTANCE.register(false, dispatcher -> dispatcher.register(command("viaversion")));
|
||||||
|
CommandRegistry.INSTANCE.register(false, dispatcher -> dispatcher.register(command("viaver")));
|
||||||
|
CommandRegistry.INSTANCE.register(false, dispatcher -> dispatcher.register(command("vvfabric")));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,77 @@
|
|||||||
|
package com.viaversion.fabric.mc115;
|
||||||
|
|
||||||
|
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
public class ViaFabricAddress {
|
||||||
|
public int protocol = 0;
|
||||||
|
public String viaSuffix = null;
|
||||||
|
public String realAddress = null;
|
||||||
|
|
||||||
|
public ViaFabricAddress parse(String address) {
|
||||||
|
if (address == null) return null;
|
||||||
|
String[] parts = address.split("\\.");
|
||||||
|
|
||||||
|
boolean foundDomain = false;
|
||||||
|
boolean foundOptions = false;
|
||||||
|
|
||||||
|
StringBuilder ourParts = new StringBuilder();
|
||||||
|
StringBuilder realAddrBuilder = new StringBuilder();
|
||||||
|
|
||||||
|
for (int i = parts.length - 1; i >= 0; i--) {
|
||||||
|
String part = parts[i];
|
||||||
|
boolean realAddrPart = false;
|
||||||
|
if (foundDomain) {
|
||||||
|
if (!foundOptions) {
|
||||||
|
if (part.startsWith("_")) {
|
||||||
|
String arg = part.substring(2);
|
||||||
|
if (part.toLowerCase(Locale.ROOT).startsWith("_v")) {
|
||||||
|
try {
|
||||||
|
protocol = Integer.parseInt(arg);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
ProtocolVersion closest = ProtocolVersion.getClosest(arg.replace("_", "."));
|
||||||
|
if (closest != null) {
|
||||||
|
protocol = closest.getVersion();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
foundOptions = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (foundOptions) {
|
||||||
|
realAddrPart = true;
|
||||||
|
}
|
||||||
|
} else if (part.equalsIgnoreCase("viafabric")) {
|
||||||
|
foundDomain = true;
|
||||||
|
}
|
||||||
|
if (realAddrPart) {
|
||||||
|
realAddrBuilder.insert(0, part + ".");
|
||||||
|
} else {
|
||||||
|
ourParts.insert(0, part + ".");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String realAddr = realAddrBuilder.toString().replaceAll("\\.$", "");
|
||||||
|
String suffix = ourParts.toString().replaceAll("\\.$", "");
|
||||||
|
|
||||||
|
if (realAddr.isEmpty()) {
|
||||||
|
this.realAddress = address;
|
||||||
|
} else {
|
||||||
|
this.realAddress = realAddr;
|
||||||
|
this.viaSuffix = suffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "ViaFabricAddress{" +
|
||||||
|
"protocol=" + protocol +
|
||||||
|
", viaSuffix='" + viaSuffix + '\'' +
|
||||||
|
", realAddress='" + realAddress + '\'' +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,61 @@
|
|||||||
|
package com.viaversion.fabric.mc115.commands;
|
||||||
|
|
||||||
|
import io.github.cottonmc.clientcommands.CottonClientCommandSource;
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.server.command.CommandSource;
|
||||||
|
import net.minecraft.server.command.ServerCommandSource;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import com.viaversion.viaversion.api.command.ViaCommandSender;
|
||||||
|
import com.viaversion.viaversion.libs.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||||
|
import com.viaversion.viaversion.libs.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class NMSCommandSender implements ViaCommandSender {
|
||||||
|
private final CommandSource source;
|
||||||
|
|
||||||
|
public NMSCommandSender(CommandSource source) {
|
||||||
|
this.source = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasPermission(String s) {
|
||||||
|
// https://gaming.stackexchange.com/questions/138602/what-does-op-permission-level-do
|
||||||
|
return source.hasPermissionLevel(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendMessage(String s) {
|
||||||
|
if (source instanceof ServerCommandSource) {
|
||||||
|
((ServerCommandSource) source).sendFeedback(Text.Serializer.fromJson(legacyToJson(s)), false);
|
||||||
|
} else if (source instanceof CottonClientCommandSource) {
|
||||||
|
((CottonClientCommandSource) source).sendFeedback(Text.Serializer.fromJson(legacyToJson(s)), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String legacyToJson(String legacy) {
|
||||||
|
return GsonComponentSerializer.gson().serialize(LegacyComponentSerializer.legacySection().deserialize(legacy));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UUID getUUID() {
|
||||||
|
if (source instanceof ServerCommandSource) {
|
||||||
|
Entity entity = ((ServerCommandSource) source).getEntity();
|
||||||
|
if (entity != null) return entity.getUuid();
|
||||||
|
} else if (source instanceof CottonClientCommandSource) {
|
||||||
|
return MinecraftClient.getInstance().player.getUuid();
|
||||||
|
}
|
||||||
|
return UUID.fromString(getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
if (source instanceof ServerCommandSource) {
|
||||||
|
return ((ServerCommandSource) source).getName();
|
||||||
|
} else if (source instanceof CottonClientCommandSource) {
|
||||||
|
return MinecraftClient.getInstance().player.getEntityName();
|
||||||
|
}
|
||||||
|
return "?";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
package com.viaversion.fabric.mc115.commands;
|
||||||
|
|
||||||
|
import com.viaversion.viaversion.api.Via;
|
||||||
|
import com.viaversion.viaversion.api.command.ViaCommandSender;
|
||||||
|
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class UserCommandSender implements ViaCommandSender {
|
||||||
|
private UserConnection con;
|
||||||
|
|
||||||
|
public UserCommandSender(UserConnection con) {
|
||||||
|
this.con = con;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasPermission(String s) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendMessage(String s) {
|
||||||
|
Via.getPlatform().sendMessage(getUUID(), s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UUID getUUID() {
|
||||||
|
return con.getProtocolInfo().getUuid();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return con.getProtocolInfo().getUsername();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
package com.viaversion.fabric.mc115.commands;
|
||||||
|
|
||||||
|
import com.viaversion.fabric.mc115.ViaFabric;
|
||||||
|
import com.mojang.brigadier.CommandDispatcher;
|
||||||
|
import io.github.cottonmc.clientcommands.ClientCommandPlugin;
|
||||||
|
import io.github.cottonmc.clientcommands.CottonClientCommandSource;
|
||||||
|
|
||||||
|
public class VRClientCommands implements ClientCommandPlugin {
|
||||||
|
@Override
|
||||||
|
public void registerCommands(CommandDispatcher<CottonClientCommandSource> commandDispatcher) {
|
||||||
|
commandDispatcher.register(ViaFabric.command("viafabricclient"));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
package com.viaversion.fabric.mc115.commands;
|
||||||
|
|
||||||
|
import com.viaversion.fabric.mc115.commands.subs.LeakDetectSubCommand;
|
||||||
|
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||||
|
import com.mojang.brigadier.context.CommandContext;
|
||||||
|
import com.mojang.brigadier.suggestion.Suggestions;
|
||||||
|
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
|
||||||
|
import net.minecraft.server.command.CommandSource;
|
||||||
|
import com.viaversion.viaversion.commands.ViaCommandHandler;
|
||||||
|
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
public class VRCommandHandler extends ViaCommandHandler {
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
registerSubCommand(new LeakDetectSubCommand());
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int execute(CommandContext<? extends CommandSource> ctx) {
|
||||||
|
String[] args = new String[0];
|
||||||
|
try {
|
||||||
|
args = StringArgumentType.getString(ctx, "args").split(" ");
|
||||||
|
} catch (IllegalArgumentException ignored) {
|
||||||
|
}
|
||||||
|
onCommand(
|
||||||
|
new NMSCommandSender(ctx.getSource()),
|
||||||
|
args
|
||||||
|
);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<Suggestions> suggestion(CommandContext<? extends CommandSource> ctx, SuggestionsBuilder builder) {
|
||||||
|
String[] args;
|
||||||
|
try {
|
||||||
|
args = StringArgumentType.getString(ctx, "args").split(" ", -1);
|
||||||
|
} catch (IllegalArgumentException ignored) {
|
||||||
|
args = new String[]{""};
|
||||||
|
}
|
||||||
|
String[] pref = args.clone();
|
||||||
|
pref[pref.length - 1] = "";
|
||||||
|
String prefix = String.join(" ", pref);
|
||||||
|
onTabComplete(new NMSCommandSender(ctx.getSource()), args)
|
||||||
|
.stream()
|
||||||
|
.map(it -> {
|
||||||
|
SuggestionsBuilder b = new SuggestionsBuilder(builder.getInput(), prefix.length() + builder.getStart());
|
||||||
|
b.suggest(it);
|
||||||
|
return b;
|
||||||
|
})
|
||||||
|
.forEach(builder::add);
|
||||||
|
return builder.buildFuture();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
package com.viaversion.fabric.mc115.commands.subs;
|
||||||
|
|
||||||
|
import io.netty.util.ResourceLeakDetector;
|
||||||
|
import com.viaversion.viaversion.api.command.ViaCommandSender;
|
||||||
|
import com.viaversion.viaversion.api.command.ViaSubCommand;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class LeakDetectSubCommand extends ViaSubCommand {
|
||||||
|
@Override
|
||||||
|
public String name() {
|
||||||
|
return "leakdetect";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String description() {
|
||||||
|
return "Sets ResourceLeakDetector level";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean execute(ViaCommandSender viaCommandSender, String[] strings) {
|
||||||
|
if (strings.length == 1) {
|
||||||
|
try {
|
||||||
|
ResourceLeakDetector.Level level = ResourceLeakDetector.Level.valueOf(strings[0]);
|
||||||
|
ResourceLeakDetector.setLevel(level);
|
||||||
|
viaCommandSender.sendMessage("Set leak detector level to " + level);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
viaCommandSender.sendMessage("Invalid level (" + Arrays.toString(ResourceLeakDetector.Level.values()) + ")");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
viaCommandSender.sendMessage("Current leak detection level is " + ResourceLeakDetector.getLevel());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> onTabComplete(ViaCommandSender sender, String[] args) {
|
||||||
|
if (args.length == 1) {
|
||||||
|
return Arrays.stream(ResourceLeakDetector.Level.values())
|
||||||
|
.map(Enum::name)
|
||||||
|
.filter(it -> it.startsWith(args[0]))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
return super.onTabComplete(sender, args);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
package com.viaversion.fabric.mc115.config;
|
||||||
|
|
||||||
|
import com.viaversion.viaversion.util.Config;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class VRConfig extends Config {
|
||||||
|
public static final String ENABLE_CLIENT_SIDE = "enable-client-side";
|
||||||
|
public static final String CLIENT_SIDE_VERSION = "client-side-version";
|
||||||
|
public static final String CLIENT_SIDE_FORCE_DISABLE = "client-side-force-disable";
|
||||||
|
public static final String HIDE_BUTTON = "hide-button";
|
||||||
|
|
||||||
|
public VRConfig(File configFile) {
|
||||||
|
super(configFile);
|
||||||
|
reloadConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public URL getDefaultConfigURL() {
|
||||||
|
return getClass().getClassLoader().getResource("assets/viafabric/config.yml");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void handleConfig(Map<String, Object> map) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getUnsupportedOptions() {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isClientSideEnabled() {
|
||||||
|
return getBoolean(ENABLE_CLIENT_SIDE, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClientSideEnabled(boolean val) {
|
||||||
|
set(ENABLE_CLIENT_SIDE, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getClientSideVersion() {
|
||||||
|
return getInt(CLIENT_SIDE_VERSION, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClientSideVersion(int val) {
|
||||||
|
set(CLIENT_SIDE_VERSION, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<?> getClientSideForceDisable() {
|
||||||
|
return (List<?>) get(CLIENT_SIDE_FORCE_DISABLE, List.class, Collections.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHideButton(boolean val) {
|
||||||
|
set(HIDE_BUTTON, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isHideButton() {
|
||||||
|
return getBoolean(HIDE_BUTTON, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isForcedDisable(String line) {
|
||||||
|
return getClientSideForceDisable().contains(line);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package com.viaversion.fabric.mc115.gui;
|
||||||
|
|
||||||
|
import io.github.prospector.modmenu.api.ConfigScreenFactory;
|
||||||
|
import io.github.prospector.modmenu.api.ModMenuApi;
|
||||||
|
|
||||||
|
public class ModMenuConfig implements ModMenuApi {
|
||||||
|
@Override
|
||||||
|
public String getModId() {
|
||||||
|
return "viafabric";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConfigScreenFactory<?> getModConfigScreenFactory() {
|
||||||
|
return ViaConfigScreen::new;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,169 @@
|
|||||||
|
package com.viaversion.fabric.mc115.gui;
|
||||||
|
|
||||||
|
import com.viaversion.fabric.mc115.ViaFabric;
|
||||||
|
import com.viaversion.fabric.mc115.util.ProtocolUtils;
|
||||||
|
import com.viaversion.viaversion.api.Via;
|
||||||
|
import net.fabricmc.api.EnvType;
|
||||||
|
import net.fabricmc.api.Environment;
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.client.gui.screen.ConfirmScreen;
|
||||||
|
import net.minecraft.client.gui.screen.Screen;
|
||||||
|
import net.minecraft.client.gui.widget.ButtonWidget;
|
||||||
|
import net.minecraft.client.gui.widget.TextFieldWidget;
|
||||||
|
import net.minecraft.text.TranslatableText;
|
||||||
|
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
@Environment(EnvType.CLIENT)
|
||||||
|
public class ViaConfigScreen extends Screen {
|
||||||
|
private static CompletableFuture<Void> latestProtocolSave;
|
||||||
|
private final Screen parent;
|
||||||
|
private TextFieldWidget protocolVersion;
|
||||||
|
|
||||||
|
public ViaConfigScreen(Screen parent) {
|
||||||
|
super(new TranslatableText("gui.viafabric_config.title"));
|
||||||
|
this.parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getProtocolTextColor(boolean valid, boolean supported) {
|
||||||
|
|
||||||
|
if (!valid) {
|
||||||
|
return 0xff0000; // Red
|
||||||
|
} else if (!supported) {
|
||||||
|
return 0xFFA500; // Orange
|
||||||
|
}
|
||||||
|
return 0xE0E0E0; // Default
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void init() {
|
||||||
|
int entries = 0;
|
||||||
|
|
||||||
|
this.addButton(new ButtonWidget(this.width / 2 - 155 + entries % 2 * 160,
|
||||||
|
this.height / 6 + 24 * (entries >> 1),
|
||||||
|
150,
|
||||||
|
20, getClientSideText().asString(), this::onClickClientSide));
|
||||||
|
entries++;
|
||||||
|
|
||||||
|
this.addButton(new ButtonWidget(this.width / 2 - 155 + entries % 2 * 160,
|
||||||
|
this.height / 6 + 24 * (entries >> 1),
|
||||||
|
150,
|
||||||
|
20, getHideViaButtonText().asString(), this::onHideViaButton));
|
||||||
|
entries++;
|
||||||
|
|
||||||
|
protocolVersion = new TextFieldWidget(this.font,
|
||||||
|
this.width / 2 - 155 + entries % 2 * 160,
|
||||||
|
this.height / 6 + 24 * (entries >> 1),
|
||||||
|
150,
|
||||||
|
20, new TranslatableText("gui.protocol_version_field.name").asString());
|
||||||
|
entries++;
|
||||||
|
|
||||||
|
protocolVersion.setTextPredicate(ProtocolUtils::isStartOfProtocolText);
|
||||||
|
protocolVersion.setChangedListener(this::onChangeVersionField);
|
||||||
|
int clientSideVersion = ViaFabric.config.getClientSideVersion();
|
||||||
|
protocolVersion.setText(ProtocolUtils.getProtocolName(clientSideVersion));
|
||||||
|
|
||||||
|
this.children.add(protocolVersion);
|
||||||
|
|
||||||
|
//noinspection ConstantConditions
|
||||||
|
if (entries % 2 == 1) {
|
||||||
|
entries++;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.addButton(new ButtonWidget(this.width / 2 - 100, this.height / 6 + 24 * (entries >> 1), 200, 20, new TranslatableText("gui.done").asString(), (buttonWidget) -> MinecraftClient.getInstance().openScreen(this.parent)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onChangeVersionField(String text) {
|
||||||
|
protocolVersion.setSuggestion(null);
|
||||||
|
int newVersion = ViaFabric.config.getClientSideVersion();
|
||||||
|
|
||||||
|
Integer parsed = ProtocolUtils.parseProtocolId(text);
|
||||||
|
boolean validProtocol;
|
||||||
|
|
||||||
|
if (parsed != null) {
|
||||||
|
newVersion = parsed;
|
||||||
|
validProtocol = true;
|
||||||
|
} else {
|
||||||
|
validProtocol = false;
|
||||||
|
String[] suggestions = ProtocolUtils.getProtocolSuggestions(text);
|
||||||
|
if (suggestions.length == 1) {
|
||||||
|
protocolVersion.setSuggestion(suggestions[0].substring(text.length()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protocolVersion.setEditableColor(
|
||||||
|
getProtocolTextColor(ProtocolUtils.isSupported(newVersion, Via.getAPI().getServerVersion().lowestSupportedVersion()),
|
||||||
|
validProtocol));
|
||||||
|
|
||||||
|
int finalNewVersion = newVersion;
|
||||||
|
if (latestProtocolSave == null) latestProtocolSave = CompletableFuture.completedFuture(null);
|
||||||
|
ViaFabric.config.setClientSideVersion(finalNewVersion);
|
||||||
|
latestProtocolSave = latestProtocolSave.thenRunAsync(ViaFabric.config::saveConfig, ViaFabric.ASYNC_EXECUTOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onClickClientSide(ButtonWidget widget) {
|
||||||
|
if (!ViaFabric.config.isClientSideEnabled()) {
|
||||||
|
MinecraftClient.getInstance().openScreen(new ConfirmScreen(
|
||||||
|
answer -> {
|
||||||
|
if (answer) {
|
||||||
|
ViaFabric.config.setClientSideEnabled(true);
|
||||||
|
ViaFabric.config.setClientSideVersion(-2); // AUTO
|
||||||
|
ViaFabric.config.saveConfig();
|
||||||
|
widget.setMessage(getClientSideText().asString());
|
||||||
|
}
|
||||||
|
MinecraftClient.getInstance().openScreen(this);
|
||||||
|
},
|
||||||
|
new TranslatableText("gui.enable_client_side.question"),
|
||||||
|
new TranslatableText("gui.enable_client_side.warning"),
|
||||||
|
new TranslatableText("gui.enable_client_side.enable").asString(),
|
||||||
|
new TranslatableText("gui.cancel").asString()
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
ViaFabric.config.setClientSideEnabled(false);
|
||||||
|
ViaFabric.config.saveConfig();
|
||||||
|
}
|
||||||
|
widget.setMessage(getClientSideText().asString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removed() {
|
||||||
|
ViaFabric.config.saveConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClose() {
|
||||||
|
MinecraftClient.getInstance().openScreen(this.parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private TranslatableText getClientSideText() {
|
||||||
|
return ViaFabric.config.isClientSideEnabled() ?
|
||||||
|
new TranslatableText("gui.client_side.disable")
|
||||||
|
: new TranslatableText("gui.client_side.enable");
|
||||||
|
}
|
||||||
|
|
||||||
|
private TranslatableText getHideViaButtonText() {
|
||||||
|
return ViaFabric.config.isHideButton() ?
|
||||||
|
new TranslatableText("gui.hide_via_button.disable") : new TranslatableText("gui.hide_via_button.enable");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onHideViaButton(ButtonWidget widget) {
|
||||||
|
ViaFabric.config.setHideButton(!ViaFabric.config.isHideButton());
|
||||||
|
ViaFabric.config.saveConfig();
|
||||||
|
widget.setMessage(getHideViaButtonText().asString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(int mouseX, int mouseY, float delta) {
|
||||||
|
this.renderBackground();
|
||||||
|
drawCenteredString(this.font, this.title.asString(), this.width / 2, 20, 16777215);
|
||||||
|
super.render(mouseX, mouseY, delta);
|
||||||
|
protocolVersion.render(mouseX, mouseY, delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
super.tick();
|
||||||
|
protocolVersion.tick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,38 @@
|
|||||||
|
package com.viaversion.fabric.mc115.handler;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.channel.ChannelHandler;
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||||
|
import io.netty.handler.codec.MessageToByteEncoder;
|
||||||
|
import io.netty.handler.codec.MessageToMessageDecoder;
|
||||||
|
import com.viaversion.viaversion.util.PipelineUtil;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
|
||||||
|
public class CommonTransformer {
|
||||||
|
public static final String HANDLER_DECODER_NAME = "via-decoder";
|
||||||
|
public static final String HANDLER_ENCODER_NAME = "via-encoder";
|
||||||
|
|
||||||
|
public static void decompress(ChannelHandlerContext ctx, ByteBuf buf) throws InvocationTargetException {
|
||||||
|
ChannelHandler handler = ctx.pipeline().get("decompress");
|
||||||
|
ByteBuf decompressed = handler instanceof MessageToMessageDecoder
|
||||||
|
? (ByteBuf) PipelineUtil.callDecode((MessageToMessageDecoder<?>) handler, ctx, buf).get(0)
|
||||||
|
: (ByteBuf) PipelineUtil.callDecode((ByteToMessageDecoder) handler, ctx, buf).get(0);
|
||||||
|
try {
|
||||||
|
buf.clear().writeBytes(decompressed);
|
||||||
|
} finally {
|
||||||
|
decompressed.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void compress(ChannelHandlerContext ctx, ByteBuf buf) throws Exception {
|
||||||
|
ByteBuf compressed = ctx.alloc().buffer();
|
||||||
|
try {
|
||||||
|
PipelineUtil.callEncode((MessageToByteEncoder<?>) ctx.pipeline().get("compress"), ctx, buf, compressed);
|
||||||
|
buf.clear().writeBytes(compressed);
|
||||||
|
} finally {
|
||||||
|
compressed.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,85 @@
|
|||||||
|
package com.viaversion.fabric.mc115.handler;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.channel.ChannelHandler;
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import io.netty.handler.codec.MessageToMessageDecoder;
|
||||||
|
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||||
|
import com.viaversion.viaversion.exception.CancelCodecException;
|
||||||
|
import com.viaversion.viaversion.exception.CancelDecoderException;
|
||||||
|
import com.viaversion.viaversion.util.PipelineUtil;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@ChannelHandler.Sharable
|
||||||
|
public class FabricDecodeHandler extends MessageToMessageDecoder<ByteBuf> {
|
||||||
|
private final UserConnection info;
|
||||||
|
private boolean handledCompression;
|
||||||
|
private boolean skipDoubleTransform;
|
||||||
|
|
||||||
|
public FabricDecodeHandler(UserConnection info) {
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserConnection getInfo() {
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://github.com/ViaVersion/ViaVersion/blob/master/velocity/src/main/java/us/myles/ViaVersion/velocity/handlers/VelocityDecodeHandler.java
|
||||||
|
@Override
|
||||||
|
protected void decode(ChannelHandlerContext ctx, ByteBuf bytebuf, List<Object> out) throws Exception {
|
||||||
|
if (skipDoubleTransform) {
|
||||||
|
skipDoubleTransform = false;
|
||||||
|
out.add(bytebuf.retain());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!info.checkIncomingPacket()) throw CancelDecoderException.generate(null);
|
||||||
|
if (!info.shouldTransformPacket()) {
|
||||||
|
out.add(bytebuf.retain());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteBuf transformedBuf = ctx.alloc().buffer().writeBytes(bytebuf);
|
||||||
|
try {
|
||||||
|
boolean needsCompress = handleCompressionOrder(ctx, transformedBuf);
|
||||||
|
|
||||||
|
info.transformIncoming(transformedBuf, CancelDecoderException::generate);
|
||||||
|
|
||||||
|
if (needsCompress) {
|
||||||
|
CommonTransformer.compress(ctx, transformedBuf);
|
||||||
|
skipDoubleTransform = true;
|
||||||
|
}
|
||||||
|
out.add(transformedBuf.retain());
|
||||||
|
} finally {
|
||||||
|
transformedBuf.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean handleCompressionOrder(ChannelHandlerContext ctx, ByteBuf buf) throws InvocationTargetException {
|
||||||
|
if (handledCompression) return false;
|
||||||
|
|
||||||
|
int decoderIndex = ctx.pipeline().names().indexOf("decompress");
|
||||||
|
if (decoderIndex == -1) return false;
|
||||||
|
handledCompression = true;
|
||||||
|
if (decoderIndex > ctx.pipeline().names().indexOf("via-decoder")) {
|
||||||
|
// Need to decompress this packet due to bad order
|
||||||
|
CommonTransformer.decompress(ctx, buf);
|
||||||
|
ChannelHandler encoder = ctx.pipeline().get("via-encoder");
|
||||||
|
ChannelHandler decoder = ctx.pipeline().get("via-decoder");
|
||||||
|
ctx.pipeline().remove(encoder);
|
||||||
|
ctx.pipeline().remove(decoder);
|
||||||
|
ctx.pipeline().addAfter("compress", "via-encoder", encoder);
|
||||||
|
ctx.pipeline().addAfter("decompress", "via-decoder", decoder);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||||
|
if (PipelineUtil.containsCause(cause, CancelCodecException.class)) return;
|
||||||
|
super.exceptionCaught(ctx, cause);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,72 @@
|
|||||||
|
package com.viaversion.fabric.mc115.handler;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.channel.ChannelHandler;
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import io.netty.handler.codec.MessageToMessageEncoder;
|
||||||
|
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||||
|
import com.viaversion.viaversion.exception.CancelCodecException;
|
||||||
|
import com.viaversion.viaversion.exception.CancelEncoderException;
|
||||||
|
import com.viaversion.viaversion.util.PipelineUtil;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@ChannelHandler.Sharable
|
||||||
|
public class FabricEncodeHandler extends MessageToMessageEncoder<ByteBuf> {
|
||||||
|
private final UserConnection info;
|
||||||
|
private boolean handledCompression;
|
||||||
|
|
||||||
|
public FabricEncodeHandler(UserConnection info) {
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void encode(final ChannelHandlerContext ctx, ByteBuf bytebuf, List<Object> out) throws Exception {
|
||||||
|
if (!info.checkOutgoingPacket()) throw CancelEncoderException.generate(null);
|
||||||
|
if (!info.shouldTransformPacket()) {
|
||||||
|
out.add(bytebuf.retain());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteBuf transformedBuf = ctx.alloc().buffer().writeBytes(bytebuf);
|
||||||
|
try {
|
||||||
|
boolean needsCompress = handleCompressionOrder(ctx, transformedBuf);
|
||||||
|
|
||||||
|
info.transformOutgoing(transformedBuf, CancelEncoderException::generate);
|
||||||
|
|
||||||
|
if (needsCompress) {
|
||||||
|
CommonTransformer.compress(ctx, transformedBuf);
|
||||||
|
}
|
||||||
|
out.add(transformedBuf.retain());
|
||||||
|
} finally {
|
||||||
|
transformedBuf.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean handleCompressionOrder(ChannelHandlerContext ctx, ByteBuf buf) throws InvocationTargetException {
|
||||||
|
if (handledCompression) return false;
|
||||||
|
|
||||||
|
int encoderIndex = ctx.pipeline().names().indexOf("compress");
|
||||||
|
if (encoderIndex == -1) return false;
|
||||||
|
handledCompression = true;
|
||||||
|
if (encoderIndex > ctx.pipeline().names().indexOf("via-encoder")) {
|
||||||
|
// Need to decompress this packet due to bad order
|
||||||
|
CommonTransformer.decompress(ctx, buf);
|
||||||
|
ChannelHandler encoder = ctx.pipeline().get("via-encoder");
|
||||||
|
ChannelHandler decoder = ctx.pipeline().get("via-decoder");
|
||||||
|
ctx.pipeline().remove(encoder);
|
||||||
|
ctx.pipeline().remove(decoder);
|
||||||
|
ctx.pipeline().addAfter("compress", "via-encoder", encoder);
|
||||||
|
ctx.pipeline().addAfter("decompress", "via-decoder", decoder);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||||
|
if (PipelineUtil.containsCause(cause, CancelCodecException.class)) return;
|
||||||
|
super.exceptionCaught(ctx, cause);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,79 @@
|
|||||||
|
package com.viaversion.fabric.mc115.handler.clientside;
|
||||||
|
|
||||||
|
import com.viaversion.fabric.mc115.ViaFabric;
|
||||||
|
import com.viaversion.fabric.mc115.service.ProtocolAutoDetector;
|
||||||
|
import com.viaversion.viaversion.util.Pair;
|
||||||
|
import io.netty.channel.ChannelDuplexHandler;
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import io.netty.channel.ChannelPromise;
|
||||||
|
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.util.ArrayDeque;
|
||||||
|
import java.util.Queue;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
public class ProtocolDetectionHandler extends ChannelDuplexHandler {
|
||||||
|
private final Queue<Pair<Object, ChannelPromise>> queuedMessages = new ArrayDeque<>();
|
||||||
|
private boolean hold = true;
|
||||||
|
private boolean pendentFlush;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||||
|
super.channelActive(ctx);
|
||||||
|
if (ctx.channel().remoteAddress() instanceof InetSocketAddress) {
|
||||||
|
ScheduledFuture<?> timeoutRun = ctx.executor().schedule(() -> {
|
||||||
|
ViaFabric.JLOGGER.warning("Timeout for protocol auto-detection in "
|
||||||
|
+ ctx.channel().remoteAddress() + " server");
|
||||||
|
hold = false;
|
||||||
|
drainQueue(ctx);
|
||||||
|
ctx.pipeline().remove(this);
|
||||||
|
}, 10, TimeUnit.SECONDS);
|
||||||
|
ProtocolAutoDetector.detectVersion(((InetSocketAddress) ctx.channel().remoteAddress()))
|
||||||
|
.whenComplete((obj, ex) -> {
|
||||||
|
ctx.pipeline().remove(this);
|
||||||
|
timeoutRun.cancel(false);
|
||||||
|
});
|
||||||
|
// Let's cache it before we need it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
|
||||||
|
if (!hold) {
|
||||||
|
drainQueue(ctx);
|
||||||
|
super.write(ctx, msg, promise);
|
||||||
|
} else {
|
||||||
|
queuedMessages.add(new Pair<>(msg, promise));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void flush(ChannelHandlerContext ctx) throws Exception {
|
||||||
|
if (!hold) {
|
||||||
|
drainQueue(ctx);
|
||||||
|
super.flush(ctx);
|
||||||
|
} else {
|
||||||
|
pendentFlush = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
||||||
|
drainQueue(ctx);
|
||||||
|
super.channelInactive(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void drainQueue(ChannelHandlerContext ctx) {
|
||||||
|
queuedMessages.forEach(it -> ctx.write(it.getKey(), it.getValue()));
|
||||||
|
queuedMessages.clear();
|
||||||
|
if (pendentFlush) ctx.flush();
|
||||||
|
pendentFlush = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
|
||||||
|
drainQueue(ctx);
|
||||||
|
super.handlerRemoved(ctx);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
package com.viaversion.fabric.mc115.mixin.address.client;
|
||||||
|
|
||||||
|
import com.viaversion.fabric.mc115.ViaFabricAddress;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
|
||||||
|
@Mixin(targets = "net/minecraft/client/gui/screen/ConnectScreen$1", priority = 2000)
|
||||||
|
public class MixinConnectScreenThread {
|
||||||
|
@Redirect(method = "run()V", at = @At(value = "INVOKE",
|
||||||
|
target = "Ljava/net/InetAddress;getByName(Ljava/lang/String;)Ljava/net/InetAddress;"))
|
||||||
|
private InetAddress resolveViaFabricAddr(String address) throws UnknownHostException {
|
||||||
|
ViaFabricAddress viaAddr = new ViaFabricAddress().parse(address);
|
||||||
|
if (viaAddr.viaSuffix == null) {
|
||||||
|
return InetAddress.getByName(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
InetAddress resolved = InetAddress.getByName(viaAddr.realAddress);
|
||||||
|
return InetAddress.getByAddress(resolved.getHostName() + "." + viaAddr.viaSuffix, resolved.getAddress());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
package com.viaversion.fabric.mc115.mixin.address.client;
|
||||||
|
|
||||||
|
import com.viaversion.fabric.mc115.ViaFabricAddress;
|
||||||
|
import net.minecraft.network.ServerAddress;
|
||||||
|
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;
|
||||||
|
|
||||||
|
@Mixin(ServerAddress.class)
|
||||||
|
public abstract class MixinServerAddress {
|
||||||
|
@Shadow
|
||||||
|
private static String[] resolveSrv(String address) {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Redirect(method = "parse", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/ServerAddress;resolveSrv(Ljava/lang/String;)[Ljava/lang/String;"))
|
||||||
|
private static String[] modifySrvAddr(String address) {
|
||||||
|
ViaFabricAddress viaAddr = new ViaFabricAddress().parse(address);
|
||||||
|
if (viaAddr.viaSuffix == null) {
|
||||||
|
return resolveSrv(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] resolvedSrv = resolveSrv(viaAddr.realAddress);
|
||||||
|
resolvedSrv[0] = resolvedSrv[0].replaceAll("\\.$", "") + "." + viaAddr.viaSuffix;
|
||||||
|
|
||||||
|
return resolvedSrv;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
package com.viaversion.fabric.mc115.mixin.address.client;
|
||||||
|
|
||||||
|
import com.viaversion.fabric.mc115.ViaFabricAddress;
|
||||||
|
import net.minecraft.client.network.MultiplayerServerListPinger;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
|
||||||
|
@Mixin(MultiplayerServerListPinger.class)
|
||||||
|
public class MixinServerPinger {
|
||||||
|
@Redirect(method = "add", at = @At(value = "INVOKE",
|
||||||
|
target = "Ljava/net/InetAddress;getByName(Ljava/lang/String;)Ljava/net/InetAddress;"))
|
||||||
|
private InetAddress resolveViaFabricAddr(String address) throws UnknownHostException {
|
||||||
|
ViaFabricAddress viaAddr = new ViaFabricAddress().parse(address);
|
||||||
|
if (viaAddr.viaSuffix == null) {
|
||||||
|
return InetAddress.getByName(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
InetAddress resolved = InetAddress.getByName(viaAddr.realAddress);
|
||||||
|
return InetAddress.getByAddress(resolved.getHostName() + "." + viaAddr.viaSuffix, resolved.getAddress());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package com.viaversion.fabric.mc115.mixin.debug.client;
|
||||||
|
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
import net.minecraft.network.ClientConnection;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||||
|
|
||||||
|
@Mixin(ClientConnection.class)
|
||||||
|
public interface MixinClientConnectionAccessor {
|
||||||
|
@Accessor
|
||||||
|
Channel getChannel();
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
package com.viaversion.fabric.mc115.mixin.debug.client;
|
||||||
|
|
||||||
|
import com.viaversion.fabric.mc115.handler.CommonTransformer;
|
||||||
|
import com.viaversion.fabric.mc115.handler.FabricDecodeHandler;
|
||||||
|
import com.viaversion.viaversion.api.connection.ProtocolInfo;
|
||||||
|
import io.netty.channel.ChannelHandler;
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.client.gui.hud.DebugHud;
|
||||||
|
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;
|
||||||
|
import com.viaversion.viaversion.api.Via;
|
||||||
|
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Mixin(DebugHud.class)
|
||||||
|
public class MixinDebugHud {
|
||||||
|
@Inject(at = @At("RETURN"), method = "getLeftText")
|
||||||
|
protected void getLeftText(CallbackInfoReturnable<List<String>> info) {
|
||||||
|
String line = "[ViaFabric] I: " + Via.getManager().getConnectionManager().getConnections().size() + " (F: "
|
||||||
|
+ Via.getManager().getConnectionManager().getConnectedClients().size() + ")";
|
||||||
|
@SuppressWarnings("ConstantConditions") ChannelHandler viaDecoder = ((MixinClientConnectionAccessor) MinecraftClient.getInstance().getNetworkHandler()
|
||||||
|
.getConnection()).getChannel().pipeline().get(CommonTransformer.HANDLER_DECODER_NAME);
|
||||||
|
if (viaDecoder instanceof FabricDecodeHandler) {
|
||||||
|
ProtocolInfo protocol = ((FabricDecodeHandler) viaDecoder).getInfo().getProtocolInfo();
|
||||||
|
if (protocol != null) {
|
||||||
|
ProtocolVersion serverVer = ProtocolVersion.getProtocol(protocol.getServerProtocolVersion());
|
||||||
|
ProtocolVersion clientVer = ProtocolVersion.getProtocol(protocol.getProtocolVersion());
|
||||||
|
line += " / C: " + clientVer.getName() + " (" + clientVer.getVersion() + ") S: "
|
||||||
|
+ serverVer.getName() + " (" + serverVer.getVersion() + ") A: " + protocol.getUser().isActive();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
info.getReturnValue().add(line);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
package com.viaversion.fabric.mc115.mixin.gui.client;
|
||||||
|
|
||||||
|
import com.viaversion.fabric.mc115.ViaFabric;
|
||||||
|
import com.viaversion.fabric.mc115.gui.ViaConfigScreen;
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.client.gui.screen.Screen;
|
||||||
|
import net.minecraft.client.gui.screen.multiplayer.MultiplayerScreen;
|
||||||
|
import net.minecraft.client.gui.widget.ButtonWidget;
|
||||||
|
import net.minecraft.client.gui.widget.TexturedButtonWidget;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import net.minecraft.text.TranslatableText;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
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;
|
||||||
|
|
||||||
|
@Mixin(MultiplayerScreen.class)
|
||||||
|
public abstract class MixinMultiplayerScreen extends Screen {
|
||||||
|
protected MixinMultiplayerScreen(Text title, UnsupportedOperationException e) {
|
||||||
|
super(title);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "init", at = @At("TAIL"), remap = false)
|
||||||
|
private void onInit(CallbackInfo ci) {
|
||||||
|
ButtonWidget enableClientSideViaVersion = new TexturedButtonWidget(this.width / 2 + 113, 10,
|
||||||
|
40, 20, // Size
|
||||||
|
0, 0, // Start pos of texture
|
||||||
|
20, // v Hover offset
|
||||||
|
new Identifier("viafabric:textures/gui/widgets.png"),
|
||||||
|
256, 256, // Texture size
|
||||||
|
it -> MinecraftClient.getInstance().openScreen(new ViaConfigScreen(this)),
|
||||||
|
new TranslatableText("gui.via_button").asString());
|
||||||
|
if (ViaFabric.config.isHideButton()) enableClientSideViaVersion.visible = false;
|
||||||
|
addButton(enableClientSideViaVersion);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
package com.viaversion.fabric.mc115.mixin.pipeline;
|
||||||
|
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
import net.minecraft.network.ClientConnection;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
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;
|
||||||
|
|
||||||
|
|
||||||
|
@Mixin(ClientConnection.class)
|
||||||
|
public class MixinClientConnection {
|
||||||
|
@Shadow
|
||||||
|
private Channel channel;
|
||||||
|
|
||||||
|
@Redirect(
|
||||||
|
method = "exceptionCaught",
|
||||||
|
remap = false,
|
||||||
|
at = @At(
|
||||||
|
value = "INVOKE",
|
||||||
|
target = "Lorg/apache/logging/log4j/Logger;debug(Ljava/lang/String;Ljava/lang/Throwable;)V"
|
||||||
|
))
|
||||||
|
private void redirectDebug(Logger logger, String message, Throwable t) {
|
||||||
|
if ("Failed to sent packet".equals(message)) {
|
||||||
|
logger.info(message, t);
|
||||||
|
} else {
|
||||||
|
logger.debug(message, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
package com.viaversion.fabric.mc115.mixin.pipeline;
|
||||||
|
|
||||||
|
import com.viaversion.fabric.mc115.handler.CommonTransformer;
|
||||||
|
import com.viaversion.fabric.mc115.handler.FabricDecodeHandler;
|
||||||
|
import com.viaversion.fabric.mc115.handler.FabricEncodeHandler;
|
||||||
|
import com.viaversion.viaversion.connection.UserConnectionImpl;
|
||||||
|
import com.viaversion.viaversion.protocol.ProtocolPipelineImpl;
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
import io.netty.channel.socket.SocketChannel;
|
||||||
|
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 com.viaversion.viaversion.api.connection.UserConnection;
|
||||||
|
|
||||||
|
@Mixin(targets = "net.minecraft.server.ServerNetworkIo$1")
|
||||||
|
public class MixinServerNetworkIoChInit {
|
||||||
|
@Inject(method = "initChannel", at = @At(value = "TAIL"), remap = false)
|
||||||
|
private void onInitChannel(Channel channel, CallbackInfo ci) {
|
||||||
|
if (channel instanceof SocketChannel) {
|
||||||
|
UserConnection user = new UserConnectionImpl(channel);
|
||||||
|
new ProtocolPipelineImpl(user);
|
||||||
|
|
||||||
|
channel.pipeline().addBefore("encoder", CommonTransformer.HANDLER_ENCODER_NAME, new FabricEncodeHandler(user));
|
||||||
|
channel.pipeline().addBefore("decoder", CommonTransformer.HANDLER_DECODER_NAME, new FabricDecodeHandler(user));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
package com.viaversion.fabric.mc115.mixin.pipeline.client;
|
||||||
|
|
||||||
|
import com.viaversion.fabric.mc115.ViaFabric;
|
||||||
|
import com.viaversion.fabric.mc115.handler.CommonTransformer;
|
||||||
|
import com.viaversion.fabric.mc115.handler.FabricDecodeHandler;
|
||||||
|
import com.viaversion.fabric.mc115.handler.FabricEncodeHandler;
|
||||||
|
import com.viaversion.fabric.mc115.handler.clientside.ProtocolDetectionHandler;
|
||||||
|
import com.viaversion.fabric.mc115.protocol.ViaFabricHostnameProtocol;
|
||||||
|
import com.viaversion.viaversion.connection.UserConnectionImpl;
|
||||||
|
import com.viaversion.viaversion.protocol.ProtocolPipelineImpl;
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
import io.netty.channel.socket.SocketChannel;
|
||||||
|
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 com.viaversion.viaversion.api.connection.UserConnection;
|
||||||
|
|
||||||
|
@Mixin(targets = "net.minecraft.network.ClientConnection$1")
|
||||||
|
public class MixinClientConnectionChInit {
|
||||||
|
@Inject(method = "initChannel", at = @At(value = "TAIL"), remap = false)
|
||||||
|
private void onInitChannel(Channel channel, CallbackInfo ci) {
|
||||||
|
if (channel instanceof SocketChannel) {
|
||||||
|
UserConnection user = new UserConnectionImpl(channel, true);
|
||||||
|
new ProtocolPipelineImpl(user).add(ViaFabricHostnameProtocol.INSTANCE);
|
||||||
|
|
||||||
|
channel.pipeline()
|
||||||
|
.addBefore("encoder", CommonTransformer.HANDLER_ENCODER_NAME, new FabricEncodeHandler(user))
|
||||||
|
.addBefore("decoder", CommonTransformer.HANDLER_DECODER_NAME, new FabricDecodeHandler(user));
|
||||||
|
if (ViaFabric.config.isClientSideEnabled()) {
|
||||||
|
channel.pipeline().addAfter(CommonTransformer.HANDLER_ENCODER_NAME, "via-autoprotocol", new ProtocolDetectionHandler());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,61 @@
|
|||||||
|
package com.viaversion.fabric.mc115.platform;
|
||||||
|
|
||||||
|
import com.viaversion.fabric.mc115.handler.CommonTransformer;
|
||||||
|
import net.fabricmc.api.EnvType;
|
||||||
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
|
import net.minecraft.SharedConstants;
|
||||||
|
import com.viaversion.viaversion.api.platform.ViaInjector;
|
||||||
|
import com.viaversion.viaversion.util.GsonUtil;
|
||||||
|
import com.viaversion.viaversion.libs.gson.JsonObject;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public class VRInjector implements ViaInjector {
|
||||||
|
@Override
|
||||||
|
public void inject() {
|
||||||
|
// *looks at Mixins*
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void uninject() {
|
||||||
|
// not possible *plays sad violin*
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getServerProtocolVersion() {
|
||||||
|
return SharedConstants.getGameVersion().getProtocolVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getEncoderName() {
|
||||||
|
return CommonTransformer.HANDLER_ENCODER_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDecoderName() {
|
||||||
|
return CommonTransformer.HANDLER_DECODER_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JsonObject getDump() {
|
||||||
|
JsonObject obj = new JsonObject();
|
||||||
|
try {
|
||||||
|
obj.add("serverNetworkIOChInit", GsonUtil.getGson().toJsonTree(
|
||||||
|
Arrays.stream(Class.forName("net.minecraft.class_3242$1").getDeclaredMethods())
|
||||||
|
.map(Method::toString)
|
||||||
|
.toArray(String[]::new)));
|
||||||
|
} catch (ClassNotFoundException ignored) {
|
||||||
|
}
|
||||||
|
if (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) {
|
||||||
|
try {
|
||||||
|
obj.add("clientConnectionChInit", GsonUtil.getGson().toJsonTree(
|
||||||
|
Arrays.stream(Class.forName("net.minecraft.class_2535$1").getDeclaredMethods())
|
||||||
|
.map(Method::toString)
|
||||||
|
.toArray(String[]::new)));
|
||||||
|
} catch (ClassNotFoundException ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
package com.viaversion.fabric.mc115.platform;
|
||||||
|
|
||||||
|
import com.viaversion.fabric.mc115.providers.VRHandItemProvider;
|
||||||
|
import com.viaversion.fabric.mc115.providers.VRVersionProvider;
|
||||||
|
import net.fabricmc.api.EnvType;
|
||||||
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
|
import com.viaversion.viaversion.api.Via;
|
||||||
|
import com.viaversion.viaversion.api.platform.ViaPlatformLoader;
|
||||||
|
import com.viaversion.viaversion.bungee.providers.BungeeMovementTransmitter;
|
||||||
|
import com.viaversion.viaversion.api.protocol.version.VersionProvider;
|
||||||
|
import com.viaversion.viaversion.protocols.protocol1_9to1_8.providers.HandItemProvider;
|
||||||
|
import com.viaversion.viaversion.protocols.protocol1_9to1_8.providers.MovementTransmitterProvider;
|
||||||
|
|
||||||
|
public class VRLoader implements ViaPlatformLoader {
|
||||||
|
@Override
|
||||||
|
public void load() {
|
||||||
|
Via.getManager().getProviders().use(MovementTransmitterProvider.class, new BungeeMovementTransmitter());
|
||||||
|
Via.getManager().getProviders().use(VersionProvider.class, new VRVersionProvider());
|
||||||
|
|
||||||
|
if (Via.getPlatform().getConf().isItemCache()) {
|
||||||
|
VRHandItemProvider handProvider = new VRHandItemProvider();
|
||||||
|
if (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) {
|
||||||
|
handProvider.registerClientTick();
|
||||||
|
}
|
||||||
|
handProvider.registerServerTick();
|
||||||
|
Via.getManager().getProviders().use(HandItemProvider.class, handProvider);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unload() {
|
||||||
|
// Nothing to do
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,272 @@
|
|||||||
|
package com.viaversion.fabric.mc115.platform;
|
||||||
|
|
||||||
|
import com.viaversion.fabric.mc115.ViaFabric;
|
||||||
|
import com.viaversion.fabric.mc115.commands.NMSCommandSender;
|
||||||
|
import com.viaversion.fabric.mc115.commands.UserCommandSender;
|
||||||
|
import com.viaversion.fabric.mc115.util.FutureTaskId;
|
||||||
|
import com.viaversion.fabric.mc115.util.JLoggerToLog4j;
|
||||||
|
import com.viaversion.viaversion.api.configuration.ViaVersionConfig;
|
||||||
|
import com.viaversion.viaversion.api.platform.PlatformTask;
|
||||||
|
import io.netty.util.concurrent.Future;
|
||||||
|
import io.netty.util.concurrent.GenericFutureListener;
|
||||||
|
import net.fabricmc.api.EnvType;
|
||||||
|
import net.fabricmc.api.Environment;
|
||||||
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
|
import net.fabricmc.loader.api.ModContainer;
|
||||||
|
import net.fabricmc.loader.api.Version;
|
||||||
|
import net.fabricmc.loader.api.metadata.ModMetadata;
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.network.MessageType;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import com.viaversion.viaversion.api.Via;
|
||||||
|
import com.viaversion.viaversion.api.ViaAPI;
|
||||||
|
import com.viaversion.viaversion.api.command.ViaCommandSender;
|
||||||
|
import com.viaversion.viaversion.api.configuration.ConfigurationProvider;
|
||||||
|
import com.viaversion.viaversion.api.platform.ViaPlatform;
|
||||||
|
import com.viaversion.viaversion.dump.PluginInfo;
|
||||||
|
import com.viaversion.viaversion.util.GsonUtil;
|
||||||
|
import com.viaversion.viaversion.libs.gson.JsonObject;
|
||||||
|
import com.viaversion.viaversion.libs.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||||
|
import com.viaversion.viaversion.libs.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.CancellationException;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class VRPlatform implements ViaPlatform<UUID> {
|
||||||
|
private final Logger logger = new JLoggerToLog4j(LogManager.getLogger("ViaVersion"));
|
||||||
|
private final VRViaConfig config;
|
||||||
|
private final File dataFolder;
|
||||||
|
private final ViaAPI<UUID> api;
|
||||||
|
|
||||||
|
public VRPlatform() {
|
||||||
|
Path configDir = FabricLoader.getInstance().getConfigDirectory().toPath().resolve("ViaFabric");
|
||||||
|
config = new VRViaConfig(configDir.resolve("viaversion.yml").toFile());
|
||||||
|
dataFolder = configDir.toFile();
|
||||||
|
api = new VRViaAPI();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MinecraftServer getServer() {
|
||||||
|
if (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) {
|
||||||
|
return getIntegratedServer();
|
||||||
|
}
|
||||||
|
return (MinecraftServer) FabricLoader.getInstance().getGameInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Environment(EnvType.CLIENT)
|
||||||
|
private static MinecraftServer getIntegratedServer() {
|
||||||
|
return MinecraftClient.getInstance().getServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String legacyToJson(String legacy) {
|
||||||
|
return GsonComponentSerializer.gson().serialize(LegacyComponentSerializer.legacySection().deserialize(legacy));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Logger getLogger() {
|
||||||
|
return logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPlatformName() {
|
||||||
|
return "ViaFabric";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPlatformVersion() {
|
||||||
|
return ViaFabric.getVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPluginVersion() {
|
||||||
|
return FabricLoader.getInstance().getModContainer("viaversion").map(ModContainer::getMetadata)
|
||||||
|
.map(ModMetadata::getVersion).map(Version::getFriendlyString).orElse("UNKNOWN");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FutureTaskId runAsync(Runnable runnable) {
|
||||||
|
return new FutureTaskId(CompletableFuture
|
||||||
|
.runAsync(runnable, ViaFabric.ASYNC_EXECUTOR)
|
||||||
|
.exceptionally(throwable -> {
|
||||||
|
if (!(throwable instanceof CancellationException)) {
|
||||||
|
throwable.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FutureTaskId runSync(Runnable runnable) {
|
||||||
|
if (getServer() != null) {
|
||||||
|
return runServerSync(runnable);
|
||||||
|
} else {
|
||||||
|
return runEventLoop(runnable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private FutureTaskId runServerSync(Runnable runnable) {
|
||||||
|
// Kick task needs to be on main thread, it does already have error logger
|
||||||
|
return new FutureTaskId(CompletableFuture.runAsync(runnable, getServer()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private FutureTaskId runEventLoop(Runnable runnable) {
|
||||||
|
return new FutureTaskId(
|
||||||
|
ViaFabric.EVENT_LOOP
|
||||||
|
.submit(runnable)
|
||||||
|
.addListener(errorLogger())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PlatformTask runSync(Runnable runnable, Long ticks) {
|
||||||
|
// ViaVersion seems to not need to run delayed tasks on main thread
|
||||||
|
return new FutureTaskId(
|
||||||
|
ViaFabric.EVENT_LOOP
|
||||||
|
.schedule(() -> runSync(runnable), ticks * 50, TimeUnit.MILLISECONDS)
|
||||||
|
.addListener(errorLogger())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PlatformTask runRepeatingSync(Runnable runnable, Long ticks) {
|
||||||
|
// ViaVersion seems to not need to run repeating tasks on main thread
|
||||||
|
return new FutureTaskId(
|
||||||
|
ViaFabric.EVENT_LOOP
|
||||||
|
.scheduleAtFixedRate(() -> runSync(runnable), 0, ticks * 50, TimeUnit.MILLISECONDS)
|
||||||
|
.addListener(errorLogger())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T extends Future<?>> GenericFutureListener<T> errorLogger() {
|
||||||
|
return future -> {
|
||||||
|
if (!future.isCancelled() && future.cause() != null) {
|
||||||
|
future.cause().printStackTrace();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ViaCommandSender[] getOnlinePlayers() {
|
||||||
|
MinecraftServer server = getServer();
|
||||||
|
if (server != null && server.isOnThread()) {
|
||||||
|
return getServerPlayers();
|
||||||
|
}
|
||||||
|
return Via.getManager().getConnectionManager().getConnectedClients().values().stream()
|
||||||
|
.map(UserCommandSender::new)
|
||||||
|
.toArray(ViaCommandSender[]::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ViaCommandSender[] getServerPlayers() {
|
||||||
|
return getServer().getPlayerManager().getPlayerList().stream()
|
||||||
|
.map(Entity::getCommandSource)
|
||||||
|
.map(NMSCommandSender::new)
|
||||||
|
.toArray(ViaCommandSender[]::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendMessage(UUID uuid, String s) {
|
||||||
|
sendMessageServer(uuid, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendMessageServer(UUID uuid, String s) {
|
||||||
|
MinecraftServer server = getServer();
|
||||||
|
if (server == null) return;
|
||||||
|
runServerSync(() -> {
|
||||||
|
ServerPlayerEntity player = server.getPlayerManager().getPlayer(uuid);
|
||||||
|
if (player == null) return;
|
||||||
|
player.sendChatMessage(Text.Serializer.fromJson(legacyToJson(s)), MessageType.SYSTEM);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean kickPlayer(UUID uuid, String s) {
|
||||||
|
return kickServer(uuid, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean kickServer(UUID uuid, String s) {
|
||||||
|
MinecraftServer server = getServer();
|
||||||
|
if (server == null) return false;
|
||||||
|
Supplier<Boolean> kickTask = () -> {
|
||||||
|
ServerPlayerEntity player = server.getPlayerManager().getPlayer(uuid);
|
||||||
|
if (player == null) return false;
|
||||||
|
player.networkHandler.disconnect(Text.Serializer.fromJson(legacyToJson(s)));
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
if (server.isOnThread()) {
|
||||||
|
return kickTask.get();
|
||||||
|
} else {
|
||||||
|
ViaFabric.JLOGGER.log(Level.WARNING, "Weird!? Player kicking was called off-thread", new Throwable());
|
||||||
|
runServerSync(kickTask::get);
|
||||||
|
}
|
||||||
|
return false; // Can't know if it worked
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPluginEnabled() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ViaAPI<UUID> getApi() {
|
||||||
|
return api;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ViaVersionConfig getConf() {
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConfigurationProvider getConfigurationProvider() {
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public File getDataFolder() {
|
||||||
|
return dataFolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReload() {
|
||||||
|
// Nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JsonObject getDump() {
|
||||||
|
JsonObject platformSpecific = new JsonObject();
|
||||||
|
List<PluginInfo> mods = new ArrayList<>();
|
||||||
|
for (ModContainer mod : FabricLoader.getInstance().getAllMods()) {
|
||||||
|
mods.add(new PluginInfo(true,
|
||||||
|
mod.getMetadata().getId() + " (" + mod.getMetadata().getName() + ")",
|
||||||
|
mod.getMetadata().getVersion().getFriendlyString(),
|
||||||
|
null,
|
||||||
|
mod.getMetadata().getAuthors().stream()
|
||||||
|
.map(info -> info.getName()
|
||||||
|
+ (info.getContact().asMap().isEmpty() ? "" : " " + info.getContact().asMap()))
|
||||||
|
.collect(Collectors.toList())
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
platformSpecific.add("mods", GsonUtil.getGson().toJsonTree(mods));
|
||||||
|
return platformSpecific;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isOldClientsAllowed() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
package com.viaversion.fabric.mc115.platform;
|
||||||
|
|
||||||
|
import com.viaversion.viaversion.ViaAPIBase;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class VRViaAPI extends ViaAPIBase<UUID> {
|
||||||
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
package com.viaversion.fabric.mc115.platform;
|
||||||
|
|
||||||
|
import com.viaversion.viaversion.configuration.AbstractViaConfig;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class VRViaConfig extends AbstractViaConfig {
|
||||||
|
// Based on Sponge ViaVersion
|
||||||
|
private static List<String> UNSUPPORTED = Arrays.asList("anti-xray-patch", "bungee-ping-interval",
|
||||||
|
"bungee-ping-save", "bungee-servers", "quick-move-action-fix", "nms-player-ticking",
|
||||||
|
"velocity-ping-interval", "velocity-ping-save", "velocity-servers",
|
||||||
|
"blockconnection-method", "change-1_9-hitbox", "change-1_14-hitbox");
|
||||||
|
|
||||||
|
public VRViaConfig(File configFile) {
|
||||||
|
super(configFile);
|
||||||
|
// Load config
|
||||||
|
reloadConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public URL getDefaultConfigURL() {
|
||||||
|
return getClass().getClassLoader().getResource("assets/viaversion/config.yml");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void handleConfig(Map<String, Object> config) {
|
||||||
|
// Nothing Currently
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getUnsupportedOptions() {
|
||||||
|
return UNSUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAntiXRay() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isNMSPlayerTicking() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean is1_12QuickMoveActionFix() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getBlockConnectionMethod() {
|
||||||
|
return "packet";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean is1_9HitboxFix() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean is1_14HitboxFix() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
package com.viaversion.fabric.mc115.protocol;
|
||||||
|
|
||||||
|
import com.viaversion.fabric.mc115.ViaFabricAddress;
|
||||||
|
import com.viaversion.viaversion.api.protocol.AbstractSimpleProtocol;
|
||||||
|
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
|
||||||
|
import com.viaversion.viaversion.api.protocol.remapper.PacketRemapper;
|
||||||
|
import com.viaversion.viaversion.api.protocol.remapper.ValueTransformer;
|
||||||
|
import com.viaversion.viaversion.api.type.Type;
|
||||||
|
import com.viaversion.viaversion.api.protocol.packet.State;
|
||||||
|
|
||||||
|
public class ViaFabricHostnameProtocol extends AbstractSimpleProtocol {
|
||||||
|
public static final ViaFabricHostnameProtocol INSTANCE = new ViaFabricHostnameProtocol();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void registerPackets() {
|
||||||
|
registerServerbound(State.HANDSHAKE, 0, 0, new PacketRemapper() {
|
||||||
|
@Override
|
||||||
|
public void registerMap() {
|
||||||
|
map(Type.VAR_INT); // Protocol version
|
||||||
|
map(Type.STRING, new ValueTransformer<String, String>(Type.STRING) {
|
||||||
|
@Override
|
||||||
|
public String transform(PacketWrapper packetWrapper, String s) {
|
||||||
|
return new ViaFabricAddress().parse(s).realAddress;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isBaseProtocol() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,110 @@
|
|||||||
|
package com.viaversion.fabric.mc115.providers;
|
||||||
|
|
||||||
|
import com.viaversion.fabric.mc115.ViaFabric;
|
||||||
|
import net.fabricmc.api.EnvType;
|
||||||
|
import net.fabricmc.api.Environment;
|
||||||
|
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
|
||||||
|
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
|
||||||
|
import net.fabricmc.fabric.api.event.world.WorldTickCallback;
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.client.network.ClientPlayerEntity;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.util.registry.Registry;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||||
|
import com.viaversion.viaversion.api.minecraft.item.Item;
|
||||||
|
import com.viaversion.viaversion.protocols.protocol1_9to1_8.providers.HandItemProvider;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
public class VRHandItemProvider extends HandItemProvider {
|
||||||
|
public Item clientItem = null;
|
||||||
|
public Map<UUID, Item> serverPlayers = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Item getHandItem(UserConnection info) {
|
||||||
|
Item serverItem;
|
||||||
|
if (info.isClientSide()) {
|
||||||
|
return getClientItem();
|
||||||
|
} else if ((serverItem = serverPlayers.get(info.getProtocolInfo().getUuid())) != null) {
|
||||||
|
return new Item(serverItem);
|
||||||
|
}
|
||||||
|
return super.getHandItem(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Item getClientItem() {
|
||||||
|
if (clientItem == null) {
|
||||||
|
return new Item(0, (byte) 0, (short) 0, null);
|
||||||
|
}
|
||||||
|
return new Item(clientItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Environment(EnvType.CLIENT)
|
||||||
|
public void registerClientTick() {
|
||||||
|
try {
|
||||||
|
ClientTickEvents.END_WORLD_TICK.register(clientWorld -> tickClient());
|
||||||
|
} catch (NoClassDefFoundError ignored) {
|
||||||
|
try {
|
||||||
|
WorldTickCallback.EVENT.register(world -> {
|
||||||
|
if (world.isClient) {
|
||||||
|
tickClient();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (NoClassDefFoundError ignored2) {
|
||||||
|
ViaFabric.JLOGGER.info("Fabric Lifecycle V0/V1 isn't installed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerServerTick() {
|
||||||
|
try {
|
||||||
|
ServerTickEvents.END_WORLD_TICK.register(this::tickServer);
|
||||||
|
} catch (NoClassDefFoundError ignored) {
|
||||||
|
WorldTickCallback.EVENT.register(world -> {
|
||||||
|
if (!world.isClient) {
|
||||||
|
tickServer(world);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void tickClient() {
|
||||||
|
ClientPlayerEntity p = MinecraftClient.getInstance().player;
|
||||||
|
if (p != null) {
|
||||||
|
clientItem = fromNative(p.inventory.getMainHandStack());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void tickServer(World world) {
|
||||||
|
serverPlayers.clear();
|
||||||
|
world.getPlayers().forEach(it -> serverPlayers
|
||||||
|
.put(it.getUuid(), fromNative(it.inventory.getMainHandStack())));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Item fromNative(ItemStack original) {
|
||||||
|
Identifier iid = Registry.ITEM.getId(original.getItem());
|
||||||
|
if (iid == null) return new Item(0, (byte) 0, (short) 0, null);
|
||||||
|
int id = swordId(iid.toString());
|
||||||
|
return new Item(id, (byte) original.getCount(), (short) original.getDamage(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int swordId(String id) {
|
||||||
|
// https://github.com/ViaVersion/ViaVersion/blob/8de26a0ad33f5b739f5394ed80f69d14197fddc7/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9to1_8/Protocol1_9To1_8.java#L86
|
||||||
|
switch (id) {
|
||||||
|
case "minecraft:iron_sword":
|
||||||
|
return 267;
|
||||||
|
case "minecraft:wooden_sword":
|
||||||
|
return 268;
|
||||||
|
case "minecraft:golden_sword":
|
||||||
|
return 272;
|
||||||
|
case "minecraft:diamond_sword":
|
||||||
|
return 276;
|
||||||
|
case "minecraft:stone_sword":
|
||||||
|
return 283;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,166 @@
|
|||||||
|
package com.viaversion.fabric.mc115.providers;
|
||||||
|
|
||||||
|
import com.viaversion.fabric.mc115.ViaFabric;
|
||||||
|
import com.viaversion.fabric.mc115.ViaFabricAddress;
|
||||||
|
import com.viaversion.fabric.mc115.service.ProtocolAutoDetector;
|
||||||
|
import com.viaversion.fabric.mc115.util.ProtocolUtils;
|
||||||
|
import com.google.common.primitives.Ints;
|
||||||
|
import com.viaversion.viaversion.api.connection.ProtocolInfo;
|
||||||
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
|
import net.minecraft.network.ClientConnection;
|
||||||
|
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
|
||||||
|
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||||
|
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||||
|
import com.viaversion.viaversion.api.type.Type;
|
||||||
|
import com.viaversion.viaversion.exception.CancelException;
|
||||||
|
import com.viaversion.viaversion.api.protocol.packet.State;
|
||||||
|
import com.viaversion.viaversion.protocols.base.*;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.SocketAddress;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
|
public class VRVersionProvider extends BaseVersionProvider {
|
||||||
|
private int[] multiconnectSupportedVersions = null;
|
||||||
|
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (FabricLoader.getInstance().isModLoaded("multiconnect")) {
|
||||||
|
Class<?> mcApiClass = Class.forName("net.earthcomputer.multiconnect.api.MultiConnectAPI");
|
||||||
|
Class<?> iProtocolClass = Class.forName("net.earthcomputer.multiconnect.api.IProtocol");
|
||||||
|
Object mcApiInstance = mcApiClass.getMethod("instance").invoke(null);
|
||||||
|
List<?> protocols = (List<?>) mcApiClass.getMethod("getSupportedProtocols").invoke(mcApiInstance);
|
||||||
|
Method getValue = iProtocolClass.getMethod("getValue");
|
||||||
|
Method isMulticonnectBeta;
|
||||||
|
try {
|
||||||
|
isMulticonnectBeta = iProtocolClass.getMethod("isMulticonnectBeta");
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
isMulticonnectBeta = null;
|
||||||
|
}
|
||||||
|
Set<Integer> vers = new TreeSet<>();
|
||||||
|
for (Object protocol : protocols) {
|
||||||
|
// Do not use versions with beta multiconnect support, which may have stability issues
|
||||||
|
if (isMulticonnectBeta == null || !(Boolean) isMulticonnectBeta.invoke(protocol)) {
|
||||||
|
vers.add((Integer) getValue.invoke(protocol));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
multiconnectSupportedVersions = vers.stream().mapToInt(Integer::intValue).toArray();
|
||||||
|
ViaFabric.JLOGGER.info("ViaFabric will integrate with multiconnect");
|
||||||
|
}
|
||||||
|
} catch (ClassNotFoundException | IllegalAccessException | InvocationTargetException | NoSuchMethodException
|
||||||
|
| ClassCastException ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getClosestServerProtocol(UserConnection connection) throws Exception {
|
||||||
|
if (connection.isClientSide()) {
|
||||||
|
ProtocolInfo info = Objects.requireNonNull(connection.getProtocolInfo());
|
||||||
|
|
||||||
|
if (!ViaFabric.config.isClientSideEnabled()) {
|
||||||
|
return info.getProtocolVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
int serverVer = ViaFabric.config.getClientSideVersion();
|
||||||
|
SocketAddress addr = connection.getChannel().remoteAddress();
|
||||||
|
|
||||||
|
if (addr instanceof InetSocketAddress) {
|
||||||
|
int addrVersion = new ViaFabricAddress().parse(((InetSocketAddress) addr).getHostName()).protocol;
|
||||||
|
if (addrVersion != 0) serverVer = addrVersion;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (serverVer == -2) {
|
||||||
|
// Hope protocol was autodetected
|
||||||
|
ProtocolVersion autoVer =
|
||||||
|
ProtocolAutoDetector.detectVersion((InetSocketAddress) addr).getNow(null);
|
||||||
|
if (autoVer != null) {
|
||||||
|
serverVer = autoVer.getVersion();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
ViaFabric.JLOGGER.warning("Couldn't auto detect: " + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean blocked = checkAddressBlocked(addr);
|
||||||
|
boolean supported = ProtocolUtils.isSupported(serverVer, info.getProtocolVersion());
|
||||||
|
|
||||||
|
handleMulticonnectPing(connection, info, blocked, serverVer);
|
||||||
|
|
||||||
|
if (blocked || !supported) serverVer = info.getProtocolVersion();
|
||||||
|
|
||||||
|
return serverVer;
|
||||||
|
}
|
||||||
|
return super.getClosestServerProtocol(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkAddressBlocked(SocketAddress addr) {
|
||||||
|
return addr instanceof InetSocketAddress && (isDisabled(((InetSocketAddress) addr).getHostString())
|
||||||
|
|| ((((InetSocketAddress) addr).getAddress() != null) &&
|
||||||
|
(isDisabled(((InetSocketAddress) addr).getAddress().getHostAddress())
|
||||||
|
|| isDisabled(((InetSocketAddress) addr).getAddress().getHostName()))));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleMulticonnectPing(UserConnection connection, ProtocolInfo info, boolean blocked, int serverVer) throws Exception {
|
||||||
|
if (info.getState() == State.STATUS
|
||||||
|
&& info.getProtocolVersion() == -1
|
||||||
|
&& connection.getChannel().pipeline().get(ClientConnection.class).getPacketListener()
|
||||||
|
.getClass().getName().startsWith("net.earthcomputer.multiconnect")
|
||||||
|
&& (blocked || ProtocolUtils.isSupported(serverVer, getVersionForMulticonnect(serverVer)))) { // Intercept the connection
|
||||||
|
int multiconnectSuggestion = blocked ? -1 : getVersionForMulticonnect(serverVer);
|
||||||
|
ViaFabric.JLOGGER.info("Sending " + ProtocolVersion.getProtocol(multiconnectSuggestion) + " for multiconnect version detector");
|
||||||
|
PacketWrapper newAnswer = PacketWrapper.create(0x00, null, connection);
|
||||||
|
newAnswer.write(Type.STRING, "{\"version\":{\"name\":\"viafabric integration\",\"protocol\":" + multiconnectSuggestion + "}}");
|
||||||
|
newAnswer.send(info.getPipeline().contains(BaseProtocol1_16.class) ? BaseProtocol1_16.class : BaseProtocol1_7.class, true, true);
|
||||||
|
throw CancelException.generate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getVersionForMulticonnect(int clientSideVersion) {
|
||||||
|
// https://github.com/ViaVersion/ViaVersion/blob/master/velocity/src/main/java/us/myles/ViaVersion/velocity/providers/VelocityVersionProvider.java
|
||||||
|
int[] compatibleProtocols = multiconnectSupportedVersions;
|
||||||
|
|
||||||
|
if (Arrays.binarySearch(compatibleProtocols, clientSideVersion) >= 0) {
|
||||||
|
return clientSideVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clientSideVersion < compatibleProtocols[0]) {
|
||||||
|
return compatibleProtocols[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: This needs a better fix, i.e checking ProtocolRegistry to see if it would work.
|
||||||
|
for (int i = compatibleProtocols.length - 1; i >= 0; i--) {
|
||||||
|
int protocol = compatibleProtocols[i];
|
||||||
|
if (clientSideVersion > protocol && ProtocolVersion.isRegistered(protocol)) {
|
||||||
|
return protocol;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ViaFabric.JLOGGER.severe("multiconnect integration: Panic, no protocol id found for " + clientSideVersion);
|
||||||
|
return clientSideVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isDisabled(String addr) {
|
||||||
|
String[] parts = addr.split("\\.");
|
||||||
|
boolean isNumericIp = parts.length == 4 && Arrays.stream(parts).map(Ints::tryParse).allMatch(Objects::nonNull);
|
||||||
|
return IntStream.range(0, parts.length).anyMatch(i -> {
|
||||||
|
String query;
|
||||||
|
if (isNumericIp) {
|
||||||
|
query = String.join(".", Arrays.stream(parts, 0, i + 1)
|
||||||
|
.toArray(String[]::new)) + ((i != 3) ? ".*" : "");
|
||||||
|
} else {
|
||||||
|
query = ((i != 0) ? "*." : "") + String.join(".", Arrays.stream(parts, i, parts.length)
|
||||||
|
.toArray(String[]::new));
|
||||||
|
}
|
||||||
|
if (ViaFabric.config.isForcedDisable(query)) {
|
||||||
|
ViaFabric.JLOGGER.info(addr + " is force-disabled. (Matches " + query + ")");
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,125 @@
|
|||||||
|
package com.viaversion.fabric.mc115.service;
|
||||||
|
|
||||||
|
import com.viaversion.fabric.mc115.ViaFabric;
|
||||||
|
import com.viaversion.fabric.mc115.ViaFabricAddress;
|
||||||
|
import com.google.common.cache.CacheBuilder;
|
||||||
|
import com.google.common.cache.CacheLoader;
|
||||||
|
import com.google.common.cache.LoadingCache;
|
||||||
|
import io.netty.bootstrap.Bootstrap;
|
||||||
|
import io.netty.channel.*;
|
||||||
|
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||||
|
import io.netty.handler.timeout.ReadTimeoutHandler;
|
||||||
|
import net.fabricmc.api.EnvType;
|
||||||
|
import net.fabricmc.api.Environment;
|
||||||
|
import net.minecraft.network.*;
|
||||||
|
import net.minecraft.network.listener.ClientQueryPacketListener;
|
||||||
|
import net.minecraft.network.packet.c2s.handshake.HandshakeC2SPacket;
|
||||||
|
import net.minecraft.network.packet.c2s.query.QueryRequestC2SPacket;
|
||||||
|
import net.minecraft.network.packet.s2c.query.QueryPongS2CPacket;
|
||||||
|
import net.minecraft.network.packet.s2c.query.QueryResponseS2CPacket;
|
||||||
|
import net.minecraft.server.ServerMetadata;
|
||||||
|
import net.minecraft.text.LiteralText;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||||
|
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
|
@Environment(EnvType.CLIENT)
|
||||||
|
public class ProtocolAutoDetector {
|
||||||
|
private static LoadingCache<InetSocketAddress, CompletableFuture<ProtocolVersion>> SERVER_VER = CacheBuilder.newBuilder()
|
||||||
|
.expireAfterAccess(100, TimeUnit.SECONDS)
|
||||||
|
.build(CacheLoader.from((address) -> {
|
||||||
|
CompletableFuture<ProtocolVersion> future = new CompletableFuture<>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
final ClientConnection clientConnection = new ClientConnection(NetworkSide.CLIENTBOUND);
|
||||||
|
|
||||||
|
ChannelFuture ch = new Bootstrap()
|
||||||
|
.group(ClientConnection.CLIENT_IO_GROUP.get())
|
||||||
|
.channel(NioSocketChannel.class)
|
||||||
|
.handler(new ChannelInitializer<Channel>() {
|
||||||
|
protected void initChannel(Channel channel) {
|
||||||
|
try {
|
||||||
|
channel.config().setOption(ChannelOption.TCP_NODELAY, true);
|
||||||
|
channel.config().setOption(ChannelOption.IP_TOS, 0x18); // Stolen from Velocity, low delay, high reliability
|
||||||
|
} catch (ChannelException ignored) {
|
||||||
|
}
|
||||||
|
|
||||||
|
channel.pipeline()
|
||||||
|
.addLast("timeout", new ReadTimeoutHandler(30))
|
||||||
|
.addLast("splitter", new SplitterHandler())
|
||||||
|
.addLast("decoder", new DecoderHandler(NetworkSide.CLIENTBOUND))
|
||||||
|
.addLast("prepender", new SizePrepender())
|
||||||
|
.addLast("encoder", new PacketEncoder(NetworkSide.SERVERBOUND))
|
||||||
|
.addLast("packet_handler", clientConnection);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.connect(address);
|
||||||
|
|
||||||
|
ch.addListener(future1 -> {
|
||||||
|
if (!future1.isSuccess()) {
|
||||||
|
future.completeExceptionally(future1.cause());
|
||||||
|
} else {
|
||||||
|
ch.channel().eventLoop().execute(() -> { // needs to execute after channel init
|
||||||
|
clientConnection.setPacketListener(new ClientQueryPacketListener() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(QueryResponseS2CPacket packet) {
|
||||||
|
ServerMetadata meta = packet.getServerMetadata();
|
||||||
|
ServerMetadata.Version version;
|
||||||
|
if (meta != null && (version = meta.getVersion()) != null) {
|
||||||
|
ProtocolVersion ver = ProtocolVersion.getProtocol(version.getProtocolVersion());
|
||||||
|
future.complete(ver);
|
||||||
|
ViaFabric.JLOGGER.info("Auto-detected " + ver + " for " + address);
|
||||||
|
} else {
|
||||||
|
future.completeExceptionally(new IllegalArgumentException("Null version in query response"));
|
||||||
|
}
|
||||||
|
clientConnection.disconnect(new LiteralText(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPong(QueryPongS2CPacket packet) {
|
||||||
|
clientConnection.disconnect(new LiteralText("Pong not requested!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisconnected(Text reason) {
|
||||||
|
future.completeExceptionally(new IllegalStateException(reason.asString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClientConnection getConnection() {
|
||||||
|
return clientConnection;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
clientConnection.send(new HandshakeC2SPacket(address.getHostString(),
|
||||||
|
address.getPort(), NetworkState.STATUS));
|
||||||
|
clientConnection.send(new QueryRequestC2SPacket());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (Throwable throwable) {
|
||||||
|
future.completeExceptionally(throwable);
|
||||||
|
}
|
||||||
|
|
||||||
|
return future;
|
||||||
|
}));
|
||||||
|
|
||||||
|
public static CompletableFuture<ProtocolVersion> detectVersion(InetSocketAddress address) {
|
||||||
|
try {
|
||||||
|
InetSocketAddress real = new InetSocketAddress(InetAddress.getByAddress
|
||||||
|
(new ViaFabricAddress().parse(address.getHostString()).realAddress,
|
||||||
|
address.getAddress().getAddress()), address.getPort());
|
||||||
|
return SERVER_VER.get(real);
|
||||||
|
} catch (UnknownHostException | ExecutionException e) {
|
||||||
|
ViaFabric.JLOGGER.log(Level.WARNING, "Protocol auto detector error: ", e);
|
||||||
|
return CompletableFuture.completedFuture(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package com.viaversion.fabric.mc115.util;
|
||||||
|
|
||||||
|
import com.viaversion.viaversion.api.platform.PlatformTask;
|
||||||
|
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
|
||||||
|
public class FutureTaskId implements PlatformTask<Future<?>> {
|
||||||
|
private final Future<?> object;
|
||||||
|
|
||||||
|
public FutureTaskId(Future<?> object) {
|
||||||
|
this.object = object;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Future<?> getObject() {
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cancel() {
|
||||||
|
object.cancel(false);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
package com.viaversion.fabric.mc115.util;
|
||||||
|
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.LogRecord;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
public class JLoggerToLog4j extends Logger {
|
||||||
|
private final org.apache.logging.log4j.Logger base;
|
||||||
|
|
||||||
|
public JLoggerToLog4j(org.apache.logging.log4j.Logger logger) {
|
||||||
|
super("logger", null);
|
||||||
|
this.base = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void log(LogRecord record) {
|
||||||
|
this.log(record.getLevel(), record.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void log(Level level, String msg) {
|
||||||
|
if (level == Level.FINE) {
|
||||||
|
this.base.debug(msg);
|
||||||
|
} else if (level == Level.WARNING) {
|
||||||
|
this.base.warn(msg);
|
||||||
|
} else if (level == Level.SEVERE) {
|
||||||
|
this.base.error(msg);
|
||||||
|
} else if (level == Level.INFO) {
|
||||||
|
this.base.info(msg);
|
||||||
|
} else {
|
||||||
|
this.base.trace(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void log(Level level, String msg, Object param1) {
|
||||||
|
if (level == Level.FINE) {
|
||||||
|
this.base.debug(msg, param1);
|
||||||
|
} else if (level == Level.WARNING) {
|
||||||
|
this.base.warn(msg, param1);
|
||||||
|
} else if (level == Level.SEVERE) {
|
||||||
|
this.base.error(msg, param1);
|
||||||
|
} else if (level == Level.INFO) {
|
||||||
|
this.base.info(msg, param1);
|
||||||
|
} else {
|
||||||
|
this.base.trace(msg, param1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void log(Level level, String msg, Object[] params) {
|
||||||
|
log(level, MessageFormat.format(msg, params));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void log(Level level, String msg, Throwable params) {
|
||||||
|
if (level == Level.FINE) {
|
||||||
|
this.base.debug(msg, params);
|
||||||
|
} else if (level == Level.WARNING) {
|
||||||
|
this.base.warn(msg, params);
|
||||||
|
} else if (level == Level.SEVERE) {
|
||||||
|
this.base.error(msg, params);
|
||||||
|
} else if (level == Level.INFO) {
|
||||||
|
this.base.info(msg, params);
|
||||||
|
} else {
|
||||||
|
this.base.trace(msg, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,60 @@
|
|||||||
|
package com.viaversion.fabric.mc115.util;
|
||||||
|
|
||||||
|
import com.viaversion.viaversion.api.Via;
|
||||||
|
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public class ProtocolUtils {
|
||||||
|
public static boolean isSupported(int server, int client) {
|
||||||
|
return server == client || Via.getManager().getProtocolManager().getProtocolPath(client, server) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getProtocolName(int id) {
|
||||||
|
if (!ProtocolVersion.isRegistered(id)) return Integer.toString(id);
|
||||||
|
return ProtocolVersion.getProtocol(id).getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isStartOfProtocolText(String s) {
|
||||||
|
try {
|
||||||
|
Integer.parseInt(s);
|
||||||
|
return true;
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
try {
|
||||||
|
Integer.parseInt(s + '0');
|
||||||
|
return true;
|
||||||
|
} catch (NumberFormatException e2) {
|
||||||
|
return ProtocolVersion.getProtocols().stream()
|
||||||
|
.map(ProtocolVersion::getName)
|
||||||
|
.flatMap(str -> Stream.concat(
|
||||||
|
Arrays.stream(str.split("-")),
|
||||||
|
Arrays.stream(new String[]{str})
|
||||||
|
))
|
||||||
|
.anyMatch(ver -> ver.startsWith(s));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Integer parseProtocolId(String s) {
|
||||||
|
try {
|
||||||
|
return Integer.parseInt(s);
|
||||||
|
} catch (NumberFormatException ignored) {
|
||||||
|
ProtocolVersion closest = ProtocolVersion.getClosest(s);
|
||||||
|
if (closest == null) return null;
|
||||||
|
return closest.getVersion();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String[] getProtocolSuggestions(String text) {
|
||||||
|
return ProtocolVersion.getProtocols().stream()
|
||||||
|
.map(ProtocolVersion::getName)
|
||||||
|
.flatMap(str -> Stream.concat(
|
||||||
|
Arrays.stream(str.split("-")),
|
||||||
|
Arrays.stream(new String[]{str})
|
||||||
|
))
|
||||||
|
.distinct()
|
||||||
|
.filter(ver -> ver.startsWith(text))
|
||||||
|
.toArray(String[]::new);
|
||||||
|
}
|
||||||
|
}
|
61
viafabric-mc115/src/main/resources/fabric.mod.json
Normal file
61
viafabric-mc115/src/main/resources/fabric.mod.json
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
{
|
||||||
|
"schemaVersion": 1,
|
||||||
|
"id": "viafabric-mc115",
|
||||||
|
"name": "ViaFabric",
|
||||||
|
"version": "@version@",
|
||||||
|
"description": "@description@",
|
||||||
|
"license": "GPL-3.0",
|
||||||
|
"contact": {
|
||||||
|
"homepage": "https://viaversion.com/fabric",
|
||||||
|
"issues": "https://github.com/ViaVersion/ViaFabric/issues",
|
||||||
|
"sources": "https://github.com/ViaVersion/ViaFabric"
|
||||||
|
},
|
||||||
|
"environment": "*",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "creeper123123321",
|
||||||
|
"contact": {
|
||||||
|
"homepage": "https://creeper123123321.github.io/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"contributors": [
|
||||||
|
{
|
||||||
|
"name": "GitHub contributors",
|
||||||
|
"contact": {
|
||||||
|
"homepage": "https://github.com/ViaVersion/ViaFabric/graphs/contributors"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"entrypoints": {
|
||||||
|
"main": [
|
||||||
|
"com.viaversion.fabric.mc115.ViaFabric"
|
||||||
|
],
|
||||||
|
"cotton-client-commands": [
|
||||||
|
"com.viaversion.fabric.mc115.commands.VRClientCommands"
|
||||||
|
],
|
||||||
|
"modmenu": [
|
||||||
|
"com.viaversion.fabric.mc115.gui.ModMenuConfig"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"depends": {
|
||||||
|
"cotton-client-commands": "*",
|
||||||
|
"fabricloader": ">=0.4.0",
|
||||||
|
"fabric-resource-loader-v0": "*",
|
||||||
|
"minecraft": "1.15.x",
|
||||||
|
"viaversion": ">3.0.1"
|
||||||
|
},
|
||||||
|
"conflicts": {
|
||||||
|
"fabric-registry-sync-v0": "*"
|
||||||
|
},
|
||||||
|
"recommends": {
|
||||||
|
"fabric-command-api-v1": "*"
|
||||||
|
},
|
||||||
|
"icon": "assets/viafabric/textures/logo.png",
|
||||||
|
"mixins": [
|
||||||
|
"mixins.viafabric.address.json",
|
||||||
|
"mixins.viafabric.gui.json",
|
||||||
|
"mixins.viafabric.debug.json",
|
||||||
|
"mixins.viafabric.pipeline.json"
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"required": true,
|
||||||
|
"compatibilityLevel": "JAVA_8",
|
||||||
|
"mixins": [
|
||||||
|
],
|
||||||
|
"client": [
|
||||||
|
"com.viaversion.fabric.mc115.mixin.address.client.MixinConnectScreenThread",
|
||||||
|
"com.viaversion.fabric.mc115.mixin.address.client.MixinServerAddress",
|
||||||
|
"com.viaversion.fabric.mc115.mixin.address.client.MixinServerPinger"
|
||||||
|
],
|
||||||
|
"injectors": {
|
||||||
|
"defaultRequire": 1
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"required": true,
|
||||||
|
"compatibilityLevel": "JAVA_8",
|
||||||
|
"mixins": [
|
||||||
|
],
|
||||||
|
"client": [
|
||||||
|
"com.viaversion.fabric.mc115.mixin.debug.client.MixinClientConnectionAccessor",
|
||||||
|
"com.viaversion.fabric.mc115.mixin.debug.client.MixinDebugHud"
|
||||||
|
],
|
||||||
|
"injectors": {
|
||||||
|
"defaultRequire": 0
|
||||||
|
}
|
||||||
|
}
|
12
viafabric-mc115/src/main/resources/mixins.viafabric.gui.json
Normal file
12
viafabric-mc115/src/main/resources/mixins.viafabric.gui.json
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"required": true,
|
||||||
|
"compatibilityLevel": "JAVA_8",
|
||||||
|
"mixins": [
|
||||||
|
],
|
||||||
|
"client": [
|
||||||
|
"com.viaversion.fabric.mc115.mixin.gui.client.MixinMultiplayerScreen"
|
||||||
|
],
|
||||||
|
"injectors": {
|
||||||
|
"defaultRequire": 0
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"required": true,
|
||||||
|
"compatibilityLevel": "JAVA_8",
|
||||||
|
"mixins": [
|
||||||
|
"com.viaversion.fabric.mc115.mixin.pipeline.MixinClientConnection",
|
||||||
|
"com.viaversion.fabric.mc115.mixin.pipeline.MixinServerNetworkIoChInit"
|
||||||
|
],
|
||||||
|
"client": [
|
||||||
|
"com.viaversion.fabric.mc115.mixin.pipeline.client.MixinClientConnectionChInit"
|
||||||
|
],
|
||||||
|
"injectors": {
|
||||||
|
"defaultRequire": 1
|
||||||
|
}
|
||||||
|
}
|
@ -1,11 +1,10 @@
|
|||||||
version = rootProject.version
|
version = rootProject.version
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
minecraft("com.mojang:minecraft:1.14.4")
|
minecraft("com.mojang:minecraft:1.16.5")
|
||||||
mappings("net.fabricmc:yarn:1.14.4+build.16:v2")
|
mappings("net.fabricmc:yarn:1.16.5+build.6:v2")
|
||||||
modImplementation("net.fabricmc:fabric-loader:0.8.2+build.194")
|
modImplementation("net.fabricmc:fabric-loader:0.11.3")
|
||||||
|
|
||||||
modImplementation("net.fabricmc.fabric-api:fabric-api:0.13.1+build.257-1.14")
|
modImplementation("net.fabricmc.fabric-api:fabric-api:0.32.5+1.16")
|
||||||
modImplementation("io.github.prospector:modmenu:1.7.16.1.14.4+build.128")
|
modImplementation("com.terraformersmc:modmenu:1.16.9")
|
||||||
modImplementation("io.github.cottonmc:cotton-client-commands:1.0.0+1.15.2")
|
|
||||||
}
|
}
|
@ -0,0 +1,115 @@
|
|||||||
|
package com.viaversion.fabric.mc116;
|
||||||
|
|
||||||
|
import com.viaversion.fabric.mc116.commands.VRCommandHandler;
|
||||||
|
import com.viaversion.fabric.mc116.config.VRConfig;
|
||||||
|
import com.viaversion.fabric.mc116.platform.VRInjector;
|
||||||
|
import com.viaversion.fabric.mc116.platform.VRLoader;
|
||||||
|
import com.viaversion.fabric.mc116.platform.VRPlatform;
|
||||||
|
import com.viaversion.fabric.mc116.protocol.ViaFabricHostnameProtocol;
|
||||||
|
import com.viaversion.fabric.mc116.util.JLoggerToLog4j;
|
||||||
|
import com.google.common.collect.Range;
|
||||||
|
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||||
|
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||||
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||||
|
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
|
||||||
|
import io.netty.channel.DefaultEventLoop;
|
||||||
|
import io.netty.channel.EventLoop;
|
||||||
|
import net.fabricmc.api.EnvType;
|
||||||
|
import net.fabricmc.api.ModInitializer;
|
||||||
|
import net.fabricmc.fabric.api.client.command.v1.ClientCommandManager;
|
||||||
|
import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback;
|
||||||
|
import net.fabricmc.fabric.api.registry.CommandRegistry;
|
||||||
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
|
import net.minecraft.command.CommandSource;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import com.viaversion.viaversion.ViaManagerImpl;
|
||||||
|
import com.viaversion.viaversion.api.Via;
|
||||||
|
import com.viaversion.viaversion.api.data.MappingDataLoader;
|
||||||
|
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||||
|
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ThreadFactory;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
public class ViaFabric implements ModInitializer {
|
||||||
|
public static final Logger JLOGGER = new JLoggerToLog4j(LogManager.getLogger("ViaFabric"));
|
||||||
|
public static final ExecutorService ASYNC_EXECUTOR;
|
||||||
|
public static final EventLoop EVENT_LOOP;
|
||||||
|
public static CompletableFuture<Void> INIT_FUTURE = new CompletableFuture<>();
|
||||||
|
public static VRConfig config;
|
||||||
|
|
||||||
|
static {
|
||||||
|
ThreadFactory factory = new ThreadFactoryBuilder().setDaemon(true).setNameFormat("ViaFabric-%d").build();
|
||||||
|
ASYNC_EXECUTOR = Executors.newFixedThreadPool(8, factory);
|
||||||
|
EVENT_LOOP = new DefaultEventLoop(factory);
|
||||||
|
EVENT_LOOP.submit(INIT_FUTURE::join); // https://github.com/ViaVersion/ViaFabric/issues/53 ugly workaround code but works tm
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getVersion() {
|
||||||
|
return FabricLoader.getInstance().getModContainer("viafabric")
|
||||||
|
.get().getMetadata().getVersion().getFriendlyString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <S extends CommandSource> LiteralArgumentBuilder<S> command(String commandName) {
|
||||||
|
return LiteralArgumentBuilder.<S>literal(commandName)
|
||||||
|
.then(
|
||||||
|
RequiredArgumentBuilder
|
||||||
|
.<S, String>argument("args", StringArgumentType.greedyString())
|
||||||
|
.executes(((VRCommandHandler) Via.getManager().getCommandHandler())::execute)
|
||||||
|
.suggests(((VRCommandHandler) Via.getManager().getCommandHandler())::suggestion)
|
||||||
|
)
|
||||||
|
.executes(((VRCommandHandler) Via.getManager().getCommandHandler())::execute);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInitialize() {
|
||||||
|
Via.init(ViaManagerImpl.builder()
|
||||||
|
.injector(new VRInjector())
|
||||||
|
.loader(new VRLoader())
|
||||||
|
.commandHandler(new VRCommandHandler())
|
||||||
|
.platform(new VRPlatform()).build());
|
||||||
|
|
||||||
|
FabricLoader.getInstance().getModContainer("viabackwards").ifPresent(mod -> MappingDataLoader.enableMappingsCache());
|
||||||
|
|
||||||
|
((ViaManagerImpl) Via.getManager()).init();
|
||||||
|
|
||||||
|
Via.getManager().getProtocolManager().registerBaseProtocol(ViaFabricHostnameProtocol.INSTANCE, Range.lessThan(Integer.MIN_VALUE));
|
||||||
|
ProtocolVersion.register(-2, "AUTO");
|
||||||
|
|
||||||
|
FabricLoader.getInstance().getEntrypoints("viafabric:via_api_initialized", Runnable.class).forEach(Runnable::run);
|
||||||
|
|
||||||
|
try {
|
||||||
|
registerCommandsV1();
|
||||||
|
} catch (NoClassDefFoundError ignored) {
|
||||||
|
try {
|
||||||
|
registerCommandsV0();
|
||||||
|
JLOGGER.info("Using Fabric Commands V0");
|
||||||
|
} catch (NoClassDefFoundError ignored2) {
|
||||||
|
JLOGGER.info("Couldn't register command as Fabric Commands isn't installed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
config = new VRConfig(FabricLoader.getInstance().getConfigDir().resolve("ViaFabric")
|
||||||
|
.resolve("viafabric.yml").toFile());
|
||||||
|
|
||||||
|
INIT_FUTURE.complete(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerCommandsV1() {
|
||||||
|
CommandRegistrationCallback.EVENT.register((dispatcher, dedicated) -> dispatcher.register(command("viaversion")));
|
||||||
|
CommandRegistrationCallback.EVENT.register((dispatcher, dedicated) -> dispatcher.register(command("viaver")));
|
||||||
|
CommandRegistrationCallback.EVENT.register((dispatcher, dedicated) -> dispatcher.register(command("vvfabric")));
|
||||||
|
if (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) {
|
||||||
|
ClientCommandManager.DISPATCHER.register(command("viafabricclient"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
private void registerCommandsV0() {
|
||||||
|
CommandRegistry.INSTANCE.register(false, dispatcher -> dispatcher.register(command("viaversion")));
|
||||||
|
CommandRegistry.INSTANCE.register(false, dispatcher -> dispatcher.register(command("viaver")));
|
||||||
|
CommandRegistry.INSTANCE.register(false, dispatcher -> dispatcher.register(command("vvfabric")));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,77 @@
|
|||||||
|
package com.viaversion.fabric.mc116;
|
||||||
|
|
||||||
|
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
public class ViaFabricAddress {
|
||||||
|
public int protocol = 0;
|
||||||
|
public String viaSuffix = null;
|
||||||
|
public String realAddress = null;
|
||||||
|
|
||||||
|
public ViaFabricAddress parse(String address) {
|
||||||
|
if (address == null) return null;
|
||||||
|
String[] parts = address.split("\\.");
|
||||||
|
|
||||||
|
boolean foundDomain = false;
|
||||||
|
boolean foundOptions = false;
|
||||||
|
|
||||||
|
StringBuilder ourParts = new StringBuilder();
|
||||||
|
StringBuilder realAddrBuilder = new StringBuilder();
|
||||||
|
|
||||||
|
for (int i = parts.length - 1; i >= 0; i--) {
|
||||||
|
String part = parts[i];
|
||||||
|
boolean realAddrPart = false;
|
||||||
|
if (foundDomain) {
|
||||||
|
if (!foundOptions) {
|
||||||
|
if (part.startsWith("_")) {
|
||||||
|
String arg = part.substring(2);
|
||||||
|
if (part.toLowerCase(Locale.ROOT).startsWith("_v")) {
|
||||||
|
try {
|
||||||
|
protocol = Integer.parseInt(arg);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
ProtocolVersion closest = ProtocolVersion.getClosest(arg.replace("_", "."));
|
||||||
|
if (closest != null) {
|
||||||
|
protocol = closest.getVersion();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
foundOptions = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (foundOptions) {
|
||||||
|
realAddrPart = true;
|
||||||
|
}
|
||||||
|
} else if (part.equalsIgnoreCase("viafabric")) {
|
||||||
|
foundDomain = true;
|
||||||
|
}
|
||||||
|
if (realAddrPart) {
|
||||||
|
realAddrBuilder.insert(0, part + ".");
|
||||||
|
} else {
|
||||||
|
ourParts.insert(0, part + ".");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String realAddr = realAddrBuilder.toString().replaceAll("\\.$", "");
|
||||||
|
String suffix = ourParts.toString().replaceAll("\\.$", "");
|
||||||
|
|
||||||
|
if (realAddr.isEmpty()) {
|
||||||
|
this.realAddress = address;
|
||||||
|
} else {
|
||||||
|
this.realAddress = realAddr;
|
||||||
|
this.viaSuffix = suffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "ViaFabricAddress{" +
|
||||||
|
"protocol=" + protocol +
|
||||||
|
", viaSuffix='" + viaSuffix + '\'' +
|
||||||
|
", realAddress='" + realAddress + '\'' +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,61 @@
|
|||||||
|
package com.viaversion.fabric.mc116.commands;
|
||||||
|
|
||||||
|
import com.viaversion.fabric.mc116.platform.VRPlatform;
|
||||||
|
import net.fabricmc.fabric.api.client.command.v1.FabricClientCommandSource;
|
||||||
|
import net.minecraft.command.CommandSource;
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.server.command.ServerCommandSource;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import com.viaversion.viaversion.api.command.ViaCommandSender;
|
||||||
|
import com.viaversion.viaversion.libs.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||||
|
import com.viaversion.viaversion.libs.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class NMSCommandSender implements ViaCommandSender {
|
||||||
|
private final CommandSource source;
|
||||||
|
|
||||||
|
public NMSCommandSender(CommandSource source) {
|
||||||
|
this.source = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasPermission(String s) {
|
||||||
|
// https://gaming.stackexchange.com/questions/138602/what-does-op-permission-level-do
|
||||||
|
return source.hasPermissionLevel(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendMessage(String s) {
|
||||||
|
if (source instanceof ServerCommandSource) {
|
||||||
|
((ServerCommandSource) source).sendFeedback(Text.Serializer.fromJson(VRPlatform.legacyToJson(s)), false);
|
||||||
|
} else if (source instanceof FabricClientCommandSource) {
|
||||||
|
((FabricClientCommandSource) source).sendFeedback(Text.Serializer.fromJson(VRPlatform.legacyToJson(s)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String legacyToJson(String legacy) {
|
||||||
|
return GsonComponentSerializer.gson().serialize(LegacyComponentSerializer.legacySection().deserialize(legacy));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UUID getUUID() {
|
||||||
|
if (source instanceof ServerCommandSource) {
|
||||||
|
Entity entity = ((ServerCommandSource) source).getEntity();
|
||||||
|
if (entity != null) return entity.getUuid();
|
||||||
|
} else if (source instanceof FabricClientCommandSource) {
|
||||||
|
return ((FabricClientCommandSource) source).getPlayer().getUuid();
|
||||||
|
}
|
||||||
|
return UUID.fromString(getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
if (source instanceof ServerCommandSource) {
|
||||||
|
return ((ServerCommandSource) source).getName();
|
||||||
|
} else if (source instanceof FabricClientCommandSource) {
|
||||||
|
return ((FabricClientCommandSource) source).getPlayer().getEntityName();
|
||||||
|
}
|
||||||
|
return "?";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
package com.viaversion.fabric.mc116.commands;
|
||||||
|
|
||||||
|
import com.viaversion.viaversion.api.Via;
|
||||||
|
import com.viaversion.viaversion.api.command.ViaCommandSender;
|
||||||
|
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class UserCommandSender implements ViaCommandSender {
|
||||||
|
private UserConnection con;
|
||||||
|
|
||||||
|
public UserCommandSender(UserConnection con) {
|
||||||
|
this.con = con;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasPermission(String s) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendMessage(String s) {
|
||||||
|
Via.getPlatform().sendMessage(getUUID(), s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UUID getUUID() {
|
||||||
|
return con.getProtocolInfo().getUuid();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return con.getProtocolInfo().getUsername();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
package com.viaversion.fabric.mc116.commands;
|
||||||
|
|
||||||
|
import com.viaversion.fabric.mc116.commands.subs.LeakDetectSubCommand;
|
||||||
|
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||||
|
import com.mojang.brigadier.context.CommandContext;
|
||||||
|
import com.mojang.brigadier.suggestion.Suggestions;
|
||||||
|
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
|
||||||
|
import net.minecraft.command.CommandSource;
|
||||||
|
import com.viaversion.viaversion.commands.ViaCommandHandler;
|
||||||
|
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
public class VRCommandHandler extends ViaCommandHandler {
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
registerSubCommand(new LeakDetectSubCommand());
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int execute(CommandContext<? extends CommandSource> ctx) {
|
||||||
|
String[] args = new String[0];
|
||||||
|
try {
|
||||||
|
args = StringArgumentType.getString(ctx, "args").split(" ");
|
||||||
|
} catch (IllegalArgumentException ignored) {
|
||||||
|
}
|
||||||
|
onCommand(
|
||||||
|
new NMSCommandSender(ctx.getSource()),
|
||||||
|
args
|
||||||
|
);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<Suggestions> suggestion(CommandContext<? extends CommandSource> ctx, SuggestionsBuilder builder) {
|
||||||
|
String[] args;
|
||||||
|
try {
|
||||||
|
args = StringArgumentType.getString(ctx, "args").split(" ", -1);
|
||||||
|
} catch (IllegalArgumentException ignored) {
|
||||||
|
args = new String[]{""};
|
||||||
|
}
|
||||||
|
String[] pref = args.clone();
|
||||||
|
pref[pref.length - 1] = "";
|
||||||
|
String prefix = String.join(" ", pref);
|
||||||
|
onTabComplete(new NMSCommandSender(ctx.getSource()), args)
|
||||||
|
.stream()
|
||||||
|
.map(it -> {
|
||||||
|
SuggestionsBuilder b = new SuggestionsBuilder(builder.getInput(), prefix.length() + builder.getStart());
|
||||||
|
b.suggest(it);
|
||||||
|
return b;
|
||||||
|
})
|
||||||
|
.forEach(builder::add);
|
||||||
|
return builder.buildFuture();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
package com.viaversion.fabric.mc116.commands.subs;
|
||||||
|
|
||||||
|
import io.netty.util.ResourceLeakDetector;
|
||||||
|
import com.viaversion.viaversion.api.command.ViaCommandSender;
|
||||||
|
import com.viaversion.viaversion.api.command.ViaSubCommand;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class LeakDetectSubCommand extends ViaSubCommand {
|
||||||
|
@Override
|
||||||
|
public String name() {
|
||||||
|
return "leakdetect";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String description() {
|
||||||
|
return "Sets ResourceLeakDetector level";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean execute(ViaCommandSender viaCommandSender, String[] strings) {
|
||||||
|
if (strings.length == 1) {
|
||||||
|
try {
|
||||||
|
ResourceLeakDetector.Level level = ResourceLeakDetector.Level.valueOf(strings[0]);
|
||||||
|
ResourceLeakDetector.setLevel(level);
|
||||||
|
viaCommandSender.sendMessage("Set leak detector level to " + level);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
viaCommandSender.sendMessage("Invalid level (" + Arrays.toString(ResourceLeakDetector.Level.values()) + ")");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
viaCommandSender.sendMessage("Current leak detection level is " + ResourceLeakDetector.getLevel());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> onTabComplete(ViaCommandSender sender, String[] args) {
|
||||||
|
if (args.length == 1) {
|
||||||
|
return Arrays.stream(ResourceLeakDetector.Level.values())
|
||||||
|
.map(Enum::name)
|
||||||
|
.filter(it -> it.startsWith(args[0]))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
return super.onTabComplete(sender, args);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
package com.viaversion.fabric.mc116.config;
|
||||||
|
|
||||||
|
import com.viaversion.viaversion.util.Config;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class VRConfig extends Config {
|
||||||
|
public static final String ENABLE_CLIENT_SIDE = "enable-client-side";
|
||||||
|
public static final String CLIENT_SIDE_VERSION = "client-side-version";
|
||||||
|
public static final String CLIENT_SIDE_FORCE_DISABLE = "client-side-force-disable";
|
||||||
|
public static final String HIDE_BUTTON = "hide-button";
|
||||||
|
|
||||||
|
public VRConfig(File configFile) {
|
||||||
|
super(configFile);
|
||||||
|
reloadConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public URL getDefaultConfigURL() {
|
||||||
|
return getClass().getClassLoader().getResource("assets/viafabric/config.yml");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void handleConfig(Map<String, Object> map) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getUnsupportedOptions() {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isClientSideEnabled() {
|
||||||
|
return getBoolean(ENABLE_CLIENT_SIDE, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClientSideEnabled(boolean val) {
|
||||||
|
set(ENABLE_CLIENT_SIDE, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getClientSideVersion() {
|
||||||
|
return getInt(CLIENT_SIDE_VERSION, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClientSideVersion(int val) {
|
||||||
|
set(CLIENT_SIDE_VERSION, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<?> getClientSideForceDisable() {
|
||||||
|
return (List<?>) get(CLIENT_SIDE_FORCE_DISABLE, List.class, Collections.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHideButton(boolean val) {
|
||||||
|
set(HIDE_BUTTON, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isHideButton() {
|
||||||
|
return getBoolean(HIDE_BUTTON, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isForcedDisable(String line) {
|
||||||
|
return getClientSideForceDisable().contains(line);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
package com.viaversion.fabric.mc116.gui;
|
||||||
|
|
||||||
|
import io.github.prospector.modmenu.api.ConfigScreenFactory;
|
||||||
|
import io.github.prospector.modmenu.api.ModMenuApi;
|
||||||
|
|
||||||
|
public class ModMenuConfig implements ModMenuApi {
|
||||||
|
@Override
|
||||||
|
public ConfigScreenFactory<?> getModConfigScreenFactory() {
|
||||||
|
return ViaConfigScreen::new;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,171 @@
|
|||||||
|
package com.viaversion.fabric.mc116.gui;
|
||||||
|
|
||||||
|
import com.viaversion.fabric.mc116.ViaFabric;
|
||||||
|
import com.viaversion.fabric.mc116.util.ProtocolUtils;
|
||||||
|
import com.viaversion.viaversion.api.Via;
|
||||||
|
import net.fabricmc.api.EnvType;
|
||||||
|
import net.fabricmc.api.Environment;
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.client.gui.screen.ConfirmScreen;
|
||||||
|
import net.minecraft.client.gui.screen.Screen;
|
||||||
|
import net.minecraft.client.gui.screen.ScreenTexts;
|
||||||
|
import net.minecraft.client.gui.widget.ButtonWidget;
|
||||||
|
import net.minecraft.client.gui.widget.TextFieldWidget;
|
||||||
|
import net.minecraft.client.util.math.MatrixStack;
|
||||||
|
import net.minecraft.text.TranslatableText;
|
||||||
|
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
@Environment(EnvType.CLIENT)
|
||||||
|
public class ViaConfigScreen extends Screen {
|
||||||
|
private static CompletableFuture<Void> latestProtocolSave;
|
||||||
|
private final Screen parent;
|
||||||
|
private TextFieldWidget protocolVersion;
|
||||||
|
|
||||||
|
public ViaConfigScreen(Screen parent) {
|
||||||
|
super(new TranslatableText("gui.viafabric_config.title"));
|
||||||
|
this.parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getProtocolTextColor(boolean valid, boolean supported) {
|
||||||
|
|
||||||
|
if (!valid) {
|
||||||
|
return 0xff0000; // Red
|
||||||
|
} else if (!supported) {
|
||||||
|
return 0xFFA500; // Orange
|
||||||
|
}
|
||||||
|
return 0xE0E0E0; // Default
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void init() {
|
||||||
|
int entries = 0;
|
||||||
|
|
||||||
|
this.addButton(new ButtonWidget(this.width / 2 - 155 + entries % 2 * 160,
|
||||||
|
this.height / 6 + 24 * (entries >> 1),
|
||||||
|
150,
|
||||||
|
20, getClientSideText(), this::onClickClientSide));
|
||||||
|
entries++;
|
||||||
|
|
||||||
|
this.addButton(new ButtonWidget(this.width / 2 - 155 + entries % 2 * 160,
|
||||||
|
this.height / 6 + 24 * (entries >> 1),
|
||||||
|
150,
|
||||||
|
20, getHideViaButtonText(), this::onHideViaButton));
|
||||||
|
entries++;
|
||||||
|
|
||||||
|
protocolVersion = new TextFieldWidget(this.textRenderer,
|
||||||
|
this.width / 2 - 155 + entries % 2 * 160,
|
||||||
|
this.height / 6 + 24 * (entries >> 1),
|
||||||
|
150,
|
||||||
|
20, new TranslatableText("gui.protocol_version_field.name"));
|
||||||
|
entries++;
|
||||||
|
|
||||||
|
protocolVersion.setTextPredicate(ProtocolUtils::isStartOfProtocolText);
|
||||||
|
protocolVersion.setChangedListener(this::onChangeVersionField);
|
||||||
|
int clientSideVersion = ViaFabric.config.getClientSideVersion();
|
||||||
|
protocolVersion.setText(ProtocolUtils.getProtocolName(clientSideVersion));
|
||||||
|
|
||||||
|
this.children.add(protocolVersion);
|
||||||
|
|
||||||
|
//noinspection ConstantConditions
|
||||||
|
if (entries % 2 == 1) {
|
||||||
|
entries++;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.addButton(new ButtonWidget(this.width / 2 - 100, this.height / 6 + 24 * (entries >> 1), 200, 20, ScreenTexts.DONE, (buttonWidget) -> this.client.openScreen(this.parent)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onChangeVersionField(String text) {
|
||||||
|
protocolVersion.setSuggestion(null);
|
||||||
|
int newVersion = ViaFabric.config.getClientSideVersion();
|
||||||
|
|
||||||
|
Integer parsed = ProtocolUtils.parseProtocolId(text);
|
||||||
|
boolean validProtocol;
|
||||||
|
|
||||||
|
if (parsed != null) {
|
||||||
|
newVersion = parsed;
|
||||||
|
validProtocol = true;
|
||||||
|
} else {
|
||||||
|
validProtocol = false;
|
||||||
|
String[] suggestions = ProtocolUtils.getProtocolSuggestions(text);
|
||||||
|
if (suggestions.length == 1) {
|
||||||
|
protocolVersion.setSuggestion(suggestions[0].substring(text.length()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protocolVersion.setEditableColor(
|
||||||
|
getProtocolTextColor(ProtocolUtils.isSupported(newVersion, Via.getAPI().getServerVersion().lowestSupportedVersion()),
|
||||||
|
validProtocol));
|
||||||
|
|
||||||
|
int finalNewVersion = newVersion;
|
||||||
|
if (latestProtocolSave == null) latestProtocolSave = CompletableFuture.completedFuture(null);
|
||||||
|
ViaFabric.config.setClientSideVersion(finalNewVersion);
|
||||||
|
latestProtocolSave = latestProtocolSave.thenRunAsync(ViaFabric.config::saveConfig, ViaFabric.ASYNC_EXECUTOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onClickClientSide(ButtonWidget widget) {
|
||||||
|
if (!ViaFabric.config.isClientSideEnabled()) {
|
||||||
|
MinecraftClient.getInstance().openScreen(new ConfirmScreen(
|
||||||
|
answer -> {
|
||||||
|
if (answer) {
|
||||||
|
ViaFabric.config.setClientSideEnabled(true);
|
||||||
|
ViaFabric.config.setClientSideVersion(-2); // AUTO
|
||||||
|
ViaFabric.config.saveConfig();
|
||||||
|
widget.setMessage(getClientSideText());
|
||||||
|
}
|
||||||
|
MinecraftClient.getInstance().openScreen(this);
|
||||||
|
},
|
||||||
|
new TranslatableText("gui.enable_client_side.question"),
|
||||||
|
new TranslatableText("gui.enable_client_side.warning"),
|
||||||
|
new TranslatableText("gui.enable_client_side.enable"),
|
||||||
|
new TranslatableText("gui.cancel")
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
ViaFabric.config.setClientSideEnabled(false);
|
||||||
|
ViaFabric.config.saveConfig();
|
||||||
|
}
|
||||||
|
widget.setMessage(getClientSideText());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removed() {
|
||||||
|
ViaFabric.config.saveConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClose() {
|
||||||
|
this.client.openScreen(this.parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private TranslatableText getClientSideText() {
|
||||||
|
return ViaFabric.config.isClientSideEnabled() ?
|
||||||
|
new TranslatableText("gui.client_side.disable")
|
||||||
|
: new TranslatableText("gui.client_side.enable");
|
||||||
|
}
|
||||||
|
|
||||||
|
private TranslatableText getHideViaButtonText() {
|
||||||
|
return ViaFabric.config.isHideButton() ?
|
||||||
|
new TranslatableText("gui.hide_via_button.disable") : new TranslatableText("gui.hide_via_button.enable");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onHideViaButton(ButtonWidget widget) {
|
||||||
|
ViaFabric.config.setHideButton(!ViaFabric.config.isHideButton());
|
||||||
|
ViaFabric.config.saveConfig();
|
||||||
|
widget.setMessage(getHideViaButtonText());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) {
|
||||||
|
this.renderBackground(matrices);
|
||||||
|
drawCenteredText(matrices, this.textRenderer, this.title, this.width / 2, 20, 16777215);
|
||||||
|
super.render(matrices, mouseX, mouseY, delta);
|
||||||
|
protocolVersion.render(matrices, mouseX, mouseY, delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
super.tick();
|
||||||
|
protocolVersion.tick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,38 @@
|
|||||||
|
package com.viaversion.fabric.mc116.handler;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.channel.ChannelHandler;
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||||
|
import io.netty.handler.codec.MessageToByteEncoder;
|
||||||
|
import io.netty.handler.codec.MessageToMessageDecoder;
|
||||||
|
import com.viaversion.viaversion.util.PipelineUtil;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
|
||||||
|
public class CommonTransformer {
|
||||||
|
public static final String HANDLER_DECODER_NAME = "via-decoder";
|
||||||
|
public static final String HANDLER_ENCODER_NAME = "via-encoder";
|
||||||
|
|
||||||
|
public static void decompress(ChannelHandlerContext ctx, ByteBuf buf) throws InvocationTargetException {
|
||||||
|
ChannelHandler handler = ctx.pipeline().get("decompress");
|
||||||
|
ByteBuf decompressed = handler instanceof MessageToMessageDecoder
|
||||||
|
? (ByteBuf) PipelineUtil.callDecode((MessageToMessageDecoder<?>) handler, ctx, buf).get(0)
|
||||||
|
: (ByteBuf) PipelineUtil.callDecode((ByteToMessageDecoder) handler, ctx, buf).get(0);
|
||||||
|
try {
|
||||||
|
buf.clear().writeBytes(decompressed);
|
||||||
|
} finally {
|
||||||
|
decompressed.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void compress(ChannelHandlerContext ctx, ByteBuf buf) throws Exception {
|
||||||
|
ByteBuf compressed = ctx.alloc().buffer();
|
||||||
|
try {
|
||||||
|
PipelineUtil.callEncode((MessageToByteEncoder<?>) ctx.pipeline().get("compress"), ctx, buf, compressed);
|
||||||
|
buf.clear().writeBytes(compressed);
|
||||||
|
} finally {
|
||||||
|
compressed.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,85 @@
|
|||||||
|
package com.viaversion.fabric.mc116.handler;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.channel.ChannelHandler;
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import io.netty.handler.codec.MessageToMessageDecoder;
|
||||||
|
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||||
|
import com.viaversion.viaversion.exception.CancelCodecException;
|
||||||
|
import com.viaversion.viaversion.exception.CancelDecoderException;
|
||||||
|
import com.viaversion.viaversion.util.PipelineUtil;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@ChannelHandler.Sharable
|
||||||
|
public class FabricDecodeHandler extends MessageToMessageDecoder<ByteBuf> {
|
||||||
|
private final UserConnection info;
|
||||||
|
private boolean handledCompression;
|
||||||
|
private boolean skipDoubleTransform;
|
||||||
|
|
||||||
|
public FabricDecodeHandler(UserConnection info) {
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserConnection getInfo() {
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://github.com/ViaVersion/ViaVersion/blob/master/velocity/src/main/java/us/myles/ViaVersion/velocity/handlers/VelocityDecodeHandler.java
|
||||||
|
@Override
|
||||||
|
protected void decode(ChannelHandlerContext ctx, ByteBuf bytebuf, List<Object> out) throws Exception {
|
||||||
|
if (skipDoubleTransform) {
|
||||||
|
skipDoubleTransform = false;
|
||||||
|
out.add(bytebuf.retain());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!info.checkIncomingPacket()) throw CancelDecoderException.generate(null);
|
||||||
|
if (!info.shouldTransformPacket()) {
|
||||||
|
out.add(bytebuf.retain());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteBuf transformedBuf = ctx.alloc().buffer().writeBytes(bytebuf);
|
||||||
|
try {
|
||||||
|
boolean needsCompress = handleCompressionOrder(ctx, transformedBuf);
|
||||||
|
|
||||||
|
info.transformIncoming(transformedBuf, CancelDecoderException::generate);
|
||||||
|
|
||||||
|
if (needsCompress) {
|
||||||
|
CommonTransformer.compress(ctx, transformedBuf);
|
||||||
|
skipDoubleTransform = true;
|
||||||
|
}
|
||||||
|
out.add(transformedBuf.retain());
|
||||||
|
} finally {
|
||||||
|
transformedBuf.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean handleCompressionOrder(ChannelHandlerContext ctx, ByteBuf buf) throws InvocationTargetException {
|
||||||
|
if (handledCompression) return false;
|
||||||
|
|
||||||
|
int decoderIndex = ctx.pipeline().names().indexOf("decompress");
|
||||||
|
if (decoderIndex == -1) return false;
|
||||||
|
handledCompression = true;
|
||||||
|
if (decoderIndex > ctx.pipeline().names().indexOf("via-decoder")) {
|
||||||
|
// Need to decompress this packet due to bad order
|
||||||
|
CommonTransformer.decompress(ctx, buf);
|
||||||
|
ChannelHandler encoder = ctx.pipeline().get("via-encoder");
|
||||||
|
ChannelHandler decoder = ctx.pipeline().get("via-decoder");
|
||||||
|
ctx.pipeline().remove(encoder);
|
||||||
|
ctx.pipeline().remove(decoder);
|
||||||
|
ctx.pipeline().addAfter("compress", "via-encoder", encoder);
|
||||||
|
ctx.pipeline().addAfter("decompress", "via-decoder", decoder);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||||
|
if (PipelineUtil.containsCause(cause, CancelCodecException.class)) return;
|
||||||
|
super.exceptionCaught(ctx, cause);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,72 @@
|
|||||||
|
package com.viaversion.fabric.mc116.handler;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.channel.ChannelHandler;
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import io.netty.handler.codec.MessageToMessageEncoder;
|
||||||
|
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||||
|
import com.viaversion.viaversion.exception.CancelCodecException;
|
||||||
|
import com.viaversion.viaversion.exception.CancelEncoderException;
|
||||||
|
import com.viaversion.viaversion.util.PipelineUtil;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@ChannelHandler.Sharable
|
||||||
|
public class FabricEncodeHandler extends MessageToMessageEncoder<ByteBuf> {
|
||||||
|
private final UserConnection info;
|
||||||
|
private boolean handledCompression;
|
||||||
|
|
||||||
|
public FabricEncodeHandler(UserConnection info) {
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void encode(final ChannelHandlerContext ctx, ByteBuf bytebuf, List<Object> out) throws Exception {
|
||||||
|
if (!info.checkOutgoingPacket()) throw CancelEncoderException.generate(null);
|
||||||
|
if (!info.shouldTransformPacket()) {
|
||||||
|
out.add(bytebuf.retain());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteBuf transformedBuf = ctx.alloc().buffer().writeBytes(bytebuf);
|
||||||
|
try {
|
||||||
|
boolean needsCompress = handleCompressionOrder(ctx, transformedBuf);
|
||||||
|
|
||||||
|
info.transformOutgoing(transformedBuf, CancelEncoderException::generate);
|
||||||
|
|
||||||
|
if (needsCompress) {
|
||||||
|
CommonTransformer.compress(ctx, transformedBuf);
|
||||||
|
}
|
||||||
|
out.add(transformedBuf.retain());
|
||||||
|
} finally {
|
||||||
|
transformedBuf.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean handleCompressionOrder(ChannelHandlerContext ctx, ByteBuf buf) throws InvocationTargetException {
|
||||||
|
if (handledCompression) return false;
|
||||||
|
|
||||||
|
int encoderIndex = ctx.pipeline().names().indexOf("compress");
|
||||||
|
if (encoderIndex == -1) return false;
|
||||||
|
handledCompression = true;
|
||||||
|
if (encoderIndex > ctx.pipeline().names().indexOf("via-encoder")) {
|
||||||
|
// Need to decompress this packet due to bad order
|
||||||
|
CommonTransformer.decompress(ctx, buf);
|
||||||
|
ChannelHandler encoder = ctx.pipeline().get("via-encoder");
|
||||||
|
ChannelHandler decoder = ctx.pipeline().get("via-decoder");
|
||||||
|
ctx.pipeline().remove(encoder);
|
||||||
|
ctx.pipeline().remove(decoder);
|
||||||
|
ctx.pipeline().addAfter("compress", "via-encoder", encoder);
|
||||||
|
ctx.pipeline().addAfter("decompress", "via-decoder", decoder);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||||
|
if (PipelineUtil.containsCause(cause, CancelCodecException.class)) return;
|
||||||
|
super.exceptionCaught(ctx, cause);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,79 @@
|
|||||||
|
package com.viaversion.fabric.mc116.handler.clientside;
|
||||||
|
|
||||||
|
import com.viaversion.fabric.mc116.ViaFabric;
|
||||||
|
import com.viaversion.fabric.mc116.service.ProtocolAutoDetector;
|
||||||
|
import com.viaversion.viaversion.util.Pair;
|
||||||
|
import io.netty.channel.ChannelDuplexHandler;
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import io.netty.channel.ChannelPromise;
|
||||||
|
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.util.ArrayDeque;
|
||||||
|
import java.util.Queue;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
public class ProtocolDetectionHandler extends ChannelDuplexHandler {
|
||||||
|
private final Queue<Pair<Object, ChannelPromise>> queuedMessages = new ArrayDeque<>();
|
||||||
|
private boolean hold = true;
|
||||||
|
private boolean pendentFlush;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||||
|
super.channelActive(ctx);
|
||||||
|
if (ctx.channel().remoteAddress() instanceof InetSocketAddress) {
|
||||||
|
ScheduledFuture<?> timeoutRun = ctx.executor().schedule(() -> {
|
||||||
|
ViaFabric.JLOGGER.warning("Timeout for protocol auto-detection in "
|
||||||
|
+ ctx.channel().remoteAddress() + " server");
|
||||||
|
hold = false;
|
||||||
|
drainQueue(ctx);
|
||||||
|
ctx.pipeline().remove(this);
|
||||||
|
}, 10, TimeUnit.SECONDS);
|
||||||
|
ProtocolAutoDetector.detectVersion(((InetSocketAddress) ctx.channel().remoteAddress()))
|
||||||
|
.whenComplete((obj, ex) -> {
|
||||||
|
ctx.pipeline().remove(this);
|
||||||
|
timeoutRun.cancel(false);
|
||||||
|
});
|
||||||
|
// Let's cache it before we need it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
|
||||||
|
if (!hold) {
|
||||||
|
drainQueue(ctx);
|
||||||
|
super.write(ctx, msg, promise);
|
||||||
|
} else {
|
||||||
|
queuedMessages.add(new Pair<>(msg, promise));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void flush(ChannelHandlerContext ctx) throws Exception {
|
||||||
|
if (!hold) {
|
||||||
|
drainQueue(ctx);
|
||||||
|
super.flush(ctx);
|
||||||
|
} else {
|
||||||
|
pendentFlush = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
||||||
|
drainQueue(ctx);
|
||||||
|
super.channelInactive(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void drainQueue(ChannelHandlerContext ctx) {
|
||||||
|
queuedMessages.forEach(it -> ctx.write(it.getKey(), it.getValue()));
|
||||||
|
queuedMessages.clear();
|
||||||
|
if (pendentFlush) ctx.flush();
|
||||||
|
pendentFlush = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
|
||||||
|
drainQueue(ctx);
|
||||||
|
super.handlerRemoved(ctx);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
package com.viaversion.fabric.mc116.mixin.address.client;
|
||||||
|
|
||||||
|
import com.viaversion.fabric.mc116.ViaFabricAddress;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
|
||||||
|
@Mixin(targets = "net/minecraft/client/gui/screen/ConnectScreen$1", priority = 2000)
|
||||||
|
public class MixinConnectScreenThread {
|
||||||
|
@Redirect(method = "run()V", at = @At(value = "INVOKE",
|
||||||
|
target = "Ljava/net/InetAddress;getByName(Ljava/lang/String;)Ljava/net/InetAddress;"))
|
||||||
|
private InetAddress resolveViaFabricAddr(String address) throws UnknownHostException {
|
||||||
|
ViaFabricAddress viaAddr = new ViaFabricAddress().parse(address);
|
||||||
|
if (viaAddr.viaSuffix == null) {
|
||||||
|
return InetAddress.getByName(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
InetAddress resolved = InetAddress.getByName(viaAddr.realAddress);
|
||||||
|
return InetAddress.getByAddress(resolved.getHostName() + "." + viaAddr.viaSuffix, resolved.getAddress());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package com.viaversion.fabric.mc116.mixin.address.client;
|
||||||
|
|
||||||
|
import com.viaversion.fabric.mc116.ViaFabricAddress;
|
||||||
|
import com.mojang.datafixers.util.Pair;
|
||||||
|
import net.minecraft.network.ServerAddress;
|
||||||
|
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;
|
||||||
|
|
||||||
|
@Mixin(ServerAddress.class)
|
||||||
|
public abstract class MixinServerAddress {
|
||||||
|
@Shadow
|
||||||
|
private static Pair<String, Integer> resolveServer(String address) {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Redirect(method = "parse", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/ServerAddress;resolveServer(Ljava/lang/String;)Lcom/mojang/datafixers/util/Pair;"))
|
||||||
|
private static Pair<String, Integer> modifySrvAddr(String address) {
|
||||||
|
ViaFabricAddress viaAddr = new ViaFabricAddress().parse(address);
|
||||||
|
if (viaAddr.viaSuffix == null) {
|
||||||
|
return resolveServer(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolveServer(viaAddr.realAddress).mapFirst(it -> it.replaceAll("\\.$", "") + "." + viaAddr.viaSuffix);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
package com.viaversion.fabric.mc116.mixin.address.client;
|
||||||
|
|
||||||
|
import com.viaversion.fabric.mc116.ViaFabricAddress;
|
||||||
|
import net.minecraft.client.network.MultiplayerServerListPinger;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
|
||||||
|
@Mixin(MultiplayerServerListPinger.class)
|
||||||
|
public class MixinServerPinger {
|
||||||
|
@Redirect(method = "add", at = @At(value = "INVOKE",
|
||||||
|
target = "Ljava/net/InetAddress;getByName(Ljava/lang/String;)Ljava/net/InetAddress;"))
|
||||||
|
private InetAddress resolveViaFabricAddr(String address) throws UnknownHostException {
|
||||||
|
ViaFabricAddress viaAddr = new ViaFabricAddress().parse(address);
|
||||||
|
if (viaAddr.viaSuffix == null) {
|
||||||
|
return InetAddress.getByName(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
InetAddress resolved = InetAddress.getByName(viaAddr.realAddress);
|
||||||
|
return InetAddress.getByAddress(resolved.getHostName() + "." + viaAddr.viaSuffix, resolved.getAddress());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package com.viaversion.fabric.mc116.mixin.debug.client;
|
||||||
|
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
import net.minecraft.network.ClientConnection;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||||
|
|
||||||
|
@Mixin(ClientConnection.class)
|
||||||
|
public interface MixinClientConnectionAccessor {
|
||||||
|
@Accessor
|
||||||
|
Channel getChannel();
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
package com.viaversion.fabric.mc116.mixin.debug.client;
|
||||||
|
|
||||||
|
import com.viaversion.fabric.mc116.handler.CommonTransformer;
|
||||||
|
import com.viaversion.fabric.mc116.handler.FabricDecodeHandler;
|
||||||
|
import com.viaversion.viaversion.api.connection.ProtocolInfo;
|
||||||
|
import io.netty.channel.ChannelHandler;
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.client.gui.hud.DebugHud;
|
||||||
|
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;
|
||||||
|
import com.viaversion.viaversion.api.Via;
|
||||||
|
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Mixin(DebugHud.class)
|
||||||
|
public class MixinDebugHud {
|
||||||
|
@Inject(at = @At("RETURN"), method = "getLeftText")
|
||||||
|
protected void getLeftText(CallbackInfoReturnable<List<String>> info) {
|
||||||
|
String line = "[ViaFabric] I: " + Via.getManager().getConnectionManager().getConnections().size() + " (F: "
|
||||||
|
+ Via.getManager().getConnectionManager().getConnectedClients().size() + ")";
|
||||||
|
@SuppressWarnings("ConstantConditions") ChannelHandler viaDecoder = ((MixinClientConnectionAccessor) MinecraftClient.getInstance().getNetworkHandler()
|
||||||
|
.getConnection()).getChannel().pipeline().get(CommonTransformer.HANDLER_DECODER_NAME);
|
||||||
|
if (viaDecoder instanceof FabricDecodeHandler) {
|
||||||
|
ProtocolInfo protocol = ((FabricDecodeHandler) viaDecoder).getInfo().getProtocolInfo();
|
||||||
|
if (protocol != null) {
|
||||||
|
ProtocolVersion serverVer = ProtocolVersion.getProtocol(protocol.getServerProtocolVersion());
|
||||||
|
ProtocolVersion clientVer = ProtocolVersion.getProtocol(protocol.getProtocolVersion());
|
||||||
|
line += " / C: " + clientVer.getName() + " (" + clientVer.getVersion() + ") S: "
|
||||||
|
+ serverVer.getName() + " (" + serverVer.getVersion() + ") A: " + protocol.getUser().isActive();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
info.getReturnValue().add(line);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
package com.viaversion.fabric.mc116.mixin.gui.client;
|
||||||
|
|
||||||
|
import com.viaversion.fabric.mc116.ViaFabric;
|
||||||
|
import com.viaversion.fabric.mc116.gui.ViaConfigScreen;
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.client.gui.screen.Screen;
|
||||||
|
import net.minecraft.client.gui.screen.multiplayer.MultiplayerScreen;
|
||||||
|
import net.minecraft.client.gui.widget.ButtonWidget;
|
||||||
|
import net.minecraft.client.gui.widget.TexturedButtonWidget;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import net.minecraft.text.TranslatableText;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
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;
|
||||||
|
|
||||||
|
@Mixin(MultiplayerScreen.class)
|
||||||
|
public abstract class MixinMultiplayerScreen extends Screen {
|
||||||
|
protected MixinMultiplayerScreen(Text title, UnsupportedOperationException e) {
|
||||||
|
super(title);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "init", at = @At("TAIL"))
|
||||||
|
private void onInit(CallbackInfo ci) {
|
||||||
|
ButtonWidget enableClientSideViaVersion = new TexturedButtonWidget(this.width / 2 + 113, 10,
|
||||||
|
40, 20, // Size
|
||||||
|
0, 0, // Start pos of texture
|
||||||
|
20, // v Hover offset
|
||||||
|
new Identifier("viafabric:textures/gui/widgets.png"),
|
||||||
|
256, 256, // Texture size
|
||||||
|
it -> MinecraftClient.getInstance().openScreen(new ViaConfigScreen(this)),
|
||||||
|
new TranslatableText("gui.via_button"));
|
||||||
|
if (ViaFabric.config.isHideButton()) enableClientSideViaVersion.visible = false;
|
||||||
|
addButton(enableClientSideViaVersion);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
package com.viaversion.fabric.mc116.mixin.pipeline;
|
||||||
|
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
import net.minecraft.network.ClientConnection;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
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;
|
||||||
|
|
||||||
|
|
||||||
|
@Mixin(ClientConnection.class)
|
||||||
|
public class MixinClientConnection {
|
||||||
|
@Shadow
|
||||||
|
private Channel channel;
|
||||||
|
|
||||||
|
@Redirect(
|
||||||
|
method = "exceptionCaught",
|
||||||
|
remap = false,
|
||||||
|
at = @At(
|
||||||
|
value = "INVOKE",
|
||||||
|
target = "Lorg/apache/logging/log4j/Logger;debug(Ljava/lang/String;Ljava/lang/Throwable;)V"
|
||||||
|
))
|
||||||
|
private void redirectDebug(Logger logger, String message, Throwable t) {
|
||||||
|
if ("Failed to sent packet".equals(message)) {
|
||||||
|
logger.info(message, t);
|
||||||
|
} else {
|
||||||
|
logger.debug(message, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
package com.viaversion.fabric.mc116.mixin.pipeline;
|
||||||
|
|
||||||
|
import com.viaversion.fabric.mc116.handler.CommonTransformer;
|
||||||
|
import com.viaversion.fabric.mc116.handler.FabricDecodeHandler;
|
||||||
|
import com.viaversion.fabric.mc116.handler.FabricEncodeHandler;
|
||||||
|
import com.viaversion.viaversion.connection.UserConnectionImpl;
|
||||||
|
import com.viaversion.viaversion.protocol.ProtocolPipelineImpl;
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
import io.netty.channel.socket.SocketChannel;
|
||||||
|
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 com.viaversion.viaversion.api.connection.UserConnection;
|
||||||
|
|
||||||
|
@Mixin(targets = "net.minecraft.server.ServerNetworkIo$1")
|
||||||
|
public class MixinServerNetworkIoChInit {
|
||||||
|
@Inject(method = "initChannel", at = @At(value = "TAIL"), remap = false)
|
||||||
|
private void onInitChannel(Channel channel, CallbackInfo ci) {
|
||||||
|
if (channel instanceof SocketChannel) {
|
||||||
|
UserConnection user = new UserConnectionImpl(channel);
|
||||||
|
new ProtocolPipelineImpl(user);
|
||||||
|
|
||||||
|
channel.pipeline().addBefore("encoder", CommonTransformer.HANDLER_ENCODER_NAME, new FabricEncodeHandler(user));
|
||||||
|
channel.pipeline().addBefore("decoder", CommonTransformer.HANDLER_DECODER_NAME, new FabricDecodeHandler(user));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
package com.viaversion.fabric.mc116.mixin.pipeline.client;
|
||||||
|
|
||||||
|
import com.viaversion.fabric.mc116.ViaFabric;
|
||||||
|
import com.viaversion.fabric.mc116.handler.CommonTransformer;
|
||||||
|
import com.viaversion.fabric.mc116.handler.FabricDecodeHandler;
|
||||||
|
import com.viaversion.fabric.mc116.handler.FabricEncodeHandler;
|
||||||
|
import com.viaversion.fabric.mc116.handler.clientside.ProtocolDetectionHandler;
|
||||||
|
import com.viaversion.fabric.mc116.protocol.ViaFabricHostnameProtocol;
|
||||||
|
import com.viaversion.viaversion.connection.UserConnectionImpl;
|
||||||
|
import com.viaversion.viaversion.protocol.ProtocolPipelineImpl;
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
import io.netty.channel.socket.SocketChannel;
|
||||||
|
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 com.viaversion.viaversion.api.connection.UserConnection;
|
||||||
|
|
||||||
|
@Mixin(targets = "net.minecraft.network.ClientConnection$1")
|
||||||
|
public class MixinClientConnectionChInit {
|
||||||
|
@Inject(method = "initChannel", at = @At(value = "TAIL"), remap = false)
|
||||||
|
private void onInitChannel(Channel channel, CallbackInfo ci) {
|
||||||
|
if (channel instanceof SocketChannel) {
|
||||||
|
UserConnection user = new UserConnectionImpl(channel, true);
|
||||||
|
new ProtocolPipelineImpl(user).add(ViaFabricHostnameProtocol.INSTANCE);
|
||||||
|
|
||||||
|
channel.pipeline()
|
||||||
|
.addBefore("encoder", CommonTransformer.HANDLER_ENCODER_NAME, new FabricEncodeHandler(user))
|
||||||
|
.addBefore("decoder", CommonTransformer.HANDLER_DECODER_NAME, new FabricDecodeHandler(user));
|
||||||
|
if (ViaFabric.config.isClientSideEnabled()) {
|
||||||
|
channel.pipeline().addAfter(CommonTransformer.HANDLER_ENCODER_NAME, "via-autoprotocol", new ProtocolDetectionHandler());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,61 @@
|
|||||||
|
package com.viaversion.fabric.mc116.platform;
|
||||||
|
|
||||||
|
import com.viaversion.fabric.mc116.handler.CommonTransformer;
|
||||||
|
import net.fabricmc.api.EnvType;
|
||||||
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
|
import net.minecraft.SharedConstants;
|
||||||
|
import com.viaversion.viaversion.api.platform.ViaInjector;
|
||||||
|
import com.viaversion.viaversion.util.GsonUtil;
|
||||||
|
import com.viaversion.viaversion.libs.gson.JsonObject;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public class VRInjector implements ViaInjector {
|
||||||
|
@Override
|
||||||
|
public void inject() {
|
||||||
|
// *looks at Mixins*
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void uninject() {
|
||||||
|
// not possible *plays sad violin*
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getServerProtocolVersion() {
|
||||||
|
return SharedConstants.getGameVersion().getProtocolVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getEncoderName() {
|
||||||
|
return CommonTransformer.HANDLER_ENCODER_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDecoderName() {
|
||||||
|
return CommonTransformer.HANDLER_DECODER_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JsonObject getDump() {
|
||||||
|
JsonObject obj = new JsonObject();
|
||||||
|
try {
|
||||||
|
obj.add("serverNetworkIOChInit", GsonUtil.getGson().toJsonTree(
|
||||||
|
Arrays.stream(Class.forName("net.minecraft.class_3242$1").getDeclaredMethods())
|
||||||
|
.map(Method::toString)
|
||||||
|
.toArray(String[]::new)));
|
||||||
|
} catch (ClassNotFoundException ignored) {
|
||||||
|
}
|
||||||
|
if (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) {
|
||||||
|
try {
|
||||||
|
obj.add("clientConnectionChInit", GsonUtil.getGson().toJsonTree(
|
||||||
|
Arrays.stream(Class.forName("net.minecraft.class_2535$1").getDeclaredMethods())
|
||||||
|
.map(Method::toString)
|
||||||
|
.toArray(String[]::new)));
|
||||||
|
} catch (ClassNotFoundException ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
package com.viaversion.fabric.mc116.platform;
|
||||||
|
|
||||||
|
import com.viaversion.fabric.mc116.providers.VRHandItemProvider;
|
||||||
|
import com.viaversion.fabric.mc116.providers.VRVersionProvider;
|
||||||
|
import net.fabricmc.api.EnvType;
|
||||||
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
|
import com.viaversion.viaversion.api.Via;
|
||||||
|
import com.viaversion.viaversion.api.platform.ViaPlatformLoader;
|
||||||
|
import com.viaversion.viaversion.bungee.providers.BungeeMovementTransmitter;
|
||||||
|
import com.viaversion.viaversion.api.protocol.version.VersionProvider;
|
||||||
|
import com.viaversion.viaversion.protocols.protocol1_9to1_8.providers.HandItemProvider;
|
||||||
|
import com.viaversion.viaversion.protocols.protocol1_9to1_8.providers.MovementTransmitterProvider;
|
||||||
|
|
||||||
|
public class VRLoader implements ViaPlatformLoader {
|
||||||
|
@Override
|
||||||
|
public void load() {
|
||||||
|
Via.getManager().getProviders().use(MovementTransmitterProvider.class, new BungeeMovementTransmitter());
|
||||||
|
Via.getManager().getProviders().use(VersionProvider.class, new VRVersionProvider());
|
||||||
|
|
||||||
|
if (Via.getPlatform().getConf().isItemCache()) {
|
||||||
|
VRHandItemProvider handProvider = new VRHandItemProvider();
|
||||||
|
if (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) {
|
||||||
|
handProvider.registerClientTick();
|
||||||
|
}
|
||||||
|
handProvider.registerServerTick();
|
||||||
|
Via.getManager().getProviders().use(HandItemProvider.class, handProvider);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unload() {
|
||||||
|
// Nothing to do
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,273 @@
|
|||||||
|
package com.viaversion.fabric.mc116.platform;
|
||||||
|
|
||||||
|
import com.viaversion.fabric.mc116.ViaFabric;
|
||||||
|
import com.viaversion.fabric.mc116.commands.NMSCommandSender;
|
||||||
|
import com.viaversion.fabric.mc116.commands.UserCommandSender;
|
||||||
|
import com.viaversion.fabric.mc116.util.FutureTaskId;
|
||||||
|
import com.viaversion.fabric.mc116.util.JLoggerToLog4j;
|
||||||
|
import com.viaversion.viaversion.api.configuration.ViaVersionConfig;
|
||||||
|
import com.viaversion.viaversion.api.platform.PlatformTask;
|
||||||
|
import io.netty.util.concurrent.Future;
|
||||||
|
import io.netty.util.concurrent.GenericFutureListener;
|
||||||
|
import net.fabricmc.api.EnvType;
|
||||||
|
import net.fabricmc.api.Environment;
|
||||||
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
|
import net.fabricmc.loader.api.ModContainer;
|
||||||
|
import net.fabricmc.loader.api.Version;
|
||||||
|
import net.fabricmc.loader.api.metadata.ModMetadata;
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import com.viaversion.viaversion.api.Via;
|
||||||
|
import com.viaversion.viaversion.api.ViaAPI;
|
||||||
|
import com.viaversion.viaversion.api.command.ViaCommandSender;
|
||||||
|
import com.viaversion.viaversion.api.configuration.ConfigurationProvider;
|
||||||
|
import com.viaversion.viaversion.api.platform.ViaPlatform;
|
||||||
|
import com.viaversion.viaversion.dump.PluginInfo;
|
||||||
|
import com.viaversion.viaversion.util.GsonUtil;
|
||||||
|
import com.viaversion.viaversion.libs.gson.JsonObject;
|
||||||
|
import com.viaversion.viaversion.libs.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||||
|
import com.viaversion.viaversion.libs.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.CancellationException;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class VRPlatform implements ViaPlatform<UUID> {
|
||||||
|
private final Logger logger = new JLoggerToLog4j(LogManager.getLogger("ViaVersion"));
|
||||||
|
private final VRViaConfig config;
|
||||||
|
private final File dataFolder;
|
||||||
|
private final ViaAPI<UUID> api;
|
||||||
|
|
||||||
|
public VRPlatform() {
|
||||||
|
Path configDir = FabricLoader.getInstance().getConfigDirectory().toPath().resolve("ViaFabric");
|
||||||
|
config = new VRViaConfig(configDir.resolve("viaversion.yml").toFile());
|
||||||
|
dataFolder = configDir.toFile();
|
||||||
|
api = new VRViaAPI();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MinecraftServer getServer() {
|
||||||
|
if (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) {
|
||||||
|
return getIntegratedServer();
|
||||||
|
}
|
||||||
|
return (MinecraftServer) FabricLoader.getInstance().getGameInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Environment(EnvType.CLIENT)
|
||||||
|
private static MinecraftServer getIntegratedServer() {
|
||||||
|
return MinecraftClient.getInstance().getServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String legacyToJson(String legacy) {
|
||||||
|
return GsonComponentSerializer.gson().serialize(LegacyComponentSerializer.legacySection().deserialize(legacy));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Logger getLogger() {
|
||||||
|
return logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPlatformName() {
|
||||||
|
return "ViaFabric";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPlatformVersion() {
|
||||||
|
return ViaFabric.getVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPluginVersion() {
|
||||||
|
return FabricLoader.getInstance().getModContainer("viaversion").map(ModContainer::getMetadata)
|
||||||
|
.map(ModMetadata::getVersion).map(Version::getFriendlyString).orElse("UNKNOWN");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FutureTaskId runAsync(Runnable runnable) {
|
||||||
|
return new FutureTaskId(CompletableFuture
|
||||||
|
.runAsync(runnable, ViaFabric.ASYNC_EXECUTOR)
|
||||||
|
.exceptionally(throwable -> {
|
||||||
|
if (!(throwable instanceof CancellationException)) {
|
||||||
|
throwable.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FutureTaskId runSync(Runnable runnable) {
|
||||||
|
if (getServer() != null) {
|
||||||
|
return runServerSync(runnable);
|
||||||
|
} else {
|
||||||
|
return runEventLoop(runnable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private FutureTaskId runServerSync(Runnable runnable) {
|
||||||
|
// Kick task needs to be on main thread, it does already have error logger
|
||||||
|
return new FutureTaskId(CompletableFuture.runAsync(runnable, getServer()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private FutureTaskId runEventLoop(Runnable runnable) {
|
||||||
|
return new FutureTaskId(
|
||||||
|
ViaFabric.EVENT_LOOP
|
||||||
|
.submit(runnable)
|
||||||
|
.addListener(errorLogger())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PlatformTask runSync(Runnable runnable, Long ticks) {
|
||||||
|
// ViaVersion seems to not need to run delayed tasks on main thread
|
||||||
|
return new FutureTaskId(
|
||||||
|
ViaFabric.EVENT_LOOP
|
||||||
|
.schedule(() -> runSync(runnable), ticks * 50, TimeUnit.MILLISECONDS)
|
||||||
|
.addListener(errorLogger())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PlatformTask runRepeatingSync(Runnable runnable, Long ticks) {
|
||||||
|
// ViaVersion seems to not need to run repeating tasks on main thread
|
||||||
|
return new FutureTaskId(
|
||||||
|
ViaFabric.EVENT_LOOP
|
||||||
|
.scheduleAtFixedRate(() -> runSync(runnable), 0, ticks * 50, TimeUnit.MILLISECONDS)
|
||||||
|
.addListener(errorLogger())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T extends Future<?>> GenericFutureListener<T> errorLogger() {
|
||||||
|
return future -> {
|
||||||
|
if (!future.isCancelled() && future.cause() != null) {
|
||||||
|
future.cause().printStackTrace();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ViaCommandSender[] getOnlinePlayers() {
|
||||||
|
MinecraftServer server = getServer();
|
||||||
|
if (server != null && server.isOnThread()) {
|
||||||
|
return getServerPlayers();
|
||||||
|
}
|
||||||
|
return Via.getManager().getConnectionManager().getConnectedClients().values().stream()
|
||||||
|
.map(UserCommandSender::new)
|
||||||
|
.toArray(ViaCommandSender[]::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ViaCommandSender[] getServerPlayers() {
|
||||||
|
return getServer().getPlayerManager().getPlayerList().stream()
|
||||||
|
.map(Entity::getCommandSource)
|
||||||
|
.map(NMSCommandSender::new)
|
||||||
|
.toArray(ViaCommandSender[]::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendMessage(UUID uuid, String s) {
|
||||||
|
sendMessageServer(uuid, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendMessageServer(UUID uuid, String s) {
|
||||||
|
MinecraftServer server = getServer();
|
||||||
|
if (server == null) return;
|
||||||
|
runServerSync(() -> {
|
||||||
|
ServerPlayerEntity player = server.getPlayerManager().getPlayer(uuid);
|
||||||
|
if (player == null) return;
|
||||||
|
player.sendMessage(Text.Serializer.fromJson(
|
||||||
|
legacyToJson(s)
|
||||||
|
), false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean kickPlayer(UUID uuid, String s) {
|
||||||
|
return kickServer(uuid, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean kickServer(UUID uuid, String s) {
|
||||||
|
MinecraftServer server = getServer();
|
||||||
|
if (server == null) return false;
|
||||||
|
Supplier<Boolean> kickTask = () -> {
|
||||||
|
ServerPlayerEntity player = server.getPlayerManager().getPlayer(uuid);
|
||||||
|
if (player == null) return false;
|
||||||
|
player.networkHandler.disconnect(Text.Serializer.fromJson(legacyToJson(s)));
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
if (server.isOnThread()) {
|
||||||
|
return kickTask.get();
|
||||||
|
} else {
|
||||||
|
ViaFabric.JLOGGER.log(Level.WARNING, "Weird!? Player kicking was called off-thread", new Throwable());
|
||||||
|
runServerSync(kickTask::get);
|
||||||
|
}
|
||||||
|
return false; // Can't know if it worked
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPluginEnabled() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ViaAPI<UUID> getApi() {
|
||||||
|
return api;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ViaVersionConfig getConf() {
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConfigurationProvider getConfigurationProvider() {
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public File getDataFolder() {
|
||||||
|
return dataFolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReload() {
|
||||||
|
// Nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JsonObject getDump() {
|
||||||
|
JsonObject platformSpecific = new JsonObject();
|
||||||
|
List<PluginInfo> mods = new ArrayList<>();
|
||||||
|
for (ModContainer mod : FabricLoader.getInstance().getAllMods()) {
|
||||||
|
mods.add(new PluginInfo(true,
|
||||||
|
mod.getMetadata().getId() + " (" + mod.getMetadata().getName() + ")",
|
||||||
|
mod.getMetadata().getVersion().getFriendlyString(),
|
||||||
|
null,
|
||||||
|
mod.getMetadata().getAuthors().stream()
|
||||||
|
.map(info -> info.getName()
|
||||||
|
+ (info.getContact().asMap().isEmpty() ? "" : " " + info.getContact().asMap()))
|
||||||
|
.collect(Collectors.toList())
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
platformSpecific.add("mods", GsonUtil.getGson().toJsonTree(mods));
|
||||||
|
return platformSpecific;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isOldClientsAllowed() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
package com.viaversion.fabric.mc116.platform;
|
||||||
|
|
||||||
|
import com.viaversion.viaversion.ViaAPIBase;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class VRViaAPI extends ViaAPIBase<UUID> {
|
||||||
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
package com.viaversion.fabric.mc116.platform;
|
||||||
|
|
||||||
|
import com.viaversion.viaversion.configuration.AbstractViaConfig;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class VRViaConfig extends AbstractViaConfig {
|
||||||
|
// Based on Sponge ViaVersion
|
||||||
|
private static List<String> UNSUPPORTED = Arrays.asList("anti-xray-patch", "bungee-ping-interval",
|
||||||
|
"bungee-ping-save", "bungee-servers", "quick-move-action-fix", "nms-player-ticking",
|
||||||
|
"velocity-ping-interval", "velocity-ping-save", "velocity-servers",
|
||||||
|
"blockconnection-method", "change-1_9-hitbox", "change-1_14-hitbox");
|
||||||
|
|
||||||
|
public VRViaConfig(File configFile) {
|
||||||
|
super(configFile);
|
||||||
|
// Load config
|
||||||
|
reloadConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public URL getDefaultConfigURL() {
|
||||||
|
return getClass().getClassLoader().getResource("assets/viaversion/config.yml");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void handleConfig(Map<String, Object> config) {
|
||||||
|
// Nothing Currently
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getUnsupportedOptions() {
|
||||||
|
return UNSUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAntiXRay() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isNMSPlayerTicking() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean is1_12QuickMoveActionFix() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getBlockConnectionMethod() {
|
||||||
|
return "packet";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean is1_9HitboxFix() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean is1_14HitboxFix() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
package com.viaversion.fabric.mc116.protocol;
|
||||||
|
|
||||||
|
import com.viaversion.fabric.mc116.ViaFabricAddress;
|
||||||
|
import com.viaversion.viaversion.api.protocol.AbstractSimpleProtocol;
|
||||||
|
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
|
||||||
|
import com.viaversion.viaversion.api.protocol.remapper.PacketRemapper;
|
||||||
|
import com.viaversion.viaversion.api.protocol.remapper.ValueTransformer;
|
||||||
|
import com.viaversion.viaversion.api.type.Type;
|
||||||
|
import com.viaversion.viaversion.api.protocol.packet.State;
|
||||||
|
|
||||||
|
public class ViaFabricHostnameProtocol extends AbstractSimpleProtocol {
|
||||||
|
public static final ViaFabricHostnameProtocol INSTANCE = new ViaFabricHostnameProtocol();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void registerPackets() {
|
||||||
|
registerServerbound(State.HANDSHAKE, 0, 0, new PacketRemapper() {
|
||||||
|
@Override
|
||||||
|
public void registerMap() {
|
||||||
|
map(Type.VAR_INT); // Protocol version
|
||||||
|
map(Type.STRING, new ValueTransformer<String, String>(Type.STRING) {
|
||||||
|
@Override
|
||||||
|
public String transform(PacketWrapper packetWrapper, String s) {
|
||||||
|
return new ViaFabricAddress().parse(s).realAddress;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isBaseProtocol() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,110 @@
|
|||||||
|
package com.viaversion.fabric.mc116.providers;
|
||||||
|
|
||||||
|
import com.viaversion.fabric.mc116.ViaFabric;
|
||||||
|
import net.fabricmc.api.EnvType;
|
||||||
|
import net.fabricmc.api.Environment;
|
||||||
|
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
|
||||||
|
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
|
||||||
|
import net.fabricmc.fabric.api.event.world.WorldTickCallback;
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.client.network.ClientPlayerEntity;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.util.registry.Registry;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||||
|
import com.viaversion.viaversion.api.minecraft.item.Item;
|
||||||
|
import com.viaversion.viaversion.protocols.protocol1_9to1_8.providers.HandItemProvider;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
public class VRHandItemProvider extends HandItemProvider {
|
||||||
|
public Item clientItem = null;
|
||||||
|
public Map<UUID, Item> serverPlayers = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Item getHandItem(UserConnection info) {
|
||||||
|
Item serverItem;
|
||||||
|
if (info.isClientSide()) {
|
||||||
|
return getClientItem();
|
||||||
|
} else if ((serverItem = serverPlayers.get(info.getProtocolInfo().getUuid())) != null) {
|
||||||
|
return new Item(serverItem);
|
||||||
|
}
|
||||||
|
return super.getHandItem(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Item getClientItem() {
|
||||||
|
if (clientItem == null) {
|
||||||
|
return new Item(0, (byte) 0, (short) 0, null);
|
||||||
|
}
|
||||||
|
return new Item(clientItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Environment(EnvType.CLIENT)
|
||||||
|
public void registerClientTick() {
|
||||||
|
try {
|
||||||
|
ClientTickEvents.END_WORLD_TICK.register(clientWorld -> tickClient());
|
||||||
|
} catch (NoClassDefFoundError ignored) {
|
||||||
|
try {
|
||||||
|
WorldTickCallback.EVENT.register(world -> {
|
||||||
|
if (world.isClient) {
|
||||||
|
tickClient();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (NoClassDefFoundError ignored2) {
|
||||||
|
ViaFabric.JLOGGER.info("Fabric Lifecycle V0/V1 isn't installed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerServerTick() {
|
||||||
|
try {
|
||||||
|
ServerTickEvents.END_WORLD_TICK.register(this::tickServer);
|
||||||
|
} catch (NoClassDefFoundError ignored) {
|
||||||
|
WorldTickCallback.EVENT.register(world -> {
|
||||||
|
if (!world.isClient) {
|
||||||
|
tickServer(world);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void tickClient() {
|
||||||
|
ClientPlayerEntity p = MinecraftClient.getInstance().player;
|
||||||
|
if (p != null) {
|
||||||
|
clientItem = fromNative(p.inventory.getMainHandStack());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void tickServer(World world) {
|
||||||
|
serverPlayers.clear();
|
||||||
|
world.getPlayers().forEach(it -> serverPlayers
|
||||||
|
.put(it.getUuid(), fromNative(it.inventory.getMainHandStack())));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Item fromNative(ItemStack original) {
|
||||||
|
Identifier iid = Registry.ITEM.getId(original.getItem());
|
||||||
|
if (iid == null) return new Item(0, (byte) 0, (short) 0, null);
|
||||||
|
int id = swordId(iid.toString());
|
||||||
|
return new Item(id, (byte) original.getCount(), (short) original.getDamage(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int swordId(String id) {
|
||||||
|
// https://github.com/ViaVersion/ViaVersion/blob/8de26a0ad33f5b739f5394ed80f69d14197fddc7/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9to1_8/Protocol1_9To1_8.java#L86
|
||||||
|
switch (id) {
|
||||||
|
case "minecraft:iron_sword":
|
||||||
|
return 267;
|
||||||
|
case "minecraft:wooden_sword":
|
||||||
|
return 268;
|
||||||
|
case "minecraft:golden_sword":
|
||||||
|
return 272;
|
||||||
|
case "minecraft:diamond_sword":
|
||||||
|
return 276;
|
||||||
|
case "minecraft:stone_sword":
|
||||||
|
return 283;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,166 @@
|
|||||||
|
package com.viaversion.fabric.mc116.providers;
|
||||||
|
|
||||||
|
import com.viaversion.fabric.mc116.ViaFabric;
|
||||||
|
import com.viaversion.fabric.mc116.ViaFabricAddress;
|
||||||
|
import com.viaversion.fabric.mc116.service.ProtocolAutoDetector;
|
||||||
|
import com.viaversion.fabric.mc116.util.ProtocolUtils;
|
||||||
|
import com.google.common.primitives.Ints;
|
||||||
|
import com.viaversion.viaversion.api.connection.ProtocolInfo;
|
||||||
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
|
import net.minecraft.network.ClientConnection;
|
||||||
|
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
|
||||||
|
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||||
|
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||||
|
import com.viaversion.viaversion.api.type.Type;
|
||||||
|
import com.viaversion.viaversion.exception.CancelException;
|
||||||
|
import com.viaversion.viaversion.api.protocol.packet.State;
|
||||||
|
import com.viaversion.viaversion.protocols.base.*;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.SocketAddress;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
|
public class VRVersionProvider extends BaseVersionProvider {
|
||||||
|
private int[] multiconnectSupportedVersions = null;
|
||||||
|
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (FabricLoader.getInstance().isModLoaded("multiconnect")) {
|
||||||
|
Class<?> mcApiClass = Class.forName("net.earthcomputer.multiconnect.api.MultiConnectAPI");
|
||||||
|
Class<?> iProtocolClass = Class.forName("net.earthcomputer.multiconnect.api.IProtocol");
|
||||||
|
Object mcApiInstance = mcApiClass.getMethod("instance").invoke(null);
|
||||||
|
List<?> protocols = (List<?>) mcApiClass.getMethod("getSupportedProtocols").invoke(mcApiInstance);
|
||||||
|
Method getValue = iProtocolClass.getMethod("getValue");
|
||||||
|
Method isMulticonnectBeta;
|
||||||
|
try {
|
||||||
|
isMulticonnectBeta = iProtocolClass.getMethod("isMulticonnectBeta");
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
isMulticonnectBeta = null;
|
||||||
|
}
|
||||||
|
Set<Integer> vers = new TreeSet<>();
|
||||||
|
for (Object protocol : protocols) {
|
||||||
|
// Do not use versions with beta multiconnect support, which may have stability issues
|
||||||
|
if (isMulticonnectBeta == null || !(Boolean) isMulticonnectBeta.invoke(protocol)) {
|
||||||
|
vers.add((Integer) getValue.invoke(protocol));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
multiconnectSupportedVersions = vers.stream().mapToInt(Integer::intValue).toArray();
|
||||||
|
ViaFabric.JLOGGER.info("ViaFabric will integrate with multiconnect");
|
||||||
|
}
|
||||||
|
} catch (ClassNotFoundException | IllegalAccessException | InvocationTargetException | NoSuchMethodException
|
||||||
|
| ClassCastException ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getClosestServerProtocol(UserConnection connection) throws Exception {
|
||||||
|
if (connection.isClientSide()) {
|
||||||
|
ProtocolInfo info = Objects.requireNonNull(connection.getProtocolInfo());
|
||||||
|
|
||||||
|
if (!ViaFabric.config.isClientSideEnabled()) {
|
||||||
|
return info.getProtocolVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
int serverVer = ViaFabric.config.getClientSideVersion();
|
||||||
|
SocketAddress addr = connection.getChannel().remoteAddress();
|
||||||
|
|
||||||
|
if (addr instanceof InetSocketAddress) {
|
||||||
|
int addrVersion = new ViaFabricAddress().parse(((InetSocketAddress) addr).getHostName()).protocol;
|
||||||
|
if (addrVersion != 0) serverVer = addrVersion;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (serverVer == -2) {
|
||||||
|
// Hope protocol was autodetected
|
||||||
|
ProtocolVersion autoVer =
|
||||||
|
ProtocolAutoDetector.detectVersion((InetSocketAddress) addr).getNow(null);
|
||||||
|
if (autoVer != null) {
|
||||||
|
serverVer = autoVer.getVersion();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
ViaFabric.JLOGGER.warning("Couldn't auto detect: " + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean blocked = checkAddressBlocked(addr);
|
||||||
|
boolean supported = ProtocolUtils.isSupported(serverVer, info.getProtocolVersion());
|
||||||
|
|
||||||
|
handleMulticonnectPing(connection, info, blocked, serverVer);
|
||||||
|
|
||||||
|
if (blocked || !supported) serverVer = info.getProtocolVersion();
|
||||||
|
|
||||||
|
return serverVer;
|
||||||
|
}
|
||||||
|
return super.getClosestServerProtocol(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkAddressBlocked(SocketAddress addr) {
|
||||||
|
return addr instanceof InetSocketAddress && (isDisabled(((InetSocketAddress) addr).getHostString())
|
||||||
|
|| ((((InetSocketAddress) addr).getAddress() != null) &&
|
||||||
|
(isDisabled(((InetSocketAddress) addr).getAddress().getHostAddress())
|
||||||
|
|| isDisabled(((InetSocketAddress) addr).getAddress().getHostName()))));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleMulticonnectPing(UserConnection connection, ProtocolInfo info, boolean blocked, int serverVer) throws Exception {
|
||||||
|
if (info.getState() == State.STATUS
|
||||||
|
&& info.getProtocolVersion() == -1
|
||||||
|
&& connection.getChannel().pipeline().get(ClientConnection.class).getPacketListener()
|
||||||
|
.getClass().getName().startsWith("net.earthcomputer.multiconnect")
|
||||||
|
&& (blocked || ProtocolUtils.isSupported(serverVer, getVersionForMulticonnect(serverVer)))) { // Intercept the connection
|
||||||
|
int multiconnectSuggestion = blocked ? -1 : getVersionForMulticonnect(serverVer);
|
||||||
|
ViaFabric.JLOGGER.info("Sending " + ProtocolVersion.getProtocol(multiconnectSuggestion) + " for multiconnect version detector");
|
||||||
|
PacketWrapper newAnswer = PacketWrapper.create(0x00, null, connection);
|
||||||
|
newAnswer.write(Type.STRING, "{\"version\":{\"name\":\"viafabric integration\",\"protocol\":" + multiconnectSuggestion + "}}");
|
||||||
|
newAnswer.send(info.getPipeline().contains(BaseProtocol1_16.class) ? BaseProtocol1_16.class : BaseProtocol1_7.class, true, true);
|
||||||
|
throw CancelException.generate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getVersionForMulticonnect(int clientSideVersion) {
|
||||||
|
// https://github.com/ViaVersion/ViaVersion/blob/master/velocity/src/main/java/us/myles/ViaVersion/velocity/providers/VelocityVersionProvider.java
|
||||||
|
int[] compatibleProtocols = multiconnectSupportedVersions;
|
||||||
|
|
||||||
|
if (Arrays.binarySearch(compatibleProtocols, clientSideVersion) >= 0) {
|
||||||
|
return clientSideVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clientSideVersion < compatibleProtocols[0]) {
|
||||||
|
return compatibleProtocols[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: This needs a better fix, i.e checking ProtocolRegistry to see if it would work.
|
||||||
|
for (int i = compatibleProtocols.length - 1; i >= 0; i--) {
|
||||||
|
int protocol = compatibleProtocols[i];
|
||||||
|
if (clientSideVersion > protocol && ProtocolVersion.isRegistered(protocol)) {
|
||||||
|
return protocol;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ViaFabric.JLOGGER.severe("multiconnect integration: Panic, no protocol id found for " + clientSideVersion);
|
||||||
|
return clientSideVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isDisabled(String addr) {
|
||||||
|
String[] parts = addr.split("\\.");
|
||||||
|
boolean isNumericIp = parts.length == 4 && Arrays.stream(parts).map(Ints::tryParse).allMatch(Objects::nonNull);
|
||||||
|
return IntStream.range(0, parts.length).anyMatch(i -> {
|
||||||
|
String query;
|
||||||
|
if (isNumericIp) {
|
||||||
|
query = String.join(".", Arrays.stream(parts, 0, i + 1)
|
||||||
|
.toArray(String[]::new)) + ((i != 3) ? ".*" : "");
|
||||||
|
} else {
|
||||||
|
query = ((i != 0) ? "*." : "") + String.join(".", Arrays.stream(parts, i, parts.length)
|
||||||
|
.toArray(String[]::new));
|
||||||
|
}
|
||||||
|
if (ViaFabric.config.isForcedDisable(query)) {
|
||||||
|
ViaFabric.JLOGGER.info(addr + " is force-disabled. (Matches " + query + ")");
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,125 @@
|
|||||||
|
package com.viaversion.fabric.mc116.service;
|
||||||
|
|
||||||
|
import com.viaversion.fabric.mc116.ViaFabric;
|
||||||
|
import com.viaversion.fabric.mc116.ViaFabricAddress;
|
||||||
|
import com.google.common.cache.CacheBuilder;
|
||||||
|
import com.google.common.cache.CacheLoader;
|
||||||
|
import com.google.common.cache.LoadingCache;
|
||||||
|
import io.netty.bootstrap.Bootstrap;
|
||||||
|
import io.netty.channel.*;
|
||||||
|
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||||
|
import io.netty.handler.timeout.ReadTimeoutHandler;
|
||||||
|
import net.fabricmc.api.EnvType;
|
||||||
|
import net.fabricmc.api.Environment;
|
||||||
|
import net.minecraft.network.*;
|
||||||
|
import net.minecraft.network.listener.ClientQueryPacketListener;
|
||||||
|
import net.minecraft.network.packet.c2s.handshake.HandshakeC2SPacket;
|
||||||
|
import net.minecraft.network.packet.c2s.query.QueryRequestC2SPacket;
|
||||||
|
import net.minecraft.network.packet.s2c.query.QueryPongS2CPacket;
|
||||||
|
import net.minecraft.network.packet.s2c.query.QueryResponseS2CPacket;
|
||||||
|
import net.minecraft.server.ServerMetadata;
|
||||||
|
import net.minecraft.text.LiteralText;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||||
|
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
|
@Environment(EnvType.CLIENT)
|
||||||
|
public class ProtocolAutoDetector {
|
||||||
|
private static LoadingCache<InetSocketAddress, CompletableFuture<ProtocolVersion>> SERVER_VER = CacheBuilder.newBuilder()
|
||||||
|
.expireAfterAccess(100, TimeUnit.SECONDS)
|
||||||
|
.build(CacheLoader.from((address) -> {
|
||||||
|
CompletableFuture<ProtocolVersion> future = new CompletableFuture<>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
final ClientConnection clientConnection = new ClientConnection(NetworkSide.CLIENTBOUND);
|
||||||
|
|
||||||
|
ChannelFuture ch = new Bootstrap()
|
||||||
|
.group(ClientConnection.CLIENT_IO_GROUP.get())
|
||||||
|
.channel(NioSocketChannel.class)
|
||||||
|
.handler(new ChannelInitializer<Channel>() {
|
||||||
|
protected void initChannel(Channel channel) {
|
||||||
|
try {
|
||||||
|
channel.config().setOption(ChannelOption.TCP_NODELAY, true);
|
||||||
|
channel.config().setOption(ChannelOption.IP_TOS, 0x18); // Stolen from Velocity, low delay, high reliability
|
||||||
|
} catch (ChannelException ignored) {
|
||||||
|
}
|
||||||
|
|
||||||
|
channel.pipeline()
|
||||||
|
.addLast("timeout", new ReadTimeoutHandler(30))
|
||||||
|
.addLast("splitter", new SplitterHandler())
|
||||||
|
.addLast("decoder", new DecoderHandler(NetworkSide.CLIENTBOUND))
|
||||||
|
.addLast("prepender", new SizePrepender())
|
||||||
|
.addLast("encoder", new PacketEncoder(NetworkSide.SERVERBOUND))
|
||||||
|
.addLast("packet_handler", clientConnection);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.connect(address);
|
||||||
|
|
||||||
|
ch.addListener(future1 -> {
|
||||||
|
if (!future1.isSuccess()) {
|
||||||
|
future.completeExceptionally(future1.cause());
|
||||||
|
} else {
|
||||||
|
ch.channel().eventLoop().execute(() -> { // needs to execute after channel init
|
||||||
|
clientConnection.setPacketListener(new ClientQueryPacketListener() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(QueryResponseS2CPacket packet) {
|
||||||
|
ServerMetadata meta = packet.getServerMetadata();
|
||||||
|
ServerMetadata.Version version;
|
||||||
|
if (meta != null && (version = meta.getVersion()) != null) {
|
||||||
|
ProtocolVersion ver = ProtocolVersion.getProtocol(version.getProtocolVersion());
|
||||||
|
future.complete(ver);
|
||||||
|
ViaFabric.JLOGGER.info("Auto-detected " + ver + " for " + address);
|
||||||
|
} else {
|
||||||
|
future.completeExceptionally(new IllegalArgumentException("Null version in query response"));
|
||||||
|
}
|
||||||
|
clientConnection.disconnect(LiteralText.EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPong(QueryPongS2CPacket packet) {
|
||||||
|
clientConnection.disconnect(new LiteralText("Pong not requested!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisconnected(Text reason) {
|
||||||
|
future.completeExceptionally(new IllegalStateException(reason.asString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClientConnection getConnection() {
|
||||||
|
return clientConnection;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
clientConnection.send(new HandshakeC2SPacket(address.getHostString(),
|
||||||
|
address.getPort(), NetworkState.STATUS));
|
||||||
|
clientConnection.send(new QueryRequestC2SPacket());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (Throwable throwable) {
|
||||||
|
future.completeExceptionally(throwable);
|
||||||
|
}
|
||||||
|
|
||||||
|
return future;
|
||||||
|
}));
|
||||||
|
|
||||||
|
public static CompletableFuture<ProtocolVersion> detectVersion(InetSocketAddress address) {
|
||||||
|
try {
|
||||||
|
InetSocketAddress real = new InetSocketAddress(InetAddress.getByAddress
|
||||||
|
(new ViaFabricAddress().parse(address.getHostString()).realAddress,
|
||||||
|
address.getAddress().getAddress()), address.getPort());
|
||||||
|
return SERVER_VER.get(real);
|
||||||
|
} catch (UnknownHostException | ExecutionException e) {
|
||||||
|
ViaFabric.JLOGGER.log(Level.WARNING, "Protocol auto detector error: ", e);
|
||||||
|
return CompletableFuture.completedFuture(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package com.viaversion.fabric.mc116.util;
|
||||||
|
|
||||||
|
import com.viaversion.viaversion.api.platform.PlatformTask;
|
||||||
|
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
|
||||||
|
public class FutureTaskId implements PlatformTask<Future<?>> {
|
||||||
|
private final Future<?> object;
|
||||||
|
|
||||||
|
public FutureTaskId(Future<?> object) {
|
||||||
|
this.object = object;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Future<?> getObject() {
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cancel() {
|
||||||
|
object.cancel(false);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
package com.viaversion.fabric.mc116.util;
|
||||||
|
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.LogRecord;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
public class JLoggerToLog4j extends Logger {
|
||||||
|
private final org.apache.logging.log4j.Logger base;
|
||||||
|
|
||||||
|
public JLoggerToLog4j(org.apache.logging.log4j.Logger logger) {
|
||||||
|
super("logger", null);
|
||||||
|
this.base = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void log(LogRecord record) {
|
||||||
|
this.log(record.getLevel(), record.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void log(Level level, String msg) {
|
||||||
|
if (level == Level.FINE) {
|
||||||
|
this.base.debug(msg);
|
||||||
|
} else if (level == Level.WARNING) {
|
||||||
|
this.base.warn(msg);
|
||||||
|
} else if (level == Level.SEVERE) {
|
||||||
|
this.base.error(msg);
|
||||||
|
} else if (level == Level.INFO) {
|
||||||
|
this.base.info(msg);
|
||||||
|
} else {
|
||||||
|
this.base.trace(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void log(Level level, String msg, Object param1) {
|
||||||
|
if (level == Level.FINE) {
|
||||||
|
this.base.debug(msg, param1);
|
||||||
|
} else if (level == Level.WARNING) {
|
||||||
|
this.base.warn(msg, param1);
|
||||||
|
} else if (level == Level.SEVERE) {
|
||||||
|
this.base.error(msg, param1);
|
||||||
|
} else if (level == Level.INFO) {
|
||||||
|
this.base.info(msg, param1);
|
||||||
|
} else {
|
||||||
|
this.base.trace(msg, param1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void log(Level level, String msg, Object[] params) {
|
||||||
|
log(level, MessageFormat.format(msg, params));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void log(Level level, String msg, Throwable params) {
|
||||||
|
if (level == Level.FINE) {
|
||||||
|
this.base.debug(msg, params);
|
||||||
|
} else if (level == Level.WARNING) {
|
||||||
|
this.base.warn(msg, params);
|
||||||
|
} else if (level == Level.SEVERE) {
|
||||||
|
this.base.error(msg, params);
|
||||||
|
} else if (level == Level.INFO) {
|
||||||
|
this.base.info(msg, params);
|
||||||
|
} else {
|
||||||
|
this.base.trace(msg, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,60 @@
|
|||||||
|
package com.viaversion.fabric.mc116.util;
|
||||||
|
|
||||||
|
import com.viaversion.viaversion.api.Via;
|
||||||
|
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public class ProtocolUtils {
|
||||||
|
public static boolean isSupported(int server, int client) {
|
||||||
|
return server == client || Via.getManager().getProtocolManager().getProtocolPath(client, server) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getProtocolName(int id) {
|
||||||
|
if (!ProtocolVersion.isRegistered(id)) return Integer.toString(id);
|
||||||
|
return ProtocolVersion.getProtocol(id).getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isStartOfProtocolText(String s) {
|
||||||
|
try {
|
||||||
|
Integer.parseInt(s);
|
||||||
|
return true;
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
try {
|
||||||
|
Integer.parseInt(s + '0');
|
||||||
|
return true;
|
||||||
|
} catch (NumberFormatException e2) {
|
||||||
|
return ProtocolVersion.getProtocols().stream()
|
||||||
|
.map(ProtocolVersion::getName)
|
||||||
|
.flatMap(str -> Stream.concat(
|
||||||
|
Arrays.stream(str.split("-")),
|
||||||
|
Arrays.stream(new String[]{str})
|
||||||
|
))
|
||||||
|
.anyMatch(ver -> ver.startsWith(s));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Integer parseProtocolId(String s) {
|
||||||
|
try {
|
||||||
|
return Integer.parseInt(s);
|
||||||
|
} catch (NumberFormatException ignored) {
|
||||||
|
ProtocolVersion closest = ProtocolVersion.getClosest(s);
|
||||||
|
if (closest == null) return null;
|
||||||
|
return closest.getVersion();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String[] getProtocolSuggestions(String text) {
|
||||||
|
return ProtocolVersion.getProtocols().stream()
|
||||||
|
.map(ProtocolVersion::getName)
|
||||||
|
.flatMap(str -> Stream.concat(
|
||||||
|
Arrays.stream(str.split("-")),
|
||||||
|
Arrays.stream(new String[]{str})
|
||||||
|
))
|
||||||
|
.distinct()
|
||||||
|
.filter(ver -> ver.startsWith(text))
|
||||||
|
.toArray(String[]::new);
|
||||||
|
}
|
||||||
|
}
|
57
viafabric-mc116/src/main/resources/fabric.mod.json
Normal file
57
viafabric-mc116/src/main/resources/fabric.mod.json
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
{
|
||||||
|
"schemaVersion": 1,
|
||||||
|
"id": "viafabric-mc116",
|
||||||
|
"name": "ViaFabric",
|
||||||
|
"version": "@version@",
|
||||||
|
"description": "@description@",
|
||||||
|
"license": "GPL-3.0",
|
||||||
|
"contact": {
|
||||||
|
"homepage": "https://viaversion.com/fabric",
|
||||||
|
"issues": "https://github.com/ViaVersion/ViaFabric/issues",
|
||||||
|
"sources": "https://github.com/ViaVersion/ViaFabric"
|
||||||
|
},
|
||||||
|
"environment": "*",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "creeper123123321",
|
||||||
|
"contact": {
|
||||||
|
"homepage": "https://creeper123123321.github.io/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"contributors": [
|
||||||
|
{
|
||||||
|
"name": "GitHub contributors",
|
||||||
|
"contact": {
|
||||||
|
"homepage": "https://github.com/ViaVersion/ViaFabric/graphs/contributors"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"entrypoints": {
|
||||||
|
"main": [
|
||||||
|
"com.viaversion.fabric.mc116.ViaFabric"
|
||||||
|
],
|
||||||
|
"modmenu": [
|
||||||
|
"com.viaversion.fabric.mc116.gui.ModMenuConfig"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"depends": {
|
||||||
|
"fabricloader": ">=0.4.0",
|
||||||
|
"fabric-resource-loader-v0": "*",
|
||||||
|
"minecraft": "1.16.x",
|
||||||
|
"viaversion": ">3.0.1"
|
||||||
|
},
|
||||||
|
"conflicts": {
|
||||||
|
"fabric-registry-sync-v0": "*"
|
||||||
|
},
|
||||||
|
"recommends": {
|
||||||
|
"fabric-command-api-v1": "*"
|
||||||
|
},
|
||||||
|
"icon": "assets/viafabric/textures/logo.png",
|
||||||
|
"mixins": [
|
||||||
|
"mixins.viafabric.address.json",
|
||||||
|
"mixins.viafabric.gui.json",
|
||||||
|
"mixins.viafabric.debug.json",
|
||||||
|
"mixins.viafabric.pipeline.json"
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"required": true,
|
||||||
|
"compatibilityLevel": "JAVA_8",
|
||||||
|
"mixins": [
|
||||||
|
],
|
||||||
|
"client": [
|
||||||
|
"com.viaversion.fabric.mc116.mixin.address.client.MixinConnectScreenThread",
|
||||||
|
"com.viaversion.fabric.mc116.mixin.address.client.MixinServerAddress",
|
||||||
|
"com.viaversion.fabric.mc116.mixin.address.client.MixinServerPinger"
|
||||||
|
],
|
||||||
|
"injectors": {
|
||||||
|
"defaultRequire": 1
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"required": true,
|
||||||
|
"compatibilityLevel": "JAVA_8",
|
||||||
|
"mixins": [
|
||||||
|
],
|
||||||
|
"client": [
|
||||||
|
"com.viaversion.fabric.mc116.mixin.debug.client.MixinClientConnectionAccessor",
|
||||||
|
"com.viaversion.fabric.mc116.mixin.debug.client.MixinDebugHud"
|
||||||
|
],
|
||||||
|
"injectors": {
|
||||||
|
"defaultRequire": 0
|
||||||
|
}
|
||||||
|
}
|
12
viafabric-mc116/src/main/resources/mixins.viafabric.gui.json
Normal file
12
viafabric-mc116/src/main/resources/mixins.viafabric.gui.json
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"required": true,
|
||||||
|
"compatibilityLevel": "JAVA_8",
|
||||||
|
"mixins": [
|
||||||
|
],
|
||||||
|
"client": [
|
||||||
|
"com.viaversion.fabric.mc116.mixin.gui.client.MixinMultiplayerScreen"
|
||||||
|
],
|
||||||
|
"injectors": {
|
||||||
|
"defaultRequire": 0
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"required": true,
|
||||||
|
"compatibilityLevel": "JAVA_8",
|
||||||
|
"mixins": [
|
||||||
|
"com.viaversion.fabric.mc116.mixin.pipeline.MixinClientConnection",
|
||||||
|
"com.viaversion.fabric.mc116.mixin.pipeline.MixinServerNetworkIoChInit"
|
||||||
|
],
|
||||||
|
"client": [
|
||||||
|
"com.viaversion.fabric.mc116.mixin.pipeline.client.MixinClientConnectionChInit"
|
||||||
|
],
|
||||||
|
"injectors": {
|
||||||
|
"defaultRequire": 1
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"schemaVersion": 1,
|
"schemaVersion": 1,
|
||||||
"id": "viafabric-impl",
|
"id": "viafabric-mc117",
|
||||||
"name": "ViaFabric",
|
"name": "ViaFabric",
|
||||||
"version": "@version@",
|
"version": "@version@",
|
||||||
"description": "@description@",
|
"description": "@description@",
|
||||||
@ -8,8 +8,7 @@
|
|||||||
"contact": {
|
"contact": {
|
||||||
"homepage": "https://viaversion.com/fabric",
|
"homepage": "https://viaversion.com/fabric",
|
||||||
"issues": "https://github.com/ViaVersion/ViaFabric/issues",
|
"issues": "https://github.com/ViaVersion/ViaFabric/issues",
|
||||||
"sources": "https://github.com/ViaVersion/ViaFabric",
|
"sources": "https://github.com/ViaVersion/ViaFabric"
|
||||||
"discord": "https://discord.gg/viaversion"
|
|
||||||
},
|
},
|
||||||
"environment": "*",
|
"environment": "*",
|
||||||
"authors": [
|
"authors": [
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
{
|
{
|
||||||
"required": true,
|
"required": true,
|
||||||
"compatibilityLevel": "JAVA_8",
|
"compatibilityLevel": "JAVA_8",
|
||||||
"package": "com.viaversion.fabric.mc117.mixin.address",
|
|
||||||
"mixins": [
|
"mixins": [
|
||||||
],
|
],
|
||||||
"client": [
|
"client": [
|
||||||
"client.MixinConnectScreenThread",
|
"com.viaversion.fabric.mc117.mixin.address.client.MixinConnectScreenThread",
|
||||||
"client.MixinServerAddress",
|
"com.viaversion.fabric.mc117.mixin.address.client.MixinServerAddress",
|
||||||
"client.MixinServerPinger"
|
"com.viaversion.fabric.mc117.mixin.address.client.MixinServerPinger"
|
||||||
],
|
],
|
||||||
"injectors": {
|
"injectors": {
|
||||||
"defaultRequire": 1
|
"defaultRequire": 1
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
{
|
{
|
||||||
"required": true,
|
"required": true,
|
||||||
"compatibilityLevel": "JAVA_8",
|
"compatibilityLevel": "JAVA_8",
|
||||||
"package": "com.viaversion.fabric.mc117.mixin.debug",
|
|
||||||
"mixins": [
|
"mixins": [
|
||||||
],
|
],
|
||||||
"client": [
|
"client": [
|
||||||
"client.MixinClientConnectionAccessor",
|
"com.viaversion.fabric.mc117.mixin.debug.client.MixinClientConnectionAccessor",
|
||||||
"client.MixinDebugHud"
|
"com.viaversion.fabric.mc117.mixin.debug.client.MixinDebugHud"
|
||||||
],
|
],
|
||||||
"injectors": {
|
"injectors": {
|
||||||
"defaultRequire": 0
|
"defaultRequire": 0
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
{
|
{
|
||||||
"required": true,
|
"required": true,
|
||||||
"compatibilityLevel": "JAVA_8",
|
"compatibilityLevel": "JAVA_8",
|
||||||
"package": "com.viaversion.fabric.mc117.mixin.gui",
|
|
||||||
"mixins": [
|
"mixins": [
|
||||||
],
|
],
|
||||||
"client": [
|
"client": [
|
||||||
"client.MixinMultiplayerScreen"
|
"com.viaversion.fabric.mc117.mixin.gui.client.MixinMultiplayerScreen"
|
||||||
],
|
],
|
||||||
"injectors": {
|
"injectors": {
|
||||||
"defaultRequire": 0
|
"defaultRequire": 0
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
{
|
{
|
||||||
"required": true,
|
"required": true,
|
||||||
"compatibilityLevel": "JAVA_8",
|
"compatibilityLevel": "JAVA_8",
|
||||||
"package": "com.viaversion.fabric.mc117.mixin.pipeline",
|
|
||||||
"mixins": [
|
"mixins": [
|
||||||
"MixinClientConnection",
|
"com.viaversion.fabric.mc117.mixin.pipeline.MixinClientConnection",
|
||||||
"MixinServerNetworkIoChInit"
|
"com.viaversion.fabric.mc117.mixin.pipeline.MixinServerNetworkIoChInit"
|
||||||
],
|
],
|
||||||
"client": [
|
"client": [
|
||||||
"client.MixinClientConnectionChInit"
|
"com.viaversion.fabric.mc117.mixin.pipeline.client.MixinClientConnectionChInit"
|
||||||
],
|
],
|
||||||
"injectors": {
|
"injectors": {
|
||||||
"defaultRequire": 1
|
"defaultRequire": 1
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import java.util.function.Function as JFun
|
||||||
version = rootProject.version
|
version = rootProject.version
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
@ -8,3 +9,9 @@ dependencies {
|
|||||||
modImplementation("net.legacyfabric.legacy-fabric-api:legacy-fabric-api:1.1.0+1.8.9")
|
modImplementation("net.legacyfabric.legacy-fabric-api:legacy-fabric-api:1.1.0+1.8.9")
|
||||||
modImplementation("io.github.boogiemonster1o1:modmenu:0.1.0+1.8.9")
|
modImplementation("io.github.boogiemonster1o1:modmenu:0.1.0+1.8.9")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
minecraft {
|
||||||
|
intermediaryUrl = JFun {
|
||||||
|
"https://maven.legacyfabric.net/net/fabricmc/intermediary/$it/intermediary-$it-v2.jar"
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"schemaVersion": 1,
|
"schemaVersion": 1,
|
||||||
"id": "viafabric-impl",
|
"id": "viafabric-mc18",
|
||||||
"name": "ViaFabric",
|
"name": "ViaFabric",
|
||||||
"version": "@version@",
|
"version": "@version@",
|
||||||
"description": "@description@",
|
"description": "@description@",
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
{
|
{
|
||||||
"required": true,
|
"required": true,
|
||||||
"compatibilityLevel": "JAVA_8",
|
"compatibilityLevel": "JAVA_8",
|
||||||
"package": "com.viaversion.fabric.mc18.mixin.address",
|
|
||||||
"mixins": [
|
"mixins": [
|
||||||
],
|
],
|
||||||
"client": [
|
"client": [
|
||||||
"client.MixinConnectScreenThread",
|
"com.viaversion.fabric.mc18.mixin.address.client.MixinConnectScreenThread",
|
||||||
"client.MixinServerAddress",
|
"com.viaversion.fabric.mc18.mixin.address.client.MixinServerAddress",
|
||||||
"client.MixinServerPinger"
|
"com.viaversion.fabric.mc18.mixin.address.client.MixinServerPinger"
|
||||||
],
|
],
|
||||||
"injectors": {
|
"injectors": {
|
||||||
"defaultRequire": 1
|
"defaultRequire": 1
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
{
|
{
|
||||||
"required": true,
|
"required": true,
|
||||||
"compatibilityLevel": "JAVA_8",
|
"compatibilityLevel": "JAVA_8",
|
||||||
"package": "com.viaversion.fabric.mc18.mixin.debug",
|
|
||||||
"mixins": [
|
"mixins": [
|
||||||
],
|
],
|
||||||
"client": [
|
"client": [
|
||||||
"client.MixinClientConnectionAccessor",
|
"com.viaversion.fabric.mc18.mixin.debug.client.MixinClientConnectionAccessor",
|
||||||
"client.MixinDebugHud"
|
"com.viaversion.fabric.mc18.mixin.debug.client.MixinDebugHud"
|
||||||
],
|
],
|
||||||
"injectors": {
|
"injectors": {
|
||||||
"defaultRequire": 0
|
"defaultRequire": 0
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
{
|
{
|
||||||
"required": true,
|
"required": true,
|
||||||
"compatibilityLevel": "JAVA_8",
|
"compatibilityLevel": "JAVA_8",
|
||||||
"package": "com.viaversion.fabric.mc18.mixin.gui",
|
|
||||||
"mixins": [
|
"mixins": [
|
||||||
],
|
],
|
||||||
"client": [
|
"client": [
|
||||||
"client.MixinMultiplayerScreen"
|
"com.viaversion.fabric.mc18.mixin.gui.client.MixinMultiplayerScreen"
|
||||||
],
|
],
|
||||||
"injectors": {
|
"injectors": {
|
||||||
"defaultRequire": 0
|
"defaultRequire": 0
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user