wip modding api: PluginChannelHandler

This commit is contained in:
Bixilon 2020-06-19 14:25:56 +02:00
parent 967e612257
commit 3630aecf5f
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
5 changed files with 197 additions and 16 deletions

View File

@ -0,0 +1,21 @@
/*
* Codename Minosoft
* Copyright (C) 2020 Moritz Zwerger
*
* 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 <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.protocol.modding.channels;
import de.bixilon.minosoft.protocol.protocol.InByteBuffer;
public interface ChannelHandler {
void handle(PluginChannelHandler handler, InByteBuffer buffer);
}

View File

@ -0,0 +1,38 @@
/*
* Codename Minosoft
* Copyright (C) 2020 Moritz Zwerger
*
* 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 <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.protocol.modding.channels;
public enum DefaultPluginChannels {
MC_BRAND("MC|Brand");
final String name;
DefaultPluginChannels(String name) {
this.name = name;
}
public static DefaultPluginChannels byName(String name) {
for (DefaultPluginChannels d : values()) {
if (d.getName().equals(name)) {
return d;
}
}
return null;
}
public String getName() {
return name;
}
}

View File

@ -0,0 +1,112 @@
/*
* Codename Minosoft
* Copyright (C) 2020 Moritz Zwerger
*
* 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 <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.protocol.modding.channels;
import de.bixilon.minosoft.logging.Log;
import de.bixilon.minosoft.protocol.network.Connection;
import de.bixilon.minosoft.protocol.packets.serverbound.play.PacketPluginMessageSending;
import de.bixilon.minosoft.protocol.protocol.InByteBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class PluginChannelHandler {
final Map<String, List<ChannelHandler>> channels;
final List<String> registeredClientChannels;
final List<String> registeredServerChannels;
final Connection connection;
public PluginChannelHandler(Connection connection) {
channels = new HashMap<>();
registeredClientChannels = new ArrayList<>();
registeredServerChannels = new ArrayList<>();
this.connection = connection;
}
public void registerClientHandler(String name, ChannelHandler handler) {
if (channels.get(name) == null) {
// no channel with that name was registered yet
List<ChannelHandler> handlerList = new ArrayList<>();
handlerList.add(handler);
channels.put(name, handlerList);
return;
}
// was registered, appending to list
channels.get(name).add(handler);
}
public void unregisterClientHandler(String name, ChannelHandler handler) {
if (channels.get(name) == null) {
// not registered
return;
}
channels.get(name).remove(handler);
}
public void handle(String name, byte[] data) {
if (name.equals("REGISTER")) {
// register this channel
String toRegisterName = new String(data);
registeredClientChannels.add(toRegisterName);
Log.debug(String.format("Server registered plugin channel \"%s\"", toRegisterName));
return;
}
if (name.equals("UNREGISTER")) {
// register this channel
String toUnregisterName = new String(data);
registeredClientChannels.remove(toUnregisterName);
Log.debug(String.format("Server unregistered plugin channel \"%s\"", toUnregisterName));
return;
}
// check if channel was registered or if it is a default channel
if (!registeredClientChannels.contains(name) && DefaultPluginChannels.byName(name) == null) {
Log.debug(String.format("Server tried to send data into unregistered plugin channel (name=\"%s\", messageLength=%d)", name, data.length));
return;
}
if (channels.get(name) == null) {
Log.debug(String.format("Can not handle plugin message in channel \"%s\" (messageLength=%d)", name, data.length));
return;
}
for (ChannelHandler handler : channels.get(name)) {
handler.handle(this, new InByteBuffer(data));
}
}
public void sendRawData(String channel, byte[] data) {
connection.sendPacket(new PacketPluginMessageSending(channel, data));
}
public void registerServerChannel(String name) {
if (DefaultPluginChannels.byName(name) != null) {
// channel is a default channel, can not register
throw new IllegalArgumentException(String.format("Can not register default Minecraft plugin channel (name=%s)", name));
}
sendRawData("REGISTER", name.getBytes());
registeredServerChannels.add(name);
}
public void unregisterServerChannel(String name) {
if (DefaultPluginChannels.byName(name) != null) {
// channel is a default channel, can not unregister
throw new IllegalArgumentException(String.format("Can not unregister default Minecraft plugin channel (name=%s)", name));
}
sendRawData("UNREGISTER", name.getBytes());
registeredServerChannels.remove(name);
}
}

View File

@ -13,8 +13,12 @@
package de.bixilon.minosoft.protocol.network;
import de.bixilon.minosoft.Minosoft;
import de.bixilon.minosoft.config.GameConfiguration;
import de.bixilon.minosoft.game.datatypes.Player;
import de.bixilon.minosoft.logging.Log;
import de.bixilon.minosoft.protocol.modding.channels.DefaultPluginChannels;
import de.bixilon.minosoft.protocol.modding.channels.PluginChannelHandler;
import de.bixilon.minosoft.protocol.packets.ClientboundPacket;
import de.bixilon.minosoft.protocol.packets.ServerboundPacket;
import de.bixilon.minosoft.protocol.packets.serverbound.handshaking.PacketHandshake;
@ -33,11 +37,11 @@ public class Connection {
private final int port;
private final Network network;
private final PacketHandler handler;
private final PluginChannelHandler pluginChannelHandler;
private final ArrayList<ClientboundPacket> handlingQueue;
Thread handleThread;
private Player player;
private ConnectionState state = ConnectionState.DISCONNECTED;
Thread handleThread;
private boolean onlyPing;
public Connection(String host, int port) {
@ -46,6 +50,8 @@ public class Connection {
network = new Network(this);
handlingQueue = new ArrayList<>();
handler = new PacketHandler(this);
pluginChannelHandler = new PluginChannelHandler(this);
registerDefaultChannels();
}
/**
@ -130,6 +136,10 @@ public class Connection {
return player;
}
public void setPlayer(Player player) {
this.player = player;
}
public void sendPacket(ServerboundPacket p) {
network.sendPacket(p);
}
@ -157,11 +167,20 @@ public class Connection {
handleThread.start();
}
public void setPlayer(Player player) {
this.player = player;
}
public void sendChatMessage(String message) {
sendPacket(new PacketChatMessage(message));
}
public PluginChannelHandler getPluginChannelHandler() {
return pluginChannelHandler;
}
public void registerDefaultChannels() {
// MC|Brand
getPluginChannelHandler().registerClientHandler(DefaultPluginChannels.MC_BRAND.getName(), (handler, buffer) -> {
Log.info(String.format("Server is running %s on version %s", new String(buffer.readBytes(buffer.getBytesLeft())), getVersion().getName()));
getPluginChannelHandler().sendRawData(DefaultPluginChannels.MC_BRAND.getName(), (Minosoft.getConfig().getBoolean(GameConfiguration.NETWORK_FAKE_CLIENT_BRAND) ? "vanilla" : "Minosoft").getBytes());
});
}
}

View File

@ -13,8 +13,6 @@
package de.bixilon.minosoft.protocol.protocol;
import de.bixilon.minosoft.Minosoft;
import de.bixilon.minosoft.config.GameConfiguration;
import de.bixilon.minosoft.game.datatypes.GameMode;
import de.bixilon.minosoft.game.datatypes.blocks.Blocks;
import de.bixilon.minosoft.game.datatypes.entities.meta.HumanMetaData;
@ -30,7 +28,6 @@ import de.bixilon.minosoft.protocol.packets.clientbound.status.PacketStatusRespo
import de.bixilon.minosoft.protocol.packets.serverbound.login.PacketEncryptionResponse;
import de.bixilon.minosoft.protocol.packets.serverbound.play.PacketKeepAliveResponse;
import de.bixilon.minosoft.protocol.packets.serverbound.play.PacketPlayerPositionAndRotationSending;
import de.bixilon.minosoft.protocol.packets.serverbound.play.PacketPluginMessageSending;
import javax.crypto.SecretKey;
import java.math.BigInteger;
@ -103,13 +100,7 @@ public class PacketHandler {
}
public void handle(PacketPluginMessageReceiving pkg) {
if (pkg.getChannel().equals("MC|Brand")) {
// server brand received
Log.info(String.format("Server is running %s on version %s", new String(pkg.getData()), connection.getVersion().getName()));
// send back own brand
connection.sendPacket(new PacketPluginMessageSending("MC|Brand", (Minosoft.getConfig().getBoolean(GameConfiguration.NETWORK_FAKE_CLIENT_BRAND) ? "vanilla" : "Minosoft")));
}
connection.getPluginChannelHandler().handle(pkg.getChannel(), pkg.getData());
}
public void handle(PacketSpawnLocation pkg) {