Removed ClassicProtocolCommands, Implemented ViaVersion commands

This commit is contained in:
FlorianMichael 2023-04-30 21:34:54 +02:00
parent bfb28f7835
commit ecddd21132
13 changed files with 215 additions and 187 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

@ -14,7 +14,7 @@ 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;
@ -62,7 +61,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

@ -18,20 +18,16 @@
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 de.florianmichael.viafabricplus.util.ScreenUtil;
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) {
public void sendFeedback(final String message) {
try {
Via.getManager().getProviders().get(ClassicCustomCommandProvider.class).sendFeedback(currentViaConnection(), ScreenUtil.prefixedMessage(message));
} catch (Exception e) {
@ -39,13 +35,7 @@ public interface ICommand {
}
}
default void sendUsage() {
sendFeedback(Formatting.RED + "Use: " + ClassicProtocolCommands.COMMAND_PREFIX + name() + (description() != null ? " " + description() : ""));
}
default UserConnection currentViaConnection() {
public UserConnection currentViaConnection() {
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,16 @@
*/
package de.florianmichael.viafabricplus.definition.c0_30.command.impl;
import com.viaversion.viaversion.api.command.ViaCommandSender;
import com.viaversion.viaversion.api.command.ViaSubCommand;
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 +34,16 @@ 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 {
public boolean execute(ViaCommandSender sender, String[] args) {
final UserConnection connection = currentViaConnection();
if (!connection.has(ExtensionProtocolMetadataStorage.class)) {
this.sendFeedback(Formatting.RED + "This command is only for " + LegacyProtocolVersion.c0_30cpe.getName());
return;
return false;
}
((IExtensionProtocolMetadataStorage) connection.get(ExtensionProtocolMetadataStorage.class)).getServerExtensions().forEach((extension, version) -> {
this.sendFeedback(Formatting.GREEN + extension.getName() + Formatting.GOLD + " v" + version);
});
((IExtensionProtocolMetadataStorage) connection.get(ExtensionProtocolMetadataStorage.class)).getServerExtensions().forEach((extension, version) -> this.sendFeedback(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,15 +32,19 @@ 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 {
public String usage() {
return name() + " " + "<Time (Long)>";
}
@Override
public boolean execute(ViaCommandSender sender, String[] args) {
final UserConnection connection = currentViaConnection();
if (!connection.has(TimeLockStorage.class)) {
this.sendFeedback(Formatting.RED + "This command is only for <=" + LegacyProtocolVersion.a1_0_16toa1_0_16_2.getName());
return;
return false;
}
try {
if (args.length == 1) {
@ -47,10 +52,11 @@ public class SetTimeCommand implements ICommand {
connection.get(TimeLockStorage.class).setTime(time);
this.sendFeedback(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

@ -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;
@ -119,6 +129,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 +182,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

@ -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);
}
}