Minecraft 1.20.2

If only it was as simple as #64
This commit is contained in:
LOOHP 2023-09-24 15:56:36 +01:00
parent 10c5915d71
commit 32499372bf
21 changed files with 52011 additions and 50367 deletions

View File

@ -24,7 +24,7 @@
<groupId>com.loohp</groupId>
<artifactId>Limbo</artifactId>
<name>Limbo</name>
<version>0.7.5-ALPHA</version>
<version>0.7.6-ALPHA</version>
<description>Standalone Limbo Minecraft Server.</description>
<url>https://github.com/LOOHP/Limbo</url>
@ -136,7 +136,7 @@
</executions>
</plugin>
</plugins>
<finalName>${project.artifactId}-${project.version}-1.20.1</finalName>
<finalName>${project.artifactId}-${project.version}-1.20.2</finalName>
</build>
<profiles>

View File

@ -139,8 +139,8 @@ public final class Limbo {
//===========================
public final String SERVER_IMPLEMENTATION_VERSION = "1.20.1";
public final int SERVER_IMPLEMENTATION_PROTOCOL = 763;
public final String SERVER_IMPLEMENTATION_VERSION = "1.20.2";
public final int SERVER_IMPLEMENTATION_PROTOCOL = 764;
public final String LIMBO_IMPLEMENTATION_VERSION;
private final AtomicBoolean isRunning;
@ -236,7 +236,7 @@ public final class Limbo {
Map<Integer, Class<? extends PacketIn>> HandshakeIn = new HashMap<>();
for (Object key : ((JSONObject) json.get("HandshakeIn")).keySet()) {
int packetId = Integer.decode((String) key);
HandshakeIn.put(packetId, (Class<? extends PacketIn>) Class.forName(classPrefix + (String) ((JSONObject) json.get("HandshakeIn")).get(key)));
HandshakeIn.put(packetId, (Class<? extends PacketIn>) Class.forName(classPrefix + ((JSONObject) json.get("HandshakeIn")).get(key)));
}
Packet.setHandshakeIn(HandshakeIn);
mappingsCount += HandshakeIn.size();
@ -244,14 +244,14 @@ public final class Limbo {
Map<Integer, Class<? extends PacketIn>> StatusIn = new HashMap<>();
for (Object key : ((JSONObject) json.get("StatusIn")).keySet()) {
int packetId = Integer.decode((String) key);
StatusIn.put(packetId, (Class<? extends PacketIn>) Class.forName(classPrefix + (String) ((JSONObject) json.get("StatusIn")).get(key)));
StatusIn.put(packetId, (Class<? extends PacketIn>) Class.forName(classPrefix + ((JSONObject) json.get("StatusIn")).get(key)));
}
Packet.setStatusIn(StatusIn);
mappingsCount += StatusIn.size();
Map<Class<? extends PacketOut>, Integer> StatusOut = new HashMap<>();
for (Object key : ((JSONObject) json.get("StatusOut")).keySet()) {
Class<? extends PacketOut> packetClass = (Class<? extends PacketOut>) Class.forName(classPrefix + (String) key);
Class<? extends PacketOut> packetClass = (Class<? extends PacketOut>) Class.forName(classPrefix + key);
StatusOut.put(packetClass, Integer.decode((String) ((JSONObject) json.get("StatusOut")).get(key)));
}
Packet.setStatusOut(StatusOut);
@ -260,30 +260,46 @@ public final class Limbo {
Map<Integer, Class<? extends PacketIn>> LoginIn = new HashMap<>();
for (Object key : ((JSONObject) json.get("LoginIn")).keySet()) {
int packetId = Integer.decode((String) key);
LoginIn.put(packetId, (Class<? extends PacketIn>) Class.forName(classPrefix + (String) ((JSONObject) json.get("LoginIn")).get(key)));
LoginIn.put(packetId, (Class<? extends PacketIn>) Class.forName(classPrefix + ((JSONObject) json.get("LoginIn")).get(key)));
}
Packet.setLoginIn(LoginIn);
mappingsCount += LoginIn.size();
Map<Class<? extends PacketOut>, Integer> LoginOut = new HashMap<>();
for (Object key : ((JSONObject) json.get("LoginOut")).keySet()) {
Class<? extends PacketOut> packetClass = (Class<? extends PacketOut>) Class.forName(classPrefix + (String) key);
Class<? extends PacketOut> packetClass = (Class<? extends PacketOut>) Class.forName(classPrefix + key);
LoginOut.put(packetClass, Integer.decode((String) ((JSONObject) json.get("LoginOut")).get(key)));
}
Packet.setLoginOut(LoginOut);
mappingsCount += LoginOut.size();
Map<Integer, Class<? extends PacketIn>> ConfigurationIn = new HashMap<>();
for (Object key : ((JSONObject) json.get("ConfigurationIn")).keySet()) {
int packetId = Integer.decode((String) key);
ConfigurationIn.put(packetId, (Class<? extends PacketIn>) Class.forName(classPrefix + ((JSONObject) json.get("ConfigurationIn")).get(key)));
}
Packet.setConfigurationIn(ConfigurationIn);
mappingsCount += ConfigurationIn.size();
Map<Class<? extends PacketOut>, Integer> ConfigurationOut = new HashMap<>();
for (Object key : ((JSONObject) json.get("ConfigurationOut")).keySet()) {
Class<? extends PacketOut> packetClass = (Class<? extends PacketOut>) Class.forName(classPrefix + key);
ConfigurationOut.put(packetClass, Integer.decode((String) ((JSONObject) json.get("ConfigurationOut")).get(key)));
}
Packet.setConfigurationOut(ConfigurationOut);
mappingsCount += ConfigurationOut.size();
Map<Integer, Class<? extends PacketIn>> PlayIn = new HashMap<>();
for (Object key : ((JSONObject) json.get("PlayIn")).keySet()) {
int packetId = Integer.decode((String) key);
PlayIn.put(packetId, (Class<? extends PacketIn>) Class.forName(classPrefix + (String) ((JSONObject) json.get("PlayIn")).get(key)));
PlayIn.put(packetId, (Class<? extends PacketIn>) Class.forName(classPrefix + ((JSONObject) json.get("PlayIn")).get(key)));
}
Packet.setPlayIn(PlayIn);
mappingsCount += PlayIn.size();
Map<Class<? extends PacketOut>, Integer> PlayOut = new HashMap<>();
for (Object key : ((JSONObject) json.get("PlayOut")).keySet()) {
Class<? extends PacketOut> packetClass = (Class<? extends PacketOut>) Class.forName(classPrefix + (String) key);
Class<? extends PacketOut> packetClass = (Class<? extends PacketOut>) Class.forName(classPrefix + key);
PlayOut.put(packetClass, Integer.decode((String) ((JSONObject) json.get("PlayOut")).get(key)));
}
Packet.setPlayOut(PlayOut);

View File

@ -34,12 +34,14 @@ import java.util.concurrent.atomic.AtomicBoolean;
public class Channel implements AutoCloseable {
private final ClientConnection client;
private final List<Pair<Key, ChannelPacketHandler>> handlers;
private final AtomicBoolean valid;
protected final DataInputStream input;
protected final DataOutputStream output;
public Channel(DataInputStream input, DataOutputStream output) {
public Channel(ClientConnection client, DataInputStream input, DataOutputStream output) {
this.client = client;
this.input = input;
this.output = output;
this.handlers = new CopyOnWriteArrayList<>();
@ -89,7 +91,13 @@ public class Channel implements AutoCloseable {
}
protected boolean writePacket(PacketOut packet) throws IOException {
if (client.getClientState() == ClientConnection.ClientState.DISCONNECTED) {
return false;
}
ensureOpen();
if (packet.getPacketState() != client.getClientState()) {
return false;
}
ChannelPacketWrite write = new ChannelPacketWrite(packet);
for (Pair<Key, ChannelPacketHandler> pair : handlers) {
write = pair.getSecond().write(write);

View File

@ -41,6 +41,8 @@ import com.loohp.limbo.inventory.AnvilInventory;
import com.loohp.limbo.inventory.Inventory;
import com.loohp.limbo.inventory.ItemStack;
import com.loohp.limbo.location.Location;
import com.loohp.limbo.network.protocol.packets.ClientboundFinishConfigurationPacket;
import com.loohp.limbo.network.protocol.packets.ClientboundRegistryDataPacket;
import com.loohp.limbo.network.protocol.packets.Packet;
import com.loohp.limbo.network.protocol.packets.PacketHandshakingIn;
import com.loohp.limbo.network.protocol.packets.PacketIn;
@ -92,6 +94,7 @@ import com.loohp.limbo.network.protocol.packets.PacketStatusInRequest;
import com.loohp.limbo.network.protocol.packets.PacketStatusOutPong;
import com.loohp.limbo.network.protocol.packets.PacketStatusOutResponse;
import com.loohp.limbo.network.protocol.packets.ServerboundChatCommandPacket;
import com.loohp.limbo.network.protocol.packets.ServerboundFinishConfigurationPacket;
import com.loohp.limbo.player.Player;
import com.loohp.limbo.player.PlayerInteractManager;
import com.loohp.limbo.player.PlayerInventory;
@ -155,7 +158,7 @@ public class ClientConnection extends Thread {
private final Socket clientSocket;
protected Channel channel;
private boolean running;
private ClientState state;
private volatile ClientState state;
private Player player;
private TimerTask keepAliveTask;
@ -271,7 +274,7 @@ public class ClientConnection extends Thread {
}
private void setChannel(DataInputStream input, DataOutputStream output) {
this.channel = new Channel(input, output);
this.channel = new Channel(this, input, output);
this.channel.addHandlerBefore(DEFAULT_HANDLER_NAMESPACE, new ChannelPacketHandler() {
@Override
@ -294,6 +297,9 @@ public class ClientConnection extends Thread {
case LOGIN:
packetType = Packet.getLoginIn().get(packetId);
break;
case CONFIGURATION:
packetType = Packet.getConfigurationIn().get(packetId);
break;
case PLAY:
packetType = Packet.getPlayIn().get(packetId);
break;
@ -498,7 +504,7 @@ public class ClientConnection extends Thread {
continue;
}
UUID uuid = isBungeecord || isBungeeGuard ? bungeeUUID : (start.hasUniqueId() ? start.getUniqueId() : null);
UUID uuid = isBungeecord || isBungeeGuard ? bungeeUUID : start.getUniqueId();
if (uuid == null) {
uuid = UUID.nameUUIDFromBytes(("OfflinePlayer:" + username).getBytes(StandardCharsets.UTF_8));
}
@ -511,11 +517,10 @@ public class ClientConnection extends Thread {
PacketLoginOutLoginSuccess success = new PacketLoginOutLoginSuccess(uuid, username);
sendPacket(success);
state = ClientState.PLAY;
state = ClientState.CONFIGURATION;
player = new Player(this, username, uuid, Limbo.getInstance().getNextEntityId(), Limbo.getInstance().getServerProperties().getWorldSpawn(), new PlayerInteractManager());
player.setSkinLayers((byte) (0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40));
Limbo.getInstance().getUnsafe().a(player);
break;
} else if (packetIn instanceof PacketLoginInPluginMessaging) {
PacketLoginInPluginMessaging response = (PacketLoginInPluginMessaging) packetIn;
@ -539,12 +544,10 @@ public class ClientConnection extends Thread {
PacketLoginOutLoginSuccess success = new PacketLoginOutLoginSuccess(data.getUuid(), data.getUsername());
sendPacket(success);
state = ClientState.PLAY;
state = ClientState.CONFIGURATION;
player = new Player(this, data.getUsername(), data.getUuid(), Limbo.getInstance().getNextEntityId(), Limbo.getInstance().getServerProperties().getWorldSpawn(), new PlayerInteractManager());
player.setSkinLayers((byte) (0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40));
Limbo.getInstance().getUnsafe().a(player);
break;
}
}
@ -562,7 +565,20 @@ public class ClientConnection extends Thread {
state = ClientState.DISCONNECTED;
}
if (state == ClientState.PLAY) {
if (state == ClientState.CONFIGURATION) {
TimeUnit.MILLISECONDS.sleep(500);
ClientboundRegistryDataPacket registryDataPacket = new ClientboundRegistryDataPacket(Limbo.getInstance().getDimensionRegistry().getCodec());
sendPacket(registryDataPacket);
ClientboundFinishConfigurationPacket clientboundFinishConfigurationPacket = new ClientboundFinishConfigurationPacket();
sendPacket(clientboundFinishConfigurationPacket);
ServerboundFinishConfigurationPacket serverboundFinishConfigurationPacket = (ServerboundFinishConfigurationPacket) channel.readPacket();
state = ClientState.PLAY;
Limbo.getInstance().getUnsafe().a(player);
TimeUnit.MILLISECONDS.sleep(500);
@ -573,7 +589,7 @@ public class ClientConnection extends Thread {
worldSpawn = spawnEvent.getSpawnLocation();
World world = worldSpawn.getWorld();
PacketPlayOutLogin join = new PacketPlayOutLogin(player.getEntityId(), false, properties.getDefaultGamemode(), Limbo.getInstance().getWorlds(), Limbo.getInstance().getDimensionRegistry().getCodec(), world, 0, (byte) properties.getMaxPlayers(), 8, 8, properties.isReducedDebugInfo(), true, false, true, 0);
PacketPlayOutLogin join = new PacketPlayOutLogin(player.getEntityId(), false, Limbo.getInstance().getWorlds(), (byte) properties.getMaxPlayers(), 8, 8, properties.isReducedDebugInfo(), true, false, world.getEnvironment(), world, 0, properties.getDefaultGamemode(), false, true, 0);
sendPacket(join);
Limbo.getInstance().getUnsafe().a(player, properties.getDefaultGamemode());
@ -877,6 +893,7 @@ public class ClientConnection extends Thread {
HANDSHAKE,
STATUS,
LOGIN,
CONFIGURATION,
PLAY,
DISCONNECTED;
}

View File

@ -0,0 +1,52 @@
/*
* This file is part of Limbo.
*
* Copyright (C) 2022. LoohpJames <jamesloohp@gmail.com>
* Copyright (C) 2022. Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.loohp.limbo.network.protocol.packets;
import com.loohp.limbo.utils.DataTypeIO;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public class ClientboundChunkBatchFinishedPacket extends PacketOut {
private final int batchSize;
public ClientboundChunkBatchFinishedPacket(int batchSize) {
this.batchSize = batchSize;
}
public int getBatchSize() {
return batchSize;
}
@Override
public byte[] serializePacket() throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
DataOutputStream output = new DataOutputStream(buffer);
output.writeByte(Packet.getPlayOut().get(getClass()));
DataTypeIO.writeVarInt(output, batchSize);
return buffer.toByteArray();
}
}

View File

@ -0,0 +1,41 @@
/*
* This file is part of Limbo.
*
* Copyright (C) 2022. LoohpJames <jamesloohp@gmail.com>
* Copyright (C) 2022. Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.loohp.limbo.network.protocol.packets;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public class ClientboundChunkBatchStartPacket extends PacketOut {
public ClientboundChunkBatchStartPacket() {
}
@Override
public byte[] serializePacket() throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
DataOutputStream output = new DataOutputStream(buffer);
output.writeByte(Packet.getPlayOut().get(getClass()));
return buffer.toByteArray();
}
}

View File

@ -0,0 +1,40 @@
/*
* This file is part of Limbo.
*
* Copyright (C) 2023. LoohpJames <jamesloohp@gmail.com>
* Copyright (C) 2023. Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.loohp.limbo.network.protocol.packets;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public class ClientboundFinishConfigurationPacket extends PacketOut {
public ClientboundFinishConfigurationPacket() {
}
@Override
public byte[] serializePacket() throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
DataOutputStream output = new DataOutputStream(buffer);
output.writeByte(Packet.getConfigurationOut().get(getClass()));
return buffer.toByteArray();
}
}

View File

@ -119,7 +119,7 @@ public class ClientboundLevelChunkWithLightPacket extends PacketOut {
output.writeInt(chunkX);
output.writeInt(chunkZ);
DataTypeIO.writeCompoundTag(output, chunk.getHeightMaps());
DataTypeIO.writeTag(output, chunk.getHeightMaps());
ByteArrayOutputStream dataBuffer = new ByteArrayOutputStream();
DataOutputStream dataOut = new DataOutputStream(dataBuffer);
@ -222,13 +222,13 @@ public class ClientboundLevelChunkWithLightPacket extends PacketOut {
}
int biome;
if (environment.equals(Environment.END)) {
biome = 9; //the_end
biome = 55; //the_end
} else if (environment.equals(Environment.NETHER)) {
biome = 8; //nether_waste
biome = 34; //nether_waste
} else if (environment.equals(Environment.NORMAL)) {
biome = 1; //plains
biome = 39; //plains
} else {
biome = 1; //plains
biome = 39; //plains
}
dataOut.writeByte(0);
DataTypeIO.writeVarInt(dataOut, biome);
@ -249,7 +249,7 @@ public class ClientboundLevelChunkWithLightPacket extends PacketOut {
output.writeShort(y);
Integer id = Registry.BLOCK_ENTITY_TYPE.getId(Key.key(chunk.getBlockStateAt(x, y, z).getString("Name")));
DataTypeIO.writeVarInt(output, id == null ? -1 : id);
DataTypeIO.writeCompoundTag(output, each);
DataTypeIO.writeTag(output, each);
}
DataTypeIO.writeVarInt(output, skyLightBitMasks.length);

View File

@ -0,0 +1,52 @@
/*
* This file is part of Limbo.
*
* Copyright (C) 2023. LoohpJames <jamesloohp@gmail.com>
* Copyright (C) 2023. Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.loohp.limbo.network.protocol.packets;
import com.loohp.limbo.utils.DataTypeIO;
import net.querz.nbt.tag.CompoundTag;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public class ClientboundRegistryDataPacket extends PacketOut {
private final CompoundTag dimensionCodec;
public ClientboundRegistryDataPacket(CompoundTag dimensionCodec) {
this.dimensionCodec = dimensionCodec;
}
public CompoundTag getDimensionCodec() {
return dimensionCodec;
}
@Override
public byte[] serializePacket() throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
DataOutputStream output = new DataOutputStream(buffer);
output.writeByte(Packet.getConfigurationOut().get(getClass()));
DataTypeIO.writeTag(output, dimensionCodec);
return buffer.toByteArray();
}
}

View File

@ -19,9 +19,11 @@
package com.loohp.limbo.network.protocol.packets;
import com.loohp.limbo.network.ClientConnection;
import java.util.Map;
public class Packet {
public abstract class Packet {
private static Map<Integer, Class<? extends PacketIn>> handshakeIn;
@ -31,6 +33,9 @@ public class Packet {
private static Map<Integer, Class<? extends PacketIn>> loginIn;
private static Map<Class<? extends PacketOut>, Integer> loginOut;
private static Map<Integer, Class<? extends PacketIn>> configurationIn;
private static Map<Class<? extends PacketOut>, Integer> configurationOut;
private static Map<Integer, Class<? extends PacketIn>> playIn;
private static Map<Class<? extends PacketOut>, Integer> playOut;
@ -74,6 +79,22 @@ public class Packet {
Packet.loginOut = loginOut;
}
public static Map<Integer, Class<? extends PacketIn>> getConfigurationIn() {
return configurationIn;
}
public static void setConfigurationIn(Map<Integer, Class<? extends PacketIn>> configurationIn) {
Packet.configurationIn = configurationIn;
}
public static Map<Class<? extends PacketOut>, Integer> getConfigurationOut() {
return configurationOut;
}
public static void setConfigurationOut(Map<Class<? extends PacketOut>, Integer> configurationOut) {
Packet.configurationOut = configurationOut;
}
public static Map<Integer, Class<? extends PacketIn>> getPlayIn() {
return playIn;
}
@ -90,4 +111,19 @@ public class Packet {
Packet.playOut = playOut;
}
public ClientConnection.ClientState getPacketState() {
Class<? extends Packet> type = getClass();
if (handshakeIn.containsValue(type)) {
return ClientConnection.ClientState.HANDSHAKE;
} else if (loginIn.containsValue(type) || loginOut.containsKey(type)) {
return ClientConnection.ClientState.LOGIN;
} else if (configurationIn.containsValue(type) || configurationOut.containsKey(type)) {
return ClientConnection.ClientState.CONFIGURATION;
} else if (playIn.containsValue(type) || playOut.containsKey(type)) {
return ClientConnection.ClientState.PLAY;
} else {
throw new IllegalStateException("This packet is not registered!");
}
}
}

View File

@ -24,36 +24,27 @@ import com.loohp.limbo.utils.DataTypeIO;
import java.io.DataInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Optional;
import java.util.UUID;
public class PacketLoginInLoginStart extends PacketIn {
private String username;
private Optional<UUID> uuid;
private final String username;
private final UUID uuid;
public PacketLoginInLoginStart(String username) {
public PacketLoginInLoginStart(String username, UUID uuid) {
this.username = username;
this.uuid = uuid;
}
public PacketLoginInLoginStart(DataInputStream in) throws IOException {
this.username = DataTypeIO.readString(in, StandardCharsets.UTF_8);
if (in.readBoolean()) {
this.uuid = Optional.of(DataTypeIO.readUUID(in));
} else {
this.uuid = Optional.empty();
}
this(DataTypeIO.readString(in, StandardCharsets.UTF_8), DataTypeIO.readUUID(in));
}
public String getUsername() {
return username;
}
public boolean hasUniqueId() {
return uuid.isPresent();
}
public UUID getUniqueId() {
return uuid.orElse(null);
return uuid;
}
}

View File

@ -24,7 +24,6 @@ import com.loohp.limbo.utils.GameMode;
import com.loohp.limbo.world.Environment;
import com.loohp.limbo.world.World;
import net.kyori.adventure.key.Key;
import net.querz.nbt.tag.CompoundTag;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
@ -34,37 +33,37 @@ import java.util.List;
public class PacketPlayOutLogin extends PacketOut {
private int entityId;
private boolean isHardcore;
private GameMode gamemode;
private List<World> worlds;
private CompoundTag dimensionCodec;
private Environment dimension;
private World world;
private long hashedSeed;
private byte maxPlayers;
private int viewDistance;
private int simulationDistance;
private boolean reducedDebugInfo;
private boolean enableRespawnScreen;
private boolean isDebug;
private boolean isFlat;
private int portalCooldown;
private final int entityId;
private final boolean isHardcore;
private final List<World> worlds;
private final byte maxPlayers;
private final int viewDistance;
private final int simulationDistance;
private final boolean reducedDebugInfo;
private final boolean enableRespawnScreen;
private final boolean doLimitedCrafting;
private final Environment dimension;
private final World world;
private final long hashedSeed;
private final GameMode gamemode;
private final boolean isDebug;
private final boolean isFlat;
private final int portalCooldown;
public PacketPlayOutLogin(int entityId, boolean isHardcore, GameMode gamemode, List<World> worlds, CompoundTag dimensionCodec, World world, long hashedSeed, byte maxPlayers, int viewDistance, int simulationDistance, boolean reducedDebugInfo, boolean enableRespawnScreen, boolean isDebug, boolean isFlat, int portalCooldown) {
public PacketPlayOutLogin(int entityId, boolean isHardcore, List<World> worlds, byte maxPlayers, int viewDistance, int simulationDistance, boolean reducedDebugInfo, boolean enableRespawnScreen, boolean doLimitedCrafting, Environment dimension, World world, long hashedSeed, GameMode gamemode, boolean isDebug, boolean isFlat, int portalCooldown) {
this.entityId = entityId;
this.isHardcore = isHardcore;
this.gamemode = gamemode;
this.worlds = worlds;
this.dimensionCodec = dimensionCodec;
this.dimension = world.getEnvironment();
this.world = world;
this.hashedSeed = hashedSeed;
this.maxPlayers = maxPlayers;
this.viewDistance = viewDistance;
this.simulationDistance = simulationDistance;
this.reducedDebugInfo = reducedDebugInfo;
this.enableRespawnScreen = enableRespawnScreen;
this.doLimitedCrafting = doLimitedCrafting;
this.dimension = dimension;
this.world = world;
this.hashedSeed = hashedSeed;
this.gamemode = gamemode;
this.isDebug = isDebug;
this.isFlat = isFlat;
this.portalCooldown = portalCooldown;
@ -78,30 +77,10 @@ public class PacketPlayOutLogin extends PacketOut {
return isHardcore;
}
public GameMode getGamemode() {
return gamemode;
}
public List<World> getWorldsNames() {
public List<World> getWorlds() {
return worlds;
}
public CompoundTag getDimensionCodec() {
return dimensionCodec;
}
public Environment getDimension() {
return dimension;
}
public World getWorld() {
return world;
}
public long getHashedSeed() {
return hashedSeed;
}
public byte getMaxPlayers() {
return maxPlayers;
}
@ -122,6 +101,26 @@ public class PacketPlayOutLogin extends PacketOut {
return enableRespawnScreen;
}
public boolean isDoLimitedCrafting() {
return doLimitedCrafting;
}
public Environment getDimension() {
return dimension;
}
public World getWorld() {
return world;
}
public long getHashedSeed() {
return hashedSeed;
}
public GameMode getGamemode() {
return gamemode;
}
public boolean isDebug() {
return isDebug;
}
@ -130,6 +129,10 @@ public class PacketPlayOutLogin extends PacketOut {
return isFlat;
}
public int getPortalCooldown() {
return portalCooldown;
}
@Override
public byte[] serializePacket() throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
@ -138,21 +141,21 @@ public class PacketPlayOutLogin extends PacketOut {
output.writeByte(Packet.getPlayOut().get(getClass()));
output.writeInt(entityId);
output.writeBoolean(isHardcore);
output.writeByte((byte) gamemode.getId());
output.writeByte(-1);
DataTypeIO.writeVarInt(output, worlds.size());
for (World world : worlds) {
DataTypeIO.writeString(output, Key.key(world.getName()).toString(), StandardCharsets.UTF_8);
}
DataTypeIO.writeCompoundTag(output, dimensionCodec);
DataTypeIO.writeString(output, world.getEnvironment().getKey().toString(), StandardCharsets.UTF_8);
DataTypeIO.writeString(output, Key.key(world.getName()).toString(), StandardCharsets.UTF_8);
output.writeLong(hashedSeed);
DataTypeIO.writeVarInt(output, maxPlayers);
DataTypeIO.writeVarInt(output, viewDistance);
DataTypeIO.writeVarInt(output, simulationDistance);
output.writeBoolean(reducedDebugInfo);
output.writeBoolean(enableRespawnScreen);
output.writeBoolean(doLimitedCrafting);
DataTypeIO.writeString(output, world.getEnvironment().getKey().toString(), StandardCharsets.UTF_8);
DataTypeIO.writeString(output, Key.key(world.getName()).toString(), StandardCharsets.UTF_8);
output.writeLong(hashedSeed);
output.writeByte((byte) gamemode.getId());
output.writeByte(-1);
output.writeBoolean(isDebug);
output.writeBoolean(isFlat);
output.writeBoolean(false);

View File

@ -100,7 +100,7 @@ public class PacketPlayOutRespawn extends PacketOut {
break;
}
}
DataTypeIO.writeCompoundTag(output, tag != null ? tag : list.get(0));
DataTypeIO.writeTag(output, tag != null ? tag : list.get(0));
DataTypeIO.writeString(output, worldName, StandardCharsets.UTF_8);
output.writeLong(hashedSeed);
output.writeByte((byte) gamemode.getId());

View File

@ -0,0 +1,33 @@
/*
* This file is part of Limbo.
*
* Copyright (C) 2023. LoohpJames <jamesloohp@gmail.com>
* Copyright (C) 2023. Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.loohp.limbo.network.protocol.packets;
import java.io.DataInputStream;
import java.io.IOException;
public class ServerboundFinishConfigurationPacket extends PacketIn {
public ServerboundFinishConfigurationPacket() {
}
public ServerboundFinishConfigurationPacket(DataInputStream in) throws IOException {
this();
}
}

View File

@ -0,0 +1,34 @@
/*
* This file is part of Limbo.
*
* Copyright (C) 2023. LoohpJames <jamesloohp@gmail.com>
* Copyright (C) 2023. Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.loohp.limbo.network.protocol.packets;
import java.io.DataInputStream;
import java.io.IOException;
public class ServerboundLoginAcknowledgedPacket extends PacketIn {
public ServerboundLoginAcknowledgedPacket() {
}
public ServerboundLoginAcknowledgedPacket(DataInputStream in) throws IOException {
this();
}
}

View File

@ -22,6 +22,9 @@ package com.loohp.limbo.player;
import com.loohp.limbo.Limbo;
import com.loohp.limbo.entity.Entity;
import com.loohp.limbo.location.Location;
import com.loohp.limbo.network.ClientConnection;
import com.loohp.limbo.network.protocol.packets.ClientboundChunkBatchFinishedPacket;
import com.loohp.limbo.network.protocol.packets.ClientboundChunkBatchStartPacket;
import com.loohp.limbo.network.protocol.packets.ClientboundLevelChunkWithLightPacket;
import com.loohp.limbo.network.protocol.packets.PacketPlayOutEntityDestroy;
import com.loohp.limbo.network.protocol.packets.PacketPlayOutEntityMetadata;
@ -68,6 +71,10 @@ public class PlayerInteractManager {
}
public void update() throws IOException {
if (player.clientConnection.getClientState() != ClientConnection.ClientState.PLAY) {
return;
}
int viewDistanceChunks = Limbo.getInstance().getServerProperties().getViewDistance();
int viewDistanceBlocks = viewDistanceChunks << 4;
Location location = player.getLocation();
@ -119,6 +126,9 @@ public class PlayerInteractManager {
}
}
int counter = 0;
ClientboundChunkBatchStartPacket chunkBatchStartPacket = new ClientboundChunkBatchStartPacket();
player.clientConnection.sendPacket(chunkBatchStartPacket);
for (Entry<ChunkPosition, Chunk> entry : chunksInRange.entrySet()) {
ChunkPosition chunkPos = entry.getKey();
if (!currentViewing.containsKey(chunkPos)) {
@ -126,7 +136,7 @@ public class PlayerInteractManager {
if (chunk == null) {
ClientboundLevelChunkWithLightPacket chunkdata = new ClientboundLevelChunkWithLightPacket(chunkPos.getChunkX(), chunkPos.getChunkZ(), entry.getValue(), world.getEnvironment(), Collections.emptyList(), Collections.emptyList());
player.clientConnection.sendPacket(chunkdata);
} else {
} else {
List<Byte[]> blockChunk = world.getLightEngineBlock().getBlockLightBitMask(chunkPos.getChunkX(), chunkPos.getChunkZ());
if (blockChunk == null) {
blockChunk = new ArrayList<>();
@ -140,9 +150,12 @@ public class PlayerInteractManager {
}
ClientboundLevelChunkWithLightPacket chunkdata = new ClientboundLevelChunkWithLightPacket(chunkPos.getChunkX(), chunkPos.getChunkZ(), chunk, world.getEnvironment(), skyChunk, blockChunk);
player.clientConnection.sendPacket(chunkdata);
}
}
}
counter++;
}
}
ClientboundChunkBatchFinishedPacket chunkBatchFinishedPacket = new ClientboundChunkBatchFinishedPacket(counter);
player.clientConnection.sendPacket(chunkBatchFinishedPacket);
currentViewing = chunksInRange;
}

View File

@ -29,6 +29,7 @@ import net.kyori.adventure.key.Key;
import net.querz.nbt.io.NBTInputStream;
import net.querz.nbt.io.NBTOutputStream;
import net.querz.nbt.tag.CompoundTag;
import net.querz.nbt.tag.EndTag;
import net.querz.nbt.tag.Tag;
import java.io.ByteArrayOutputStream;
@ -51,7 +52,7 @@ public class DataTypeIO {
out.writeBoolean(true);
writeVarInt(out, Registry.ITEM_REGISTRY.getId(itemstack.type()));
out.writeByte(itemstack.amount());
writeCompoundTag(out, itemstack.nbt());
writeTag(out, itemstack.nbt());
}
}
@ -61,7 +62,7 @@ public class DataTypeIO {
} else {
Key key = Registry.ITEM_REGISTRY.fromId(readVarInt(in));
byte amount = in.readByte();
CompoundTag nbt = readCompoundTag(in);
CompoundTag nbt = readTag(in, CompoundTag.class);
return new ItemStack(key, amount, nbt);
}
}
@ -152,22 +153,25 @@ public class DataTypeIO {
return new UUID(in.readLong(), in.readLong());
}
public static void writeCompoundTag(DataOutputStream out, CompoundTag tag) throws IOException {
public static void writeTag(DataOutputStream out, Tag<?> tag) throws IOException {
if (tag == null) {
out.writeByte(0);
} else {
new NBTOutputStream(out).writeTag(tag, Tag.DEFAULT_MAX_DEPTH);
tag = EndTag.INSTANCE;
}
out.writeByte(tag.getID());
if (tag.getID() != 0) {
new NBTOutputStream(out).writeRawTag(tag, Tag.DEFAULT_MAX_DEPTH);
}
}
public static CompoundTag readCompoundTag(DataInputStream in) throws IOException {
@SuppressWarnings("unchecked")
public static <T extends Tag<?>> T readTag(DataInputStream in, Class<T> type) throws IOException {
byte b = in.readByte();
if (b == 0) {
return null;
return type.isInstance(EndTag.INSTANCE) ? (T) EndTag.INSTANCE : null;
}
PushbackInputStream buffered = new PushbackInputStream(in);
buffered.unread(b);
return (CompoundTag) new NBTInputStream(buffered).readTag(Tag.DEFAULT_MAX_DEPTH).getTag();
return (T) new NBTInputStream(buffered).readRawTag(Tag.DEFAULT_MAX_DEPTH);
}
public static String readString(DataInputStream in, Charset charset) throws IOException {

File diff suppressed because it is too large Load Diff

View File

@ -457,6 +457,10 @@
"asset_id": {
"type": "StringTag",
"value": "minecraft:coast"
},
"decal": {
"type": "ByteTag",
"value": 0
}
}
}
@ -489,6 +493,10 @@
"asset_id": {
"type": "StringTag",
"value": "minecraft:dune"
},
"decal": {
"type": "ByteTag",
"value": 0
}
}
}
@ -521,6 +529,10 @@
"asset_id": {
"type": "StringTag",
"value": "minecraft:eye"
},
"decal": {
"type": "ByteTag",
"value": 0
}
}
}
@ -553,6 +565,10 @@
"asset_id": {
"type": "StringTag",
"value": "minecraft:host"
},
"decal": {
"type": "ByteTag",
"value": 0
}
}
}
@ -585,6 +601,10 @@
"asset_id": {
"type": "StringTag",
"value": "minecraft:raiser"
},
"decal": {
"type": "ByteTag",
"value": 0
}
}
}
@ -617,6 +637,10 @@
"asset_id": {
"type": "StringTag",
"value": "minecraft:rib"
},
"decal": {
"type": "ByteTag",
"value": 0
}
}
}
@ -649,6 +673,10 @@
"asset_id": {
"type": "StringTag",
"value": "minecraft:sentry"
},
"decal": {
"type": "ByteTag",
"value": 0
}
}
}
@ -681,6 +709,10 @@
"asset_id": {
"type": "StringTag",
"value": "minecraft:shaper"
},
"decal": {
"type": "ByteTag",
"value": 0
}
}
}
@ -713,6 +745,10 @@
"asset_id": {
"type": "StringTag",
"value": "minecraft:silence"
},
"decal": {
"type": "ByteTag",
"value": 0
}
}
}
@ -745,6 +781,10 @@
"asset_id": {
"type": "StringTag",
"value": "minecraft:snout"
},
"decal": {
"type": "ByteTag",
"value": 0
}
}
}
@ -777,6 +817,10 @@
"asset_id": {
"type": "StringTag",
"value": "minecraft:spire"
},
"decal": {
"type": "ByteTag",
"value": 0
}
}
}
@ -809,6 +853,10 @@
"asset_id": {
"type": "StringTag",
"value": "minecraft:tide"
},
"decal": {
"type": "ByteTag",
"value": 0
}
}
}
@ -841,6 +889,10 @@
"asset_id": {
"type": "StringTag",
"value": "minecraft:vex"
},
"decal": {
"type": "ByteTag",
"value": 0
}
}
}
@ -873,6 +925,10 @@
"asset_id": {
"type": "StringTag",
"value": "minecraft:ward"
},
"decal": {
"type": "ByteTag",
"value": 0
}
}
}
@ -905,6 +961,10 @@
"asset_id": {
"type": "StringTag",
"value": "minecraft:wayfinder"
},
"decal": {
"type": "ByteTag",
"value": 0
}
}
}
@ -937,6 +997,10 @@
"asset_id": {
"type": "StringTag",
"value": "minecraft:wild"
},
"decal": {
"type": "ByteTag",
"value": 0
}
}
}

View File

@ -4,69 +4,79 @@
},
"LoginIn": {
"0x00": "PacketLoginInLoginStart",
"0x02": "PacketLoginInPluginMessaging"
"0x02": "PacketLoginInPluginMessaging",
"0x03": "ServerboundLoginAcknowledgedPacket"
},
"LoginOut": {
"PacketLoginOutLoginSuccess": "0x02",
"PacketLoginOutDisconnect": "0x00",
"PacketLoginOutPluginMessaging": "0x04"
},
"ConfigurationIn": {
"0x02": "ServerboundFinishConfigurationPacket"
},
"ConfigurationOut": {
"ClientboundRegistryDataPacket": "0x05",
"ClientboundFinishConfigurationPacket": "0x02"
},
"PlayIn": {
"0x12": "PacketPlayInKeepAlive",
"0x14": "PacketPlayInKeepAlive",
"0x04": "ServerboundChatCommandPacket",
"0x05": "PacketPlayInChat",
"0x15": "PacketPlayInPositionAndLook",
"0x14": "PacketPlayInPosition",
"0x16": "PacketPlayInRotation",
"0x0D": "PacketPlayInPluginMessaging",
"0x09": "PacketPlayInTabComplete",
"0x28": "PacketPlayInHeldItemChange",
"0x24": "PacketPlayInResourcePackStatus",
"0x32": "PacketPlayInBlockPlace",
"0x31": "PacketPlayInUseItem",
"0x2B": "PacketPlayInSetCreativeSlot",
"0x0B": "PacketPlayInWindowClick",
"0x0C": "PacketPlayInCloseWindow",
"0x1A": "PacketPlayInPickItem",
"0x1D": "PacketPlayInBlockDig",
"0x23": "PacketPlayInItemName"
"0x16": "PacketPlayInPosition",
"0x17": "PacketPlayInPositionAndLook",
"0x18": "PacketPlayInRotation",
"0x0F": "PacketPlayInPluginMessaging",
"0x0A": "PacketPlayInTabComplete",
"0x2B": "PacketPlayInHeldItemChange",
"0x27": "PacketPlayInResourcePackStatus",
"0x34": "PacketPlayInUseItem",
"0x35": "PacketPlayInBlockPlace",
"0x2E": "PacketPlayInSetCreativeSlot",
"0x0D": "PacketPlayInWindowClick",
"0x0E": "PacketPlayInCloseWindow",
"0x1C": "PacketPlayInPickItem",
"0x20": "PacketPlayInBlockDig",
"0x26": "PacketPlayInItemName"
},
"PlayOut": {
"PacketPlayOutLogin": "0x28",
"PacketPlayOutPositionAndLook": "0x3C",
"PacketPlayOutSpawnPosition": "0x50",
"ClientboundSystemChatPacket": "0x64",
"PacketPlayOutPlayerAbilities": "0x34",
"ClientboundLevelChunkWithLightPacket": "0x24",
"PacketPlayOutUnloadChunk": "0x1E",
"PacketPlayOutKeepAlive": "0x23",
"PacketPlayOutPlayerInfo": "0x3A",
"PacketPlayOutUpdateViewPosition": "0x4E",
"PacketPlayOutDisconnect": "0x1A",
"PacketPlayOutPluginMessaging": "0x17",
"PacketPlayOutTabComplete": "0x0F",
"PacketPlayOutDeclareCommands": "0x10",
"PacketPlayOutRespawn": "0x41",
"PacketPlayOutGameState": "0x1F",
"PacketPlayOutEntityDestroy": "0x3E",
"PacketPlayOutEntityMetadata": "0x52",
"PacketPlayOutLogin": "0x29",
"PacketPlayOutPositionAndLook": "0x3E",
"PacketPlayOutSpawnPosition": "0x52",
"ClientboundSystemChatPacket": "0x67",
"PacketPlayOutPlayerAbilities": "0x36",
"ClientboundLevelChunkWithLightPacket": "0x25",
"PacketPlayOutUnloadChunk": "0x1F",
"PacketPlayOutKeepAlive": "0x24",
"PacketPlayOutPlayerInfo": "0x3C",
"PacketPlayOutUpdateViewPosition": "0x50",
"PacketPlayOutDisconnect": "0x1B",
"PacketPlayOutPluginMessaging": "0x18",
"PacketPlayOutTabComplete": "0x10",
"PacketPlayOutDeclareCommands": "0x11",
"PacketPlayOutRespawn": "0x43",
"PacketPlayOutGameState": "0x20",
"PacketPlayOutEntityDestroy": "0x40",
"PacketPlayOutEntityMetadata": "0x54",
"PacketPlayOutSpawnEntity": "0x01",
"PacketPlayOutHeldItemChange": "0x4D",
"PacketPlayOutPlayerListHeaderFooter": "0x65",
"PacketPlayOutResourcePackSend": "0x40",
"ClientboundSetTitlesAnimationPacket": "0x60",
"ClientboundSetTitleTextPacket": "0x5F",
"ClientboundSetSubtitleTextPacket": "0x5D",
"ClientboundSetActionBarTextPacket": "0x46",
"ClientboundClearTitlesPacket": "0x0E",
"PacketPlayOutBoss": "0x0B",
"PacketPlayOutNamedSoundEffect": "0x62",
"PacketPlayOutStopSound": "0x63",
"PacketPlayOutWindowItems": "0x12",
"PacketPlayOutSetSlot": "0x14",
"PacketPlayOutOpenWindow": "0x30",
"PacketPlayOutCloseWindow": "0x11",
"PacketPlayOutWindowData": "0x13"
"PacketPlayOutHeldItemChange": "0x4F",
"PacketPlayOutPlayerListHeaderFooter": "0x68",
"PacketPlayOutResourcePackSend": "0x42",
"ClientboundSetTitlesAnimationPacket": "0x62",
"ClientboundSetTitleTextPacket": "0x61",
"ClientboundSetSubtitleTextPacket": "0x5F",
"ClientboundSetActionBarTextPacket": "0x48",
"ClientboundClearTitlesPacket": "0x0F",
"PacketPlayOutBoss": "0x0A",
"PacketPlayOutNamedSoundEffect": "0x64",
"PacketPlayOutStopSound": "0x66",
"PacketPlayOutWindowItems": "0x13",
"PacketPlayOutSetSlot": "0x15",
"PacketPlayOutOpenWindow": "0x31",
"PacketPlayOutCloseWindow": "0x12",
"PacketPlayOutWindowData": "0x14",
"ClientboundChunkBatchFinishedPacket": "0x0C",
"ClientboundChunkBatchStartPacket": "0x0D"
},
"StatusIn": {
"0x01": "PacketStatusInPing",

File diff suppressed because it is too large Load Diff