Merge remote-tracking branch 'origin/main' into 1.20-recode

# Conflicts:
#	src/main/java/de/florianmichael/viafabricplus/injection/mixin/fixes/minecraft/entity/MixinClientPlayerEntity.java
This commit is contained in:
FlorianMichael 2023-04-30 22:03:21 +02:00
commit d19e7e79cd
24 changed files with 386 additions and 401 deletions

6
.github/USAGE.md vendored
View File

@ -13,6 +13,12 @@ ViaFabricPlus will use the version set there, the versions are stored in the ser
If you don't want to specify a specific version anymore, you can simply press the button and select **"Cancel and reset"**.
## Commands
You can use the ViaVersion commands with **/viafabricplus** or **/viaversion**, and a few classic only commands are also implemented:
- **/viafabricplus settime <Time (Long)>** - Changes the Clientside World Time, available from: **c0.28-c0.30**
- **/viafabricplus listextensions** - Displays all classic protocol extensions, available in: **c0.30 CPE**
### Settings are optional settings that can turn fixes on and off, originally they were used for debugging<br>
![](images/settings.png)

View File

@ -52,18 +52,6 @@ ViaFabricPlus is intended to replace [multiconnect](https://github.com/Earthcomp
- [x] Fixed clientside packet handling (1.16.5 transactions, 1.19.0 tablist, ...)
</details>
## Classic stuff
### Custom protocol extensions
ViaFabricPlus implements new Classic Extensions into the CPE protocol of ViaLegacy which are rather client side. <br>
- **WeatherType** extension (version **1**)
### Protocol commands
To better control the Classic Protocol, there are a few clientside commands, the command prefix is **/v**: <br>
- **/vhelp** - Displays all commands, available from: **c0.28-c0.30**
- **/vsettime <Time (Long)>** - Changes the Clientside World Time, available from: **c0.28-c0.30**
- **/vlistextensions** - Displays all classic protocol extensions, available in: **c0.30 CPE**
# For developers and translators
Contributions in the form of pull requests are always welcome, please just stick to my code style and make sure your code is easy to update and compatible with other mods.

View File

@ -9,12 +9,12 @@ loader_version=0.14.19
fabric_api_version=0.79.1+1.20
# viafabricplus
mod_version=2.6.8
mod_version=2.6.9
maven_group=de.florianmichael
archives_base_name=viafabricplus
# base lib
vialoadingbase_version=4.4.8
vialoadingbase_version=1f4e409d86
raknet_transport_version=1.0.0.CR1-SNAPSHOT
classic4j_version=1.2.0

View File

@ -27,7 +27,6 @@ import de.florianmichael.viafabricplus.definition.bedrock.BedrockAccountHandler;
import de.florianmichael.viafabricplus.screen.ClassicItemSelectionScreen;
import de.florianmichael.viafabricplus.definition.c0_30.ClassiCubeAccountHandler;
import de.florianmichael.viafabricplus.definition.c0_30.protocol.CustomClassicProtocolExtensions;
import de.florianmichael.viafabricplus.definition.c0_30.command.ClassicProtocolCommands;
import de.florianmichael.viafabricplus.mappings.ArmorPointsMappings;
import de.florianmichael.viafabricplus.event.FinishMinecraftLoadCallback;
import de.florianmichael.viafabricplus.event.PreLoadCallback;
@ -79,7 +78,6 @@ public class ViaFabricPlus {
// Classic Stuff
CustomClassicProtocolExtensions.create();
ClassicProtocolCommands.create();
// Account Handler
ClassiCubeAccountHandler.create();

View File

@ -1,40 +0,0 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.definition.c0_30.command;
import de.florianmichael.viafabricplus.definition.c0_30.command.impl.HelpCommand;
import de.florianmichael.viafabricplus.definition.c0_30.command.impl.ListExtensionsCommand;
import de.florianmichael.viafabricplus.definition.c0_30.command.impl.SetTimeCommand;
import java.util.ArrayList;
import java.util.List;
public class ClassicProtocolCommands {
public final static String COMMAND_PREFIX = "/v";
public static ClassicProtocolCommands INSTANCE;
public final List<ICommand> commands = new ArrayList<>();
public static void create() {
INSTANCE = new ClassicProtocolCommands();
INSTANCE.commands.add(new HelpCommand());
INSTANCE.commands.add(new SetTimeCommand());
INSTANCE.commands.add(new ListExtensionsCommand());
}
}

View File

@ -17,35 +17,14 @@
*/
package de.florianmichael.viafabricplus.definition.c0_30.command;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.command.ViaSubCommand;
import com.viaversion.viaversion.api.connection.UserConnection;
import de.florianmichael.viafabricplus.util.ScreenUtil;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import net.minecraft.client.MinecraftClient;
import net.minecraft.util.Formatting;
import net.raphimc.vialegacy.protocols.classic.protocola1_0_15toc0_28_30.providers.ClassicCustomCommandProvider;
@SuppressWarnings("DataFlowIssue")
public interface ICommand {
public abstract class ClassicViaSubCommand extends ViaSubCommand {
String name();
String description();
default void sendFeedback(final String message) {
try {
Via.getManager().getProviders().get(ClassicCustomCommandProvider.class).sendFeedback(currentViaConnection(), ScreenUtil.prefixedMessage(message));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
default void sendUsage() {
sendFeedback(Formatting.RED + "Use: " + ClassicProtocolCommands.COMMAND_PREFIX + name() + (description() != null ? " " + description() : ""));
}
default UserConnection currentViaConnection() {
public UserConnection getUser() {
return MinecraftClient.getInstance().getNetworkHandler().getConnection().channel.attr(ProtocolHack.LOCAL_VIA_CONNECTION).get();
}
void execute(String[] args) throws Exception;
}

View File

@ -1,45 +0,0 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.definition.c0_30.command.impl;
import de.florianmichael.viafabricplus.definition.c0_30.command.ClassicProtocolCommands;
import de.florianmichael.viafabricplus.definition.c0_30.command.ICommand;
import net.minecraft.util.Formatting;
public class HelpCommand implements ICommand {
@Override
public String name() {
return "help";
}
@Override
public String description() {
return null;
}
@Override
public void execute(String[] args) {
sendFeedback(Formatting.GREEN + "Loaded " + Formatting.GOLD + (ClassicProtocolCommands.INSTANCE.commands.size() - 1) + Formatting.GREEN + " commands");
for (ICommand command : ClassicProtocolCommands.INSTANCE.commands) {
if (command.name().equals(name())) continue;
command.sendUsage();
}
}
}

View File

@ -17,14 +17,15 @@
*/
package de.florianmichael.viafabricplus.definition.c0_30.command.impl;
import com.viaversion.viaversion.api.command.ViaCommandSender;
import com.viaversion.viaversion.api.connection.UserConnection;
import de.florianmichael.viafabricplus.definition.c0_30.command.ICommand;
import de.florianmichael.viafabricplus.definition.c0_30.command.ClassicViaSubCommand;
import de.florianmichael.viafabricplus.injection.access.IExtensionProtocolMetadataStorage;
import net.minecraft.util.Formatting;
import net.raphimc.vialegacy.api.LegacyProtocolVersion;
import net.raphimc.vialegacy.protocols.classic.protocolc0_28_30toc0_28_30cpe.storage.ExtensionProtocolMetadataStorage;
public class ListExtensionsCommand implements ICommand {
public class ListExtensionsCommand extends ClassicViaSubCommand {
@Override
public String name() {
return "listextensions";
@ -32,18 +33,19 @@ public class ListExtensionsCommand implements ICommand {
@Override
public String description() {
return null;
return "Shows all classic extensions (only for " + LegacyProtocolVersion.c0_30cpe.getName() + ")";
}
@Override
public void execute(String[] args) throws Exception {
final UserConnection connection = currentViaConnection();
public boolean execute(ViaCommandSender sender, String[] args) {
final UserConnection connection = getUser();
if (!connection.has(ExtensionProtocolMetadataStorage.class)) {
this.sendFeedback(Formatting.RED + "This command is only for " + LegacyProtocolVersion.c0_30cpe.getName());
return;
sendMessage(sender, Formatting.RED + "Only for " + LegacyProtocolVersion.c0_30cpe.getName());
return true;
}
((IExtensionProtocolMetadataStorage) connection.get(ExtensionProtocolMetadataStorage.class)).getServerExtensions().forEach((extension, version) -> {
this.sendFeedback(Formatting.GREEN + extension.getName() + Formatting.GOLD + " v" + version);
sendMessage(sender, Formatting.GREEN + extension.getName() + Formatting.GOLD + " v" + version);
});
return true;
}
}

View File

@ -17,13 +17,14 @@
*/
package de.florianmichael.viafabricplus.definition.c0_30.command.impl;
import com.viaversion.viaversion.api.command.ViaCommandSender;
import com.viaversion.viaversion.api.connection.UserConnection;
import de.florianmichael.viafabricplus.definition.c0_30.command.ICommand;
import de.florianmichael.viafabricplus.definition.c0_30.command.ClassicViaSubCommand;
import net.minecraft.util.Formatting;
import net.raphimc.vialegacy.api.LegacyProtocolVersion;
import net.raphimc.vialegacy.protocols.alpha.protocola1_0_17_1_0_17_4toa1_0_16_2.storage.TimeLockStorage;
public class SetTimeCommand implements ICommand {
public class SetTimeCommand extends ClassicViaSubCommand {
@Override
public String name() {
return "settime";
@ -31,26 +32,32 @@ public class SetTimeCommand implements ICommand {
@Override
public String description() {
return "<Time (Long)>";
return "Changes the time (Only for <= " + LegacyProtocolVersion.a1_0_16toa1_0_16_2.getName() + ")";
}
@Override
public void execute(String[] args) throws Exception {
final UserConnection connection = currentViaConnection();
public String usage() {
return name() + " " + "<Time (Long)>";
}
@Override
public boolean execute(ViaCommandSender sender, String[] args) {
final UserConnection connection = getUser();
if (!connection.has(TimeLockStorage.class)) {
this.sendFeedback(Formatting.RED + "This command is only for <=" + LegacyProtocolVersion.a1_0_16toa1_0_16_2.getName());
return;
sendMessage(sender, Formatting.RED + "Only for <= " + LegacyProtocolVersion.a1_0_16toa1_0_16_2.getName());
return true;
}
try {
if (args.length == 1) {
final long time = Long.parseLong(args[0]) % 24_000L;
connection.get(TimeLockStorage.class).setTime(time);
this.sendFeedback(Formatting.GREEN + "Time has been set to " + Formatting.GOLD + time);
sendMessage(sender, Formatting.GREEN + "Time has been set to " + Formatting.GOLD + time);
} else {
this.sendUsage();
return false;
}
} catch (Throwable ignored) {
this.sendUsage();
}
return false;
}
return true;
}
}

View File

@ -24,6 +24,7 @@ import de.florianmichael.viafabricplus.injection.access.IFontStorage;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import de.florianmichael.viafabricplus.settings.groups.ExperimentalSettings;
import de.florianmichael.vialoadingbase.ViaLoadingBase;
import de.florianmichael.vialoadingbase.model.ComparableProtocolVersion;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.font.Glyph;
@ -37,20 +38,22 @@ import java.util.function.Supplier;
public class FontCacheFix {
public final static boolean DASH_LOADER = FabricLoader.getInstance().isModLoaded("dashloader");
private static ComparableProtocolVersion protocolVersion;
public static void init() {
if (DASH_LOADER) return;
ChangeProtocolVersionCallback.EVENT.register(protocolVersion -> MinecraftClient.getInstance().fontManager.fontStorages.values().forEach(fontStorage -> {
RenderSystem.recordRenderCall(() -> {
((IFontStorage) fontStorage).viafabricplus_clearCaches();
ChangeProtocolVersionCallback.EVENT.register(protocolVersion -> {
FontCacheFix.protocolVersion = protocolVersion;
MinecraftClient.getInstance().fontManager.fontStorages.values().forEach(fontStorage -> RenderSystem.recordRenderCall(() -> ((IFontStorage) fontStorage).viafabricplus_clearCaches()));
});
}));
}
public static boolean shouldReplaceFontRenderer() {
if (ViaLoadingBase.getInstance() == null || DASH_LOADER) return false;
if (ViaLoadingBase.getInstance() == null || DASH_LOADER || protocolVersion == null) return false;
return ExperimentalSettings.INSTANCE.fixFontCache.getValue() && ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(ProtocolVersion.v1_12_2);
return ExperimentalSettings.INSTANCE.fixFontCache.getValue() && protocolVersion.isOlderThanOrEqualTo(ProtocolVersion.v1_12_2);
}
public enum BuiltinEmptyGlyph1_12_2 implements Glyph {

View File

@ -41,6 +41,8 @@ public class MixinConnectScreen_1 {
@Redirect(method = "run", at = @At(value = "INVOKE", target = "Ljava/util/Optional;get()Ljava/lang/Object;"))
public Object mapSocketAddress(Optional<InetSocketAddress> instance) {
final InetSocketAddress address = instance.get();
if (field_40415 == null) return address;
final ComparableProtocolVersion forcedVersion = ((IServerInfo) field_40415).viafabricplus_forcedVersion();
if (forcedVersion != null) {
ProtocolHack.getForcedVersions().put(address, forcedVersion);

View File

@ -19,6 +19,7 @@ package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft;
import com.mojang.authlib.GameProfile;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import de.florianmichael.viafabricplus.ViaFabricPlus;
import de.florianmichael.viafabricplus.settings.groups.VisualSettings;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import net.minecraft.client.MinecraftClient;
@ -29,14 +30,12 @@ import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.client.network.PlayerListEntry;
import net.minecraft.client.network.ServerInfo;
import net.minecraft.client.util.telemetry.WorldSession;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.vehicle.BoatEntity;
import net.minecraft.network.ClientConnection;
import net.minecraft.network.listener.ServerPlayPacketListener;
import net.minecraft.network.packet.Packet;
import net.minecraft.network.packet.s2c.play.*;
import net.minecraft.screen.ScreenHandler;
import net.minecraft.util.math.Vec3d;
import org.slf4j.Logger;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
@ -153,4 +152,12 @@ public abstract class MixinClientPlayNetworkHandler {
public boolean removeSecureChatWarning(ServerMetadataS2CPacket instance) {
return instance.isSecureChatEnforced() || VisualSettings.INSTANCE.disableSecureChatWarning.getValue();
}
@Inject(method = "onSetTradeOffers", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/NetworkThreadUtils;forceMainThread(Lnet/minecraft/network/packet/Packet;Lnet/minecraft/network/listener/PacketListener;Lnet/minecraft/util/thread/ThreadExecutor;)V", shift = At.Shift.AFTER), cancellable = true)
public void checkLoginPacket(SetTradeOffersS2CPacket packet, CallbackInfo ci) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(ProtocolVersion.v1_13_2) && this.client.player == null) {
ViaFabricPlus.LOGGER.error("Server tried to send Play packet in Login process, dropping \"SetTradeOffers\"");
ci.cancel();
}
}
}

View File

@ -113,7 +113,7 @@ public abstract class MixinClientPlayerEntity extends AbstractClientPlayerEntity
this.networkHandler.sendPacket(new PlayerMoveC2SPacket.PositionAndOnGround(this.getX(), this.getY(), this.getZ(), this.isOnGround()));
} else if (bl4) {
this.networkHandler.sendPacket(new PlayerMoveC2SPacket.LookAndOnGround(this.getYaw(), this.getPitch(), this.isOnGround()));
} else if (this.lastOnGround != this.isOnGround() || DebugSettings.INSTANCE.sendIdlePacket.getValue()) {
} else if ((this.lastOnGround != this.isOnGround() && !DebugSettings.INSTANCE.sendIdlePacket.getValue()) || DebugSettings.INSTANCE.sendIdlePacket.getValue()) {
this.networkHandler.sendPacket(new PlayerMoveC2SPacket.OnGroundOnly(this.isOnGround()));
} else {
SkipIdlePacketCallback.EVENT.invoker().onSkipIdlePacket();

View File

@ -38,14 +38,14 @@ public class MixinJoinPackets {
return seed;
}
@Redirect(method = "lambda$register$2", at = @At(value = "INVOKE", target = "Lcom/viaversion/viaversion/api/protocol/packet/PacketWrapper;read(Lcom/viaversion/viaversion/api/type/Type;)Ljava/lang/Object;", ordinal = 54))
@Redirect(method = "lambda$register$2", at = @At(value = "INVOKE", target = "Lcom/viaversion/viaversion/api/protocol/packet/PacketWrapper;read(Lcom/viaversion/viaversion/api/type/Type;)Ljava/lang/Object;", ordinal = 56))
private static Object trackLevelId(PacketWrapper instance, Type<StringType> tType) throws Exception {
final Object levelId = instance.read(tType);
instance.user().get(JoinGameStorage.class).setLevelId((String) levelId);
return levelId;
}
@Redirect(method = "lambda$register$2", at = @At(value = "INVOKE", target = "Lcom/viaversion/viaversion/api/protocol/packet/PacketWrapper;read(Lcom/viaversion/viaversion/api/type/Type;)Ljava/lang/Object;", ordinal = 62))
@Redirect(method = "lambda$register$2", at = @At(value = "INVOKE", target = "Lcom/viaversion/viaversion/api/protocol/packet/PacketWrapper;read(Lcom/viaversion/viaversion/api/type/Type;)Ljava/lang/Object;", ordinal = 64))
private static Object trackEnchantmentSeed(PacketWrapper instance, Type<VarIntType> tType) throws Exception {
final Object enchantmentSeed = instance.read(tType);
instance.user().get(JoinGameStorage.class).setEnchantmentSeed((Integer) enchantmentSeed);

View File

@ -17,10 +17,16 @@
*/
package de.florianmichael.viafabricplus.protocolhack;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import com.viaversion.viaversion.api.protocol.version.VersionProvider;
import com.viaversion.viaversion.connection.UserConnectionImpl;
import com.viaversion.viaversion.libs.gson.JsonArray;
import com.viaversion.viaversion.libs.gson.JsonObject;
import com.viaversion.viaversion.protocol.ProtocolPipelineImpl;
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.providers.PlayerLookTargetProvider;
import com.viaversion.viaversion.protocols.protocol1_9to1_8.providers.HandItemProvider;
@ -30,6 +36,7 @@ import de.florianmichael.viafabricplus.definition.v1_19_0.provider.CommandArgume
import de.florianmichael.viafabricplus.event.ChangeProtocolVersionCallback;
import de.florianmichael.viafabricplus.event.FinishViaLoadingBaseStartupCallback;
import de.florianmichael.viafabricplus.event.ViaLoadingBaseBuilderCallback;
import de.florianmichael.viafabricplus.protocolhack.command.ViaFabricPlusVLBViaCommandHandler;
import de.florianmichael.viafabricplus.protocolhack.netty.ViaFabricPlusVLBPipeline;
import de.florianmichael.viafabricplus.protocolhack.platform.ViaAprilFoolsPlatformImpl;
import de.florianmichael.viafabricplus.protocolhack.platform.ViaBedrockPlatformImpl;
@ -47,6 +54,9 @@ import de.florianmichael.vialoadingbase.model.ComparableProtocolVersion;
import de.florianmichael.vialoadingbase.model.Platform;
import io.netty.channel.*;
import io.netty.util.AttributeKey;
import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback;
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.SharedConstants;
import net.minecraft.client.MinecraftClient;
import net.minecraft.network.ClientConnection;
@ -55,7 +65,6 @@ import net.raphimc.viabedrock.api.BedrockProtocolVersion;
import net.raphimc.viabedrock.protocol.providers.BlobCacheProvider;
import net.raphimc.viabedrock.protocol.providers.NettyPipelineProvider;
import net.raphimc.vialegacy.api.LegacyProtocolVersion;
import net.raphimc.vialegacy.protocols.classic.protocola1_0_15toc0_28_30.providers.ClassicCustomCommandProvider;
import net.raphimc.vialegacy.protocols.classic.protocola1_0_15toc0_28_30.providers.ClassicMPPassProvider;
import net.raphimc.vialegacy.protocols.classic.protocola1_0_15toc0_28_30.providers.ClassicWorldHeightProvider;
import net.raphimc.vialegacy.protocols.release.protocol1_3_1_2to1_2_4_5.providers.OldAuthProvider;
@ -119,6 +128,19 @@ public class ProtocolHack {
channel.pipeline().addLast(new ViaFabricPlusVLBPipeline(user, address, ProtocolHack.getTargetVersion(channel)));
}
private static void initCommands() {
// Adding ViaVersion commands
ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> {
final ViaFabricPlusVLBViaCommandHandler commandHandler = (ViaFabricPlusVLBViaCommandHandler) Via.getManager().getCommandHandler();
final RequiredArgumentBuilder<FabricClientCommandSource, String> executor = RequiredArgumentBuilder.
<FabricClientCommandSource, String>argument("args", StringArgumentType.greedyString()).executes(commandHandler::execute).suggests(commandHandler::suggestion);
dispatcher.register(LiteralArgumentBuilder.<FabricClientCommandSource>literal("viaversion").then(executor).executes(commandHandler::execute));
dispatcher.register(LiteralArgumentBuilder.<FabricClientCommandSource>literal("viafabricplus").then(executor).executes(commandHandler::execute));
});
}
public static void init() {
ViaLoadingBase.ViaLoadingBaseBuilder builder = ViaLoadingBase.ViaLoadingBaseBuilder.create();
@ -159,14 +181,44 @@ public class ProtocolHack {
providers.use(EncryptionProvider.class, new ViaFabricPlusEncryptionProvider());
providers.use(GameProfileFetcher.class, new ViaFabricPlusGameProfileFetcher());
providers.use(ClassicMPPassProvider.class, new ViaFabricPlusClassicMPPassProvider());
providers.use(ClassicCustomCommandProvider.class, new ViaFabricPlusClassicCustomCommandProvider());
providers.use(NettyPipelineProvider.class, new ViaFabricPlusNettyPipelineProvider());
providers.use(BlobCacheProvider.class, new ViaFabricPlusBlobCacheProvider());
});
builder = builder.onProtocolReload(protocolVersion -> ChangeProtocolVersionCallback.EVENT.invoker().onChangeProtocolVersion(protocolVersion));
builder = builder.dumpSupplier(() -> {
JsonObject platformSpecific = new JsonObject();
JsonArray mods = new JsonArray();
FabricLoader.getInstance().getAllMods().stream().map((mod) -> {
JsonObject jsonMod = new JsonObject();
jsonMod.addProperty("id", mod.getMetadata().getId());
jsonMod.addProperty("name", mod.getMetadata().getName());
jsonMod.addProperty("version", mod.getMetadata().getVersion().getFriendlyString());
JsonArray authors = new JsonArray();
mod.getMetadata().getAuthors().stream().map(it -> {
JsonObject info = new JsonObject();
JsonObject contact = new JsonObject();
it.getContact().asMap().forEach(contact::addProperty);
if (contact.size() != 0) info.add("contact", contact);
info.addProperty("name", it.getName());
return info;
}).forEach(authors::add);
jsonMod.add("authors", authors);
return jsonMod;
}).forEach(mods::add);
platformSpecific.add("mods", mods);
platformSpecific.addProperty("native version", SharedConstants.getProtocolVersion());
return platformSpecific;
});
builder = builder.managerBuilderConsumer(viaManagerBuilder -> viaManagerBuilder.commandHandler(new ViaFabricPlusVLBViaCommandHandler()));
ViaLoadingBaseBuilderCallback.EVENT.invoker().onBuildViaLoadingBase(builder);
builder.build();
initCommands();
FinishViaLoadingBaseStartupCallback.EVENT.invoker().onFinishViaLoadingBaseStartup();
}

View File

@ -0,0 +1,73 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.protocolhack.command;
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 de.florianmichael.viafabricplus.definition.c0_30.command.impl.ListExtensionsCommand;
import de.florianmichael.viafabricplus.definition.c0_30.command.impl.SetTimeCommand;
import de.florianmichael.vialoadingbase.platform.viaversion.VLBViaCommandHandler;
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
import java.util.concurrent.CompletableFuture;
public class ViaFabricPlusVLBViaCommandHandler extends VLBViaCommandHandler {
public ViaFabricPlusVLBViaCommandHandler() {
super();
this.registerSubCommand(new ListExtensionsCommand());
this.registerSubCommand(new SetTimeCommand());
}
public int execute(CommandContext<FabricClientCommandSource> ctx) {
String[] args = new String[0];
try {
args = StringArgumentType.getString(ctx, "args").split(" ");
} catch (IllegalArgumentException ignored) {
}
onCommand(
new ViaFabricPlusViaCommandSender(ctx.getSource()),
args
);
return 1;
}
public CompletableFuture<Suggestions> suggestion(CommandContext<FabricClientCommandSource> 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 ViaFabricPlusViaCommandSender(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();
}
}

View File

@ -0,0 +1,53 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.protocolhack.command;
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
import net.minecraft.command.CommandSource;
import net.minecraft.text.Text;
import com.viaversion.viaversion.api.command.ViaCommandSender;
import java.util.UUID;
public class ViaFabricPlusViaCommandSender implements ViaCommandSender {
private final CommandSource source;
public ViaFabricPlusViaCommandSender(final CommandSource source) {
this.source = source;
}
@Override
public boolean hasPermission(String s) {
return source.hasPermissionLevel(4);
}
@Override
public void sendMessage(String s) {
((FabricClientCommandSource) source).sendFeedback(Text.of(s));
}
@Override
public UUID getUUID() {
return ((FabricClientCommandSource) source).getPlayer().getUuid();
}
@Override
public String getName() {
return ((FabricClientCommandSource) source).getPlayer().getEntityName();
}
}

View File

@ -23,8 +23,6 @@ import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import de.florianmichael.viafabricplus.protocolhack.netty.viabedrock.DisconnectAdapter;
import de.florianmichael.viafabricplus.protocolhack.netty.viabedrock.codec.PingEncapsulationCodec;
import de.florianmichael.viafabricplus.protocolhack.netty.viabedrock.codec.RakMessageEncapsulationCodec;
import de.florianmichael.viafabricplus.protocolhack.netty.viabedrock.codec.library_fix.FixedUnconnectedPingEncoder;
import de.florianmichael.viafabricplus.protocolhack.netty.viabedrock.codec.library_fix.FixedUnconnectedPongDecoder;
import de.florianmichael.vialoadingbase.model.ComparableProtocolVersion;
import de.florianmichael.vialoadingbase.netty.VLBPipeline;
import de.florianmichael.vialoadingbase.netty.event.CompressionReorderEvent;
@ -38,9 +36,6 @@ import net.raphimc.vialegacy.api.LegacyProtocolVersion;
import net.raphimc.vialegacy.netty.PreNettyLengthPrepender;
import net.raphimc.vialegacy.netty.PreNettyLengthRemover;
import net.raphimc.vialegacy.protocols.release.protocol1_7_2_5to1_6_4.baseprotocols.PreNettyBaseProtocol;
import org.cloudburstmc.netty.channel.raknet.RakClientChannel;
import org.cloudburstmc.netty.handler.codec.raknet.common.UnconnectedPingEncoder;
import org.cloudburstmc.netty.handler.codec.raknet.common.UnconnectedPongDecoder;
import java.net.InetSocketAddress;
@ -99,13 +94,6 @@ public class ViaFabricPlusVLBPipeline extends VLBPipeline {
// Pinging in RakNet is something different
if (ProtocolHack.getRakNetPingSessions().contains(address)) {
{ // Temporary fix for the ping encoder
final RakClientChannel rakChannel = (RakClientChannel) ctx.channel();
rakChannel.parent().pipeline().replace(UnconnectedPingEncoder.NAME, UnconnectedPingEncoder.NAME, new FixedUnconnectedPingEncoder(rakChannel));
rakChannel.parent().pipeline().replace(UnconnectedPongDecoder.NAME, UnconnectedPongDecoder.NAME, new FixedUnconnectedPongDecoder(rakChannel));
}
pipeline.replace(VIA_BEDROCK_FRAME_ENCAPSULATION_HANDLER_NAME, VIA_BEDROCK_PING_ENCAPSULATION_HANDLER_NAME, new PingEncapsulationCodec(address));
pipeline.remove(VIA_BEDROCK_PACKET_ENCAPSULATION_HANDLER_NAME);

View File

@ -1,60 +0,0 @@
/*
* This file is part of ViaBedrock - https://github.com/RaphiMC/ViaBedrock
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.protocolhack.netty.viabedrock.codec.library_fix;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOutboundHandlerAdapter;
import io.netty.channel.ChannelPromise;
import io.netty.channel.socket.DatagramPacket;
import org.cloudburstmc.netty.channel.raknet.RakClientChannel;
import org.cloudburstmc.netty.channel.raknet.RakPing;
import org.cloudburstmc.netty.channel.raknet.config.RakChannelOption;
import static org.cloudburstmc.netty.channel.raknet.RakConstants.ID_UNCONNECTED_PING;
// Temporary fix until the library fixes the issue
public class FixedUnconnectedPingEncoder extends ChannelOutboundHandlerAdapter {
private final RakClientChannel rakClientChannel;
public FixedUnconnectedPingEncoder(final RakClientChannel rakClientChannel) {
this.rakClientChannel = rakClientChannel;
}
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
if (!(msg instanceof RakPing)) {
ctx.write(msg, promise);
return;
}
RakPing ping = (RakPing) msg;
ByteBuf magicBuf = this.rakClientChannel.config().getOption(RakChannelOption.RAK_UNCONNECTED_MAGIC);
long guid = this.rakClientChannel.config().getOption(RakChannelOption.RAK_GUID);
ByteBuf pingBuffer = ctx.alloc().ioBuffer(magicBuf.readableBytes() + 17);
pingBuffer.writeByte(ID_UNCONNECTED_PING);
pingBuffer.writeLong(ping.getPingTime());
pingBuffer.writeBytes(magicBuf, magicBuf.readerIndex(), magicBuf.readableBytes());
pingBuffer.writeLong(guid);
ctx.write(new DatagramPacket(pingBuffer, ping.getSender()));
}
}

View File

@ -1,74 +0,0 @@
/*
* This file is part of ViaBedrock - https://github.com/RaphiMC/ViaBedrock
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.protocolhack.netty.viabedrock.codec.library_fix;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.socket.DatagramPacket;
import org.cloudburstmc.netty.channel.raknet.RakClientChannel;
import org.cloudburstmc.netty.channel.raknet.RakPong;
import org.cloudburstmc.netty.channel.raknet.config.RakChannelOption;
import org.cloudburstmc.netty.handler.codec.raknet.AdvancedChannelInboundHandler;
import static org.cloudburstmc.netty.channel.raknet.RakConstants.ID_UNCONNECTED_PONG;
// Temporary fix until the library fixes the issue
public class FixedUnconnectedPongDecoder extends AdvancedChannelInboundHandler<DatagramPacket> {
private final RakClientChannel rakClientChannel;
public FixedUnconnectedPongDecoder(final RakClientChannel rakClientChannel) {
this.rakClientChannel = rakClientChannel;
}
@Override
protected boolean acceptInboundMessage(ChannelHandlerContext ctx, Object msg) throws Exception {
if (!super.acceptInboundMessage(ctx, msg)) {
return false;
}
DatagramPacket packet = (DatagramPacket) msg;
ByteBuf buf = packet.content();
return buf.isReadable() && buf.getUnsignedByte(buf.readerIndex()) == ID_UNCONNECTED_PONG;
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) throws Exception {
ByteBuf buf = packet.content();
buf.readUnsignedByte(); // Packet ID
long pingTime = buf.readLong();
long guid = buf.readLong();
ByteBuf magicBuf = this.rakClientChannel.config().getOption(RakChannelOption.RAK_UNCONNECTED_MAGIC);
if (!buf.isReadable(magicBuf.readableBytes()) || !ByteBufUtil.equals(buf.readSlice(magicBuf.readableBytes()), magicBuf)) {
// Magic does not match
return;
}
ByteBuf pongData = Unpooled.EMPTY_BUFFER;
if (buf.isReadable(2)) { // Length
pongData = buf.readRetainedSlice(buf.readUnsignedShort());
}
ctx.fireChannelRead(new RakPong(pingTime, guid, pongData, packet.sender()));
}
}

View File

@ -1,54 +0,0 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.protocolhack.provider.vialegacy;
import com.viaversion.viaversion.api.connection.UserConnection;
import de.florianmichael.viafabricplus.definition.c0_30.command.ClassicProtocolCommands;
import de.florianmichael.viafabricplus.definition.c0_30.command.ICommand;
import de.florianmichael.viafabricplus.settings.groups.GeneralSettings;
import net.raphimc.vialegacy.ViaLegacy;
import net.raphimc.vialegacy.protocols.classic.protocola1_0_15toc0_28_30.providers.ClassicCustomCommandProvider;
import java.util.Arrays;
import java.util.logging.Level;
public class ViaFabricPlusClassicCustomCommandProvider extends ClassicCustomCommandProvider {
@Override
public boolean handleChatMessage(UserConnection user, String message) {
if (!GeneralSettings.INSTANCE.allowClassicProtocolCommandUsage.getValue()) return super.handleChatMessage(user, message);
try {
if (message.startsWith(ClassicProtocolCommands.COMMAND_PREFIX)) {
message = message.substring(ClassicProtocolCommands.COMMAND_PREFIX.length());
final String[] input = message.split(" ");
if (input.length == 0) return super.handleChatMessage(user, message);
for (ICommand command : ClassicProtocolCommands.INSTANCE.commands) {
if (input[0].equalsIgnoreCase(command.name())) {
command.execute(Arrays.copyOfRange(input, 1, input.length));
return true;
}
}
}
} catch (Throwable e) {
ViaLegacy.getPlatform().getLogger().log(Level.WARNING, "Error handling custom classic command", e);
}
return super.handleChatMessage(user, message);
}
}

View File

@ -0,0 +1,79 @@
{
"words.viafabricplus.settings": "Paramètres",
"words.viafabricplus.on": "Activé",
"words.viafabricplus.off": "Désactivé",
"words.viafabricplus.lt": "Gauche; Haut",
"words.viafabricplus.rt": "Droite; Haut",
"words.viafabricplus.lb": "Gauche; Bas",
"words.viafabricplus.rb": "Droite; Bas",
"words.viafabricplus.cancel": "Annuler",
"words.viafabricplus.cancelreset": "Annuler et Réinitialiser",
"words.viafabricplus.logout": "Se déconnecter",
"words.viafabricplus.online": "Mode en ligne",
"words.viafabricplus.reset": "Réinitialiser",
"words.viafabricplus.copy": "Copier le code",
"general.viafabricplus.secret": "Montrer les Super Secret Settings",
"general.viafabricplus.extrainformation": "Afficher des informations supplémentaires dans le Hud de debug",
"general.viafabricplus.classicloading": "Afficher la progression du chargement classique dans l'écran de connexion",
"general.viafabricplus.main": "Orientation du bouton principal",
"general.viafabricplus.creative": "Supprimer les éléments non disponibles de l'inventaire créatif",
"general.viafabricplus.classiccommands": "Autoriser l'utilisation de la commande de protocole classique",
"general.viafabricplus.protocolsync": "Modifier automatiquement les paramètres en fonction de la version utilisée",
"general.viafabricplus.autodetect": "Détecter automatiquement la version",
"experimental.viafabricplus.chunkborderfix": "Réparer les bordures de Chunk",
"experimental.viafabricplus.watermovement": "Détection des bords du mouvement de l'eau",
"experimental.viafabricplus.fontcachefix": "Correction du cache de polices",
"debug.viafabricplus.sequence": "Désactiver le séquençage",
"debug.viafabricplus.merchant": "Lisser les écrans des marchands",
"debug.viafabricplus.postfix": "Exécuter les entrées de manière synchronisée",
"debug.viafabricplus.sneakinstant": "Sneak instantané",
"debug.viafabricplus.inventory": "Envoyer le paquet d'inventaire ouvert",
"debug.viafabricplus.cooldown": "Supprimer les temps de recharge",
"debug.viafabricplus.idle": "Envoyer le paquet d'inactivité",
"debug.viafabricplus.attribute": "Remplacer les modificateurs d'attribut",
"debug.viafabricplus.replacesneak": "Remplacer le sneaking",
"debug.viafabricplus.longsneak": "Sneaking prolongé",
"debug.viafabricplus.legacypseeds": "Vitesses d'exploitation minière héritées",
"authentication.viafabricplus.betacraft": "Utiliser l'authentification BetaCraft",
"authentication.viafabricplus.verify": "Autoriser ViaLegacy à appeler joinServer() pour vérifier la session",
"authentication.viafabricplus.fail": "Déconnecter si l'appel joinServer() échoue",
"authentication.viafabricplus.classicube": "Forcer la version CPE si ClassiCube est utilisé",
"authentication.viafabricplus.spoof": "Fausser le nom d'utilisateur pour le nom ClassiCube si ClassiCube est utilisé",
"authentication.viafabricplus.skin": "Permettre à ViaLegacy de charger les skins dans les versions héritées",
"authentication.viafabricplus.bedrock": "Cliquer pour définir un compte pour l'édition Bedrock",
"visual.viafabricplus.secure": "Désactiver l'avertissement de chat sécurisé",
"visual.viafabricplus.indicator": "Masquer l'indicateur de signature",
"visual.viafabricplus.jigsaw": "Supprimer les fonctionnalités plus récentes de l'écran Jigsaw",
"visual.viafabricplus.stoneslab": "Remplacer la dalle en chêne pétrifiée",
"visual.viafabricplus.armor": "Émuler l'HUD d'armure",
"visual.viafabricplus.command": "Supprimer les fonctionnalités plus récentes de l'écran du bloc de commande",
"visual.viafabricplus.oof": "Remplacer le son de blessure par le son OOF",
"visual.viafabricplus.betahud": "Supprimer les nouveaux éléments de l'HUD",
"visual.viafabricplus.classic": "Remplacer l'inventaire créatif",
"visual.viafabricplus.walkanimation": "Ancienne animation de marche",
"visual.viafabricplus.sodium": "Corriger le rendu de chunk de Sodium",
"bedrocklogin.viafabricplus.text": "Votre navigateur devrait s'être ouvert. Veuillez entrer le code suivant: %s. Fermer cette fenêtre annulera le processus!",
"bedrocklogin.viafabricplus.error": "Une erreur s'est produite ! Veuillez consulter latest.log pour plus d'informations. Veuillez signaler le bogue à l'adresse : \nhttps://github.com/FlorianMichael/ViaFabricPlus/issues",
"forceversion.viafabricplus.title": "Veuillez sélectionner la version avec laquelle le serveur doit être pingé/connecté",
"classicube.viafabricplus.account": "Vous pouvez créer un compte ici : https://www.classicube.net/",
"classicube.viafabricplus.loading": "Chargement des informations de profil et de la liste des serveurs...",
"classicube.viafabricplus.error.token": "Jeton incorrect. ViaFabricPlus est à jour ?",
"classicube.viafabricplus.error.username": "Nom d'utilisateur invalide.",
"classicube.viafabricplus.error.password": "Mot de passe invalide.",
"classicube.viafabricplus.error.verification": "L'utilisateur n'a pas encore vérifié son adresse e-mail.",
"classicube.viafabricplus.error.logincode": "L'authentification multifacteur a été demandée. Veuillez vérifier votre courrier électronique.",
"classicube.viafabricplus.warning": "Cette fonctionnalité enverra des requêtes API à l'API ClassiCube.",
"betacraft.viafabricplus.warning": "Appuyer sur ce bouton enverra des requêtes API à betacraft.uk/serverlist",
"betacraft.viafabricplus.error": "Quelque chose s'est mal passé ! Veuillez réessayer plus tard."
}

View File

@ -1,7 +1,7 @@
{
"words.viafabricplus.settings": "设置",
"words.viafabricplus.on": "开",
"words.viafabricplus.off": "关",
"words.viafabricplus.on": "开",
"words.viafabricplus.off": "关",
"words.viafabricplus.lt": "左上",
"words.viafabricplus.rt": "右上",
"words.viafabricplus.lb": "左下",
@ -14,12 +14,17 @@
"words.viafabricplus.copy": "复制代码",
"general.viafabricplus.secret": "显示“Super Secret Settings”超级秘密设置",
"general.viafabricplus.extrainformation": "在\u00a76[调试]\u00a7rF3中显示额外信息",
"general.viafabricplus.extrainformation": "在 \u00a76[调试]\u00a7r (F3) 中显示额外信息",
"general.viafabricplus.classicloading": "在连接服务器时使用旧版进度显示",
"general.viafabricplus.main": "模组按钮位置",
"general.viafabricplus.creative": "从创造模式选项内移除不可用的物品",
"general.viafabricplus.classiccommands": "允许使用旧版命令协议",
"general.viafabricplus.protocolsync": "自动根据所选版本调整设置",
"general.viafabricplus.autodetect": "自动检测版本",
"experimental.viafabricplus.chunkborderfix": "修复区块边界",
"experimental.viafabricplus.watermovement": "水中移动边缘检测",
"experimental.viafabricplus.fontcachefix": "修复字体缓存",
"debug.viafabricplus.sequence": "禁用排序",
"debug.viafabricplus.merchant": "平滑屏幕",
@ -39,7 +44,7 @@
"authentication.viafabricplus.classicube": "如果使用 ClassicCube MP Pass则强制 CPE 版本",
"authentication.viafabricplus.spoof": "如果使用 ClassiCube ,则显示为 ClassiCube 名称",
"authentication.viafabricplus.skin": "允许 ViaLegacy 加载旧版本皮肤",
"authentication.viafabricplus.bedrock": "点击以设置基岩版账",
"authentication.viafabricplus.bedrock": "点击以设置基岩版账",
"visual.viafabricplus.secure": "禁用安全聊天警告",
"visual.viafabricplus.indicator": "隐藏聊天签名提示",
@ -51,24 +56,24 @@
"visual.viafabricplus.betahud": "移除新的 HUD 要素(包括饥饿值、护甲值)",
"visual.viafabricplus.classic": "将创造模式物品栏替换为旧版本样式",
"visual.viafabricplus.walkanimation": "旧版行走动画",
"visual.viafabricplus.sodium": "修复钠Sodium渲染器",
"visual.viafabricplus.sodium": "修复钠 (Sodium) 渲染器",
"bedrocklogin.viafabricplus.text": "你的浏览器现在应该打开了。\n请输入这个代码%s\n关闭这个屏幕等于取消操作",
"bedrocklogin.viafabricplus.error": "发生错误!详情请查看 latest.log\n请在这个链接反馈 BUG\nhttps://github.com/FlorianMichael/ViaFabricPlus/issues",
"forceversion.viafabricplus.title": "请选择连接这个服务器要使用的版本",
"classicube.viafabricplus.account": "您可以这里创建一个账户: https://www.classicube.net/",
"classicube.viafabricplus.loading": "正在加载个人信息和服务器列表···",
"classicube.viafabricplus.account": "您可以这里创建一个账户: https://www.classicube.net",
"classicube.viafabricplus.loading": "正在加载个人信息和服务器列表",
"classicube.viafabricplus.error.token": "Token 不正确。你的 ViaFabricPlus 是否已经过时?",
"classicube.viafabricplus.error.username": "无效的用户名",
"classicube.viafabricplus.error.password": "无效的密码",
"classicube.viafabricplus.error.verification": "用戶尚未验证电子邮箱地址",
"classicube.viafabricplus.error.verification": "用戶尚未验证电子邮箱地址",
"classicube.viafabricplus.error.logincode": "已请求身份验证。请查看你的电子邮箱!",
"classicube.viafabricplus.warning": "该功能会向 ClassiCube API 发送请求",
"classicube.viafabricplus.warning": "该功能会向 ClassiCube API 发送请求",
"betacraft.viafabricplus.warning": "点击这个按钮会向\"betacraft.uk/serverlist\"发送API请求",
"betacraft.viafabricplus.warning": "点击这个按钮会向 \"betacraft.uk/serverlist\" 发送 API 请求",
"betacraft.viafabricplus.error": "出错了! 请稍后再试!"
}

View File

@ -8,56 +8,72 @@
"words.viafabricplus.rb": "右下",
"words.viafabricplus.cancel": "取消",
"words.viafabricplus.cancelreset": "返回並重置",
"words.viafabricplus.logout": "登出",
"words.viafabricplus.online": "線上模式",
"words.viafabricplus.reset": "重置",
"words.viafabricplus.copy": "複製程式碼",
"general.viafabricplus.secret": "顯示“Super Secret Settings”超級秘密設定",
"general.viafabricplus.extrainformation": "在\u00a76[調試]\u00a7rF3中顯示額外資訊",
"general.viafabricplus.classicloading": "在連接伺服器時使用舊版加載進度顯示",
"general.viafabricplus.extrainformation": "在 \u00a76[調試]\u00a7r (F3) 中顯示額外資訊",
"general.viafabricplus.classicloading": "在連接伺服器時使用舊版進度顯示",
"general.viafabricplus.main": "模組按鈕位置",
"general.viafabricplus.creative": "從創造模式選項內移除不可用的物品",
"general.viafabricplus.classiccommands": "允許使用舊版命令協定",
"general.viafabricplus.creative": "從創造模式物品欄內移除不可用的物品",
"general.viafabricplus.classiccommands": "允許使用舊版指令協議",
"general.viafabricplus.protocolsync": "自動根據所選版本調整設定",
"general.viafabricplus.autodetect": "自動偵測版本",
"experimental.viafabricplus.chunkborderfix": "修復區塊邊界",
"experimental.viafabricplus.watermovement": "水中移動邊緣偵測",
"experimental.viafabricplus.fontcachefix": "修復字體緩存",
"debug.viafabricplus.sequence": "禁用排序",
"debug.viafabricplus.merchant": "平滑荧幕顯示",
"debug.viafabricplus.merchant": "平滑螢幕",
"debug.viafabricplus.postfix": "同步執行輸入",
"debug.viafabricplus.sneakinstant": "瞬間潜行",
"debug.viafabricplus.inventory": "發送“打開物品欄”數包",
"debug.viafabricplus.sneakinstant": "瞬間行",
"debug.viafabricplus.inventory": "發送“打開物品欄”數包",
"debug.viafabricplus.cooldown": "移除攻擊冷卻",
"debug.viafabricplus.idle": "發送“空閒”數包",
"debug.viafabricplus.attribute": "替換内容修飾符為舊版本樣式",
"debug.viafabricplus.replacesneak": "替換行樣式",
"debug.viafabricplus.longsneak": "一直潜行",
"debug.viafabricplus.legacypseeds": "遠古版本挖掘速度",
"debug.viafabricplus.idle": "發送“空閒”數包",
"debug.viafabricplus.attribute": "替換屬性修飾符為舊版本樣式",
"debug.viafabricplus.replacesneak": "替換行樣式",
"debug.viafabricplus.longsneak": "保持潛行",
"debug.viafabricplus.legacypseeds": "老舊版本挖掘速度",
"authentication.viafabricplus.betacraft": "使用 BetaCraft 身份驗證",
"authentication.viafabricplus.verify": "允許 ViaLegacy 調用 joinServer() 來驗證會話",
"authentication.viafabricplus.fail": "joinServer() 調用失敗時斷開連接",
"authentication.viafabricplus.classicube": "如果使用 ClassicCube MP Pass則強制 CPE 版本",
"authentication.viafabricplus.bedrock": "點擊這裡以登入基岩版帳號",
"authentication.viafabricplus.spoof": "如果使用 ClassiCube ,則顯示為 ClassiCube 名稱",
"authentication.viafabricplus.skin": "允許 ViaLegacy 載入舊版本外觀",
"authentication.viafabricplus.bedrock": "點擊以設定基岩版帳戶",
"visual.viafabricplus.secure": "禁用安全聊天警告",
"visual.viafabricplus.indicator": "隱藏聊天簽名提示",
"visual.viafabricplus.jigsaw": "從方塊介面中移除新版本特性",
"visual.viafabricplus.stoneslab": "替換石化橡木臺階",
"visual.viafabricplus.armor": "類比護甲值(護甲值不顯示請打開)",
"visual.viafabricplus.command": "從令方塊編輯介面中移除新版本特性",
"visual.viafabricplus.jigsaw": "從拼圖方塊介面中移除新版本特性",
"visual.viafabricplus.stoneslab": "替換石化橡木半磚",
"visual.viafabricplus.armor": "模擬護甲值(護甲值不顯示請打開)",
"visual.viafabricplus.command": "從令方塊編輯介面中移除新版本特性",
"visual.viafabricplus.oof": "將受傷音效替換為舊版本的“oof/噢!”",
"visual.viafabricplus.betahud": "移除新HUD要素包括饑餓值、護甲值",
"visual.viafabricplus.betahud": "移除新HUD 要素(包括饑餓值、護甲值)",
"visual.viafabricplus.classic": "將創造模式物品欄替換為舊版本樣式",
"visual.viafabricplus.walkanimation": "舊版行走動畫",
"visual.viafabricplus.sodium": "修復鈉Sodium渲染器",
"visual.viafabricplus.sodium": "修復鈉 (Sodium) 渲染器",
"bedrocklogin.viafabricplus.text": "你的瀏覽器現在應該已經打開了。\n請輸入這個程式碼 %s\n關閉這個荧幕等於取消操作。",
"bedrocklogin.viafabricplus.error": "發生錯誤! 詳情請查看 latest.log \n請在這個網站報告BUG \nhttps://github.com/FlorianMichael/ViaFabricPlus/issues",
"bedrocklogin.viafabricplus.text": "你的瀏覽器現在應該打開了。\n請輸入這個程式碼%s\n關閉這個螢幕等於取消操作",
"bedrocklogin.viafabricplus.error": "發生錯誤!詳情請查看 latest.log\n請在這個連結回饋 BUG\nhttps://github.com/FlorianMichael/ViaFabricPlus/issues",
"forceversion.viafabricplus.title": "請選擇連接這個伺服器要使用的版本",
"forceversion.viafabricplus.title": "請選擇連接這個伺服器要使用的版本",
"classicube.viafabricplus.account": "您可以在此處創建帳戶: https://www.classicube.net/",
"classicube.viafabricplus.loading": "正在加載个人資訊和伺服器列表",
"classicube.viafabricplus.account": "您可以這裡創建一個帳戶: https://www.classicube.net",
"classicube.viafabricplus.loading": "正在載入個人資訊和伺服器清單…",
"classicube.viafabricplus.error.token": "Token不正確。 你的ViaFabricPlus已經過時了嗎",
"classicube.viafabricplus.error.token": "Token 不正確。你的 ViaFabricPlus 是否已經過時?",
"classicube.viafabricplus.error.username": "無效的用戶名",
"classicube.viafabricplus.error.password": "無效的密碼",
"classicube.viafabricplus.error.verification": "用戶尚未驗證其電子郵件。",
"classicube.viafabricplus.error.logincode": "已請求身份驗證。 請檢查您的電子郵件!"
"classicube.viafabricplus.error.verification": "用戶尚未驗證電子郵箱位址",
"classicube.viafabricplus.error.logincode": "已請求身份驗證。請查看你的電子郵箱!",
"classicube.viafabricplus.warning": "該功能會向 ClassiCube API 發送請求",
"betacraft.viafabricplus.warning": "點擊這個按鈕會向 \"betacraft.uk/serverlist\" 發送 API 請求",
"betacraft.viafabricplus.error": "出錯了! 請稍後再試!"
}