This commit is contained in:
LOOHP
2020-08-03 22:54:12 +08:00
parent ad0d9b5c85
commit 39b631c89d
105 changed files with 346837 additions and 0 deletions
@@ -0,0 +1,331 @@
package com.loohp.limbo.Server;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import com.loohp.limbo.Limbo;
import com.loohp.limbo.File.ServerProperties;
import com.loohp.limbo.Location.Location;
import com.loohp.limbo.Server.Packets.Packet;
import com.loohp.limbo.Server.Packets.PacketHandshakingIn;
import com.loohp.limbo.Server.Packets.PacketLoginInLoginStart;
import com.loohp.limbo.Server.Packets.PacketLoginOutLoginSuccess;
import com.loohp.limbo.Server.Packets.PacketPlayInChat;
import com.loohp.limbo.Server.Packets.PacketPlayInKeepAlive;
import com.loohp.limbo.Server.Packets.PacketPlayInPosition;
import com.loohp.limbo.Server.Packets.PacketPlayInPositionAndLook;
import com.loohp.limbo.Server.Packets.PacketPlayOutChat;
import com.loohp.limbo.Server.Packets.PacketPlayOutLogin;
import com.loohp.limbo.Server.Packets.PacketPlayOutMapChunk;
import com.loohp.limbo.Server.Packets.PacketPlayOutPlayerAbilities;
import com.loohp.limbo.Server.Packets.PacketPlayOutPlayerAbilities.PlayerAbilityFlags;
import com.loohp.limbo.Server.Packets.PacketPlayOutPlayerInfo;
import com.loohp.limbo.Server.Packets.PacketPlayOutPlayerInfo.PlayerInfoAction;
import com.loohp.limbo.Server.Packets.PacketPlayOutPlayerInfo.PlayerInfoData;
import com.loohp.limbo.Server.Packets.PacketPlayOutPlayerInfo.PlayerInfoData.PlayerInfoDataAddPlayer.PlayerSkinProperty;
import com.loohp.limbo.Server.Packets.PacketPlayOutPositionAndLook;
import com.loohp.limbo.Server.Packets.PacketPlayOutShowPlayerSkins;
import com.loohp.limbo.Server.Packets.PacketPlayOutSpawnPosition;
import com.loohp.limbo.Server.Packets.PacketPlayOutUpdateViewPosition;
import com.loohp.limbo.Server.Packets.PacketStatusInPing;
import com.loohp.limbo.Server.Packets.PacketStatusInRequest;
import com.loohp.limbo.Server.Packets.PacketStatusOutPong;
import com.loohp.limbo.Server.Packets.PacketStatusOutResponse;
import com.loohp.limbo.Utils.DataTypeIO;
import com.loohp.limbo.Utils.SkinUtils;
import com.loohp.limbo.Utils.SkinUtils.SkinResponse;
import com.loohp.limbo.World.BlockPosition;
import com.loohp.limbo.World.DimensionRegistry;
import com.loohp.limbo.World.World;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.chat.ComponentSerializer;
import net.querz.mca.Chunk;
public class ClientConnection extends Thread {
public enum ClientState {
HANDSHAKE,
STATUS,
LOGIN,
PLAY,
DISCONNECTED;
}
private Socket client_socket;
private boolean running;
private ClientState state;
private String username;
private UUID uuid;
private Location location;
private long lastKeepAlivePayLoad;
public long getLastKeepAlivePayLoad() {
return lastKeepAlivePayLoad;
}
public void setLastKeepAlivePayLoad(long payLoad) {
this.lastKeepAlivePayLoad = payLoad;
}
public Location getLocation() {
return location;
}
public void setLocation(Location location) {
this.location = location;
}
public String getUsername() {
return username;
}
public UUID getUuid() {
return uuid;
}
public ClientConnection(Socket client_socket) {
this.client_socket = client_socket;
}
public ClientState getClientState() {
return state;
}
public Socket getSocket() {
return client_socket;
}
public boolean isRunning() {
return running;
}
public int getEntityId() {
return Limbo.getInstance().getServerConnection().getClients().indexOf(this);
}
public void sendMessage(String message) {
sendMessage(TextComponent.fromLegacyText(message));
}
public void sendMessage(BaseComponent component) {
sendMessage(new BaseComponent[] {component});
}
public void sendMessage(BaseComponent[] component) {
try {
DataOutputStream output = new DataOutputStream(client_socket.getOutputStream());
PacketPlayOutChat chat = new PacketPlayOutChat(ComponentSerializer.toString(component), 0, new UUID(0, 0));
byte[] packetByte = chat.getBytes();
DataTypeIO.writeVarInt(output, packetByte.length);
output.write(packetByte);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
running = true;
state = ClientState.HANDSHAKE;
try {
client_socket.setKeepAlive(true);
DataInputStream input = new DataInputStream(client_socket.getInputStream());
DataOutputStream output = new DataOutputStream(client_socket.getOutputStream());
DataTypeIO.readVarInt(input);
int handShakeId = DataTypeIO.readVarInt(input);
PacketHandshakingIn handshake = (PacketHandshakingIn) Packet.getHandshakeIn().get(handShakeId).getConstructor(DataInputStream.class).newInstance(input);
switch (handshake.getHandshakeType()) {
case STATUS:
state = ClientState.STATUS;
while (client_socket.isConnected()) {
DataTypeIO.readVarInt(input);
int packetId = DataTypeIO.readVarInt(input);
Class<? extends Packet> packetType = Packet.getStatusIn().get(packetId);
if (packetType == null) {
//do nothing
} else if (packetType.equals(PacketStatusInRequest.class)) {
String str = client_socket.getInetAddress().getHostName() + ":" + client_socket.getPort();
System.out.println("[/" + str + "] <-> InitialHandler has pinged");
PacketStatusOutResponse packet = new PacketStatusOutResponse(Limbo.getInstance().getServerListResponseJson());
byte[] packetByte = packet.getBytes();
DataTypeIO.writeVarInt(output, packetByte.length);
output.write(packetByte);
} else if (packetType.equals(PacketStatusInPing.class)) {
PacketStatusInPing ping = (PacketStatusInPing) packetType.getConstructor(DataInputStream.class).newInstance(input);
PacketStatusOutPong packet = new PacketStatusOutPong(ping.getPayload());
byte[] packetByte = packet.getBytes();
DataTypeIO.writeVarInt(output, packetByte.length);
output.write(packetByte);
break;
}
}
break;
case LOGIN:
state = ClientState.LOGIN;
while (client_socket.isConnected()) {
int size = DataTypeIO.readVarInt(input);
int packetId = DataTypeIO.readVarInt(input);
Class<? extends Packet> packetType = Packet.getLoginIn().get(packetId);
if (packetType == null) {
input.skipBytes(size - DataTypeIO.getVarIntLength(packetId));
} else if (packetType.equals(PacketLoginInLoginStart.class)) {
PacketLoginInLoginStart start = (PacketLoginInLoginStart) packetType.getConstructor(DataInputStream.class).newInstance(input);
username = start.getUsername();
uuid = UUID.nameUUIDFromBytes(("OfflinePlayer:" + username).getBytes(StandardCharsets.UTF_8));
PacketLoginOutLoginSuccess success = new PacketLoginOutLoginSuccess(uuid, start.getUsername());
byte[] packetByte = success.getBytes();
DataTypeIO.writeVarInt(output, packetByte.length);
output.write(packetByte);
state = ClientState.PLAY;
break;
}
}
break;
}
if (state == ClientState.PLAY) {
TimeUnit.MILLISECONDS.sleep(500);
ServerProperties p = Limbo.getInstance().getServerProperties();
PacketPlayOutLogin join = new PacketPlayOutLogin(getEntityId(), false, p.getDefaultGamemode(), new String[] {p.getLevelName().toString()}, DimensionRegistry.getCodec(), p.getLevelDimension().toString(), p.getLevelName().toString(), 0, (byte) p.getMaxPlayers(), 8, p.isReducedDebugInfo(), true, false, false);
byte[] packetByte = join.getBytes();
DataTypeIO.writeVarInt(output, packetByte.length);
output.write(packetByte);
Location s = p.getWorldSpawn();
//PacketPlayOutKeepAlive alive = new PacketPlayOutKeepAlive((long) (Math.random() * Long.MAX_VALUE));
World world = s.getWorld();
for (int x = 0; x < world.getChunks().length; x++) {
for (int z = 0; z < world.getChunks()[x].length; z++) {
Chunk chunk = world.getChunks()[x][z];
if (chunk != null) {
PacketPlayOutMapChunk chunkdata = new PacketPlayOutMapChunk(x, z, chunk);
packetByte = chunkdata.getBytes();
DataTypeIO.writeVarInt(output, packetByte.length);
output.write(packetByte);
//System.out.println(x + ", " + z);
}
}
}
PacketPlayOutSpawnPosition spawnPos = new PacketPlayOutSpawnPosition(BlockPosition.from(s));
packetByte = spawnPos.getBytes();
DataTypeIO.writeVarInt(output, packetByte.length);
output.write(packetByte);
PacketPlayOutPositionAndLook positionLook = new PacketPlayOutPositionAndLook(s.getX(), s.getY(), s.getZ(), s.getYaw(), s.getPitch(), 1);
location = new Location(world, s.getX(), s.getY(), s.getZ(), s.getYaw(), s.getPitch());
packetByte = positionLook.getBytes();
DataTypeIO.writeVarInt(output, packetByte.length);
output.write(packetByte);
SkinResponse skinresponce = SkinUtils.getSkinFromMojangServer(username);
PlayerSkinProperty skin = skinresponce != null ? new PlayerSkinProperty(skinresponce.getSkin(), skinresponce.getSignature()) : null;
PacketPlayOutPlayerInfo info = new PacketPlayOutPlayerInfo(PlayerInfoAction.ADD_PLAYER, uuid, new PlayerInfoData.PlayerInfoDataAddPlayer(username, Optional.ofNullable(skin), p.getDefaultGamemode(), 0, false, Optional.empty()));
packetByte = info.getBytes();
DataTypeIO.writeVarInt(output, packetByte.length);
output.write(packetByte);
/*
for (ClientConnection client : Limbo.getInstance().getServerConnection().getClients()) {
DataOutputStream other = new DataOutputStream(client.getSocket().getOutputStream());
DataTypeIO.writeVarInt(other, packetByte.length);
other.write(packetByte);
}
*/
PacketPlayOutShowPlayerSkins show = new PacketPlayOutShowPlayerSkins(getEntityId());
packetByte = show.getBytes();
DataTypeIO.writeVarInt(output, packetByte.length);
output.write(packetByte);
PacketPlayOutPlayerAbilities abilities;
if (p.isAllowFlight()) {
abilities = new PacketPlayOutPlayerAbilities(0.05F, 0.1F, PlayerAbilityFlags.ALLOW_FLYING);
} else {
abilities = new PacketPlayOutPlayerAbilities(0.05F, 0.1F);
}
packetByte = abilities.getBytes();
DataTypeIO.writeVarInt(output, packetByte.length);
output.write(packetByte);
String str = client_socket.getInetAddress().getHostName() + ":" + client_socket.getPort() + "|" + username;
System.out.println("[/" + str + "] <-> Player had connected to the Limbo server!");
while (client_socket.isConnected()) {
try {
int size = DataTypeIO.readVarInt(input);
int packetId = DataTypeIO.readVarInt(input);
Class<? extends Packet> packetType = Packet.getPlayIn().get(packetId);
//System.out.println(packetId);
if (packetType == null) {
input.skipBytes(size - DataTypeIO.getVarIntLength(packetId));
} else if (packetType.equals(PacketPlayInPositionAndLook.class)) {
PacketPlayInPositionAndLook pos = new PacketPlayInPositionAndLook(input);
location = new Location(location.getWorld(), pos.getX(), pos.getY(), pos.getZ(), pos.getYaw(), pos.getPitch());
PacketPlayOutUpdateViewPosition response = new PacketPlayOutUpdateViewPosition((int) location.getX() >> 4, (int) location.getZ() >> 4);
packetByte = response.getBytes();
DataTypeIO.writeVarInt(output, packetByte.length);
output.write(packetByte);
} else if (packetType.equals(PacketPlayInPosition.class)) {
PacketPlayInPosition pos = new PacketPlayInPosition(input);
location = new Location(location.getWorld(), pos.getX(), pos.getY(), pos.getZ(), location.getYaw(), location.getPitch());
PacketPlayOutUpdateViewPosition response = new PacketPlayOutUpdateViewPosition((int) location.getX() >> 4, (int) location.getZ() >> 4);
packetByte = response.getBytes();
DataTypeIO.writeVarInt(output, packetByte.length);
output.write(packetByte);
} else if (packetType.equals(PacketPlayInKeepAlive.class)) {
PacketPlayInKeepAlive alive = new PacketPlayInKeepAlive(input);
if (alive.getPayload() != lastKeepAlivePayLoad) {
System.out.println("Incorrect Payload recieved in KeepAlive packet for player " + username);
break;
}
} else if (packetType.equals(PacketPlayInChat.class)) {
PacketPlayInChat chat = new PacketPlayInChat(input);
if (chat.getMessage().startsWith("/")) {
//TO-DO COMMANDS
} else {
String message = "<" + username + "> " + chat.getMessage();
Limbo.getInstance().getConsole().sendMessage(message);
for (ClientConnection client : Limbo.getInstance().getServerConnection().getClients()) {
client.sendMessage(message);
}
}
}
} catch (Exception e) {
break;
}
}
str = client_socket.getInetAddress().getHostName() + ":" + client_socket.getPort() + "|" + username;
System.out.println("[/" + str + "] <-> Player had disconnected!");
}
} catch (Exception e) {}
try {
client_socket.close();
} catch (IOException e) {}
state = ClientState.DISCONNECTED;
Limbo.getInstance().getServerConnection().getClients().remove(this);
running = false;
}
}
@@ -0,0 +1,44 @@
package com.loohp.limbo.Server;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import com.loohp.limbo.Limbo;
import com.loohp.limbo.Server.ClientConnection.ClientState;
import com.loohp.limbo.Server.Packets.PacketPlayOutKeepAlive;
import com.loohp.limbo.Utils.DataTypeIO;
public class KeepAliveSender extends Thread {
private Random random = new Random();
public KeepAliveSender() {
start();
}
@Override
public void run() {
while (true) {
try {
for (ClientConnection client : Limbo.getInstance().getServerConnection().getClients()) {
if (client.getClientState().equals(ClientState.PLAY)) {
try {
DataOutputStream output = new DataOutputStream(client.getSocket().getOutputStream());
PacketPlayOutKeepAlive packet = new PacketPlayOutKeepAlive(random.nextLong());
byte[] packetByte = packet.getBytes();
DataTypeIO.writeVarInt(output, packetByte.length);
output.write(packetByte);
client.setLastKeepAlivePayLoad(packet.getPayload());
} catch (IOException ignore) {}
}
}
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
@@ -0,0 +1,80 @@
package com.loohp.limbo.Server.Packets;
import java.util.Map;
public class Packet {
private static Map<Integer, Class<? extends Packet>> HandshakeIn;
private static Map<Integer, Class<? extends Packet>> StatusIn;
private static Map<Class<? extends Packet>, Integer> StatusOut;
private static Map<Integer, Class<? extends Packet>> LoginIn;
private static Map<Class<? extends Packet>, Integer> LoginOut;
private static Map<Integer, Class<? extends Packet>> PlayIn;
private static Map<Class<? extends Packet>, Integer> PlayOut;
public static Map<Integer, Class<? extends Packet>> getHandshakeIn() {
return HandshakeIn;
}
public static void setHandshakeIn(Map<Integer, Class<? extends Packet>> handshakeIn) {
HandshakeIn = handshakeIn;
}
public static Map<Integer, Class<? extends Packet>> getStatusIn() {
return StatusIn;
}
public static void setStatusIn(Map<Integer, Class<? extends Packet>> statusIn) {
StatusIn = statusIn;
}
public static Map<Class<? extends Packet>, Integer> getStatusOut() {
return StatusOut;
}
public static void setStatusOut(Map<Class<? extends Packet>, Integer> statusOut) {
StatusOut = statusOut;
}
public static Map<Integer, Class<? extends Packet>> getLoginIn() {
return LoginIn;
}
public static void setLoginIn(Map<Integer, Class<? extends Packet>> loginIn) {
LoginIn = loginIn;
}
public static Map<Class<? extends Packet>, Integer> getLoginOut() {
return LoginOut;
}
public static void setLoginOut(Map<Class<? extends Packet>, Integer> loginOut) {
LoginOut = loginOut;
}
public static Map<Integer, Class<? extends Packet>> getPlayIn() {
return PlayIn;
}
public static void setPlayIn(Map<Integer, Class<? extends Packet>> playIn) {
PlayIn = playIn;
}
public static Map<Class<? extends Packet>, Integer> getPlayOut() {
return PlayOut;
}
public static void setPlayOut(Map<Class<? extends Packet>, Integer> playOut) {
PlayOut = playOut;
}
//===========================================
public Packet() {
}
}
@@ -0,0 +1,69 @@
package com.loohp.limbo.Server.Packets;
import java.io.DataInputStream;
import java.io.IOException;
import com.loohp.limbo.Utils.DataTypeIO;
public class PacketHandshakingIn extends Packet {
public static enum HandshakeType {
STATUS(1),
LOGIN(2);
int networkId;
HandshakeType(int networkId) {
this.networkId = networkId;
}
public int getNetworkId() {
return networkId;
}
public static HandshakeType fromNetworkId(int networkId) {
for (HandshakeType type : HandshakeType.values()) {
if (type.getNetworkId() == networkId) {
return type;
}
}
System.out.println("Invalid HandshakeType networkId, expected 0 or 1, but got " + networkId);
return null;
}
}
//==============================
private int protocolVersion;
private String serverAddress;
private int serverPort;
private HandshakeType handshakeType;
public PacketHandshakingIn(int protocolVersion, String serverAddress, int serverPort, HandshakeType handshakeType) {
this.protocolVersion = protocolVersion;
this.serverAddress = serverAddress;
this.serverPort = serverPort;
this.handshakeType = handshakeType;
}
public PacketHandshakingIn(DataInputStream in) throws IOException {
this(DataTypeIO.readVarInt(in), DataTypeIO.readString(in), in.readShort() & 0xFFFF, HandshakeType.fromNetworkId(DataTypeIO.readVarInt(in)));
}
public int getProtocolVersion() {
return protocolVersion;
}
public String getServerAddress() {
return serverAddress;
}
public int getServerPort() {
return serverPort;
}
public HandshakeType getHandshakeType() {
return handshakeType;
}
}
@@ -0,0 +1,24 @@
package com.loohp.limbo.Server.Packets;
import java.io.DataInputStream;
import java.io.IOException;
import com.loohp.limbo.Utils.DataTypeIO;
public class PacketLoginInLoginStart extends Packet {
private String username;
public PacketLoginInLoginStart(String username) {
this.username = username;
}
public PacketLoginInLoginStart(DataInputStream in) throws IOException {
this(DataTypeIO.readString(in));
}
public String getUsername() {
return username;
}
}
@@ -0,0 +1,40 @@
package com.loohp.limbo.Server.Packets;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.UUID;
import com.loohp.limbo.Utils.DataTypeIO;
public class PacketLoginOutLoginSuccess extends Packet {
private UUID uuid;
private String username;
public PacketLoginOutLoginSuccess(UUID uuid, String username) {
this.uuid = uuid;
this.username = username;
}
public UUID getUuid() {
return uuid;
}
public String getUsername() {
return username;
}
public byte[] getBytes() throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
DataOutputStream output = new DataOutputStream(buffer);
output.writeByte(Packet.getLoginOut().get(getClass()));
DataTypeIO.writeUUID(output, uuid);
DataTypeIO.writeString(output, username, StandardCharsets.UTF_8);
return buffer.toByteArray();
}
}
@@ -0,0 +1,24 @@
package com.loohp.limbo.Server.Packets;
import java.io.DataInputStream;
import java.io.IOException;
import com.loohp.limbo.Utils.DataTypeIO;
public class PacketPlayInChat extends Packet {
private String message;
public PacketPlayInChat(String message) {
this.message = message;
}
public PacketPlayInChat(DataInputStream in) throws IOException {
this(DataTypeIO.readString(in));
}
public String getMessage() {
return message;
}
}
@@ -0,0 +1,22 @@
package com.loohp.limbo.Server.Packets;
import java.io.DataInputStream;
import java.io.IOException;
public class PacketPlayInKeepAlive extends Packet {
long payload;
public PacketPlayInKeepAlive(long payload) {
this.payload = payload;
}
public PacketPlayInKeepAlive(DataInputStream in) throws IOException {
this(in.readLong());
}
public long getPayload() {
return payload;
}
}
@@ -0,0 +1,40 @@
package com.loohp.limbo.Server.Packets;
import java.io.DataInputStream;
import java.io.IOException;
public class PacketPlayInPosition extends Packet {
private double x;
private double y;
private double z;
private boolean onGround;
public PacketPlayInPosition(double x, double y, double z, boolean onGround) {
this.x = x;
this.y = y;
this.z = z;
this.onGround = onGround;
}
public PacketPlayInPosition(DataInputStream in) throws IOException {
this(in.readDouble(), in.readDouble(), in.readDouble(), in.readBoolean());
}
public double getX() {
return x;
}
public double getY() {
return y;
}
public double getZ() {
return z;
}
public boolean onGround() {
return onGround;
}
}
@@ -0,0 +1,52 @@
package com.loohp.limbo.Server.Packets;
import java.io.DataInputStream;
import java.io.IOException;
public class PacketPlayInPositionAndLook extends Packet {
private double x;
private double y;
private double z;
private float yaw;
private float pitch;
private boolean onGround;
public PacketPlayInPositionAndLook(double x, double y, double z, float yaw, float pitch, boolean onGround) {
this.x = x;
this.y = y;
this.z = z;
this.yaw = yaw;
this.pitch = pitch;
this.onGround = onGround;
}
public PacketPlayInPositionAndLook(DataInputStream in) throws IOException {
this(in.readDouble(), in.readDouble(), in.readDouble(), in.readFloat(), in.readFloat(), in.readBoolean());
}
public double getX() {
return x;
}
public double getY() {
return y;
}
public double getZ() {
return z;
}
public float getYaw() {
return yaw;
}
public float getPitch() {
return pitch;
}
public boolean onGround() {
return onGround;
}
}
@@ -0,0 +1,47 @@
package com.loohp.limbo.Server.Packets;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.UUID;
import com.loohp.limbo.Utils.DataTypeIO;
public class PacketPlayOutChat extends Packet {
private String json;
private int position;
private UUID sender;
public PacketPlayOutChat(String json, int position, UUID sender) {
this.json = json;
this.position = position;
this.sender = sender;
}
public String getJson() {
return json;
}
public int getPosition() {
return position;
}
public UUID getSender() {
return sender;
}
public byte[] getBytes() throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
DataOutputStream output = new DataOutputStream(buffer);
output.writeByte(Packet.getPlayOut().get(getClass()));
DataTypeIO.writeString(output, json, StandardCharsets.UTF_8);
output.writeByte(position);
DataTypeIO.writeUUID(output, sender);
return buffer.toByteArray();
}
}
@@ -0,0 +1,29 @@
package com.loohp.limbo.Server.Packets;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public class PacketPlayOutKeepAlive extends Packet {
long payload;
public PacketPlayOutKeepAlive(long payload) {
this.payload = payload;
}
public long getPayload() {
return payload;
}
public byte[] getBytes() throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
DataOutputStream output = new DataOutputStream(buffer);
output.writeByte(Packet.getPlayOut().get(getClass()));
output.writeLong(payload);
return buffer.toByteArray();
}
}
@@ -0,0 +1,136 @@
package com.loohp.limbo.Server.Packets;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import com.loohp.limbo.Utils.DataTypeIO;
import com.loohp.limbo.Utils.GameMode;
import net.querz.nbt.tag.CompoundTag;
public class PacketPlayOutLogin extends Packet {
private int entityId;
private boolean isHardcore;
private GameMode gamemode;
private String[] worldsNames;
private CompoundTag dimensionCodec;
private String dimension;
private String worldName;
private long hashedSeed;
private byte maxPlayers;
private int viewDistance;
private boolean reducedDebugInfo;
private boolean enableRespawnScreen;
private boolean isDebug;
private boolean isFlat;
public PacketPlayOutLogin(int entityId, boolean isHardcore, GameMode gamemode,
String[] worldsNames, CompoundTag dimensionCodec, String dimension, String worldName, long hashedSeed,
byte maxPlayers, int viewDistance, boolean reducedDebugInfo, boolean enableRespawnScreen, boolean isDebug,
boolean isFlat) {
this.entityId = entityId;
this.isHardcore = isHardcore;
this.gamemode = gamemode;
this.worldsNames = worldsNames;
this.dimensionCodec = dimensionCodec;
this.dimension = dimension;
this.worldName = worldName;
this.hashedSeed = hashedSeed;
this.maxPlayers = maxPlayers;
this.viewDistance = viewDistance;
this.reducedDebugInfo = reducedDebugInfo;
this.enableRespawnScreen = enableRespawnScreen;
this.isDebug = isDebug;
this.isFlat = isFlat;
}
public int getEntityId() {
return entityId;
}
public boolean isHardcore() {
return isHardcore;
}
public GameMode getGamemode() {
return gamemode;
}
public String[] getWorldsNames() {
return worldsNames;
}
public CompoundTag getDimensionCodec() {
return dimensionCodec;
}
public String getDimension() {
return dimension;
}
public String getWorldName() {
return worldName;
}
public long getHashedSeed() {
return hashedSeed;
}
public byte getMaxPlayers() {
return maxPlayers;
}
public int getViewDistance() {
return viewDistance;
}
public boolean isReducedDebugInfo() {
return reducedDebugInfo;
}
public boolean isEnableRespawnScreen() {
return enableRespawnScreen;
}
public boolean isDebug() {
return isDebug;
}
public boolean isFlat() {
return isFlat;
}
public byte[] getBytes() throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
DataOutputStream output = new DataOutputStream(buffer);
output.writeByte(Packet.getPlayOut().get(getClass()));
output.writeInt(entityId);
int i = gamemode.getId();
if (isHardcore) {
i |= 8;
}
output.writeByte((byte) i);
output.writeByte((byte) gamemode.getId());
DataTypeIO.writeVarInt(output, worldsNames.length);
for (int u = 0; u < worldsNames.length; u++) {
DataTypeIO.writeString(output, worldsNames[u], StandardCharsets.UTF_8);
}
DataTypeIO.writeCompoundTag(output, dimensionCodec);
DataTypeIO.writeString(output, dimension, StandardCharsets.UTF_8);
DataTypeIO.writeString(output, worldName, StandardCharsets.UTF_8);
output.writeLong(hashedSeed);
output.writeByte((byte) maxPlayers);
DataTypeIO.writeVarInt(output, viewDistance);
output.writeBoolean(reducedDebugInfo);
output.writeBoolean(enableRespawnScreen);
output.writeBoolean(isDebug);
output.writeBoolean(isFlat);
return buffer.toByteArray();
}
}
@@ -0,0 +1,131 @@
package com.loohp.limbo.Server.Packets;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Iterator;
import com.loohp.limbo.Utils.ChunkDataUtils;
import com.loohp.limbo.Utils.DataTypeIO;
import com.loohp.limbo.Utils.GeneratedDataUtils;
import net.querz.mca.Chunk;
import net.querz.mca.Section;
import net.querz.nbt.tag.CompoundTag;
import net.querz.nbt.tag.ListTag;
public class PacketPlayOutMapChunk extends Packet {
private int chunkX;
private int chunkZ;
private Chunk chunk;
public PacketPlayOutMapChunk(int chunkX, int chunkZ, Chunk chunk) {
this.chunkX = chunkX;
this.chunkZ = chunkZ;
this.chunk = chunk;
}
public Chunk getChunk() {
return chunk;
}
public int getChunkX() {
return chunkX;
}
public int getChunkZ() {
return chunkZ;
}
public byte[] getBytes() throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
DataOutputStream output = new DataOutputStream(buffer);
output.writeByte(Packet.getPlayOut().get(getClass()));
output.writeInt(chunkX);
output.writeInt(chunkZ);
output.writeBoolean(true);
output.writeBoolean(true);
int bitmask = 0;
for (int i = 0; i < 16; i++) {
Section section = chunk.getSection(i);
if (section != null) {
bitmask = bitmask | (int) Math.pow(2, i);
}
}
DataTypeIO.writeVarInt(output, bitmask);
DataTypeIO.writeCompoundTag(output, chunk.getHeightMaps());
//for (int i : chunk.getBiomes()) {
// output.writeInt(i);
//}
for (int i = 0; i < 1024; i++) {
output.writeInt(17);
}
ByteArrayOutputStream dataBuffer = new ByteArrayOutputStream();
DataOutputStream dataOut = new DataOutputStream(dataBuffer);
for (int i = 0; i < 16; i++) {
Section section = chunk.getSection(i);
if (section != null) {
int counter = 0;
for (int x = 0; x < 16; x++) {
for (int z = 0; z < 16; z++) {
for (int y = 0; y < 16; y++) {
CompoundTag tag = section.getBlockStateAt(x, y, z);
if (tag != null && !tag.getString("Name").equals("minecraft:air")) {
counter++;
}
}
}
}
dataOut.writeShort(counter);
int newBits = 32 - Integer.numberOfLeadingZeros(section.getPalette().size() - 1);
newBits = Math.max(newBits, 4);
if (newBits <= 8) {
if (newBits == 4) {
dataOut.writeByte(4);
} else {
newBits = 8;
ChunkDataUtils.adjustBlockStateBits(newBits, section, chunk.getDataVersion());
dataOut.writeByte(8);
}
DataTypeIO.writeVarInt(dataOut, section.getPalette().size());
//System.out.println(section.getPalette().size());
Iterator<CompoundTag> itr1 = section.getPalette().iterator();
//System.out.println("Nonnull -> " + i + " " + newBits);
counter = 0;
while (itr1.hasNext()) {
CompoundTag tag = itr1.next();
DataTypeIO.writeVarInt(dataOut, GeneratedDataUtils.getGlobalPaletteIDFromState(tag));
//System.out.println(tag + " -> " + GeneratedDataUtils.getGlobalPaletteIDFromState(tag));
}
} else {
dataOut.writeByte(14);
}
DataTypeIO.writeVarInt(dataOut, section.getBlockStates().length);
for (int u = 0; u < section.getBlockStates().length; u++) {
dataOut.writeLong(section.getBlockStates()[u]);
//System.out.println(Arrays.toString(section.getBlockStates()));
}
}
}
byte[] data = dataBuffer.toByteArray();
DataTypeIO.writeVarInt(output, data.length);
output.write(data);
ListTag<CompoundTag> tileEntities = chunk.getTileEntities();
DataTypeIO.writeVarInt(output, tileEntities.size());
for (CompoundTag each : tileEntities) {
DataTypeIO.writeCompoundTag(output, each);
}
return buffer.toByteArray();
}
}
@@ -0,0 +1,65 @@
package com.loohp.limbo.Server.Packets;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public class PacketPlayOutPlayerAbilities extends Packet {
public enum PlayerAbilityFlags {
INVULNERABLE(0x01),
FLY(0x02),
ALLOW_FLYING(0x04),
INSTANT_BREAK(0x08);
int bitvalue;
PlayerAbilityFlags(int bitvalue) {
this.bitvalue = bitvalue;
}
public int getValue() {
return bitvalue;
}
}
private PlayerAbilityFlags[] flags;
private float flySpeed;
private float fieldOfField;
public PacketPlayOutPlayerAbilities(float flySpeed, float fieldOfField, PlayerAbilityFlags... flags) {
this.flags = flags;
this.flySpeed = flySpeed;
this.fieldOfField = fieldOfField;
}
public PlayerAbilityFlags[] getFlags() {
return flags;
}
public float getFlySpeed() {
return flySpeed;
}
public float getFieldOfField() {
return fieldOfField;
}
public byte[] getBytes() throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
DataOutputStream output = new DataOutputStream(buffer);
output.writeByte(Packet.getPlayOut().get(getClass()));
int value = 0;
for (PlayerAbilityFlags flag : flags) {
value = value | flag.getValue();
}
output.writeByte(value);
output.writeFloat(flySpeed);
output.writeFloat(fieldOfField);
return buffer.toByteArray();
}
}
@@ -0,0 +1,167 @@
package com.loohp.limbo.Server.Packets;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Optional;
import java.util.UUID;
import com.loohp.limbo.Server.Packets.PacketPlayOutPlayerInfo.PlayerInfoData.PlayerInfoDataAddPlayer;
import com.loohp.limbo.Utils.DataTypeIO;
import com.loohp.limbo.Utils.GameMode;
public class PacketPlayOutPlayerInfo extends Packet {
public enum PlayerInfoAction {
ADD_PLAYER(0), UPDATE_GAMEMODE(1), UPDATE_LATENCY(2), UPDATE_DISPLAY_NAME(3), REMOVE_PLAYER(4);
int id;
PlayerInfoAction(int id) {
this.id = id;
}
public int getId() {
return id;
}
}
private PlayerInfoAction action;
private UUID uuid;
private PlayerInfoData data;
public PacketPlayOutPlayerInfo(PlayerInfoAction action, UUID uuid, PlayerInfoData data) {
this.action = action;
this.uuid = uuid;
this.data = data;
}
public PlayerInfoAction getAction() {
return action;
}
public UUID getUuid() {
return uuid;
}
public PlayerInfoData getData() {
return data;
}
public byte[] getBytes() throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
DataOutputStream output = new DataOutputStream(buffer);
output.writeByte(Packet.getPlayOut().get(getClass()));
DataTypeIO.writeVarInt(output, action.getId());
DataTypeIO.writeVarInt(output, 1);
DataTypeIO.writeUUID(output, uuid);
switch (action) {
case ADD_PLAYER:
PlayerInfoDataAddPlayer data = (PlayerInfoDataAddPlayer) this.data;
DataTypeIO.writeString(output, data.getName(), StandardCharsets.UTF_8);
if (data.getProperty().isPresent()) {
DataTypeIO.writeVarInt(output, 1);
DataTypeIO.writeString(output, "textures", StandardCharsets.UTF_8);
DataTypeIO.writeString(output, data.getProperty().get().getSkin(), StandardCharsets.UTF_8);
output.writeBoolean(true);
DataTypeIO.writeString(output, data.getProperty().get().getSignature(), StandardCharsets.UTF_8);
} else {
DataTypeIO.writeVarInt(output, 0);
}
DataTypeIO.writeVarInt(output, data.getGamemode().getId());
DataTypeIO.writeVarInt(output, data.getPing());
if (data.getDisplayNameJson().isPresent()) {
output.writeBoolean(true);
DataTypeIO.writeString(output, data.getDisplayNameJson().get(), StandardCharsets.UTF_8);
} else {
output.writeBoolean(false);
}
break;
case REMOVE_PLAYER:
break;
case UPDATE_DISPLAY_NAME:
break;
case UPDATE_GAMEMODE:
break;
case UPDATE_LATENCY:
break;
}
return buffer.toByteArray();
}
// =========
public static class PlayerInfoData {
public static class PlayerInfoDataAddPlayer extends PlayerInfoData {
private String name;
private Optional<PlayerSkinProperty> skin;
private GameMode gamemode;
private int ping;
private boolean hasDisplayName;
private Optional<String> displayNameJson;
public PlayerInfoDataAddPlayer(String name, Optional<PlayerSkinProperty> skin, GameMode gamemode, int ping,
boolean hasDisplayName, Optional<String> displayNameJson) {
this.name = name;
this.skin = skin;
this.gamemode = gamemode;
this.ping = ping;
this.hasDisplayName = hasDisplayName;
this.displayNameJson = displayNameJson;
}
public String getName() {
return name;
}
public Optional<PlayerSkinProperty> getProperty() {
return skin;
}
public GameMode getGamemode() {
return gamemode;
}
public int getPing() {
return ping;
}
public boolean isHasDisplayName() {
return hasDisplayName;
}
public Optional<String> getDisplayNameJson() {
return displayNameJson;
}
public static class PlayerSkinProperty {
private String skin;
private String signature;
public PlayerSkinProperty(String skin, String signature) {
this.skin = skin;
this.signature = signature;
}
public String getSkin() {
return skin;
}
public String getSignature() {
return signature;
}
}
}
}
}
@@ -0,0 +1,100 @@
package com.loohp.limbo.Server.Packets;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;
import com.loohp.limbo.Utils.DataTypeIO;
public class PacketPlayOutPositionAndLook extends Packet {
public enum PlayerTeleportFlags {
X((byte) 0x01),
Y((byte) 0x02),
Z((byte) 0x04),
Y_ROT((byte) 0x08),
X_ROT((byte) 0x10);
byte bit;
PlayerTeleportFlags(byte bit) {
this.bit = bit;
}
public byte getBit() {
return bit;
}
}
private double x;
private double y;
private double z;
private float yaw;
private float pitch;
private Set<PlayerTeleportFlags> flags;
private int teleportId;
public PacketPlayOutPositionAndLook(double x, double y, double z, float yaw, float pitch, int teleportId, PlayerTeleportFlags... flags) {
this.x = x;
this.y = y;
this.z = z;
this.yaw = yaw;
this.pitch = pitch;
this.teleportId = teleportId;
this.flags = Arrays.asList(flags).stream().collect(Collectors.toSet());
}
public double getX() {
return x;
}
public double getY() {
return y;
}
public double getZ() {
return z;
}
public float getYaw() {
return yaw;
}
public float getPitch() {
return pitch;
}
public Set<PlayerTeleportFlags> getFlags() {
return flags;
}
public int getTeleportId() {
return teleportId;
}
public byte[] getBytes() throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
DataOutputStream output = new DataOutputStream(buffer);
output.writeByte(Packet.getPlayOut().get(getClass()));
output.writeDouble(x);
output.writeDouble(y);
output.writeDouble(z);
output.writeFloat(yaw);
output.writeFloat(pitch);
byte flag = 0;
for (PlayerTeleportFlags each : flags) {
flag = (byte) (flag | each.getBit());
}
output.writeByte(flag);
DataTypeIO.writeVarInt(output, teleportId);
return buffer.toByteArray();
}
}
@@ -0,0 +1,37 @@
package com.loohp.limbo.Server.Packets;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import com.loohp.limbo.Utils.DataTypeIO;
public class PacketPlayOutShowPlayerSkins extends Packet {
private int entityId;
public PacketPlayOutShowPlayerSkins(int entityId) {
this.entityId = entityId;
}
public int getEntityId() {
return entityId;
}
public byte[] getBytes() throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
DataOutputStream output = new DataOutputStream(buffer);
output.writeByte(Packet.getPlayOut().get(getClass()));
DataTypeIO.writeVarInt(output, entityId);
output.writeByte(16);
DataTypeIO.writeVarInt(output, 0);
int bitmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40;
output.writeByte(bitmask);
output.writeByte(0xff);
return buffer.toByteArray();
}
}
@@ -0,0 +1,34 @@
package com.loohp.limbo.Server.Packets;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import com.loohp.limbo.World.BlockPosition;
public class PacketPlayOutSpawnPosition extends Packet {
private BlockPosition position;
public PacketPlayOutSpawnPosition(BlockPosition position) {
this.position = position;
}
public BlockPosition getPosition() {
return position;
}
public byte[] getBytes() throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
DataOutputStream output = new DataOutputStream(buffer);
output.writeByte(Packet.getPlayOut().get(getClass()));
int x = position.getX();
int y = position.getY();
int z = position.getZ();
output.writeLong(((x & 0x3FFFFFF) << 38) | ((z & 0x3FFFFFF) << 12) | (y & 0xFFF));
return buffer.toByteArray();
}
}
@@ -0,0 +1,38 @@
package com.loohp.limbo.Server.Packets;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import com.loohp.limbo.Utils.DataTypeIO;
public class PacketPlayOutUpdateViewPosition extends Packet {
private int chunkX;
private int chunkZ;
public PacketPlayOutUpdateViewPosition(int chunkX, int chunkZ) {
this.chunkX = chunkX;
this.chunkZ = chunkZ;
}
public int getChunkX() {
return chunkX;
}
public int getChunkZ() {
return chunkZ;
}
public byte[] getBytes() throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
DataOutputStream output = new DataOutputStream(buffer);
output.writeByte(Packet.getPlayOut().get(getClass()));
DataTypeIO.writeVarInt(output, chunkX);
DataTypeIO.writeVarInt(output, chunkZ);
return buffer.toByteArray();
}
}
@@ -0,0 +1,22 @@
package com.loohp.limbo.Server.Packets;
import java.io.DataInputStream;
import java.io.IOException;
public class PacketStatusInPing extends Packet {
private long payload;
public PacketStatusInPing(long payload) {
this.payload = payload;
}
public PacketStatusInPing(DataInputStream in) throws IOException {
this(in.readLong());
}
public long getPayload() {
return payload;
}
}
@@ -0,0 +1,15 @@
package com.loohp.limbo.Server.Packets;
import java.io.DataInputStream;
public class PacketStatusInRequest extends Packet {
public PacketStatusInRequest() {
}
public PacketStatusInRequest(DataInputStream in) {
this();
}
}
@@ -0,0 +1,29 @@
package com.loohp.limbo.Server.Packets;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public class PacketStatusOutPong extends Packet {
private long payload;
public PacketStatusOutPong(long payload) {
this.payload = payload;
}
public long getPayload() {
return payload;
}
public byte[] getBytes() throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
DataOutputStream output = new DataOutputStream(buffer);
output.writeByte(Packet.getStatusOut().get(getClass()));
output.writeLong(payload);
return buffer.toByteArray();
}
}
@@ -0,0 +1,32 @@
package com.loohp.limbo.Server.Packets;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import com.loohp.limbo.Utils.DataTypeIO;
public class PacketStatusOutResponse extends Packet {
private String json;
public PacketStatusOutResponse(String json) {
this.json = json;
}
public String getJson() {
return json;
}
public byte[] getBytes() throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
DataOutputStream output = new DataOutputStream(buffer);
output.writeByte(Packet.getStatusOut().get(getClass()));
DataTypeIO.writeString(output, json, StandardCharsets.UTF_8);
return buffer.toByteArray();
}
}
@@ -0,0 +1,56 @@
package com.loohp.limbo.Server;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
public class ServerConnection extends Thread {
private ServerSocket serverSocket;
private List<ClientConnection> clients;
private String ip;
private int port;
private KeepAliveSender keepAliveSender;
public ServerConnection(String ip, int port) {
clients = new ArrayList<ClientConnection>();
this.ip = ip;
this.port = port;
start();
keepAliveSender = new KeepAliveSender();
}
@Override
public void run() {
try {
serverSocket = new ServerSocket(port, 50, InetAddress.getByName(ip));
System.out.println("Server listening on [" + serverSocket.getInetAddress().getHostName() + ":" + serverSocket.getLocalPort() + "]");
while (true) {
Socket connection = serverSocket.accept();
//String str = connection.getInetAddress().getHostName() + ":" + connection.getPort();
//System.out.println("[/127.0.0.1:57310] <-> InitialHandler has pinged);
ClientConnection sc = new ClientConnection(connection);
clients.add(sc);
sc.start();
}
} catch(IOException e) {
e.printStackTrace();
}
}
public KeepAliveSender getKeepAliveSender() {
return keepAliveSender;
}
public ServerSocket getServerSocket() {
return serverSocket;
}
public List<ClientConnection> getClients() {
return clients;
}
}