mirror of
https://github.com/Nan1t/NanoLimbo.git
synced 2026-02-10 10:56:13 +01:00
Renamed root packet
This commit is contained in:
27
src/main/java/ua/nanit/limbo/LimboConstants.java
Normal file
27
src/main/java/ua/nanit/limbo/LimboConstants.java
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo;
|
||||
|
||||
public final class LimboConstants {
|
||||
|
||||
public static final String VELOCITY_INFO_CHANNEL = "velocity:player_info";
|
||||
public static final String BRAND_CHANNEL = "minecraft:brand";
|
||||
|
||||
private LimboConstants() {}
|
||||
|
||||
}
|
||||
33
src/main/java/ua/nanit/limbo/NanoLimbo.java
Normal file
33
src/main/java/ua/nanit/limbo/NanoLimbo.java
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo;
|
||||
|
||||
import ua.nanit.limbo.server.LimboServer;
|
||||
import ua.nanit.limbo.server.Logger;
|
||||
|
||||
public final class NanoLimbo {
|
||||
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
new LimboServer().start();
|
||||
} catch (Exception e) {
|
||||
Logger.error("Cannot start server: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
253
src/main/java/ua/nanit/limbo/configuration/LimboConfig.java
Normal file
253
src/main/java/ua/nanit/limbo/configuration/LimboConfig.java
Normal file
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.configuration;
|
||||
|
||||
import org.spongepowered.configurate.ConfigurationNode;
|
||||
import org.spongepowered.configurate.ConfigurationOptions;
|
||||
import org.spongepowered.configurate.serialize.TypeSerializerCollection;
|
||||
import org.spongepowered.configurate.yaml.YamlConfigurationLoader;
|
||||
import ua.nanit.limbo.util.Colors;
|
||||
import ua.nanit.limbo.server.data.BossBar;
|
||||
import ua.nanit.limbo.server.data.InfoForwarding;
|
||||
import ua.nanit.limbo.server.data.PingData;
|
||||
import ua.nanit.limbo.server.data.Title;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.SocketAddress;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
public final class LimboConfig {
|
||||
|
||||
private final Path root;
|
||||
|
||||
private SocketAddress address;
|
||||
private int maxPlayers;
|
||||
private PingData pingData;
|
||||
|
||||
private String dimensionType;
|
||||
private int gameMode;
|
||||
|
||||
private boolean useBrandName;
|
||||
private boolean useJoinMessage;
|
||||
private boolean useBossBar;
|
||||
private boolean useTitle;
|
||||
private boolean usePlayerList;
|
||||
private boolean useHeaderAndFooter;
|
||||
|
||||
private String brandName;
|
||||
private String joinMessage;
|
||||
private BossBar bossBar;
|
||||
private Title title;
|
||||
|
||||
private String playerListUsername;
|
||||
private String playerListHeader;
|
||||
private String playerListFooter;
|
||||
|
||||
private InfoForwarding infoForwarding;
|
||||
private long readTimeout;
|
||||
private int debugLevel;
|
||||
|
||||
private boolean useEpoll;
|
||||
private int bossGroupSize;
|
||||
private int workerGroupSize;
|
||||
|
||||
public LimboConfig(Path root) {
|
||||
this.root = root;
|
||||
}
|
||||
|
||||
public void load() throws Exception {
|
||||
ConfigurationOptions options = ConfigurationOptions.defaults().serializers(getSerializers());
|
||||
YamlConfigurationLoader loader = YamlConfigurationLoader.builder()
|
||||
.source(this::getReader)
|
||||
.defaultOptions(options)
|
||||
.build();
|
||||
|
||||
ConfigurationNode conf = loader.load();
|
||||
|
||||
address = conf.node("bind").get(SocketAddress.class);
|
||||
maxPlayers = conf.node("maxPlayers").getInt();
|
||||
pingData = conf.node("ping").get(PingData.class);
|
||||
dimensionType = conf.node("dimension").getString("the_end");
|
||||
if (dimensionType.equalsIgnoreCase("nether")) {
|
||||
dimensionType = "the_nether";
|
||||
}
|
||||
if (dimensionType.equalsIgnoreCase("end")) {
|
||||
dimensionType = "the_end";
|
||||
}
|
||||
gameMode = conf.node("gameMode").getInt();
|
||||
useBrandName = conf.node("brandName", "enable").getBoolean();
|
||||
useJoinMessage = conf.node("joinMessage", "enable").getBoolean();
|
||||
useBossBar = conf.node("bossBar", "enable").getBoolean();
|
||||
useTitle = conf.node("title", "enable").getBoolean();
|
||||
usePlayerList = conf.node("playerList", "enable").getBoolean();
|
||||
playerListUsername = conf.node("playerList", "username").getString();
|
||||
useHeaderAndFooter = conf.node("headerAndFooter", "enable").getBoolean();
|
||||
|
||||
if (useBrandName)
|
||||
brandName = conf.node("brandName", "content").getString();
|
||||
|
||||
if (useJoinMessage)
|
||||
joinMessage = Colors.of(conf.node("joinMessage", "text").getString(""));
|
||||
|
||||
if (useBossBar)
|
||||
bossBar = conf.node("bossBar").get(BossBar.class);
|
||||
|
||||
if (useTitle)
|
||||
title = conf.node("title").get(Title.class);
|
||||
|
||||
if (useHeaderAndFooter) {
|
||||
playerListHeader = Colors.of(conf.node("headerAndFooter", "header").getString());
|
||||
playerListFooter = Colors.of(conf.node("headerAndFooter", "footer").getString());
|
||||
}
|
||||
|
||||
infoForwarding = conf.node("infoForwarding").get(InfoForwarding.class);
|
||||
readTimeout = conf.node("readTimeout").getLong();
|
||||
debugLevel = conf.node("debugLevel").getInt();
|
||||
|
||||
useEpoll = conf.node("netty", "useEpoll").getBoolean(true);
|
||||
bossGroupSize = conf.node("netty", "threads", "bossGroup").getInt(1);
|
||||
workerGroupSize = conf.node("netty", "threads", "workerGroup").getInt(4);
|
||||
}
|
||||
|
||||
private BufferedReader getReader() throws IOException {
|
||||
String name = "settings.yml";
|
||||
Path filePath = Paths.get(root.toString(), name);
|
||||
|
||||
if (!Files.exists(filePath)) {
|
||||
InputStream stream = getClass().getResourceAsStream( "/" + name);
|
||||
|
||||
if (stream == null)
|
||||
throw new FileNotFoundException("Cannot find settings resource file");
|
||||
|
||||
Files.copy(stream, filePath);
|
||||
}
|
||||
|
||||
return Files.newBufferedReader(filePath);
|
||||
}
|
||||
|
||||
private TypeSerializerCollection getSerializers() {
|
||||
return TypeSerializerCollection.builder()
|
||||
.register(SocketAddress.class, new SocketAddressSerializer())
|
||||
.register(InfoForwarding.class, new InfoForwarding.Serializer())
|
||||
.register(PingData.class, new PingData.Serializer())
|
||||
.register(BossBar.class, new BossBar.Serializer())
|
||||
.register(Title.class, new Title.Serializer())
|
||||
.build();
|
||||
}
|
||||
|
||||
public SocketAddress getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public int getMaxPlayers() {
|
||||
return maxPlayers;
|
||||
}
|
||||
|
||||
public PingData getPingData() {
|
||||
return pingData;
|
||||
}
|
||||
|
||||
public String getDimensionType() {
|
||||
return dimensionType;
|
||||
}
|
||||
|
||||
public int getGameMode() {
|
||||
return gameMode;
|
||||
}
|
||||
|
||||
public InfoForwarding getInfoForwarding() {
|
||||
return infoForwarding;
|
||||
}
|
||||
|
||||
public long getReadTimeout() {
|
||||
return readTimeout;
|
||||
}
|
||||
|
||||
public int getDebugLevel() {
|
||||
return debugLevel;
|
||||
}
|
||||
|
||||
public boolean isUseBrandName() {
|
||||
return useBrandName;
|
||||
}
|
||||
|
||||
public boolean isUseJoinMessage() {
|
||||
return useJoinMessage;
|
||||
}
|
||||
|
||||
public boolean isUseBossBar() {
|
||||
return useBossBar;
|
||||
}
|
||||
|
||||
public boolean isUseTitle() {
|
||||
return useTitle;
|
||||
}
|
||||
|
||||
public boolean isUsePlayerList() {
|
||||
return usePlayerList;
|
||||
}
|
||||
|
||||
public boolean isUseHeaderAndFooter() {
|
||||
return useHeaderAndFooter;
|
||||
}
|
||||
|
||||
public String getBrandName() {
|
||||
return brandName;
|
||||
}
|
||||
|
||||
public String getJoinMessage() {
|
||||
return joinMessage;
|
||||
}
|
||||
|
||||
public BossBar getBossBar() {
|
||||
return bossBar;
|
||||
}
|
||||
|
||||
public Title getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public String getPlayerListUsername() {
|
||||
return playerListUsername;
|
||||
}
|
||||
|
||||
public String getPlayerListHeader() {
|
||||
return playerListHeader;
|
||||
}
|
||||
|
||||
public String getPlayerListFooter() {
|
||||
return playerListFooter;
|
||||
}
|
||||
|
||||
public boolean isUseEpoll() {
|
||||
return useEpoll;
|
||||
}
|
||||
|
||||
public int getBossGroupSize() {
|
||||
return bossGroupSize;
|
||||
}
|
||||
|
||||
public int getWorkerGroupSize() {
|
||||
return workerGroupSize;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.configuration;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.spongepowered.configurate.ConfigurationNode;
|
||||
import org.spongepowered.configurate.serialize.TypeSerializer;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
|
||||
public class SocketAddressSerializer implements TypeSerializer<SocketAddress> {
|
||||
|
||||
@Override
|
||||
public SocketAddress deserialize(Type type, ConfigurationNode node) {
|
||||
String ip = node.node("ip").getString();
|
||||
int port = node.node("port").getInt();
|
||||
SocketAddress address;
|
||||
|
||||
if (ip == null || ip.isEmpty()) {
|
||||
address = new InetSocketAddress(port);
|
||||
} else {
|
||||
address = new InetSocketAddress(ip, port);
|
||||
}
|
||||
|
||||
return address;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(Type type, @Nullable SocketAddress obj, ConfigurationNode node) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.connection;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.handler.timeout.ReadTimeoutHandler;
|
||||
import ua.nanit.limbo.connection.pipeline.PacketDecoder;
|
||||
import ua.nanit.limbo.connection.pipeline.PacketEncoder;
|
||||
import ua.nanit.limbo.connection.pipeline.VarIntFrameDecoder;
|
||||
import ua.nanit.limbo.connection.pipeline.VarIntLengthEncoder;
|
||||
import ua.nanit.limbo.server.LimboServer;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class ClientChannelInitializer extends ChannelInitializer<Channel> {
|
||||
|
||||
private final LimboServer server;
|
||||
|
||||
public ClientChannelInitializer(LimboServer server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initChannel(Channel channel) {
|
||||
ChannelPipeline pipeline = channel.pipeline();
|
||||
|
||||
PacketDecoder decoder = new PacketDecoder();
|
||||
PacketEncoder encoder = new PacketEncoder();
|
||||
ClientConnection connection = new ClientConnection(channel, server, decoder, encoder);
|
||||
|
||||
pipeline.addLast("timeout", new ReadTimeoutHandler(server.getConfig().getReadTimeout(),
|
||||
TimeUnit.MILLISECONDS));
|
||||
pipeline.addLast("frame_decoder", new VarIntFrameDecoder());
|
||||
pipeline.addLast("frame_encoder", new VarIntLengthEncoder());
|
||||
pipeline.addLast("decoder", decoder);
|
||||
pipeline.addLast("encoder", encoder);
|
||||
pipeline.addLast("handler", connection);
|
||||
}
|
||||
|
||||
}
|
||||
305
src/main/java/ua/nanit/limbo/connection/ClientConnection.java
Normal file
305
src/main/java/ua/nanit/limbo/connection/ClientConnection.java
Normal file
@@ -0,0 +1,305 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.connection;
|
||||
|
||||
import com.grack.nanojson.JsonArray;
|
||||
import com.grack.nanojson.JsonObject;
|
||||
import com.grack.nanojson.JsonParser;
|
||||
import com.grack.nanojson.JsonParserException;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import ua.nanit.limbo.connection.pipeline.PacketDecoder;
|
||||
import ua.nanit.limbo.connection.pipeline.PacketEncoder;
|
||||
import ua.nanit.limbo.protocol.ByteMessage;
|
||||
import ua.nanit.limbo.protocol.Packet;
|
||||
import ua.nanit.limbo.protocol.packets.login.PacketDisconnect;
|
||||
import ua.nanit.limbo.protocol.packets.play.PacketKeepAlive;
|
||||
import ua.nanit.limbo.protocol.registry.State;
|
||||
import ua.nanit.limbo.protocol.registry.Version;
|
||||
import ua.nanit.limbo.server.LimboServer;
|
||||
import ua.nanit.limbo.server.Logger;
|
||||
import ua.nanit.limbo.util.UuidUtil;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class ClientConnection extends ChannelInboundHandlerAdapter {
|
||||
|
||||
private final LimboServer server;
|
||||
private final Channel channel;
|
||||
private final GameProfile gameProfile;
|
||||
|
||||
private final PacketDecoder decoder;
|
||||
private final PacketEncoder encoder;
|
||||
|
||||
private State state;
|
||||
private Version clientVersion;
|
||||
private SocketAddress address;
|
||||
|
||||
private int velocityLoginMessageId = -1;
|
||||
|
||||
public ClientConnection(Channel channel, LimboServer server, PacketDecoder decoder, PacketEncoder encoder) {
|
||||
this.server = server;
|
||||
this.channel = channel;
|
||||
this.decoder = decoder;
|
||||
this.encoder = encoder;
|
||||
this.address = channel.remoteAddress();
|
||||
this.gameProfile = new GameProfile();
|
||||
}
|
||||
|
||||
public UUID getUuid() {
|
||||
return gameProfile.getUuid();
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return gameProfile.getUsername();
|
||||
}
|
||||
|
||||
public SocketAddress getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public Version getClientVersion() {
|
||||
return clientVersion;
|
||||
}
|
||||
|
||||
public GameProfile getGameProfile() {
|
||||
return gameProfile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelInactive(@NotNull ChannelHandlerContext ctx) throws Exception {
|
||||
if (state.equals(State.PLAY)) {
|
||||
server.getConnections().removeConnection(this);
|
||||
}
|
||||
super.channelInactive(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
|
||||
if (channel.isActive()) {
|
||||
Logger.error("Unhandled exception: ", cause);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelRead(@NotNull ChannelHandlerContext ctx, @NotNull Object msg) {
|
||||
handlePacket(msg);
|
||||
}
|
||||
|
||||
public void handlePacket(Object packet) {
|
||||
if (packet instanceof Packet) {
|
||||
((Packet)packet).handle(this, server);
|
||||
}
|
||||
}
|
||||
|
||||
public void fireLoginSuccess() {
|
||||
if (server.getConfig().getInfoForwarding().isModern() && velocityLoginMessageId == -1) {
|
||||
disconnectLogin("You need to connect with Velocity");
|
||||
return;
|
||||
}
|
||||
|
||||
sendPacket(PacketSnapshots.PACKET_LOGIN_SUCCESS);
|
||||
updateState(State.PLAY);
|
||||
server.getConnections().addConnection(this);
|
||||
|
||||
Runnable sendPlayPackets = () -> {
|
||||
writePacket(PacketSnapshots.PACKET_JOIN_GAME);
|
||||
writePacket(PacketSnapshots.PACKET_PLAYER_ABILITIES);
|
||||
|
||||
if (clientVersion.less(Version.V1_9)) {
|
||||
writePacket(PacketSnapshots.PACKET_PLAYER_POS_AND_LOOK_LEGACY);
|
||||
} else {
|
||||
writePacket(PacketSnapshots.PACKET_PLAYER_POS_AND_LOOK);
|
||||
}
|
||||
|
||||
if (clientVersion.moreOrEqual(Version.V1_19_3))
|
||||
writePacket(PacketSnapshots.PACKET_SPAWN_POSITION);
|
||||
|
||||
if (server.getConfig().isUsePlayerList() || clientVersion.equals(Version.V1_16_4))
|
||||
writePacket(PacketSnapshots.PACKET_PLAYER_INFO);
|
||||
|
||||
if (clientVersion.moreOrEqual(Version.V1_13)) {
|
||||
writePacket(PacketSnapshots.PACKET_DECLARE_COMMANDS);
|
||||
|
||||
if (PacketSnapshots.PACKET_PLUGIN_MESSAGE != null)
|
||||
writePacket(PacketSnapshots.PACKET_PLUGIN_MESSAGE);
|
||||
}
|
||||
|
||||
if (PacketSnapshots.PACKET_BOSS_BAR != null && clientVersion.moreOrEqual(Version.V1_9))
|
||||
writePacket(PacketSnapshots.PACKET_BOSS_BAR);
|
||||
|
||||
if (PacketSnapshots.PACKET_JOIN_MESSAGE != null)
|
||||
writePacket(PacketSnapshots.PACKET_JOIN_MESSAGE);
|
||||
|
||||
if (PacketSnapshots.PACKET_TITLE_TITLE != null && clientVersion.moreOrEqual(Version.V1_8))
|
||||
writeTitle();
|
||||
|
||||
if (PacketSnapshots.PACKET_HEADER_AND_FOOTER != null && clientVersion.moreOrEqual(Version.V1_8))
|
||||
writePacket(PacketSnapshots.PACKET_HEADER_AND_FOOTER);
|
||||
|
||||
sendKeepAlive();
|
||||
};
|
||||
|
||||
if (clientVersion.lessOrEqual(Version.V1_7_6)) {
|
||||
this.channel.eventLoop().schedule(sendPlayPackets, 100, TimeUnit.MILLISECONDS);
|
||||
} else {
|
||||
sendPlayPackets.run();
|
||||
}
|
||||
}
|
||||
|
||||
public void disconnectLogin(String reason) {
|
||||
if (isConnected() && state == State.LOGIN) {
|
||||
PacketDisconnect disconnect = new PacketDisconnect();
|
||||
disconnect.setReason(reason);
|
||||
sendPacketAndClose(disconnect);
|
||||
}
|
||||
}
|
||||
|
||||
public void writeTitle() {
|
||||
if (clientVersion.moreOrEqual(Version.V1_17)) {
|
||||
writePacket(PacketSnapshots.PACKET_TITLE_TITLE);
|
||||
writePacket(PacketSnapshots.PACKET_TITLE_SUBTITLE);
|
||||
writePacket(PacketSnapshots.PACKET_TITLE_TIMES);
|
||||
} else {
|
||||
writePacket(PacketSnapshots.PACKET_TITLE_LEGACY_TITLE);
|
||||
writePacket(PacketSnapshots.PACKET_TITLE_LEGACY_SUBTITLE);
|
||||
writePacket(PacketSnapshots.PACKET_TITLE_LEGACY_TIMES);
|
||||
}
|
||||
}
|
||||
|
||||
public void sendKeepAlive() {
|
||||
if (state.equals(State.PLAY)) {
|
||||
PacketKeepAlive keepAlive = new PacketKeepAlive();
|
||||
keepAlive.setId(ThreadLocalRandom.current().nextLong());
|
||||
sendPacket(keepAlive);
|
||||
}
|
||||
}
|
||||
|
||||
public void sendPacket(Object packet) {
|
||||
if (isConnected())
|
||||
channel.writeAndFlush(packet, channel.voidPromise());
|
||||
}
|
||||
|
||||
public void sendPacketAndClose(Object packet) {
|
||||
if (isConnected())
|
||||
channel.writeAndFlush(packet).addListener(ChannelFutureListener.CLOSE);
|
||||
}
|
||||
|
||||
public void writePacket(Object packet) {
|
||||
if (isConnected())
|
||||
channel.write(packet, channel.voidPromise());
|
||||
}
|
||||
|
||||
public boolean isConnected() {
|
||||
return channel.isActive();
|
||||
}
|
||||
|
||||
public void updateState(State state) {
|
||||
this.state = state;
|
||||
decoder.updateState(state);
|
||||
encoder.updateState(state);
|
||||
}
|
||||
|
||||
public void updateVersion(Version version) {
|
||||
clientVersion = version;
|
||||
decoder.updateVersion(version);
|
||||
encoder.updateVersion(version);
|
||||
}
|
||||
|
||||
public void setAddress(String host) {
|
||||
this.address = new InetSocketAddress(host, ((InetSocketAddress)this.address).getPort());
|
||||
}
|
||||
|
||||
boolean checkBungeeGuardHandshake(String handshake) {
|
||||
String[] split = handshake.split("\00");
|
||||
|
||||
if (split.length != 4)
|
||||
return false;
|
||||
|
||||
String socketAddressHostname = split[1];
|
||||
UUID uuid = UuidUtil.fromString(split[2]);
|
||||
JsonArray arr;
|
||||
|
||||
try {
|
||||
arr = JsonParser.array().from(split[3]);
|
||||
} catch (JsonParserException e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String token = null;
|
||||
|
||||
for (Object obj : arr) {
|
||||
if (obj instanceof JsonObject) {
|
||||
JsonObject prop = (JsonObject) obj;
|
||||
if (prop.getString("name").equals("bungeeguard-token")) {
|
||||
token = prop.getString("value");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!server.getConfig().getInfoForwarding().hasToken(token))
|
||||
return false;
|
||||
|
||||
setAddress(socketAddressHostname);
|
||||
gameProfile.setUuid(uuid);
|
||||
|
||||
Logger.debug("Successfully verified BungeeGuard token");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int getVelocityLoginMessageId() {
|
||||
return velocityLoginMessageId;
|
||||
}
|
||||
|
||||
void setVelocityLoginMessageId(int velocityLoginMessageId) {
|
||||
this.velocityLoginMessageId = velocityLoginMessageId;
|
||||
}
|
||||
|
||||
boolean checkVelocityKeyIntegrity(ByteMessage buf) {
|
||||
byte[] signature = new byte[32];
|
||||
buf.readBytes(signature);
|
||||
byte[] data = new byte[buf.readableBytes()];
|
||||
buf.getBytes(buf.readerIndex(), data);
|
||||
try {
|
||||
Mac mac = Mac.getInstance("HmacSHA256");
|
||||
mac.init(new SecretKeySpec(server.getConfig().getInfoForwarding().getSecretKey(), "HmacSHA256"));
|
||||
byte[] mySignature = mac.doFinal(data);
|
||||
if (!MessageDigest.isEqual(signature, mySignature))
|
||||
return false;
|
||||
} catch (InvalidKeyException |java.security.NoSuchAlgorithmException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
int version = buf.readVarInt();
|
||||
if (version != 1)
|
||||
throw new IllegalStateException("Unsupported forwarding version " + version + ", wanted " + '\001');
|
||||
return true;
|
||||
}
|
||||
}
|
||||
42
src/main/java/ua/nanit/limbo/connection/GameProfile.java
Normal file
42
src/main/java/ua/nanit/limbo/connection/GameProfile.java
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.connection;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class GameProfile {
|
||||
|
||||
private UUID uuid;
|
||||
private String username;
|
||||
|
||||
public UUID getUuid() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public void setUuid(UUID uuid) {
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
}
|
||||
130
src/main/java/ua/nanit/limbo/connection/PacketHandler.java
Normal file
130
src/main/java/ua/nanit/limbo/connection/PacketHandler.java
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.connection;
|
||||
|
||||
import io.netty.buffer.Unpooled;
|
||||
import ua.nanit.limbo.LimboConstants;
|
||||
import ua.nanit.limbo.protocol.packets.PacketHandshake;
|
||||
import ua.nanit.limbo.protocol.packets.login.PacketLoginPluginRequest;
|
||||
import ua.nanit.limbo.protocol.packets.login.PacketLoginPluginResponse;
|
||||
import ua.nanit.limbo.protocol.packets.login.PacketLoginStart;
|
||||
import ua.nanit.limbo.protocol.packets.status.PacketStatusPing;
|
||||
import ua.nanit.limbo.protocol.packets.status.PacketStatusRequest;
|
||||
import ua.nanit.limbo.protocol.packets.status.PacketStatusResponse;
|
||||
import ua.nanit.limbo.server.LimboServer;
|
||||
import ua.nanit.limbo.server.Logger;
|
||||
import ua.nanit.limbo.util.UuidUtil;
|
||||
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
public class PacketHandler {
|
||||
|
||||
private final LimboServer server;
|
||||
|
||||
public PacketHandler(LimboServer server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
public void handle(ClientConnection conn, PacketHandshake packet) {
|
||||
conn.updateVersion(packet.getVersion());
|
||||
conn.updateState(packet.getNextState());
|
||||
|
||||
Logger.debug("Pinged from %s [%s]", conn.getAddress(),
|
||||
conn.getClientVersion().toString());
|
||||
|
||||
if (server.getConfig().getInfoForwarding().isLegacy()) {
|
||||
String[] split = packet.getHost().split("\00");
|
||||
|
||||
if (split.length == 3 || split.length == 4) {
|
||||
conn.setAddress(split[1]);
|
||||
conn.getGameProfile().setUuid(UuidUtil.fromString(split[2]));
|
||||
} else {
|
||||
conn.disconnectLogin("You've enabled player info forwarding. You need to connect with proxy");
|
||||
}
|
||||
} else if (server.getConfig().getInfoForwarding().isBungeeGuard()) {
|
||||
if (!conn.checkBungeeGuardHandshake(packet.getHost())) {
|
||||
conn.disconnectLogin("Invalid BungeeGuard token or handshake format");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void handle(ClientConnection conn, PacketStatusRequest packet) {
|
||||
conn.sendPacket(new PacketStatusResponse(server));
|
||||
}
|
||||
|
||||
public void handle(ClientConnection conn, PacketStatusPing packet) {
|
||||
conn.sendPacketAndClose(packet);
|
||||
}
|
||||
|
||||
public void handle(ClientConnection conn, PacketLoginStart packet) {
|
||||
if (server.getConfig().getMaxPlayers() > 0 &&
|
||||
server.getConnections().getCount() >= server.getConfig().getMaxPlayers()) {
|
||||
conn.disconnectLogin("Too many players connected");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!conn.getClientVersion().isSupported()) {
|
||||
conn.disconnectLogin("Unsupported client version");
|
||||
return;
|
||||
}
|
||||
|
||||
if (server.getConfig().getInfoForwarding().isModern()) {
|
||||
int loginId = ThreadLocalRandom.current().nextInt(0, Integer.MAX_VALUE);
|
||||
PacketLoginPluginRequest request = new PacketLoginPluginRequest();
|
||||
|
||||
request.setMessageId(loginId);
|
||||
request.setChannel(LimboConstants.VELOCITY_INFO_CHANNEL);
|
||||
request.setData(Unpooled.EMPTY_BUFFER);
|
||||
|
||||
conn.setVelocityLoginMessageId(loginId);
|
||||
conn.sendPacket(request);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!server.getConfig().getInfoForwarding().isModern()) {
|
||||
conn.getGameProfile().setUsername(packet.getUsername());
|
||||
conn.getGameProfile().setUuid(UuidUtil.getOfflineModeUuid(packet.getUsername()));
|
||||
}
|
||||
|
||||
conn.fireLoginSuccess();
|
||||
}
|
||||
|
||||
public void handle(ClientConnection conn, PacketLoginPluginResponse packet) {
|
||||
if (server.getConfig().getInfoForwarding().isModern()
|
||||
&& packet.getMessageId() == conn.getVelocityLoginMessageId()) {
|
||||
|
||||
if (!packet.isSuccessful() || packet.getData() == null) {
|
||||
conn.disconnectLogin("You need to connect with Velocity");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!conn.checkVelocityKeyIntegrity(packet.getData())) {
|
||||
conn.disconnectLogin("Can't verify forwarded player info");
|
||||
return;
|
||||
}
|
||||
|
||||
// Order is important
|
||||
conn.setAddress(packet.getData().readString());
|
||||
conn.getGameProfile().setUuid(packet.getData().readUuid());
|
||||
conn.getGameProfile().setUsername(packet.getData().readString());
|
||||
|
||||
conn.fireLoginSuccess();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
182
src/main/java/ua/nanit/limbo/connection/PacketSnapshots.java
Normal file
182
src/main/java/ua/nanit/limbo/connection/PacketSnapshots.java
Normal file
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.connection;
|
||||
|
||||
import ua.nanit.limbo.LimboConstants;
|
||||
import ua.nanit.limbo.protocol.PacketSnapshot;
|
||||
import ua.nanit.limbo.protocol.packets.login.PacketLoginSuccess;
|
||||
import ua.nanit.limbo.protocol.packets.play.*;
|
||||
import ua.nanit.limbo.server.LimboServer;
|
||||
import ua.nanit.limbo.server.data.Title;
|
||||
import ua.nanit.limbo.util.UuidUtil;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
public final class PacketSnapshots {
|
||||
|
||||
public static PacketSnapshot PACKET_LOGIN_SUCCESS;
|
||||
public static PacketSnapshot PACKET_JOIN_GAME;
|
||||
public static PacketSnapshot PACKET_SPAWN_POSITION;
|
||||
public static PacketSnapshot PACKET_PLUGIN_MESSAGE;
|
||||
public static PacketSnapshot PACKET_PLAYER_ABILITIES;
|
||||
public static PacketSnapshot PACKET_PLAYER_INFO;
|
||||
public static PacketSnapshot PACKET_DECLARE_COMMANDS;
|
||||
public static PacketSnapshot PACKET_JOIN_MESSAGE;
|
||||
public static PacketSnapshot PACKET_BOSS_BAR;
|
||||
public static PacketSnapshot PACKET_HEADER_AND_FOOTER;
|
||||
|
||||
public static PacketSnapshot PACKET_PLAYER_POS_AND_LOOK_LEGACY;
|
||||
// For 1.19 we need to spawn player outside world to avoid stuck in terrain loading
|
||||
public static PacketSnapshot PACKET_PLAYER_POS_AND_LOOK;
|
||||
|
||||
public static PacketSnapshot PACKET_TITLE_TITLE;
|
||||
public static PacketSnapshot PACKET_TITLE_SUBTITLE;
|
||||
public static PacketSnapshot PACKET_TITLE_TIMES;
|
||||
|
||||
public static PacketSnapshot PACKET_TITLE_LEGACY_TITLE;
|
||||
public static PacketSnapshot PACKET_TITLE_LEGACY_SUBTITLE;
|
||||
public static PacketSnapshot PACKET_TITLE_LEGACY_TIMES;
|
||||
|
||||
|
||||
private PacketSnapshots() { }
|
||||
|
||||
public static void initPackets(LimboServer server) {
|
||||
final String username = server.getConfig().getPingData().getVersion();
|
||||
final UUID uuid = UuidUtil.getOfflineModeUuid(username);
|
||||
|
||||
PacketLoginSuccess loginSuccess = new PacketLoginSuccess();
|
||||
loginSuccess.setUsername(username);
|
||||
loginSuccess.setUuid(uuid);
|
||||
|
||||
PacketJoinGame joinGame = new PacketJoinGame();
|
||||
String worldName = "minecraft:" + server.getConfig().getDimensionType().toLowerCase();
|
||||
joinGame.setEntityId(0);
|
||||
joinGame.setEnableRespawnScreen(true);
|
||||
joinGame.setFlat(false);
|
||||
joinGame.setGameMode(server.getConfig().getGameMode());
|
||||
joinGame.setHardcore(false);
|
||||
joinGame.setMaxPlayers(server.getConfig().getMaxPlayers());
|
||||
joinGame.setPreviousGameMode(-1);
|
||||
joinGame.setReducedDebugInfo(true);
|
||||
joinGame.setDebug(false);
|
||||
joinGame.setViewDistance(0);
|
||||
joinGame.setWorldName(worldName);
|
||||
joinGame.setWorldNames(worldName);
|
||||
joinGame.setHashedSeed(0);
|
||||
joinGame.setDimensionRegistry(server.getDimensionRegistry());
|
||||
|
||||
PacketPlayerAbilities playerAbilities = new PacketPlayerAbilities();
|
||||
playerAbilities.setFlyingSpeed(0.0F);
|
||||
playerAbilities.setFlags(0x02);
|
||||
playerAbilities.setFieldOfView(0.1F);
|
||||
|
||||
int teleportId = ThreadLocalRandom.current().nextInt();
|
||||
|
||||
PacketPlayerPositionAndLook positionAndLookLegacy
|
||||
= new PacketPlayerPositionAndLook(0, 64, 0, 0, 0, teleportId);
|
||||
|
||||
PacketPlayerPositionAndLook positionAndLook
|
||||
= new PacketPlayerPositionAndLook(0, 400, 0, 0, 0, teleportId);
|
||||
|
||||
PacketSpawnPosition packetSpawnPosition = new PacketSpawnPosition(0, 400, 0);
|
||||
|
||||
PacketDeclareCommands declareCommands = new PacketDeclareCommands();
|
||||
declareCommands.setCommands(Collections.emptyList());
|
||||
|
||||
PacketPlayerInfo info = new PacketPlayerInfo();
|
||||
info.setUsername(server.getConfig().getPlayerListUsername());
|
||||
info.setGameMode(server.getConfig().getGameMode());
|
||||
info.setUuid(uuid);
|
||||
|
||||
PACKET_LOGIN_SUCCESS = PacketSnapshot.of(loginSuccess);
|
||||
PACKET_JOIN_GAME = PacketSnapshot.of(joinGame);
|
||||
PACKET_PLAYER_POS_AND_LOOK_LEGACY = PacketSnapshot.of(positionAndLookLegacy);
|
||||
PACKET_PLAYER_POS_AND_LOOK = PacketSnapshot.of(positionAndLook);
|
||||
PACKET_SPAWN_POSITION = PacketSnapshot.of(packetSpawnPosition);
|
||||
PACKET_PLAYER_ABILITIES = PacketSnapshot.of(playerAbilities);
|
||||
PACKET_PLAYER_INFO = PacketSnapshot.of(info);
|
||||
|
||||
PACKET_DECLARE_COMMANDS = PacketSnapshot.of(declareCommands);
|
||||
|
||||
if (server.getConfig().isUseHeaderAndFooter()) {
|
||||
PacketPlayerListHeader header = new PacketPlayerListHeader();
|
||||
header.setHeader(server.getConfig().getPlayerListHeader());
|
||||
header.setFooter(server.getConfig().getPlayerListFooter());
|
||||
PACKET_HEADER_AND_FOOTER = PacketSnapshot.of(header);
|
||||
}
|
||||
|
||||
if (server.getConfig().isUseBrandName()){
|
||||
PacketPluginMessage pluginMessage = new PacketPluginMessage();
|
||||
pluginMessage.setChannel(LimboConstants.BRAND_CHANNEL);
|
||||
pluginMessage.setMessage(server.getConfig().getBrandName());
|
||||
PACKET_PLUGIN_MESSAGE = PacketSnapshot.of(pluginMessage);
|
||||
}
|
||||
|
||||
if (server.getConfig().isUseJoinMessage()) {
|
||||
PacketChatMessage joinMessage = new PacketChatMessage();
|
||||
joinMessage.setJsonData(server.getConfig().getJoinMessage());
|
||||
joinMessage.setPosition(PacketChatMessage.PositionLegacy.SYSTEM_MESSAGE);
|
||||
joinMessage.setSender(UUID.randomUUID());
|
||||
PACKET_JOIN_MESSAGE = PacketSnapshot.of(joinMessage);
|
||||
}
|
||||
|
||||
if (server.getConfig().isUseBossBar()) {
|
||||
PacketBossBar bossBar = new PacketBossBar();
|
||||
bossBar.setBossBar(server.getConfig().getBossBar());
|
||||
bossBar.setUuid(UUID.randomUUID());
|
||||
PACKET_BOSS_BAR = PacketSnapshot.of(bossBar);
|
||||
}
|
||||
|
||||
if (server.getConfig().isUseTitle()) {
|
||||
Title title = server.getConfig().getTitle();
|
||||
|
||||
PacketTitleSetTitle packetTitle = new PacketTitleSetTitle();
|
||||
PacketTitleSetSubTitle packetSubtitle = new PacketTitleSetSubTitle();
|
||||
PacketTitleTimes packetTimes = new PacketTitleTimes();
|
||||
|
||||
PacketTitleLegacy legacyTitle = new PacketTitleLegacy();
|
||||
PacketTitleLegacy legacySubtitle = new PacketTitleLegacy();
|
||||
PacketTitleLegacy legacyTimes = new PacketTitleLegacy();
|
||||
|
||||
packetTitle.setTitle(title.getTitle());
|
||||
packetSubtitle.setSubtitle(title.getSubtitle());
|
||||
packetTimes.setFadeIn(title.getFadeIn());
|
||||
packetTimes.setStay(title.getStay());
|
||||
packetTimes.setFadeOut(title.getFadeOut());
|
||||
|
||||
legacyTitle.setTitle(title);
|
||||
legacyTitle.setAction(PacketTitleLegacy.Action.SET_TITLE);
|
||||
|
||||
legacySubtitle.setTitle(title);
|
||||
legacySubtitle.setAction(PacketTitleLegacy.Action.SET_SUBTITLE);
|
||||
|
||||
legacyTimes.setTitle(title);
|
||||
legacyTimes.setAction(PacketTitleLegacy.Action.SET_TIMES_AND_DISPLAY);
|
||||
|
||||
PACKET_TITLE_TITLE = PacketSnapshot.of(packetTitle);
|
||||
PACKET_TITLE_SUBTITLE = PacketSnapshot.of(packetSubtitle);
|
||||
PACKET_TITLE_TIMES = PacketSnapshot.of(packetTimes);
|
||||
|
||||
PACKET_TITLE_LEGACY_TITLE = PacketSnapshot.of(legacyTitle);
|
||||
PACKET_TITLE_LEGACY_SUBTITLE = PacketSnapshot.of(legacySubtitle);
|
||||
PACKET_TITLE_LEGACY_TIMES = PacketSnapshot.of(legacyTimes);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.connection.pipeline;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToMessageDecoder;
|
||||
import ua.nanit.limbo.protocol.ByteMessage;
|
||||
import ua.nanit.limbo.protocol.Packet;
|
||||
import ua.nanit.limbo.protocol.registry.State;
|
||||
import ua.nanit.limbo.protocol.registry.Version;
|
||||
import ua.nanit.limbo.server.Logger;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PacketDecoder extends MessageToMessageDecoder<ByteBuf> {
|
||||
|
||||
private State.PacketRegistry mappings;
|
||||
private Version version;
|
||||
|
||||
public PacketDecoder() {
|
||||
updateVersion(Version.getMin());
|
||||
updateState(State.HANDSHAKING);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf buf, List<Object> out) throws Exception {
|
||||
if (!ctx.channel().isActive() || mappings == null) return;
|
||||
|
||||
ByteMessage msg = new ByteMessage(buf);
|
||||
int packetId = msg.readVarInt();
|
||||
Packet packet = mappings.getPacket(packetId);
|
||||
|
||||
if (packet != null) {
|
||||
Logger.debug("Received packet %s[0x%s]", packet.toString(), Integer.toHexString(packetId));
|
||||
try {
|
||||
packet.decode(msg, version);
|
||||
} catch (Exception e) {
|
||||
Logger.warning("Cannot decode packet 0x%s: %s", Integer.toHexString(packetId), e.getMessage());
|
||||
}
|
||||
|
||||
ctx.fireChannelRead(packet);
|
||||
} else {
|
||||
Logger.debug("Undefined incoming packet: 0x" + Integer.toHexString(packetId));
|
||||
}
|
||||
}
|
||||
|
||||
public void updateVersion(Version version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public void updateState(State state) {
|
||||
this.mappings = state.serverBound.getRegistry(version);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.connection.pipeline;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToByteEncoder;
|
||||
import ua.nanit.limbo.protocol.ByteMessage;
|
||||
import ua.nanit.limbo.protocol.Packet;
|
||||
import ua.nanit.limbo.protocol.PacketSnapshot;
|
||||
import ua.nanit.limbo.protocol.registry.State;
|
||||
import ua.nanit.limbo.protocol.registry.Version;
|
||||
import ua.nanit.limbo.server.Logger;
|
||||
|
||||
public class PacketEncoder extends MessageToByteEncoder<Packet> {
|
||||
|
||||
private State.PacketRegistry registry;
|
||||
private Version version;
|
||||
|
||||
public PacketEncoder() {
|
||||
updateVersion(Version.getMin());
|
||||
updateState(State.HANDSHAKING);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void encode(ChannelHandlerContext ctx, Packet packet, ByteBuf out) throws Exception {
|
||||
if (registry == null) return;
|
||||
|
||||
ByteMessage msg = new ByteMessage(out);
|
||||
int packetId;
|
||||
|
||||
if (packet instanceof PacketSnapshot) {
|
||||
packetId = registry.getPacketId(((PacketSnapshot)packet).getWrappedPacket().getClass());
|
||||
} else {
|
||||
packetId = registry.getPacketId(packet.getClass());
|
||||
}
|
||||
|
||||
if (packetId == -1) {
|
||||
Logger.warning("Undefined packet class: %s[0x%s]", packet.getClass().getName(), Integer.toHexString(packetId));
|
||||
return;
|
||||
}
|
||||
|
||||
msg.writeVarInt(packetId);
|
||||
|
||||
try {
|
||||
packet.encode(msg, version);
|
||||
|
||||
if (Logger.getLevel() >= Logger.Level.DEBUG.getIndex()) {
|
||||
Logger.debug("Sending %s[0x%s] packet (%d bytes)", packet.toString(), Integer.toHexString(packetId), msg.readableBytes());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Logger.error("Cannot encode packet 0x%s: %s", Integer.toHexString(packetId), e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void updateVersion(Version version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public void updateState(State state) {
|
||||
this.registry = state.clientBound.getRegistry(version);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.connection.pipeline;
|
||||
|
||||
import io.netty.util.ByteProcessor;
|
||||
|
||||
public class VarIntByteDecoder implements ByteProcessor {
|
||||
|
||||
private int readVarInt;
|
||||
private int bytesRead;
|
||||
private DecodeResult result = DecodeResult.TOO_SHORT;
|
||||
|
||||
@Override
|
||||
public boolean process(byte k) {
|
||||
readVarInt |= (k & 0x7F) << bytesRead++ * 7;
|
||||
if (bytesRead > 3) {
|
||||
result = DecodeResult.TOO_BIG;
|
||||
return false;
|
||||
}
|
||||
if ((k & 0x80) != 128) {
|
||||
result = DecodeResult.SUCCESS;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public int getReadVarInt() {
|
||||
return readVarInt;
|
||||
}
|
||||
|
||||
public int getBytesRead() {
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
public DecodeResult getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public enum DecodeResult {
|
||||
SUCCESS,
|
||||
TOO_SHORT,
|
||||
TOO_BIG
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.connection.pipeline;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||
import ua.nanit.limbo.server.Logger;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class VarIntFrameDecoder extends ByteToMessageDecoder {
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
|
||||
if (!ctx.channel().isActive()) {
|
||||
in.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
VarIntByteDecoder reader = new VarIntByteDecoder();
|
||||
int varIntEnd = in.forEachByte(reader);
|
||||
|
||||
if (varIntEnd == -1) return;
|
||||
|
||||
if (reader.getResult() == VarIntByteDecoder.DecodeResult.SUCCESS) {
|
||||
int readVarInt = reader.getReadVarInt();
|
||||
int bytesRead = reader.getBytesRead();
|
||||
if (readVarInt < 0) {
|
||||
Logger.error("[VarIntFrameDecoder] Bad data length");
|
||||
} else if (readVarInt == 0) {
|
||||
in.readerIndex(varIntEnd + 1);
|
||||
} else {
|
||||
int minimumRead = bytesRead + readVarInt;
|
||||
if (in.isReadable(minimumRead)) {
|
||||
out.add(in.retainedSlice(varIntEnd + 1, readVarInt));
|
||||
in.skipBytes(minimumRead);
|
||||
}
|
||||
}
|
||||
} else if (reader.getResult() == VarIntByteDecoder.DecodeResult.TOO_BIG) {
|
||||
Logger.error("[VarIntFrameDecoder] Too big data");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.connection.pipeline;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToByteEncoder;
|
||||
import ua.nanit.limbo.protocol.ByteMessage;
|
||||
|
||||
@ChannelHandler.Sharable
|
||||
public class VarIntLengthEncoder extends MessageToByteEncoder<ByteBuf> {
|
||||
|
||||
@Override
|
||||
protected void encode(ChannelHandlerContext ctx, ByteBuf buf, ByteBuf out) {
|
||||
ByteMessage msg = new ByteMessage(out);
|
||||
msg.writeVarInt(buf.readableBytes());
|
||||
msg.writeBytes(buf);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ByteBuf allocateBuffer(ChannelHandlerContext ctx, ByteBuf msg, boolean preferDirect) {
|
||||
int anticipatedRequiredCapacity = 5 + msg.readableBytes();
|
||||
return ctx.alloc().heapBuffer(anticipatedRequiredCapacity);
|
||||
}
|
||||
}
|
||||
1186
src/main/java/ua/nanit/limbo/protocol/ByteMessage.java
Normal file
1186
src/main/java/ua/nanit/limbo/protocol/ByteMessage.java
Normal file
File diff suppressed because it is too large
Load Diff
34
src/main/java/ua/nanit/limbo/protocol/Packet.java
Normal file
34
src/main/java/ua/nanit/limbo/protocol/Packet.java
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.protocol;
|
||||
|
||||
import ua.nanit.limbo.connection.ClientConnection;
|
||||
import ua.nanit.limbo.protocol.registry.Version;
|
||||
import ua.nanit.limbo.server.LimboServer;
|
||||
|
||||
public interface Packet {
|
||||
|
||||
void encode(ByteMessage msg, Version version);
|
||||
|
||||
void decode(ByteMessage msg, Version version);
|
||||
|
||||
default void handle(ClientConnection conn, LimboServer server) {
|
||||
// Ignored by default
|
||||
}
|
||||
|
||||
}
|
||||
29
src/main/java/ua/nanit/limbo/protocol/PacketIn.java
Normal file
29
src/main/java/ua/nanit/limbo/protocol/PacketIn.java
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.protocol;
|
||||
|
||||
import ua.nanit.limbo.protocol.registry.Version;
|
||||
|
||||
public interface PacketIn extends Packet {
|
||||
|
||||
@Override
|
||||
default void encode(ByteMessage msg, Version version) {
|
||||
// Can be ignored for incoming packets
|
||||
}
|
||||
|
||||
}
|
||||
29
src/main/java/ua/nanit/limbo/protocol/PacketOut.java
Normal file
29
src/main/java/ua/nanit/limbo/protocol/PacketOut.java
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.protocol;
|
||||
|
||||
import ua.nanit.limbo.protocol.registry.Version;
|
||||
|
||||
public interface PacketOut extends Packet {
|
||||
|
||||
@Override
|
||||
default void decode(ByteMessage msg, Version version) {
|
||||
// Can be ignored for outgoing packets
|
||||
}
|
||||
|
||||
}
|
||||
88
src/main/java/ua/nanit/limbo/protocol/PacketSnapshot.java
Normal file
88
src/main/java/ua/nanit/limbo/protocol/PacketSnapshot.java
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.protocol;
|
||||
|
||||
import ua.nanit.limbo.protocol.registry.Version;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* PacketSnapshot encodes packet to byte array for each MC version.
|
||||
* Some versions have same snapshot, so there are mappings to avoid data copying
|
||||
*/
|
||||
public class PacketSnapshot implements PacketOut {
|
||||
|
||||
private final PacketOut packet;
|
||||
private final Map<Version, byte[]> versionMessages = new HashMap<>();
|
||||
private final Map<Version, Version> mappings = new HashMap<>();
|
||||
|
||||
public PacketSnapshot(PacketOut packet) {
|
||||
this.packet = packet;
|
||||
}
|
||||
|
||||
public PacketOut getWrappedPacket() {
|
||||
return packet;
|
||||
}
|
||||
|
||||
public void encode() {
|
||||
Map<Integer, Version> hashes = new HashMap<>();
|
||||
|
||||
for (Version version : Version.values()) {
|
||||
if (version.equals(Version.UNDEFINED)) continue;
|
||||
|
||||
ByteMessage encodedMessage = ByteMessage.create();
|
||||
packet.encode(encodedMessage, version);
|
||||
|
||||
int hash = encodedMessage.hashCode();
|
||||
Version hashed = hashes.get(hash);
|
||||
|
||||
if (hashed != null) {
|
||||
mappings.put(version, hashed);
|
||||
} else {
|
||||
hashes.put(hash, version);
|
||||
mappings.put(version, version);
|
||||
versionMessages.put(version, encodedMessage.toByteArray());
|
||||
}
|
||||
|
||||
encodedMessage.release();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteMessage msg, Version version) {
|
||||
Version mapped = mappings.get(version);
|
||||
byte[] message = versionMessages.get(mapped);
|
||||
|
||||
if (message != null)
|
||||
msg.writeBytes(message);
|
||||
else
|
||||
throw new IllegalArgumentException("No mappings for version " + version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return packet.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
public static PacketSnapshot of(PacketOut packet) {
|
||||
PacketSnapshot snapshot = new PacketSnapshot(packet);
|
||||
snapshot.encode();
|
||||
return snapshot;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.protocol.packets;
|
||||
|
||||
import ua.nanit.limbo.connection.ClientConnection;
|
||||
import ua.nanit.limbo.protocol.ByteMessage;
|
||||
import ua.nanit.limbo.protocol.PacketIn;
|
||||
import ua.nanit.limbo.protocol.registry.State;
|
||||
import ua.nanit.limbo.protocol.registry.Version;
|
||||
import ua.nanit.limbo.server.LimboServer;
|
||||
|
||||
public class PacketHandshake implements PacketIn {
|
||||
|
||||
private Version version;
|
||||
private String host;
|
||||
private int port;
|
||||
private State nextState;
|
||||
|
||||
public Version getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public String getHost() {
|
||||
return host;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public State getNextState() {
|
||||
return nextState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteMessage msg, Version version) {
|
||||
try {
|
||||
this.version = Version.of(msg.readVarInt());
|
||||
} catch (IllegalArgumentException e) {
|
||||
this.version = Version.UNDEFINED;
|
||||
}
|
||||
|
||||
this.host = msg.readString();
|
||||
this.port = msg.readUnsignedShort();
|
||||
this.nextState = State.getById(msg.readVarInt());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(ClientConnection conn, LimboServer server) {
|
||||
server.getPacketHandler().handle(conn, this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.protocol.packets.login;
|
||||
|
||||
import ua.nanit.limbo.protocol.ByteMessage;
|
||||
import ua.nanit.limbo.protocol.PacketOut;
|
||||
import ua.nanit.limbo.protocol.registry.Version;
|
||||
|
||||
public class PacketDisconnect implements PacketOut {
|
||||
|
||||
private String reason;
|
||||
|
||||
public void setReason(String reason) {
|
||||
this.reason = reason;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteMessage msg, Version version) {
|
||||
msg.writeString(String.format("{\"text\": \"%s\"}", reason));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.protocol.packets.login;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import ua.nanit.limbo.protocol.ByteMessage;
|
||||
import ua.nanit.limbo.protocol.PacketOut;
|
||||
import ua.nanit.limbo.protocol.registry.Version;
|
||||
|
||||
public class PacketLoginPluginRequest implements PacketOut {
|
||||
|
||||
private int messageId;
|
||||
private String channel;
|
||||
private ByteBuf data;
|
||||
|
||||
public void setMessageId(int messageId) {
|
||||
this.messageId = messageId;
|
||||
}
|
||||
|
||||
public void setChannel(String channel) {
|
||||
this.channel = channel;
|
||||
}
|
||||
|
||||
public void setData(ByteBuf data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteMessage msg, Version version) {
|
||||
msg.writeVarInt(messageId);
|
||||
msg.writeString(channel);
|
||||
msg.writeBytes(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.protocol.packets.login;
|
||||
|
||||
import ua.nanit.limbo.connection.ClientConnection;
|
||||
import ua.nanit.limbo.protocol.ByteMessage;
|
||||
import ua.nanit.limbo.protocol.PacketIn;
|
||||
import ua.nanit.limbo.protocol.registry.Version;
|
||||
import ua.nanit.limbo.server.LimboServer;
|
||||
|
||||
public class PacketLoginPluginResponse implements PacketIn {
|
||||
|
||||
private int messageId;
|
||||
private boolean successful;
|
||||
private ByteMessage data;
|
||||
|
||||
public int getMessageId() {
|
||||
return messageId;
|
||||
}
|
||||
|
||||
public boolean isSuccessful() {
|
||||
return successful;
|
||||
}
|
||||
|
||||
public ByteMessage getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteMessage msg, Version version) {
|
||||
messageId = msg.readVarInt();
|
||||
successful = msg.readBoolean();
|
||||
|
||||
if (msg.readableBytes() > 0) {
|
||||
int i = msg.readableBytes();
|
||||
data = new ByteMessage(msg.readBytes(i));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(ClientConnection conn, LimboServer server) {
|
||||
server.getPacketHandler().handle(conn, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.protocol.packets.login;
|
||||
|
||||
import ua.nanit.limbo.connection.ClientConnection;
|
||||
import ua.nanit.limbo.protocol.ByteMessage;
|
||||
import ua.nanit.limbo.protocol.PacketIn;
|
||||
import ua.nanit.limbo.protocol.registry.Version;
|
||||
import ua.nanit.limbo.server.LimboServer;
|
||||
|
||||
public class PacketLoginStart implements PacketIn {
|
||||
|
||||
private String username;
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteMessage msg, Version version) {
|
||||
this.username = msg.readString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(ClientConnection conn, LimboServer server) {
|
||||
server.getPacketHandler().handle(conn, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.protocol.packets.login;
|
||||
|
||||
import ua.nanit.limbo.protocol.ByteMessage;
|
||||
import ua.nanit.limbo.protocol.PacketOut;
|
||||
import ua.nanit.limbo.protocol.registry.Version;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class PacketLoginSuccess implements PacketOut {
|
||||
|
||||
private UUID uuid;
|
||||
private String username;
|
||||
|
||||
public void setUuid(UUID uuid) {
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteMessage msg, Version version) {
|
||||
if (version.moreOrEqual(Version.V1_16)) {
|
||||
msg.writeUuid(uuid);
|
||||
} else if (version.moreOrEqual(Version.V1_7_6)) {
|
||||
msg.writeString(uuid.toString());
|
||||
} else {
|
||||
msg.writeString(uuid.toString().replace("-", ""));
|
||||
}
|
||||
msg.writeString(username);
|
||||
if (version.moreOrEqual(Version.V1_19)) {
|
||||
msg.writeVarInt(0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.protocol.packets.play;
|
||||
|
||||
import ua.nanit.limbo.protocol.ByteMessage;
|
||||
import ua.nanit.limbo.protocol.PacketOut;
|
||||
import ua.nanit.limbo.protocol.registry.Version;
|
||||
import ua.nanit.limbo.server.data.BossBar;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Packet for 1.9+
|
||||
*/
|
||||
public class PacketBossBar implements PacketOut {
|
||||
|
||||
private UUID uuid;
|
||||
private BossBar bossBar;
|
||||
private int flags;
|
||||
|
||||
public void setUuid(UUID uuid) {
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
public void setBossBar(BossBar bossBar) {
|
||||
this.bossBar = bossBar;
|
||||
}
|
||||
|
||||
public void setFlags(int flags) {
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteMessage msg, Version version) {
|
||||
msg.writeUuid(uuid);
|
||||
msg.writeVarInt(0); // Create bossbar
|
||||
msg.writeString(bossBar.getText());
|
||||
msg.writeFloat(bossBar.getHealth());
|
||||
msg.writeVarInt(bossBar.getColor().getIndex());
|
||||
msg.writeVarInt(bossBar.getDivision().getIndex());
|
||||
msg.writeByte(flags);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.protocol.packets.play;
|
||||
|
||||
import ua.nanit.limbo.protocol.ByteMessage;
|
||||
import ua.nanit.limbo.protocol.PacketOut;
|
||||
import ua.nanit.limbo.protocol.registry.Version;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class PacketChatMessage implements PacketOut {
|
||||
|
||||
private String jsonData;
|
||||
private PositionLegacy position;
|
||||
private UUID sender;
|
||||
|
||||
public void setJsonData(String jsonData) {
|
||||
this.jsonData = jsonData;
|
||||
}
|
||||
|
||||
public void setPosition(PositionLegacy position) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
public void setSender(UUID sender) {
|
||||
this.sender = sender;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteMessage msg, Version version) {
|
||||
msg.writeString(jsonData);
|
||||
if (version.moreOrEqual(Version.V1_19_1)) {
|
||||
msg.writeBoolean(position.index == PositionLegacy.ACTION_BAR.index);
|
||||
} else if (version.moreOrEqual(Version.V1_19)) {
|
||||
msg.writeVarInt(position.index);
|
||||
} else if (version.moreOrEqual(Version.V1_8)) {
|
||||
msg.writeByte(position.index);
|
||||
}
|
||||
|
||||
if (version.moreOrEqual(Version.V1_16) && version.less(Version.V1_19))
|
||||
msg.writeUuid(sender);
|
||||
}
|
||||
|
||||
public enum PositionLegacy {
|
||||
|
||||
CHAT(0),
|
||||
SYSTEM_MESSAGE(1),
|
||||
ACTION_BAR(2);
|
||||
|
||||
private final int index;
|
||||
|
||||
PositionLegacy(int index) {
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.protocol.packets.play;
|
||||
|
||||
import ua.nanit.limbo.protocol.ByteMessage;
|
||||
import ua.nanit.limbo.protocol.PacketOut;
|
||||
import ua.nanit.limbo.protocol.registry.Version;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Packet for 1.13+
|
||||
*/
|
||||
public class PacketDeclareCommands implements PacketOut {
|
||||
|
||||
private List<String> commands;
|
||||
|
||||
public void setCommands(List<String> commands) {
|
||||
this.commands = commands;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteMessage msg, Version version) {
|
||||
msg.writeVarInt(commands.size() * 2 + 1); // +1 because declaring root node
|
||||
|
||||
// Declare root node
|
||||
|
||||
msg.writeByte(0);
|
||||
msg.writeVarInt(commands.size());
|
||||
|
||||
for (int i = 1; i <= commands.size() * 2; i++) {
|
||||
msg.writeVarInt(i++);
|
||||
}
|
||||
|
||||
// Declare other commands
|
||||
|
||||
int i = 1;
|
||||
for (String cmd : commands) {
|
||||
msg.writeByte(1 | 0x04);
|
||||
msg.writeVarInt(1);
|
||||
msg.writeVarInt(i + 1);
|
||||
msg.writeString(cmd);
|
||||
i++;
|
||||
|
||||
msg.writeByte(2 | 0x04 | 0x10);
|
||||
msg.writeVarInt(1);
|
||||
msg.writeVarInt(i);
|
||||
msg.writeString("arg");
|
||||
msg.writeString("brigadier:string");
|
||||
msg.writeVarInt(0);
|
||||
msg.writeString("minecraft:ask_server");
|
||||
i++;
|
||||
}
|
||||
|
||||
msg.writeVarInt(0);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.protocol.packets.play;
|
||||
|
||||
import ua.nanit.limbo.protocol.ByteMessage;
|
||||
import ua.nanit.limbo.protocol.PacketOut;
|
||||
import ua.nanit.limbo.protocol.registry.Version;
|
||||
import ua.nanit.limbo.world.DimensionRegistry;
|
||||
|
||||
public class PacketJoinGame implements PacketOut {
|
||||
|
||||
private int entityId;
|
||||
private boolean isHardcore = false;
|
||||
private int gameMode = 2;
|
||||
private int previousGameMode = -1;
|
||||
private String[] worldNames;
|
||||
private DimensionRegistry dimensionRegistry;
|
||||
private String worldName;
|
||||
private long hashedSeed;
|
||||
private int maxPlayers;
|
||||
private int viewDistance = 2;
|
||||
private boolean reducedDebugInfo;
|
||||
private boolean enableRespawnScreen;
|
||||
private boolean isDebug;
|
||||
private boolean isFlat;
|
||||
|
||||
public void setEntityId(int entityId) {
|
||||
this.entityId = entityId;
|
||||
}
|
||||
|
||||
public void setHardcore(boolean hardcore) {
|
||||
isHardcore = hardcore;
|
||||
}
|
||||
|
||||
public void setGameMode(int gameMode) {
|
||||
this.gameMode = gameMode;
|
||||
}
|
||||
|
||||
public void setPreviousGameMode(int previousGameMode) {
|
||||
this.previousGameMode = previousGameMode;
|
||||
}
|
||||
|
||||
public void setWorldNames(String... worldNames) {
|
||||
this.worldNames = worldNames;
|
||||
}
|
||||
|
||||
public void setDimensionRegistry(DimensionRegistry dimensionRegistry) {
|
||||
this.dimensionRegistry = dimensionRegistry;
|
||||
}
|
||||
|
||||
public void setWorldName(String worldName) {
|
||||
this.worldName = worldName;
|
||||
}
|
||||
|
||||
public void setHashedSeed(long hashedSeed) {
|
||||
this.hashedSeed = hashedSeed;
|
||||
}
|
||||
|
||||
public void setMaxPlayers(int maxPlayers) {
|
||||
this.maxPlayers = maxPlayers;
|
||||
}
|
||||
|
||||
public void setViewDistance(int viewDistance) {
|
||||
this.viewDistance = viewDistance;
|
||||
}
|
||||
|
||||
public void setReducedDebugInfo(boolean reducedDebugInfo) {
|
||||
this.reducedDebugInfo = reducedDebugInfo;
|
||||
}
|
||||
|
||||
public void setEnableRespawnScreen(boolean enableRespawnScreen) {
|
||||
this.enableRespawnScreen = enableRespawnScreen;
|
||||
}
|
||||
|
||||
public void setDebug(boolean debug) {
|
||||
isDebug = debug;
|
||||
}
|
||||
|
||||
public void setFlat(boolean flat) {
|
||||
isFlat = flat;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteMessage msg, Version version) {
|
||||
msg.writeInt(entityId);
|
||||
|
||||
if (version.fromTo(Version.V1_7_2, Version.V1_7_6)) {
|
||||
msg.writeByte(gameMode == 3 ? 1 : gameMode);
|
||||
msg.writeByte(dimensionRegistry.getDefaultDimension_1_16().getId());
|
||||
msg.writeByte(0); // Difficulty
|
||||
msg.writeByte(maxPlayers);
|
||||
msg.writeString("flat"); // Level type
|
||||
}
|
||||
|
||||
if (version.fromTo(Version.V1_8, Version.V1_9)) {
|
||||
msg.writeByte(gameMode);
|
||||
msg.writeByte(dimensionRegistry.getDefaultDimension_1_16().getId());
|
||||
msg.writeByte(0); // Difficulty
|
||||
msg.writeByte(maxPlayers);
|
||||
msg.writeString("flat"); // Level type
|
||||
msg.writeBoolean(reducedDebugInfo);
|
||||
}
|
||||
|
||||
if (version.fromTo(Version.V1_9_1, Version.V1_13_2)) {
|
||||
msg.writeByte(gameMode);
|
||||
msg.writeInt(dimensionRegistry.getDefaultDimension_1_16().getId());
|
||||
msg.writeByte(0); // Difficulty
|
||||
msg.writeByte(maxPlayers);
|
||||
msg.writeString("flat"); // Level type
|
||||
msg.writeBoolean(reducedDebugInfo);
|
||||
}
|
||||
|
||||
if (version.fromTo(Version.V1_14, Version.V1_14_4)) {
|
||||
msg.writeByte(gameMode);
|
||||
msg.writeInt(dimensionRegistry.getDefaultDimension_1_16().getId());
|
||||
msg.writeByte(maxPlayers);
|
||||
msg.writeString("flat"); // Level type
|
||||
msg.writeVarInt(viewDistance);
|
||||
msg.writeBoolean(reducedDebugInfo);
|
||||
}
|
||||
|
||||
if (version.fromTo(Version.V1_15, Version.V1_15_2)) {
|
||||
msg.writeByte(gameMode);
|
||||
msg.writeInt(dimensionRegistry.getDefaultDimension_1_16().getId());
|
||||
msg.writeLong(hashedSeed);
|
||||
msg.writeByte(maxPlayers);
|
||||
msg.writeString("flat"); // Level type
|
||||
msg.writeVarInt(viewDistance);
|
||||
msg.writeBoolean(reducedDebugInfo);
|
||||
msg.writeBoolean(enableRespawnScreen);
|
||||
}
|
||||
|
||||
if (version.fromTo(Version.V1_16, Version.V1_16_1)) {
|
||||
msg.writeByte(gameMode);
|
||||
msg.writeByte(previousGameMode);
|
||||
msg.writeStringsArray(worldNames);
|
||||
msg.writeCompoundTag(dimensionRegistry.getOldCodec());
|
||||
msg.writeString(dimensionRegistry.getDefaultDimension_1_16().getName());
|
||||
msg.writeString(worldName);
|
||||
msg.writeLong(hashedSeed);
|
||||
msg.writeByte(maxPlayers);
|
||||
msg.writeVarInt(viewDistance);
|
||||
msg.writeBoolean(reducedDebugInfo);
|
||||
msg.writeBoolean(enableRespawnScreen);
|
||||
msg.writeBoolean(isDebug);
|
||||
msg.writeBoolean(isFlat);
|
||||
}
|
||||
|
||||
if (version.fromTo(Version.V1_16_2, Version.V1_17_1)) {
|
||||
msg.writeBoolean(isHardcore);
|
||||
msg.writeByte(gameMode);
|
||||
msg.writeByte(previousGameMode);
|
||||
msg.writeStringsArray(worldNames);
|
||||
msg.writeCompoundTag(dimensionRegistry.getCodec_1_16());
|
||||
msg.writeCompoundTag(dimensionRegistry.getDefaultDimension_1_16().getData());
|
||||
msg.writeString(worldName);
|
||||
msg.writeLong(hashedSeed);
|
||||
msg.writeVarInt(maxPlayers);
|
||||
msg.writeVarInt(viewDistance);
|
||||
msg.writeBoolean(reducedDebugInfo);
|
||||
msg.writeBoolean(enableRespawnScreen);
|
||||
msg.writeBoolean(isDebug);
|
||||
msg.writeBoolean(isFlat);
|
||||
}
|
||||
|
||||
if (version.fromTo(Version.V1_18, Version.V1_18_2)) {
|
||||
msg.writeBoolean(isHardcore);
|
||||
msg.writeByte(gameMode);
|
||||
msg.writeByte(previousGameMode);
|
||||
msg.writeStringsArray(worldNames);
|
||||
if (version.moreOrEqual(Version.V1_18_2)) {
|
||||
msg.writeCompoundTag(dimensionRegistry.getCodec_1_18_2());
|
||||
msg.writeCompoundTag(dimensionRegistry.getDefaultDimension_1_18_2().getData());
|
||||
} else {
|
||||
msg.writeCompoundTag(dimensionRegistry.getCodec_1_16());
|
||||
msg.writeCompoundTag(dimensionRegistry.getDefaultDimension_1_16().getData());
|
||||
}
|
||||
msg.writeString(worldName);
|
||||
msg.writeLong(hashedSeed);
|
||||
msg.writeVarInt(maxPlayers);
|
||||
msg.writeVarInt(viewDistance);
|
||||
msg.writeVarInt(viewDistance); // Simulation Distance
|
||||
msg.writeBoolean(reducedDebugInfo);
|
||||
msg.writeBoolean(enableRespawnScreen);
|
||||
msg.writeBoolean(isDebug);
|
||||
msg.writeBoolean(isFlat);
|
||||
}
|
||||
|
||||
if (version.moreOrEqual(Version.V1_19)) {
|
||||
msg.writeBoolean(isHardcore);
|
||||
msg.writeByte(gameMode);
|
||||
msg.writeByte(previousGameMode);
|
||||
msg.writeStringsArray(worldNames);
|
||||
if (version.moreOrEqual(Version.V1_19_1)) {
|
||||
msg.writeCompoundTag(dimensionRegistry.getCodec_1_19_1());
|
||||
}
|
||||
else {
|
||||
msg.writeCompoundTag(dimensionRegistry.getCodec_1_19());
|
||||
}
|
||||
msg.writeString(worldName); // World type
|
||||
msg.writeString(worldName);
|
||||
msg.writeLong(hashedSeed);
|
||||
msg.writeVarInt(maxPlayers);
|
||||
msg.writeVarInt(viewDistance);
|
||||
msg.writeVarInt(viewDistance); // Simulation Distance
|
||||
msg.writeBoolean(reducedDebugInfo);
|
||||
msg.writeBoolean(enableRespawnScreen);
|
||||
msg.writeBoolean(isDebug);
|
||||
msg.writeBoolean(isFlat);
|
||||
msg.writeBoolean(false);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.protocol.packets.play;
|
||||
|
||||
import ua.nanit.limbo.protocol.ByteMessage;
|
||||
import ua.nanit.limbo.protocol.Packet;
|
||||
import ua.nanit.limbo.protocol.registry.Version;
|
||||
|
||||
public class PacketKeepAlive implements Packet {
|
||||
|
||||
private long id;
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteMessage msg, Version version) {
|
||||
if (version.moreOrEqual(Version.V1_12_2)) {
|
||||
msg.writeLong(id);
|
||||
} else if (version.moreOrEqual(Version.V1_8)) {
|
||||
msg.writeVarInt((int) id);
|
||||
} else {
|
||||
msg.writeInt((int) id);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteMessage msg, Version version) {
|
||||
if (version.moreOrEqual(Version.V1_12_2)) {
|
||||
this.id = msg.readLong();
|
||||
} else if (version.moreOrEqual(Version.V1_8)) {
|
||||
this.id = msg.readVarInt();
|
||||
} else {
|
||||
this.id = msg.readInt();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.protocol.packets.play;
|
||||
|
||||
import ua.nanit.limbo.protocol.ByteMessage;
|
||||
import ua.nanit.limbo.protocol.PacketOut;
|
||||
import ua.nanit.limbo.protocol.registry.Version;
|
||||
|
||||
public class PacketPlayerAbilities implements PacketOut {
|
||||
|
||||
private int flags = 0x02;
|
||||
private float flyingSpeed = 0.0F;
|
||||
private float fieldOfView = 0.1F;
|
||||
|
||||
public void setFlags(int flags) {
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
public void setFlyingSpeed(float flyingSpeed) {
|
||||
this.flyingSpeed = flyingSpeed;
|
||||
}
|
||||
|
||||
public void setFieldOfView(float fieldOfView) {
|
||||
this.fieldOfView = fieldOfView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteMessage msg, Version version) {
|
||||
msg.writeByte(flags);
|
||||
msg.writeFloat(flyingSpeed);
|
||||
msg.writeFloat(fieldOfView);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.protocol.packets.play;
|
||||
|
||||
import ua.nanit.limbo.protocol.ByteMessage;
|
||||
import ua.nanit.limbo.protocol.PacketOut;
|
||||
import ua.nanit.limbo.protocol.registry.Version;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* This packet was very simplified and using only for ADD_PLAYER action
|
||||
*/
|
||||
public class PacketPlayerInfo implements PacketOut {
|
||||
|
||||
private int gameMode = 3;
|
||||
private String username = "";
|
||||
private UUID uuid;
|
||||
|
||||
public void setGameMode(int gameMode) {
|
||||
this.gameMode = gameMode;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public void setUuid(UUID uuid) {
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteMessage msg, Version version) {
|
||||
if (version.less(Version.V1_8)) {
|
||||
msg.writeString(username);
|
||||
msg.writeBoolean(true); // Is online
|
||||
msg.writeShort(0);
|
||||
} else {
|
||||
if (version.moreOrEqual(Version.V1_19_3)) {
|
||||
EnumSet<Action> actions = EnumSet.noneOf(Action.class);
|
||||
actions.add(Action.ADD_PLAYER);
|
||||
actions.add(Action.UPDATE_LISTED);
|
||||
actions.add(Action.UPDATE_GAMEMODE);
|
||||
msg.writeEnumSet(actions, Action.class);
|
||||
|
||||
msg.writeVarInt(1); // Array length (1 element)
|
||||
msg.writeUuid(uuid); // UUID
|
||||
msg.writeString(username); //Username
|
||||
msg.writeVarInt(0); //Properties (0 is empty)
|
||||
|
||||
msg.writeBoolean(true); //Update listed
|
||||
msg.writeVarInt(gameMode); //Gamemode
|
||||
return;
|
||||
}
|
||||
|
||||
msg.writeVarInt(0); // Add player action
|
||||
msg.writeVarInt(1);
|
||||
msg.writeUuid(uuid);
|
||||
msg.writeString(username);
|
||||
msg.writeVarInt(0);
|
||||
msg.writeVarInt(gameMode);
|
||||
msg.writeVarInt(60);
|
||||
msg.writeBoolean(false);
|
||||
|
||||
if (version.moreOrEqual(Version.V1_19)) {
|
||||
msg.writeBoolean(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static enum Action {
|
||||
ADD_PLAYER,
|
||||
INITIALIZE_CHAT,
|
||||
UPDATE_GAMEMODE,
|
||||
UPDATE_LISTED,
|
||||
UPDATE_LATENCY,
|
||||
UPDATE_DISPLAY_NAME;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.protocol.packets.play;
|
||||
|
||||
import ua.nanit.limbo.protocol.ByteMessage;
|
||||
import ua.nanit.limbo.protocol.PacketOut;
|
||||
import ua.nanit.limbo.protocol.registry.Version;
|
||||
|
||||
public class PacketPlayerListHeader implements PacketOut {
|
||||
|
||||
private String header;
|
||||
private String footer;
|
||||
|
||||
public void setHeader(String header) {
|
||||
this.header = header;
|
||||
}
|
||||
|
||||
public void setFooter(String footer) {
|
||||
this.footer = footer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteMessage msg, Version version) {
|
||||
msg.writeString(header);
|
||||
msg.writeString(footer);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.protocol.packets.play;
|
||||
|
||||
import ua.nanit.limbo.protocol.ByteMessage;
|
||||
import ua.nanit.limbo.protocol.PacketOut;
|
||||
import ua.nanit.limbo.protocol.registry.Version;
|
||||
|
||||
public class PacketPlayerPositionAndLook implements PacketOut {
|
||||
|
||||
private double x;
|
||||
private double y;
|
||||
private double z;
|
||||
private float yaw;
|
||||
private float pitch;
|
||||
private int teleportId;
|
||||
|
||||
public PacketPlayerPositionAndLook() {}
|
||||
|
||||
public PacketPlayerPositionAndLook(double x, double y, double z, float yaw, float pitch, int teleportId) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
this.yaw = yaw;
|
||||
this.pitch = pitch;
|
||||
this.teleportId = teleportId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteMessage msg, Version version) {
|
||||
msg.writeDouble(x);
|
||||
msg.writeDouble(y + (version.less(Version.V1_8) ? 1.62F : 0));
|
||||
msg.writeDouble(z);
|
||||
msg.writeFloat(yaw);
|
||||
msg.writeFloat(pitch);
|
||||
|
||||
if (version.moreOrEqual(Version.V1_8)) {
|
||||
msg.writeByte(0x08);
|
||||
} else {
|
||||
msg.writeBoolean(true);
|
||||
}
|
||||
|
||||
if (version.moreOrEqual(Version.V1_9)) {
|
||||
msg.writeVarInt(teleportId);
|
||||
}
|
||||
|
||||
if (version.moreOrEqual(Version.V1_17)) {
|
||||
msg.writeBoolean(false); // Dismount vehicle
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.protocol.packets.play;
|
||||
|
||||
import ua.nanit.limbo.protocol.ByteMessage;
|
||||
import ua.nanit.limbo.protocol.PacketOut;
|
||||
import ua.nanit.limbo.protocol.registry.Version;
|
||||
|
||||
public class PacketPluginMessage implements PacketOut {
|
||||
|
||||
private String channel;
|
||||
private String message;
|
||||
|
||||
public void setChannel(String channel) {
|
||||
this.channel = channel;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteMessage msg, Version version) {
|
||||
msg.writeString(channel);
|
||||
msg.writeString(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package ua.nanit.limbo.protocol.packets.play;
|
||||
|
||||
import ua.nanit.limbo.protocol.ByteMessage;
|
||||
import ua.nanit.limbo.protocol.PacketOut;
|
||||
import ua.nanit.limbo.protocol.registry.Version;
|
||||
|
||||
public class PacketSpawnPosition implements PacketOut {
|
||||
|
||||
private long x;
|
||||
private long y;
|
||||
private long z;
|
||||
|
||||
public PacketSpawnPosition() { }
|
||||
|
||||
public PacketSpawnPosition(long x, long y, long z) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteMessage msg, Version version) {
|
||||
msg.writeLong(encodePosition(x, y ,z));
|
||||
msg.writeFloat(0);
|
||||
}
|
||||
|
||||
private static long encodePosition(long x, long y, long z) {
|
||||
return ((x & 0x3FFFFFF) << 38) | ((z & 0x3FFFFFF) << 12) | (y & 0xFFF);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.protocol.packets.play;
|
||||
|
||||
import ua.nanit.limbo.protocol.ByteMessage;
|
||||
import ua.nanit.limbo.protocol.PacketOut;
|
||||
import ua.nanit.limbo.protocol.registry.Version;
|
||||
import ua.nanit.limbo.server.data.Title;
|
||||
|
||||
public class PacketTitleLegacy implements PacketOut {
|
||||
|
||||
private Action action;
|
||||
private final PacketTitleSetTitle title;
|
||||
private final PacketTitleSetSubTitle subtitle;
|
||||
private final PacketTitleTimes times;
|
||||
|
||||
public PacketTitleLegacy() {
|
||||
this.title = new PacketTitleSetTitle();
|
||||
this.subtitle = new PacketTitleSetSubTitle();
|
||||
this.times = new PacketTitleTimes();
|
||||
}
|
||||
|
||||
public void setAction(Action action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public void setTitle(Title title) {
|
||||
this.title.setTitle(title.getTitle());
|
||||
this.subtitle.setSubtitle(title.getSubtitle());
|
||||
this.times.setFadeIn(title.getFadeIn());
|
||||
this.times.setStay(title.getStay());
|
||||
this.times.setFadeOut(title.getFadeOut());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteMessage msg, Version version) {
|
||||
msg.writeVarInt(action.getId(version));
|
||||
|
||||
switch (action) {
|
||||
case SET_TITLE:
|
||||
title.encode(msg, version);
|
||||
break;
|
||||
case SET_SUBTITLE:
|
||||
subtitle.encode(msg, version);
|
||||
break;
|
||||
case SET_TIMES_AND_DISPLAY:
|
||||
times.encode(msg, version);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid title action: " + action);
|
||||
}
|
||||
}
|
||||
|
||||
public enum Action {
|
||||
SET_TITLE(0),
|
||||
SET_SUBTITLE(1),
|
||||
SET_TIMES_AND_DISPLAY(3, 2);
|
||||
|
||||
private final int id;
|
||||
private final int legacyId;
|
||||
|
||||
Action(int id, int legacyId) {
|
||||
this.id = id;
|
||||
this.legacyId = legacyId;
|
||||
}
|
||||
|
||||
Action(int id) {
|
||||
this(id, id);
|
||||
}
|
||||
|
||||
public int getId(Version version) {
|
||||
return version.less(Version.V1_11) ? legacyId : id;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.protocol.packets.play;
|
||||
|
||||
import ua.nanit.limbo.protocol.ByteMessage;
|
||||
import ua.nanit.limbo.protocol.PacketOut;
|
||||
import ua.nanit.limbo.protocol.registry.Version;
|
||||
|
||||
public class PacketTitleSetSubTitle implements PacketOut {
|
||||
|
||||
private String subtitle;
|
||||
|
||||
public void setSubtitle(String subtitle) {
|
||||
this.subtitle = subtitle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteMessage msg, Version version) {
|
||||
msg.writeString(subtitle);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.protocol.packets.play;
|
||||
|
||||
import ua.nanit.limbo.protocol.ByteMessage;
|
||||
import ua.nanit.limbo.protocol.PacketOut;
|
||||
import ua.nanit.limbo.protocol.registry.Version;
|
||||
|
||||
public class PacketTitleSetTitle implements PacketOut {
|
||||
|
||||
private String title;
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteMessage msg, Version version) {
|
||||
msg.writeString(title);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.protocol.packets.play;
|
||||
|
||||
import ua.nanit.limbo.protocol.ByteMessage;
|
||||
import ua.nanit.limbo.protocol.PacketOut;
|
||||
import ua.nanit.limbo.protocol.registry.Version;
|
||||
|
||||
public class PacketTitleTimes implements PacketOut {
|
||||
|
||||
private int fadeIn;
|
||||
private int stay;
|
||||
private int fadeOut;
|
||||
|
||||
public void setFadeIn(int fadeIn) {
|
||||
this.fadeIn = fadeIn;
|
||||
}
|
||||
|
||||
public void setStay(int stay) {
|
||||
this.stay = stay;
|
||||
}
|
||||
|
||||
public void setFadeOut(int fadeOut) {
|
||||
this.fadeOut = fadeOut;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteMessage msg, Version version) {
|
||||
msg.writeInt(fadeIn);
|
||||
msg.writeInt(stay);
|
||||
msg.writeInt(fadeOut);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.protocol.packets.status;
|
||||
|
||||
import ua.nanit.limbo.connection.ClientConnection;
|
||||
import ua.nanit.limbo.protocol.ByteMessage;
|
||||
import ua.nanit.limbo.protocol.Packet;
|
||||
import ua.nanit.limbo.protocol.registry.Version;
|
||||
import ua.nanit.limbo.server.LimboServer;
|
||||
|
||||
public class PacketStatusPing implements Packet {
|
||||
|
||||
private long randomId;
|
||||
|
||||
@Override
|
||||
public void encode(ByteMessage msg, Version version) {
|
||||
msg.writeLong(randomId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteMessage msg, Version version) {
|
||||
this.randomId = msg.readLong();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(ClientConnection conn, LimboServer server) {
|
||||
server.getPacketHandler().handle(conn, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.protocol.packets.status;
|
||||
|
||||
import ua.nanit.limbo.connection.ClientConnection;
|
||||
import ua.nanit.limbo.protocol.ByteMessage;
|
||||
import ua.nanit.limbo.protocol.PacketIn;
|
||||
import ua.nanit.limbo.protocol.registry.Version;
|
||||
import ua.nanit.limbo.server.LimboServer;
|
||||
|
||||
public class PacketStatusRequest implements PacketIn {
|
||||
|
||||
@Override
|
||||
public void decode(ByteMessage msg, Version version) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(ClientConnection conn, LimboServer server) {
|
||||
server.getPacketHandler().handle(conn, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.protocol.packets.status;
|
||||
|
||||
import ua.nanit.limbo.protocol.ByteMessage;
|
||||
import ua.nanit.limbo.protocol.PacketOut;
|
||||
import ua.nanit.limbo.protocol.registry.Version;
|
||||
import ua.nanit.limbo.server.LimboServer;
|
||||
|
||||
public class PacketStatusResponse implements PacketOut {
|
||||
|
||||
private static final String TEMPLATE = "{ \"version\": { \"name\": \"%s\", \"protocol\": %d }, \"players\": { \"max\": %d, \"online\": %d, \"sample\": [] }, \"description\": %s }";
|
||||
|
||||
private LimboServer server;
|
||||
|
||||
public PacketStatusResponse() { }
|
||||
|
||||
public PacketStatusResponse(LimboServer server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteMessage msg, Version version) {
|
||||
int protocol = server.getConfig().getInfoForwarding().isNone()
|
||||
? version.getProtocolNumber()
|
||||
: Version.getMax().getProtocolNumber();
|
||||
|
||||
String ver = server.getConfig().getPingData().getVersion();
|
||||
String desc = server.getConfig().getPingData().getDescription();
|
||||
|
||||
msg.writeString(getResponseJson(ver, protocol,
|
||||
server.getConfig().getMaxPlayers(),
|
||||
server.getConnections().getCount(), desc));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
|
||||
private String getResponseJson(String version, int protocol, int maxPlayers, int online, String description) {
|
||||
return String.format(TEMPLATE, version, protocol, maxPlayers, online, description);
|
||||
}
|
||||
}
|
||||
359
src/main/java/ua/nanit/limbo/protocol/registry/State.java
Normal file
359
src/main/java/ua/nanit/limbo/protocol/registry/State.java
Normal file
@@ -0,0 +1,359 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.protocol.registry;
|
||||
|
||||
import ua.nanit.limbo.protocol.Packet;
|
||||
import ua.nanit.limbo.protocol.packets.PacketHandshake;
|
||||
import ua.nanit.limbo.protocol.packets.login.*;
|
||||
import ua.nanit.limbo.protocol.packets.play.*;
|
||||
import ua.nanit.limbo.protocol.packets.status.PacketStatusPing;
|
||||
import ua.nanit.limbo.protocol.packets.status.PacketStatusRequest;
|
||||
import ua.nanit.limbo.protocol.packets.status.PacketStatusResponse;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static ua.nanit.limbo.protocol.registry.Version.*;
|
||||
|
||||
public enum State {
|
||||
|
||||
HANDSHAKING(0) {
|
||||
{
|
||||
serverBound.register(PacketHandshake::new,
|
||||
map(0x00, Version.getMin(), Version.getMax())
|
||||
);
|
||||
}
|
||||
},
|
||||
STATUS(1) {
|
||||
{
|
||||
serverBound.register(PacketStatusRequest::new,
|
||||
map(0x00, Version.getMin(), Version.getMax())
|
||||
);
|
||||
serverBound.register(PacketStatusPing::new,
|
||||
map(0x01, Version.getMin(), Version.getMax())
|
||||
);
|
||||
clientBound.register(PacketStatusResponse::new,
|
||||
map(0x00, Version.getMin(), Version.getMax())
|
||||
);
|
||||
clientBound.register(PacketStatusPing::new,
|
||||
map(0x01, Version.getMin(), Version.getMax())
|
||||
);
|
||||
}
|
||||
},
|
||||
LOGIN(2) {
|
||||
{
|
||||
serverBound.register(PacketLoginStart::new,
|
||||
map(0x00, Version.getMin(), Version.getMax())
|
||||
);
|
||||
serverBound.register(PacketLoginPluginResponse::new,
|
||||
map(0x02, Version.getMin(), Version.getMax())
|
||||
);
|
||||
clientBound.register(PacketDisconnect::new,
|
||||
map(0x00, Version.getMin(), Version.getMax())
|
||||
);
|
||||
clientBound.register(PacketLoginSuccess::new,
|
||||
map(0x02, Version.getMin(), Version.getMax())
|
||||
);
|
||||
clientBound.register(PacketLoginPluginRequest::new,
|
||||
map(0x04, Version.getMin(), Version.getMax())
|
||||
);
|
||||
}
|
||||
},
|
||||
PLAY(3) {
|
||||
{
|
||||
serverBound.register(PacketKeepAlive::new,
|
||||
map(0x00, V1_7_2, V1_8),
|
||||
map(0x0B, V1_9, V1_11_1),
|
||||
map(0x0C, V1_12, V1_12),
|
||||
map(0x0B, V1_12_1, V1_12_2),
|
||||
map(0x0E, V1_13, V1_13_2),
|
||||
map(0x0F, V1_14, V1_15_2),
|
||||
map(0x10, V1_16, V1_16_4),
|
||||
map(0x0F, V1_17, V1_18_2),
|
||||
map(0x11, V1_19, V1_19),
|
||||
map(0x12, V1_19_1, V1_19_1),
|
||||
map(0x11, V1_19_3, V1_19_3)
|
||||
);
|
||||
|
||||
clientBound.register(PacketDeclareCommands::new,
|
||||
map(0x11, V1_13, V1_14_4),
|
||||
map(0x12, V1_15, V1_15_2),
|
||||
map(0x11, V1_16, V1_16_1),
|
||||
map(0x10, V1_16_2, V1_16_4),
|
||||
map(0x12, V1_17, V1_18_2),
|
||||
map(0x0F, V1_19, V1_19_1),
|
||||
map(0x0E, V1_19_3, V1_19_3)
|
||||
);
|
||||
clientBound.register(PacketJoinGame::new,
|
||||
map(0x01, V1_7_2, V1_8),
|
||||
map(0x23, V1_9, V1_12_2),
|
||||
map(0x25, V1_13, V1_14_4),
|
||||
map(0x26, V1_15, V1_15_2),
|
||||
map(0x25, V1_16, V1_16_1),
|
||||
map(0x24, V1_16_2, V1_16_4),
|
||||
map(0x26, V1_17, V1_18_2),
|
||||
map(0x23, V1_19, V1_19),
|
||||
map(0x25, V1_19_1, V1_19_1),
|
||||
map(0x24, V1_19_3, V1_19_3)
|
||||
);
|
||||
clientBound.register(PacketPluginMessage::new,
|
||||
map(0x19, V1_13, V1_13_2),
|
||||
map(0x18, V1_14, V1_14_4),
|
||||
map(0x19, V1_15, V1_15_2),
|
||||
map(0x18, V1_16, V1_16_1),
|
||||
map(0x17, V1_16_2, V1_16_4),
|
||||
map(0x18, V1_17, V1_18_2),
|
||||
map(0x15, V1_19, V1_19),
|
||||
map(0x16, V1_19_1, V1_19_1),
|
||||
map(0x15, V1_19_3, V1_19_3)
|
||||
);
|
||||
clientBound.register(PacketPlayerAbilities::new,
|
||||
map(0x39, V1_7_2, V1_8),
|
||||
map(0x2B, V1_9, V1_12),
|
||||
map(0x2C, V1_12_1, V1_12_2),
|
||||
map(0x2E, V1_13, V1_13_2),
|
||||
map(0x31, V1_14, V1_14_4),
|
||||
map(0x32, V1_15, V1_15_2),
|
||||
map(0x31, V1_16, V1_16_1),
|
||||
map(0x30, V1_16_2, V1_16_4),
|
||||
map(0x32, V1_17, V1_18_2),
|
||||
map(0x2F, V1_19, V1_19),
|
||||
map(0x31, V1_19_1, V1_19_1),
|
||||
map(0x30, V1_19_3, V1_19_3)
|
||||
);
|
||||
clientBound.register(PacketPlayerPositionAndLook::new,
|
||||
map(0x08, V1_7_2, V1_8),
|
||||
map(0x2E, V1_9, V1_12),
|
||||
map(0x2F, V1_12_1, V1_12_2),
|
||||
map(0x32, V1_13, V1_13_2),
|
||||
map(0x35, V1_14, V1_14_4),
|
||||
map(0x36, V1_15, V1_15_2),
|
||||
map(0x35, V1_16, V1_16_1),
|
||||
map(0x34, V1_16_2, V1_16_4),
|
||||
map(0x38, V1_17, V1_18_2),
|
||||
map(0x36, V1_19, V1_19),
|
||||
map(0x39, V1_19_1, V1_19_1),
|
||||
map(0x38, V1_19_3, V1_19_3)
|
||||
);
|
||||
clientBound.register(PacketKeepAlive::new,
|
||||
map(0x00, V1_7_2, V1_8),
|
||||
map(0x1F, V1_9, V1_12_2),
|
||||
map(0x21, V1_13, V1_13_2),
|
||||
map(0x20, V1_14, V1_14_4),
|
||||
map(0x21, V1_15, V1_15_2),
|
||||
map(0x20, V1_16, V1_16_1),
|
||||
map(0x1F, V1_16_2, V1_16_4),
|
||||
map(0x21, V1_17, V1_18_2),
|
||||
map(0x1E, V1_19, V1_19),
|
||||
map(0x20, V1_19_1, V1_19_1),
|
||||
map(0x1F, V1_19_3, V1_19_3)
|
||||
);
|
||||
clientBound.register(PacketChatMessage::new,
|
||||
map(0x02, V1_7_2, V1_8),
|
||||
map(0x0F, V1_9, V1_12_2),
|
||||
map(0x0E, V1_13, V1_14_4),
|
||||
map(0x0F, V1_15, V1_15_2),
|
||||
map(0x0E, V1_16, V1_16_4),
|
||||
map(0x0F, V1_17, V1_18_2),
|
||||
map(0x5F, V1_19, V1_19),
|
||||
map(0x62, V1_19_1, V1_19_1),
|
||||
map(0x60, V1_19_3, V1_19_3)
|
||||
);
|
||||
clientBound.register(PacketBossBar::new,
|
||||
map(0x0C, V1_9, V1_14_4),
|
||||
map(0x0D, V1_15, V1_15_2),
|
||||
map(0x0C, V1_16, V1_16_4),
|
||||
map(0x0D, V1_17, V1_18_2),
|
||||
map(0x0A, V1_19, V1_19_3)
|
||||
);
|
||||
clientBound.register(PacketPlayerInfo::new,
|
||||
map(0x38, V1_7_2, V1_8),
|
||||
map(0x2D, V1_9, V1_12),
|
||||
map(0x2E, V1_12_1, V1_12_2),
|
||||
map(0x30, V1_13, V1_13_2),
|
||||
map(0x33, V1_14, V1_14_4),
|
||||
map(0x34, V1_15, V1_15_2),
|
||||
map(0x33, V1_16, V1_16_1),
|
||||
map(0x32, V1_16_2, V1_16_4),
|
||||
map(0x36, V1_17, V1_18_2),
|
||||
map(0x34, V1_19, V1_19),
|
||||
map(0x37, V1_19_1, V1_19_1),
|
||||
map(0x36, V1_19_3, V1_19_3)
|
||||
);
|
||||
clientBound.register(PacketTitleLegacy::new,
|
||||
map(0x45, V1_8, V1_11_1),
|
||||
map(0x47, V1_12, V1_12),
|
||||
map(0x48, V1_12_1, V1_12_2),
|
||||
map(0x4B, V1_13, V1_13_2),
|
||||
map(0x4F, V1_14, V1_14_4),
|
||||
map(0x50, V1_15, V1_15_2),
|
||||
map(0x4F, V1_16, V1_16_4)
|
||||
);
|
||||
clientBound.register(PacketTitleSetTitle::new,
|
||||
map(0x59, V1_17, V1_17_1),
|
||||
map(0x5A, V1_18, V1_19),
|
||||
map(0x5D, V1_19_1, V1_19_1),
|
||||
map(0x5B, V1_19_3, V1_19_3)
|
||||
);
|
||||
clientBound.register(PacketTitleSetSubTitle::new,
|
||||
map(0x57, V1_17, V1_17_1),
|
||||
map(0x58, V1_18, V1_19),
|
||||
map(0x5B, V1_19_1, V1_19_1),
|
||||
map(0x59, V1_19_3, V1_19_3)
|
||||
);
|
||||
clientBound.register(PacketTitleTimes::new,
|
||||
map(0x5A, V1_17, V1_17_1),
|
||||
map(0x5B, V1_18, V1_19),
|
||||
map(0x5E, V1_19_1, V1_19_1),
|
||||
map(0x5C, V1_19_3, V1_19_3)
|
||||
);
|
||||
clientBound.register(PacketPlayerListHeader::new,
|
||||
map(0x47, V1_8, V1_8),
|
||||
map(0x48, V1_9, V1_9_2),
|
||||
map(0x47, V1_9_4, V1_11_1),
|
||||
map(0x49, V1_12, V1_12),
|
||||
map(0x4A, V1_12_1, V1_12_2),
|
||||
map(0x4E, V1_13, V1_13_2),
|
||||
map(0x53, V1_14, V1_14_4),
|
||||
map(0x54, V1_15, V1_15_2),
|
||||
map(0x53, V1_16, V1_16_4),
|
||||
map(0x5E, V1_17, V1_17_1),
|
||||
map(0x5F, V1_18, V1_18_2),
|
||||
map(0x60, V1_19, V1_19),
|
||||
map(0x63, V1_19_1, V1_19_1),
|
||||
map(0x61, V1_19_3, V1_19_3)
|
||||
);
|
||||
clientBound.register(PacketSpawnPosition::new,
|
||||
map(0x4C, V1_19_3, V1_19_3)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
private static final Map<Integer, State> STATE_BY_ID = new HashMap<>();
|
||||
|
||||
static {
|
||||
for (State registry : values()) {
|
||||
STATE_BY_ID.put(registry.stateId, registry);
|
||||
}
|
||||
}
|
||||
|
||||
private final int stateId;
|
||||
public final ProtocolMappings serverBound = new ProtocolMappings();
|
||||
public final ProtocolMappings clientBound = new ProtocolMappings();
|
||||
|
||||
State(int stateId) {
|
||||
this.stateId = stateId;
|
||||
}
|
||||
|
||||
public static State getById(int stateId) {
|
||||
return STATE_BY_ID.get(stateId);
|
||||
}
|
||||
|
||||
public static class ProtocolMappings {
|
||||
|
||||
private final Map<Version, PacketRegistry> registry = new HashMap<>();
|
||||
|
||||
public PacketRegistry getRegistry(Version version) {
|
||||
return registry.getOrDefault(version, registry.get(getMin()));
|
||||
}
|
||||
|
||||
public void register(Supplier<?> packet, Mapping... mappings) {
|
||||
for (Mapping mapping : mappings) {
|
||||
for (Version ver : getRange(mapping)) {
|
||||
PacketRegistry reg = registry.computeIfAbsent(ver, PacketRegistry::new);
|
||||
reg.register(mapping.packetId, packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Collection<Version> getRange(Mapping mapping) {
|
||||
Version from = mapping.from;
|
||||
Version curr = mapping.to;
|
||||
|
||||
if (curr == from)
|
||||
return Collections.singletonList(from);
|
||||
|
||||
List<Version> versions = new LinkedList<>();
|
||||
|
||||
while (curr != from) {
|
||||
versions.add(curr);
|
||||
curr = curr.getPrev();
|
||||
}
|
||||
|
||||
versions.add(from);
|
||||
|
||||
return versions;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class PacketRegistry {
|
||||
|
||||
private final Version version;
|
||||
private final Map<Integer, Supplier<?>> packetsById = new HashMap<>();
|
||||
private final Map<Class<?>, Integer> packetIdByClass = new HashMap<>();
|
||||
|
||||
public PacketRegistry(Version version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public Version getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public Packet getPacket(int packetId) {
|
||||
Supplier<?> supplier = packetsById.get(packetId);
|
||||
return supplier == null ? null : (Packet) supplier.get();
|
||||
}
|
||||
|
||||
public int getPacketId(Class<?> packetClass) {
|
||||
return packetIdByClass.getOrDefault(packetClass, -1);
|
||||
}
|
||||
|
||||
public void register(int packetId, Supplier<?> supplier) {
|
||||
packetsById.put(packetId, supplier);
|
||||
packetIdByClass.put(supplier.get().getClass(), packetId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class Mapping {
|
||||
|
||||
private final int packetId;
|
||||
private final Version from;
|
||||
private final Version to;
|
||||
|
||||
public Mapping(int packetId, Version from, Version to) {
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
this.packetId = packetId;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Map packet id to version range
|
||||
* @param packetId Packet id
|
||||
* @param from Minimal version (include)
|
||||
* @param to Last version (include)
|
||||
* @return Created mapping
|
||||
*/
|
||||
private static Mapping map(int packetId, Version from, Version to) {
|
||||
return new Mapping(packetId, from, to);
|
||||
}
|
||||
|
||||
}
|
||||
137
src/main/java/ua/nanit/limbo/protocol/registry/Version.java
Normal file
137
src/main/java/ua/nanit/limbo/protocol/registry/Version.java
Normal file
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.protocol.registry;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public enum Version {
|
||||
|
||||
UNDEFINED(-1),
|
||||
V1_7_2(4),
|
||||
// 1.7.2-1.7.5 has same protocol numbers
|
||||
V1_7_6(5),
|
||||
// 1.7.6-1.7.10 has same protocol numbers
|
||||
V1_8(47),
|
||||
// 1.8-1.8.8 has same protocol numbers
|
||||
V1_9(107),
|
||||
V1_9_1(108),
|
||||
V1_9_2(109),
|
||||
V1_9_4(110),
|
||||
V1_10(210),
|
||||
// 1.10-1.10.2 has same protocol numbers
|
||||
V1_11(315),
|
||||
V1_11_1(316),
|
||||
// 1.11.2 has same protocol number
|
||||
V1_12(335),
|
||||
V1_12_1(338),
|
||||
V1_12_2(340),
|
||||
V1_13(393),
|
||||
V1_13_1(401),
|
||||
V1_13_2(404),
|
||||
V1_14(477),
|
||||
V1_14_1(480),
|
||||
V1_14_2(485),
|
||||
V1_14_3(490),
|
||||
V1_14_4(498),
|
||||
V1_15(573),
|
||||
V1_15_1(575),
|
||||
V1_15_2(578),
|
||||
V1_16(735),
|
||||
V1_16_1(736),
|
||||
V1_16_2(751),
|
||||
V1_16_3(753),
|
||||
V1_16_4(754),
|
||||
// 1.16.5 has same protocol number
|
||||
V1_17(755),
|
||||
V1_17_1(756),
|
||||
V1_18(757),
|
||||
// 1.18.1 has same protocol number
|
||||
V1_18_2(758),
|
||||
V1_19(759),
|
||||
V1_19_1(760),
|
||||
V1_19_3(761);
|
||||
|
||||
private static final Map<Integer, Version> VERSION_MAP;
|
||||
private static final Version MAX;
|
||||
|
||||
static {
|
||||
Version[] values = values();
|
||||
|
||||
VERSION_MAP = new HashMap<>();
|
||||
MAX = values[values.length - 1];
|
||||
|
||||
Version last = null;
|
||||
for (Version version : values) {
|
||||
version.prev = last;
|
||||
last = version;
|
||||
VERSION_MAP.put(version.getProtocolNumber(), version);
|
||||
}
|
||||
}
|
||||
|
||||
private final int protocolNumber;
|
||||
private Version prev;
|
||||
|
||||
Version(int protocolNumber) {
|
||||
this.protocolNumber = protocolNumber;
|
||||
}
|
||||
|
||||
public int getProtocolNumber() {
|
||||
return this.protocolNumber;
|
||||
}
|
||||
|
||||
public Version getPrev() {
|
||||
return prev;
|
||||
}
|
||||
|
||||
public boolean more(Version another) {
|
||||
return this.protocolNumber > another.protocolNumber;
|
||||
}
|
||||
|
||||
public boolean moreOrEqual(Version another) {
|
||||
return this.protocolNumber >= another.protocolNumber;
|
||||
}
|
||||
|
||||
public boolean less(Version another) {
|
||||
return this.protocolNumber < another.protocolNumber;
|
||||
}
|
||||
|
||||
public boolean lessOrEqual(Version another) {
|
||||
return this.protocolNumber <= another.protocolNumber;
|
||||
}
|
||||
|
||||
public boolean fromTo(Version min, Version max) {
|
||||
return this.protocolNumber >= min.protocolNumber && this.protocolNumber <= max.protocolNumber;
|
||||
}
|
||||
|
||||
public boolean isSupported() {
|
||||
return this != UNDEFINED;
|
||||
}
|
||||
|
||||
public static Version getMin() {
|
||||
return V1_7_2;
|
||||
}
|
||||
|
||||
public static Version getMax() {
|
||||
return MAX;
|
||||
}
|
||||
|
||||
public static Version of(int protocolNumber) {
|
||||
return VERSION_MAP.getOrDefault(protocolNumber, UNDEFINED);
|
||||
}
|
||||
}
|
||||
9
src/main/java/ua/nanit/limbo/server/Command.java
Normal file
9
src/main/java/ua/nanit/limbo/server/Command.java
Normal file
@@ -0,0 +1,9 @@
|
||||
package ua.nanit.limbo.server;
|
||||
|
||||
public interface Command {
|
||||
|
||||
void execute();
|
||||
|
||||
String description();
|
||||
|
||||
}
|
||||
59
src/main/java/ua/nanit/limbo/server/CommandManager.java
Normal file
59
src/main/java/ua/nanit/limbo/server/CommandManager.java
Normal file
@@ -0,0 +1,59 @@
|
||||
package ua.nanit.limbo.server;
|
||||
|
||||
import ua.nanit.limbo.server.commands.CmdConn;
|
||||
import ua.nanit.limbo.server.commands.CmdHelp;
|
||||
import ua.nanit.limbo.server.commands.CmdMem;
|
||||
import ua.nanit.limbo.server.commands.CmdStop;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public final class CommandManager extends Thread {
|
||||
|
||||
private final Map<String, Command> commands = new HashMap<>();
|
||||
|
||||
public Map<String, Command> getCommands() {
|
||||
return Collections.unmodifiableMap(commands);
|
||||
}
|
||||
|
||||
public Command getCommand(String name) {
|
||||
return commands.get(name.toLowerCase());
|
||||
}
|
||||
|
||||
public void register(String name, Command cmd) {
|
||||
commands.put(name.toLowerCase(), cmd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Scanner scanner = new Scanner(System.in);
|
||||
String command;
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
command = scanner.nextLine().trim();
|
||||
} catch (NoSuchElementException e) {
|
||||
break;
|
||||
}
|
||||
|
||||
Command handler = getCommand(command);
|
||||
|
||||
if (handler != null) {
|
||||
try {
|
||||
handler.execute();
|
||||
} catch (Throwable t) {
|
||||
Logger.error("Cannot execute command:", t);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
Logger.info("Unknown command. Type \"help\" to get commands list");
|
||||
}
|
||||
}
|
||||
|
||||
public void registerAll(LimboServer server) {
|
||||
register("help", new CmdHelp(server));
|
||||
register("conn", new CmdConn(server));
|
||||
register("mem", new CmdMem());
|
||||
register("stop", new CmdStop());
|
||||
}
|
||||
}
|
||||
54
src/main/java/ua/nanit/limbo/server/Connections.java
Normal file
54
src/main/java/ua/nanit/limbo/server/Connections.java
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.server;
|
||||
|
||||
import ua.nanit.limbo.connection.ClientConnection;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public final class Connections {
|
||||
|
||||
private final Map<UUID, ClientConnection> connections;
|
||||
|
||||
public Connections() {
|
||||
connections = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
public Collection<ClientConnection> getAllConnections() {
|
||||
return Collections.unmodifiableCollection(connections.values());
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return connections.size();
|
||||
}
|
||||
|
||||
public void addConnection(ClientConnection connection) {
|
||||
connections.put(connection.getUuid(), connection);
|
||||
Logger.info("Player %s connected (%s) [%s]", connection.getUsername(),
|
||||
connection.getAddress(), connection.getClientVersion());
|
||||
}
|
||||
|
||||
public void removeConnection(ClientConnection connection) {
|
||||
connections.remove(connection.getUuid());
|
||||
Logger.info("Player %s disconnected", connection.getUsername());
|
||||
}
|
||||
}
|
||||
152
src/main/java/ua/nanit/limbo/server/LimboServer.java
Normal file
152
src/main/java/ua/nanit/limbo/server/LimboServer.java
Normal file
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.server;
|
||||
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.ServerChannel;
|
||||
import io.netty.channel.epoll.Epoll;
|
||||
import io.netty.channel.epoll.EpollEventLoopGroup;
|
||||
import io.netty.channel.epoll.EpollServerSocketChannel;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
import io.netty.util.ResourceLeakDetector;
|
||||
import ua.nanit.limbo.configuration.LimboConfig;
|
||||
import ua.nanit.limbo.connection.ClientChannelInitializer;
|
||||
import ua.nanit.limbo.connection.ClientConnection;
|
||||
import ua.nanit.limbo.connection.PacketHandler;
|
||||
import ua.nanit.limbo.connection.PacketSnapshots;
|
||||
import ua.nanit.limbo.world.DimensionRegistry;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public final class LimboServer {
|
||||
|
||||
private LimboConfig config;
|
||||
private PacketHandler packetHandler;
|
||||
private Connections connections;
|
||||
private DimensionRegistry dimensionRegistry;
|
||||
private ScheduledFuture<?> keepAliveTask;
|
||||
|
||||
private EventLoopGroup bossGroup;
|
||||
private EventLoopGroup workerGroup;
|
||||
|
||||
private CommandManager commandManager;
|
||||
|
||||
public LimboConfig getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
public PacketHandler getPacketHandler() {
|
||||
return packetHandler;
|
||||
}
|
||||
|
||||
public Connections getConnections() {
|
||||
return connections;
|
||||
}
|
||||
|
||||
public DimensionRegistry getDimensionRegistry() {
|
||||
return dimensionRegistry;
|
||||
}
|
||||
|
||||
public CommandManager getCommandManager() {
|
||||
return commandManager;
|
||||
}
|
||||
|
||||
public void start() throws Exception {
|
||||
Logger.info("Starting server...");
|
||||
|
||||
ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.DISABLED);
|
||||
|
||||
config = new LimboConfig(Paths.get("./"));
|
||||
config.load();
|
||||
|
||||
packetHandler = new PacketHandler(this);
|
||||
dimensionRegistry = new DimensionRegistry(this);
|
||||
dimensionRegistry.load(config.getDimensionType());
|
||||
connections = new Connections();
|
||||
|
||||
PacketSnapshots.initPackets(this);
|
||||
|
||||
startBootstrap();
|
||||
|
||||
keepAliveTask = workerGroup.scheduleAtFixedRate(this::broadcastKeepAlive, 0L, 5L, TimeUnit.SECONDS);
|
||||
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(this::stop, "NanoLimbo shutdown thread"));
|
||||
|
||||
Logger.info("Server started on %s", config.getAddress());
|
||||
|
||||
Logger.setLevel(config.getDebugLevel());
|
||||
|
||||
commandManager = new CommandManager();
|
||||
commandManager.registerAll(this);
|
||||
commandManager.start();
|
||||
|
||||
System.gc();
|
||||
}
|
||||
|
||||
private void startBootstrap() {
|
||||
Class<? extends ServerChannel> channelClass;
|
||||
|
||||
if (config.isUseEpoll() && Epoll.isAvailable()) {
|
||||
bossGroup = new EpollEventLoopGroup(config.getBossGroupSize());
|
||||
workerGroup = new EpollEventLoopGroup(config.getWorkerGroupSize());
|
||||
channelClass = EpollServerSocketChannel.class;
|
||||
Logger.debug("Using Epoll transport type");
|
||||
} else {
|
||||
bossGroup = new NioEventLoopGroup(config.getBossGroupSize());
|
||||
workerGroup = new NioEventLoopGroup(config.getWorkerGroupSize());
|
||||
channelClass = NioServerSocketChannel.class;
|
||||
Logger.debug("Using Java NIO transport type");
|
||||
}
|
||||
|
||||
new ServerBootstrap()
|
||||
.group(bossGroup, workerGroup)
|
||||
.channel(channelClass)
|
||||
.childHandler(new ClientChannelInitializer(this))
|
||||
.childOption(ChannelOption.TCP_NODELAY, true)
|
||||
.localAddress(config.getAddress())
|
||||
.bind();
|
||||
}
|
||||
|
||||
private void broadcastKeepAlive() {
|
||||
connections.getAllConnections().forEach(ClientConnection::sendKeepAlive);
|
||||
}
|
||||
|
||||
private void stop() {
|
||||
Logger.info("Stopping server...");
|
||||
|
||||
if (keepAliveTask != null) {
|
||||
keepAliveTask.cancel(true);
|
||||
}
|
||||
|
||||
if (bossGroup != null) {
|
||||
bossGroup.shutdownGracefully();
|
||||
}
|
||||
|
||||
if (workerGroup != null) {
|
||||
workerGroup.shutdownGracefully();
|
||||
}
|
||||
|
||||
Logger.info("Server stopped, Goodbye!");
|
||||
}
|
||||
|
||||
}
|
||||
100
src/main/java/ua/nanit/limbo/server/Logger.java
Normal file
100
src/main/java/ua/nanit/limbo/server/Logger.java
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.server;
|
||||
|
||||
import java.time.LocalTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
public final class Logger {
|
||||
|
||||
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("hh:mm:ss");
|
||||
private static int debugLevel = Level.INFO.getIndex();
|
||||
|
||||
private Logger() {}
|
||||
|
||||
public static int getLevel() {
|
||||
return debugLevel;
|
||||
}
|
||||
|
||||
public static void info(Object msg, Object... args) {
|
||||
print(Level.INFO, msg, null, args);
|
||||
}
|
||||
|
||||
public static void debug(Object msg, Object... args) {
|
||||
print(Level.DEBUG, msg, null, args);
|
||||
}
|
||||
|
||||
public static void warning(Object msg, Object... args) {
|
||||
print(Level.WARNING, msg, null, args);
|
||||
}
|
||||
|
||||
public static void warning(Object msg, Throwable t, Object... args) {
|
||||
print(Level.WARNING, msg, t, args);
|
||||
}
|
||||
|
||||
public static void error(Object msg, Object... args) {
|
||||
print(Level.ERROR, msg, null, args);
|
||||
}
|
||||
|
||||
public static void error(Object msg, Throwable t, Object... args) {
|
||||
print(Level.ERROR, msg, t, args);
|
||||
}
|
||||
|
||||
public static void print(Level level, Object msg, Throwable t, Object... args) {
|
||||
if (debugLevel >= level.getIndex()) {
|
||||
System.out.printf("%s: %s%n", getPrefix(level), String.format(msg.toString(), args));
|
||||
if (t != null) t.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static String getPrefix(Level level) {
|
||||
return String.format("[%s] [%s]", getTime(), level.getDisplay());
|
||||
}
|
||||
|
||||
private static String getTime() {
|
||||
return LocalTime.now().format(FORMATTER);
|
||||
}
|
||||
|
||||
static void setLevel(int level) {
|
||||
debugLevel = level;
|
||||
}
|
||||
|
||||
public enum Level {
|
||||
|
||||
ERROR("ERROR", 0),
|
||||
WARNING("WARNING", 1),
|
||||
INFO("INFO", 2),
|
||||
DEBUG("DEBUG", 3);
|
||||
|
||||
private final String display;
|
||||
private final int index;
|
||||
|
||||
Level(String display, int index) {
|
||||
this.display = display;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
public String getDisplay() {
|
||||
return display;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
}
|
||||
24
src/main/java/ua/nanit/limbo/server/commands/CmdConn.java
Normal file
24
src/main/java/ua/nanit/limbo/server/commands/CmdConn.java
Normal file
@@ -0,0 +1,24 @@
|
||||
package ua.nanit.limbo.server.commands;
|
||||
|
||||
import ua.nanit.limbo.server.Command;
|
||||
import ua.nanit.limbo.server.LimboServer;
|
||||
import ua.nanit.limbo.server.Logger;
|
||||
|
||||
public class CmdConn implements Command {
|
||||
|
||||
private final LimboServer server;
|
||||
|
||||
public CmdConn(LimboServer server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
Logger.info("Connections: %d", server.getConnections().getCount());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return "Display connections count";
|
||||
}
|
||||
}
|
||||
32
src/main/java/ua/nanit/limbo/server/commands/CmdHelp.java
Normal file
32
src/main/java/ua/nanit/limbo/server/commands/CmdHelp.java
Normal file
@@ -0,0 +1,32 @@
|
||||
package ua.nanit.limbo.server.commands;
|
||||
|
||||
import ua.nanit.limbo.server.Command;
|
||||
import ua.nanit.limbo.server.LimboServer;
|
||||
import ua.nanit.limbo.server.Logger;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class CmdHelp implements Command {
|
||||
|
||||
private final LimboServer server;
|
||||
|
||||
public CmdHelp(LimboServer server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
Map<String, Command> commands = server.getCommandManager().getCommands();
|
||||
|
||||
Logger.info("Available commands:");
|
||||
|
||||
for (Map.Entry<String, Command> entry : commands.entrySet()) {
|
||||
Logger.info("%s - %s", entry.getKey(), entry.getValue().description());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return "Show this message";
|
||||
}
|
||||
}
|
||||
28
src/main/java/ua/nanit/limbo/server/commands/CmdMem.java
Normal file
28
src/main/java/ua/nanit/limbo/server/commands/CmdMem.java
Normal file
@@ -0,0 +1,28 @@
|
||||
package ua.nanit.limbo.server.commands;
|
||||
|
||||
import ua.nanit.limbo.server.Command;
|
||||
import ua.nanit.limbo.server.Logger;
|
||||
|
||||
public class CmdMem implements Command {
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
Runtime runtime = Runtime.getRuntime();
|
||||
long mb = 1024 * 1024;
|
||||
long used = (runtime.totalMemory() - runtime.freeMemory()) / mb;
|
||||
long total = runtime.totalMemory() / mb;
|
||||
long free = runtime.freeMemory() / mb;
|
||||
long max = runtime.maxMemory() / mb;
|
||||
|
||||
Logger.info("Memory usage:");
|
||||
Logger.info("Used: %d MB", used);
|
||||
Logger.info("Total: %d MB", total);
|
||||
Logger.info("Free: %d MB", free);
|
||||
Logger.info("Max: %d MB", max);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return "Display memory usage";
|
||||
}
|
||||
}
|
||||
16
src/main/java/ua/nanit/limbo/server/commands/CmdStop.java
Normal file
16
src/main/java/ua/nanit/limbo/server/commands/CmdStop.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package ua.nanit.limbo.server.commands;
|
||||
|
||||
import ua.nanit.limbo.server.Command;
|
||||
|
||||
public class CmdStop implements Command {
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return "Stop the server";
|
||||
}
|
||||
}
|
||||
139
src/main/java/ua/nanit/limbo/server/data/BossBar.java
Normal file
139
src/main/java/ua/nanit/limbo/server/data/BossBar.java
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.server.data;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.spongepowered.configurate.ConfigurationNode;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
import org.spongepowered.configurate.serialize.TypeSerializer;
|
||||
import ua.nanit.limbo.util.Colors;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
public class BossBar {
|
||||
|
||||
private String text;
|
||||
private float health;
|
||||
private Color color;
|
||||
private Division division;
|
||||
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
public float getHealth() {
|
||||
return health;
|
||||
}
|
||||
|
||||
public Color getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
public Division getDivision() {
|
||||
return division;
|
||||
}
|
||||
|
||||
public void setText(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public void setHealth(float health) {
|
||||
this.health = health;
|
||||
}
|
||||
|
||||
public void setColor(Color color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public void setDivision(Division division) {
|
||||
this.division = division;
|
||||
}
|
||||
|
||||
public enum Color {
|
||||
|
||||
PINK(0),
|
||||
BLUE(1),
|
||||
RED(2),
|
||||
GREEN(3),
|
||||
YELLOW(4),
|
||||
PURPLE(5),
|
||||
WHITE(6);
|
||||
|
||||
private final int index;
|
||||
|
||||
Color(int index) {
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
public enum Division {
|
||||
|
||||
SOLID(0),
|
||||
DASHES_6(1),
|
||||
DASHES_10(2),
|
||||
DASHES_12(3),
|
||||
DASHES_20(4);
|
||||
|
||||
private final int index;
|
||||
|
||||
Division(int index) {
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Serializer implements TypeSerializer<BossBar> {
|
||||
|
||||
@Override
|
||||
public BossBar deserialize(Type type, ConfigurationNode node) throws SerializationException {
|
||||
BossBar bossBar = new BossBar();
|
||||
|
||||
bossBar.setText(Colors.of(node.node("text").getString("")));
|
||||
bossBar.setHealth(node.node("health").getFloat());
|
||||
|
||||
if (bossBar.getHealth() < 0 || bossBar.getHealth() > 1)
|
||||
throw new SerializationException("BossBar health value must be between 0.0 and 1.0");
|
||||
|
||||
try {
|
||||
bossBar.setColor(Color.valueOf(node.node("color").getString("").toUpperCase()));
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new SerializationException("Invalid bossbar color");
|
||||
}
|
||||
|
||||
try {
|
||||
bossBar.setDivision(Division.valueOf(node.node("division").getString("").toUpperCase()));
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new SerializationException("Invalid bossbar division");
|
||||
}
|
||||
|
||||
return bossBar;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(Type type, @Nullable BossBar obj, ConfigurationNode node) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
102
src/main/java/ua/nanit/limbo/server/data/InfoForwarding.java
Normal file
102
src/main/java/ua/nanit/limbo/server/data/InfoForwarding.java
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.server.data;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.spongepowered.configurate.ConfigurationNode;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
import org.spongepowered.configurate.serialize.TypeSerializer;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
|
||||
public class InfoForwarding {
|
||||
|
||||
private Type type;
|
||||
private byte[] secretKey;
|
||||
private List<String> tokens;
|
||||
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public byte[] getSecretKey() {
|
||||
return secretKey;
|
||||
}
|
||||
|
||||
public List<String> getTokens() {
|
||||
return tokens;
|
||||
}
|
||||
|
||||
public boolean hasToken(String token) {
|
||||
return tokens != null && token != null && tokens.contains(token);
|
||||
}
|
||||
|
||||
public boolean isNone() {
|
||||
return type == Type.NONE;
|
||||
}
|
||||
|
||||
public boolean isLegacy() {
|
||||
return type == Type.LEGACY;
|
||||
}
|
||||
|
||||
public boolean isModern() {
|
||||
return type == Type.MODERN;
|
||||
}
|
||||
|
||||
public boolean isBungeeGuard() {
|
||||
return type == Type.BUNGEE_GUARD;
|
||||
}
|
||||
|
||||
public enum Type {
|
||||
NONE,
|
||||
LEGACY,
|
||||
MODERN,
|
||||
BUNGEE_GUARD
|
||||
}
|
||||
|
||||
public static class Serializer implements TypeSerializer<InfoForwarding> {
|
||||
|
||||
@Override
|
||||
public InfoForwarding deserialize(java.lang.reflect.Type type, ConfigurationNode node) throws SerializationException {
|
||||
InfoForwarding forwarding = new InfoForwarding();
|
||||
|
||||
try {
|
||||
forwarding.type = Type.valueOf(node.node("type").getString("").toUpperCase());
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new SerializationException("Undefined info forwarding type");
|
||||
}
|
||||
|
||||
if (forwarding.type == Type.MODERN) {
|
||||
forwarding.secretKey = node.node("secret").getString("").getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
if (forwarding.type == Type.BUNGEE_GUARD) {
|
||||
forwarding.tokens = node.node("tokens").getList(String.class);
|
||||
}
|
||||
|
||||
return forwarding;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(java.lang.reflect.Type type, @Nullable InfoForwarding obj, ConfigurationNode node) throws SerializationException {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
63
src/main/java/ua/nanit/limbo/server/data/PingData.java
Normal file
63
src/main/java/ua/nanit/limbo/server/data/PingData.java
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.server.data;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.spongepowered.configurate.ConfigurationNode;
|
||||
import org.spongepowered.configurate.serialize.TypeSerializer;
|
||||
import ua.nanit.limbo.util.Colors;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
public class PingData {
|
||||
|
||||
private String version;
|
||||
private String description;
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(String version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public static class Serializer implements TypeSerializer<PingData> {
|
||||
|
||||
@Override
|
||||
public PingData deserialize(Type type, ConfigurationNode node) {
|
||||
PingData pingData = new PingData();
|
||||
pingData.setDescription(Colors.of(node.node("description").getString("")));
|
||||
pingData.setVersion(Colors.of(node.node("version").getString("")));
|
||||
return pingData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(Type type, @Nullable PingData obj, ConfigurationNode node) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
93
src/main/java/ua/nanit/limbo/server/data/Title.java
Normal file
93
src/main/java/ua/nanit/limbo/server/data/Title.java
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.server.data;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.spongepowered.configurate.ConfigurationNode;
|
||||
import org.spongepowered.configurate.serialize.TypeSerializer;
|
||||
import ua.nanit.limbo.util.Colors;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
public class Title {
|
||||
|
||||
private String title;
|
||||
private String subtitle;
|
||||
private int fadeIn;
|
||||
private int stay;
|
||||
private int fadeOut;
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public String getSubtitle() {
|
||||
return subtitle;
|
||||
}
|
||||
|
||||
public int getFadeIn() {
|
||||
return fadeIn;
|
||||
}
|
||||
|
||||
public int getStay() {
|
||||
return stay;
|
||||
}
|
||||
|
||||
public int getFadeOut() {
|
||||
return fadeOut;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public void setSubtitle(String subtitle) {
|
||||
this.subtitle = subtitle;
|
||||
}
|
||||
|
||||
public void setFadeIn(int fadeIn) {
|
||||
this.fadeIn = fadeIn;
|
||||
}
|
||||
|
||||
public void setStay(int stay) {
|
||||
this.stay = stay;
|
||||
}
|
||||
|
||||
public void setFadeOut(int fadeOut) {
|
||||
this.fadeOut = fadeOut;
|
||||
}
|
||||
|
||||
public static class Serializer implements TypeSerializer<Title> {
|
||||
|
||||
@Override
|
||||
public Title deserialize(Type type, ConfigurationNode node) {
|
||||
Title title = new Title();
|
||||
title.setTitle(Colors.of(node.node("title").getString("")));
|
||||
title.setSubtitle(Colors.of(node.node("subtitle").getString("")));
|
||||
title.setFadeIn(node.node("fadeIn").getInt(10));
|
||||
title.setStay(node.node("stay").getInt(100));
|
||||
title.setFadeOut(node.node("fadeOut").getInt(10));
|
||||
return title;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(Type type, @Nullable Title obj, ConfigurationNode node) {
|
||||
// Not used
|
||||
}
|
||||
}
|
||||
}
|
||||
33
src/main/java/ua/nanit/limbo/util/Colors.java
Normal file
33
src/main/java/ua/nanit/limbo/util/Colors.java
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.util;
|
||||
|
||||
public final class Colors {
|
||||
|
||||
private static final char CHAR_FROM = '&';
|
||||
private static final char CHAR_TO = '\u00a7';
|
||||
|
||||
private Colors() {
|
||||
}
|
||||
|
||||
public static String of(String text) {
|
||||
if (text == null) return null;
|
||||
return text.replace(CHAR_FROM, CHAR_TO);
|
||||
}
|
||||
|
||||
}
|
||||
37
src/main/java/ua/nanit/limbo/util/UuidUtil.java
Normal file
37
src/main/java/ua/nanit/limbo/util/UuidUtil.java
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.util;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.UUID;
|
||||
|
||||
public final class UuidUtil {
|
||||
|
||||
private UuidUtil() {}
|
||||
|
||||
public static UUID getOfflineModeUuid(String username) {
|
||||
return UUID.nameUUIDFromBytes(("OfflinePlayer:" + username)
|
||||
.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
public static UUID fromString(String str) {
|
||||
if(str.contains("-")) return UUID.fromString(str);
|
||||
return UUID.fromString(str.replaceFirst("(\\p{XDigit}{8})(\\p{XDigit}{4})(\\p{XDigit}{4})(\\p{XDigit}{4})(\\p{XDigit}+)", "$1-$2-$3-$4-$5"));
|
||||
}
|
||||
|
||||
}
|
||||
45
src/main/java/ua/nanit/limbo/world/Dimension.java
Normal file
45
src/main/java/ua/nanit/limbo/world/Dimension.java
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.world;
|
||||
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
|
||||
public class Dimension {
|
||||
|
||||
private final int id;
|
||||
private final String name;
|
||||
private final CompoundBinaryTag data;
|
||||
|
||||
public Dimension(int id, String name, CompoundBinaryTag data) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public CompoundBinaryTag getData() {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
127
src/main/java/ua/nanit/limbo/world/DimensionRegistry.java
Normal file
127
src/main/java/ua/nanit/limbo/world/DimensionRegistry.java
Normal file
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ua.nanit.limbo.world;
|
||||
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.nbt.ListBinaryTag;
|
||||
import net.kyori.adventure.nbt.TagStringIO;
|
||||
import ua.nanit.limbo.server.LimboServer;
|
||||
import ua.nanit.limbo.server.Logger;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public final class DimensionRegistry {
|
||||
|
||||
private final LimboServer server;
|
||||
|
||||
private Dimension defaultDimension_1_16;
|
||||
private Dimension defaultDimension_1_18_2;
|
||||
|
||||
private CompoundBinaryTag codec_1_16;
|
||||
private CompoundBinaryTag codec_1_18_2;
|
||||
private CompoundBinaryTag codec_1_19;
|
||||
private CompoundBinaryTag codec_1_19_1;
|
||||
private CompoundBinaryTag oldCodec;
|
||||
|
||||
public DimensionRegistry(LimboServer server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
public CompoundBinaryTag getCodec_1_16() {
|
||||
return codec_1_16;
|
||||
}
|
||||
|
||||
public CompoundBinaryTag getCodec_1_18_2() {
|
||||
return codec_1_18_2;
|
||||
}
|
||||
|
||||
public CompoundBinaryTag getCodec_1_19() {
|
||||
return codec_1_19;
|
||||
}
|
||||
|
||||
public CompoundBinaryTag getCodec_1_19_1() {
|
||||
return codec_1_19_1;
|
||||
}
|
||||
|
||||
public CompoundBinaryTag getOldCodec() {
|
||||
return oldCodec;
|
||||
}
|
||||
|
||||
public Dimension getDefaultDimension_1_16() {
|
||||
return defaultDimension_1_16;
|
||||
}
|
||||
|
||||
public Dimension getDefaultDimension_1_18_2() {
|
||||
return defaultDimension_1_18_2;
|
||||
}
|
||||
|
||||
public void load(String def) throws IOException {
|
||||
codec_1_16 = readCodecFile("/dimension/codec_1_16.snbt");
|
||||
codec_1_18_2 = readCodecFile("/dimension/codec_1_18_2.snbt");
|
||||
codec_1_19 = readCodecFile("/dimension/codec_1_19.snbt");
|
||||
codec_1_19_1 = readCodecFile("/dimension/codec_1_19_1.snbt");
|
||||
// On 1.16-1.16.1 different codec format
|
||||
oldCodec = readCodecFile("/dimension/codec_old.snbt");
|
||||
|
||||
defaultDimension_1_16 = getDefaultDimension(def, codec_1_16);
|
||||
defaultDimension_1_18_2 = getDefaultDimension(def, codec_1_18_2);
|
||||
}
|
||||
|
||||
private Dimension getDefaultDimension(String def, CompoundBinaryTag tag) {
|
||||
ListBinaryTag dimensions = tag.getCompound("minecraft:dimension_type").getList("value");
|
||||
|
||||
CompoundBinaryTag overWorld = (CompoundBinaryTag) ((CompoundBinaryTag) dimensions.get(0)).get("element");
|
||||
CompoundBinaryTag nether = (CompoundBinaryTag) ((CompoundBinaryTag) dimensions.get(2)).get("element");
|
||||
CompoundBinaryTag theEnd = (CompoundBinaryTag) ((CompoundBinaryTag) dimensions.get(3)).get("element");
|
||||
|
||||
switch (def.toLowerCase()) {
|
||||
case "overworld":
|
||||
return new Dimension(0, "minecraft:overworld", overWorld);
|
||||
case "the_nether":
|
||||
return new Dimension(-1, "minecraft:nether", nether);
|
||||
case "the_end":
|
||||
return new Dimension(1, "minecraft:the_end", theEnd);
|
||||
default:
|
||||
Logger.warning("Undefined dimension type: '%s'. Using THE_END as default", def);
|
||||
return new Dimension(1, "minecraft:the_end", theEnd);
|
||||
}
|
||||
}
|
||||
|
||||
private CompoundBinaryTag readCodecFile(String resPath) throws IOException {
|
||||
InputStream in = server.getClass().getResourceAsStream(resPath);
|
||||
|
||||
if(in == null)
|
||||
throw new FileNotFoundException("Cannot find dimension registry file");
|
||||
|
||||
return TagStringIO.get().asCompound(streamToString(in));
|
||||
}
|
||||
|
||||
private String streamToString(InputStream in) throws IOException {
|
||||
InputStreamReader isReader = new InputStreamReader(in, StandardCharsets.UTF_8);
|
||||
BufferedReader bufReader = new BufferedReader(isReader);
|
||||
String content = bufReader.lines()
|
||||
.collect(Collectors.joining("\n"));
|
||||
|
||||
isReader.close();
|
||||
bufReader.close();
|
||||
|
||||
return content;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user