Initial plugin message and forum support for GeyserAddons

This commit is contained in:
RednedEpic 2020-08-08 16:37:01 -05:00
parent d49856cd7f
commit d951ee83b4
8 changed files with 332 additions and 3 deletions

View file

@ -40,6 +40,7 @@ import org.geysermc.connector.common.PlatformType;
import org.geysermc.connector.configuration.GeyserConfiguration; import org.geysermc.connector.configuration.GeyserConfiguration;
import org.geysermc.connector.metrics.Metrics; import org.geysermc.connector.metrics.Metrics;
import org.geysermc.connector.network.ConnectorServerEventHandler; import org.geysermc.connector.network.ConnectorServerEventHandler;
import org.geysermc.connector.network.addon.AddonListenerRegistry;
import org.geysermc.connector.network.remote.RemoteServer; import org.geysermc.connector.network.remote.RemoteServer;
import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.BiomeTranslator; import org.geysermc.connector.network.translators.BiomeTranslator;
@ -136,6 +137,7 @@ public class GeyserConnector {
PotionMixRegistry.init(); PotionMixRegistry.init();
SoundRegistry.init(); SoundRegistry.init();
SoundHandlerRegistry.init(); SoundHandlerRegistry.init();
AddonListenerRegistry.init();
if (platformType != PlatformType.STANDALONE) { if (platformType != PlatformType.STANDALONE) {
DockerCheck.check(bootstrap); DockerCheck.check(bootstrap);

View file

@ -30,6 +30,7 @@ import com.nukkitx.protocol.bedrock.packet.*;
import org.geysermc.connector.common.AuthType; import org.geysermc.connector.common.AuthType;
import org.geysermc.connector.configuration.GeyserConfiguration; import org.geysermc.connector.configuration.GeyserConfiguration;
import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.network.addon.FormAddonListener;
import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslatorRegistry; import org.geysermc.connector.network.translators.PacketTranslatorRegistry;
import org.geysermc.connector.utils.LoginEncryptionUtils; import org.geysermc.connector.utils.LoginEncryptionUtils;
@ -91,8 +92,12 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
@Override @Override
public boolean handle(ModalFormResponsePacket packet) { public boolean handle(ModalFormResponsePacket packet) {
if (packet.getFormId() == LoginEncryptionUtils.AUTH_FORM_ID || packet.getFormId() == LoginEncryptionUtils.AUTH_DETAILS_FORM_ID) {
return LoginEncryptionUtils.authenticateFromForm(session, connector, packet.getFormId(), packet.getFormData()); return LoginEncryptionUtils.authenticateFromForm(session, connector, packet.getFormId(), packet.getFormData());
} }
FormAddonListener.get().handleResponse(this.session, packet);
return true;
}
private boolean couldLoginUserByName(String bedrockUsername) { private boolean couldLoginUserByName(String bedrockUsername) {
if (connector.getConfig().getUserAuths() != null) { if (connector.getConfig().getUserAuths() != null) {

View file

@ -0,0 +1,60 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.connector.network.addon;
import com.nukkitx.protocol.bedrock.BedrockPacket;
import io.netty.buffer.ByteBuf;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.geysermc.connector.network.session.GeyserSession;
/**
* A listener that listens for plugin messages from
* GeyserAddons.
*/
@Getter
@AllArgsConstructor
public abstract class AddonListener<T extends BedrockPacket> {
public static final String PLUGIN_MESSAGE_CHANNEL = "geyser:addons";
private String subChannel;
/**
* Called when a message is received
* @param session the session receiving the message
* @param message the message
*/
public abstract void onMessageReceive(GeyserSession session, ByteBuf message);
/**
* Handles a response from the given packet.
*
* @param session the session listening
* @param response the response
*/
public abstract void handleResponse(GeyserSession session, T response);
}

View file

@ -0,0 +1,62 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.connector.network.addon;
import java.util.HashMap;
import java.util.Map;
/**
* A registry containing all the {@link AddonListener}s listening
* for plugin messages.
*/
public class AddonListenerRegistry {
private static final Map<String, AddonListener<?>> LISTENERS = new HashMap<>();
private AddonListenerRegistry() {
}
public static void init() {
registerListener(FormAddonListener.get());
}
/**
* Returns all the {@link AddonListener}s listening for
* plugin messages.
*
* Key: the subchannel the listener is listening on
* Value: the {@link AddonListener}
*
* @return all the {@link AddonListener}s listening for plugin messages.
*/
public static Map<String, AddonListener<?>> getListeners() {
return LISTENERS;
}
private static void registerListener(AddonListener<?> listener) {
LISTENERS.put(listener.getSubChannel(), listener);
}
}

View file

@ -0,0 +1,73 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.connector.network.addon;
import com.github.steveice10.mc.protocol.packet.ingame.client.ClientPluginMessagePacket;
import com.nukkitx.protocol.bedrock.packet.ModalFormRequestPacket;
import com.nukkitx.protocol.bedrock.packet.ModalFormResponsePacket;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.utils.NetworkUtils;
public class FormAddonListener extends AddonListener<ModalFormResponsePacket> {
private static final FormAddonListener INSTANCE = new FormAddonListener();
public static final String NAME = "form";
public FormAddonListener() {
super(NAME);
}
@Override
public void onMessageReceive(GeyserSession session, ByteBuf message) {
ModalFormRequestPacket packet = new ModalFormRequestPacket();
packet.setFormId(message.readInt());
packet.setFormData(NetworkUtils.readString(message));
session.sendUpstreamPacket(packet);
}
@Override
public void handleResponse(GeyserSession session, ModalFormResponsePacket packet) {
ByteBuf buffer = ByteBufAllocator.DEFAULT.buffer();
try {
NetworkUtils.writeString(buffer, this.getSubChannel());
buffer.writeInt(packet.getFormId());
NetworkUtils.writeString(buffer, packet.getFormData());
byte[] bytes = new byte[buffer.readableBytes()];
buffer.readBytes(bytes);
session.sendDownstreamPacket(new ClientPluginMessagePacket(PLUGIN_MESSAGE_CHANNEL, bytes));
} finally {
buffer.release();
}
}
public static FormAddonListener get() {
return INSTANCE;
}
}

View file

@ -25,15 +25,21 @@
package org.geysermc.connector.network.translators.java; package org.geysermc.connector.network.translators.java;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.network.addon.AddonListener;
import org.geysermc.connector.network.addon.AddonListenerRegistry;
import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.PacketTranslator;
import org.geysermc.connector.network.translators.Translator; import org.geysermc.connector.network.translators.Translator;
import com.github.steveice10.mc.protocol.packet.ingame.client.ClientPluginMessagePacket; import com.github.steveice10.mc.protocol.packet.ingame.client.ClientPluginMessagePacket;
import com.github.steveice10.mc.protocol.packet.ingame.server.ServerPluginMessagePacket; import com.github.steveice10.mc.protocol.packet.ingame.server.ServerPluginMessagePacket;
import org.geysermc.connector.utils.NetworkUtils;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Map;
@Translator(packet = ServerPluginMessagePacket.class) @Translator(packet = ServerPluginMessagePacket.class)
public class JavaPluginMessageTranslator extends PacketTranslator<ServerPluginMessagePacket> { public class JavaPluginMessageTranslator extends PacketTranslator<ServerPluginMessagePacket> {
@ -56,6 +62,23 @@ public class JavaPluginMessageTranslator extends PacketTranslator<ServerPluginMe
new ClientPluginMessagePacket(packet.getChannel(), brandData) new ClientPluginMessagePacket(packet.getChannel(), brandData)
); );
} }
if (packet.getChannel().equals("minecraft:register")) {
session.sendDownstreamPacket(new ClientPluginMessagePacket(packet.getChannel(), AddonListener.PLUGIN_MESSAGE_CHANNEL.getBytes(StandardCharsets.UTF_8)));
}
if (!packet.getChannel().equals(AddonListener.PLUGIN_MESSAGE_CHANNEL)) {
return;
}
for (Map.Entry<String, AddonListener<?>> entry : AddonListenerRegistry.getListeners().entrySet()) {
ByteBuf buffer = Unpooled.wrappedBuffer(packet.getData());
String subChannel = NetworkUtils.readString(buffer);
if (!subChannel.equals(entry.getKey())) {
continue;
}
entry.getValue().onMessageReceive(session, buffer);
}
} }
private static byte[] writeVarInt(int value) { private static byte[] writeVarInt(int value) {

View file

@ -152,8 +152,8 @@ public class LoginEncryptionUtils {
session.sendUpstreamPacketImmediately(packet); session.sendUpstreamPacketImmediately(packet);
} }
private static int AUTH_FORM_ID = 1336; public static int AUTH_FORM_ID = 1336;
private static int AUTH_DETAILS_FORM_ID = 1337; public static int AUTH_DETAILS_FORM_ID = 1337;
public static void showLoginWindow(GeyserSession session) { public static void showLoginWindow(GeyserSession session) {
String userLanguage = session.getClientData().getLanguageCode(); String userLanguage = session.getClientData().getLanguageCode();

View file

@ -0,0 +1,104 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.connector.utils;
import io.netty.buffer.ByteBuf;
import java.nio.charset.StandardCharsets;
public class NetworkUtils {
public static String readString(ByteBuf buf) {
return new String(readByteArray(buf), StandardCharsets.UTF_8);
}
public static void writeString(ByteBuf buf, String string) {
writeByteArray(buf, string.getBytes(StandardCharsets.UTF_8));
}
public static byte[] readByteArray(ByteBuf buf) {
byte[] bytes = new byte[readUnsignedVarInt(buf)];
buf.readBytes(bytes);
return bytes;
}
public static void writeByteArray(ByteBuf buf, byte[] bytes) {
writeUnsignedVarInt(buf, bytes.length);
buf.writeBytes(bytes);
}
public static int readVarInt(ByteBuf buf) {
int i = 0, j = 0;
while (true) {
int k = buf.readByte();
i |= (k & 0x7F) << j++ * 7;
if (j > 5) {
throw new RuntimeException("VarInt was too big!");
}
if ((k & 0x80) != 128) {
break;
}
}
return i;
}
public static void writeVarInt(ByteBuf buf, int value) {
while (true) {
if ((value & 0xFFFFFF80) == 0) {
buf.writeByte(value);
return;
}
buf.writeByte(value & 0x7F | 0x80);
value >>>= 7;
}
}
public static int readUnsignedVarInt(ByteBuf buf) {
int i = 0;
for (int j = 0; j < 64; j += 7) {
final byte b = buf.readByte();
i |= (long) (b & 0x7F) << j;
if ((b & 0x80) == 0) {
return i;
}
}
throw new RuntimeException("Varint was too big!");
}
public static void writeUnsignedVarInt(ByteBuf buf, int value) {
long i = value & 0xFFFFFFFFL;
while (true) {
if ((i & ~0x7FL) == 0) {
buf.writeByte((int) i);
return;
} else {
buf.writeByte((byte) ((i & 0x7F) | 0x80));
i >>>= 7;
}
}
}
}