diff --git a/pom.xml b/pom.xml index 3119032..be90d37 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 Limbo Limbo - 0.2.1-ALPHA + 0.2.2-ALPHA src diff --git a/src/com/loohp/limbo/Limbo.java b/src/com/loohp/limbo/Limbo.java index 1623e5a..1aace45 100644 --- a/src/com/loohp/limbo/Limbo.java +++ b/src/com/loohp/limbo/Limbo.java @@ -42,6 +42,7 @@ import com.loohp.limbo.Utils.ImageUtils; import com.loohp.limbo.Utils.NetworkUtils; import com.loohp.limbo.World.Schematic; import com.loohp.limbo.World.World; +import com.loohp.limbo.World.World.Environment; import net.querz.nbt.io.NBTUtil; import net.querz.nbt.tag.CompoundTag; @@ -285,7 +286,7 @@ public class Limbo { return null; } - World world = Schematic.toWorld(properties.getLevelName().getKey(), (CompoundTag) NBTUtil.read(schem).getTag()); + World world = Schematic.toWorld(properties.getLevelName().getKey(), Environment.fromNamespacedKey(properties.getLevelDimension()), (CompoundTag) NBTUtil.read(schem).getTag()); console.sendMessage("Loaded world " + properties.getLevelName() + "!"); diff --git a/src/com/loohp/limbo/Player/Player.java b/src/com/loohp/limbo/Player/Player.java index 920fc4b..e3b7050 100644 --- a/src/com/loohp/limbo/Player/Player.java +++ b/src/com/loohp/limbo/Player/Player.java @@ -9,7 +9,10 @@ import com.loohp.limbo.Events.PlayerChatEvent; import com.loohp.limbo.Location.Location; import com.loohp.limbo.Server.ClientConnection; import com.loohp.limbo.Server.Packets.PacketPlayOutChat; +import com.loohp.limbo.Server.Packets.PacketPlayOutGameState; import com.loohp.limbo.Server.Packets.PacketPlayOutPositionAndLook; +import com.loohp.limbo.Server.Packets.PacketPlayOutRespawn; +import com.loohp.limbo.Utils.GameMode; import com.loohp.limbo.World.World; import net.md_5.bungee.api.chat.BaseComponent; @@ -22,6 +25,7 @@ public class Player implements CommandSender { private final String username; private final UUID uuid; + private GameMode gamemode; private int entityId; @@ -35,10 +39,32 @@ public class Player implements CommandSender { this.location = location.clone(); } + public GameMode getGamemode() { + return gamemode; + } + + public void setGamemode(GameMode gamemode) { + if (!this.gamemode.equals(gamemode)) { + try { + PacketPlayOutGameState state = new PacketPlayOutGameState(3, gamemode.getId()); + clientConnection.sendPacket(state); + } catch (IOException e) { + e.printStackTrace(); + } + } + this.gamemode = gamemode; + } + + @Deprecated + public void setGamemodeSilent(GameMode gamemode) { + this.gamemode = gamemode; + } + public World getWorld() { return location.clone().getWorld(); } + @Deprecated public void setEntityId(int entityId) { this.entityId = entityId; } @@ -77,8 +103,11 @@ public class Player implements CommandSender { public void teleport(Location location) { try { - PacketPlayOutPositionAndLook positionLook = new PacketPlayOutPositionAndLook(location.getX(), - location.getY(), location.getZ(), location.getYaw(), location.getPitch(), 1); + if (!this.location.getWorld().equals(location.getWorld())) { + PacketPlayOutRespawn respawn = new PacketPlayOutRespawn(location.getWorld(), 0, gamemode, false, false, true); + clientConnection.sendPacket(respawn); + } + PacketPlayOutPositionAndLook positionLook = new PacketPlayOutPositionAndLook(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch(), 1); clientConnection.sendPacket(positionLook); } catch (IOException e) { e.printStackTrace(); diff --git a/src/com/loohp/limbo/Server/ClientConnection.java b/src/com/loohp/limbo/Server/ClientConnection.java index f5243cc..aef5c0b 100644 --- a/src/com/loohp/limbo/Server/ClientConnection.java +++ b/src/com/loohp/limbo/Server/ClientConnection.java @@ -57,6 +57,7 @@ import com.loohp.limbo.Utils.CustomStringUtils; import com.loohp.limbo.Utils.DataTypeIO; import com.loohp.limbo.Utils.MojangAPIUtils; import com.loohp.limbo.Utils.MojangAPIUtils.SkinResponse; +import com.loohp.limbo.Utils.NamespacedKey; import com.loohp.limbo.World.BlockPosition; import com.loohp.limbo.World.DimensionRegistry; import com.loohp.limbo.World.World; @@ -154,6 +155,7 @@ public class ClientConnection extends Thread { } catch (IOException e) {} } + @SuppressWarnings("deprecation") @Override public void run() { running = true; @@ -258,8 +260,9 @@ public class ClientConnection extends Thread { TimeUnit.MILLISECONDS.sleep(500); ServerProperties p = Limbo.getInstance().getServerProperties(); - PacketPlayOutLogin join = new PacketPlayOutLogin(player.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); + PacketPlayOutLogin join = new PacketPlayOutLogin(player.getEntityId(), false, p.getDefaultGamemode(), Limbo.getInstance().getWorlds().stream().map(each -> new NamespacedKey(each.getName()).toString()).collect(Collectors.toList()).toArray(new String[Limbo.getInstance().getWorlds().size()]), DimensionRegistry.getCodec(), p.getWorldSpawn().getWorld(), 0, (byte) p.getMaxPlayers(), 8, p.isReducedDebugInfo(), true, false, false); sendPacket(join); + player.setGamemodeSilent(p.getDefaultGamemode()); Location s = p.getWorldSpawn(); diff --git a/src/com/loohp/limbo/Server/Packets/PacketPlayOutGameState.java b/src/com/loohp/limbo/Server/Packets/PacketPlayOutGameState.java new file mode 100644 index 0000000..9bf839d --- /dev/null +++ b/src/com/loohp/limbo/Server/Packets/PacketPlayOutGameState.java @@ -0,0 +1,37 @@ +package com.loohp.limbo.Server.Packets; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class PacketPlayOutGameState extends PacketOut { + + private int reason; + private float value; + + public PacketPlayOutGameState(int reason, float value) { + this.reason = reason; + this.value = value; + } + + public int getReason() { + return reason; + } + + public float getValue() { + return value; + } + + @Override + public byte[] serializePacket() throws IOException { + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + + DataOutputStream output = new DataOutputStream(buffer); + output.writeByte(Packet.getPlayOut().get(getClass())); + output.writeByte(reason); + output.writeFloat(value); + + return buffer.toByteArray(); + } + +} diff --git a/src/com/loohp/limbo/Server/Packets/PacketPlayOutLogin.java b/src/com/loohp/limbo/Server/Packets/PacketPlayOutLogin.java index 5c29aa4..1263645 100644 --- a/src/com/loohp/limbo/Server/Packets/PacketPlayOutLogin.java +++ b/src/com/loohp/limbo/Server/Packets/PacketPlayOutLogin.java @@ -7,6 +7,8 @@ import java.nio.charset.StandardCharsets; import com.loohp.limbo.Utils.DataTypeIO; import com.loohp.limbo.Utils.GameMode; +import com.loohp.limbo.Utils.NamespacedKey; +import com.loohp.limbo.World.World; import net.querz.nbt.tag.CompoundTag; @@ -28,7 +30,7 @@ public class PacketPlayOutLogin extends PacketOut { private boolean isFlat; public PacketPlayOutLogin(int entityId, boolean isHardcore, GameMode gamemode, - String[] worldsNames, CompoundTag dimensionCodec, String dimension, String worldName, long hashedSeed, + String[] worldsNames, CompoundTag dimensionCodec, World world, long hashedSeed, byte maxPlayers, int viewDistance, boolean reducedDebugInfo, boolean enableRespawnScreen, boolean isDebug, boolean isFlat) { this.entityId = entityId; @@ -36,8 +38,8 @@ public class PacketPlayOutLogin extends PacketOut { this.gamemode = gamemode; this.worldsNames = worldsNames; this.dimensionCodec = dimensionCodec; - this.dimension = dimension; - this.worldName = worldName; + this.dimension = world.getEnvironment().getNamespacedKey().toString(); + this.worldName = new NamespacedKey(world.getName()).toString(); this.hashedSeed = hashedSeed; this.maxPlayers = maxPlayers; this.viewDistance = viewDistance; diff --git a/src/com/loohp/limbo/Server/Packets/PacketPlayOutRespawn.java b/src/com/loohp/limbo/Server/Packets/PacketPlayOutRespawn.java new file mode 100644 index 0000000..e2d8101 --- /dev/null +++ b/src/com/loohp/limbo/Server/Packets/PacketPlayOutRespawn.java @@ -0,0 +1,80 @@ +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 com.loohp.limbo.Utils.NamespacedKey; +import com.loohp.limbo.World.World; + +public class PacketPlayOutRespawn extends PacketOut { + + private String dimension; + private String worldName; + private long hashedSeed; + private GameMode gamemode; + private boolean isDebug; + private boolean isFlat; + private boolean copyMetaData; + + public PacketPlayOutRespawn(World world, long hashedSeed, GameMode gamemode, boolean isDebug, + boolean isFlat, boolean copyMetaData) { + this.dimension = world.getEnvironment().getNamespacedKey().toString(); + this.worldName = new NamespacedKey(world.getName()).toString(); + this.hashedSeed = hashedSeed; + this.gamemode = gamemode; + this.isDebug = isDebug; + this.isFlat = isFlat; + this.copyMetaData = copyMetaData; + } + + public String getDimension() { + return dimension; + } + + public String getWorldName() { + return worldName; + } + + public long getHashedSeed() { + return hashedSeed; + } + + public GameMode getGamemode() { + return gamemode; + } + + public boolean isDebug() { + return isDebug; + } + + public boolean isFlat() { + return isFlat; + } + + public boolean isCopyMetaData() { + return copyMetaData; + } + + @Override + public byte[] serializePacket() throws IOException { + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + + DataOutputStream output = new DataOutputStream(buffer); + output.writeByte(Packet.getPlayOut().get(getClass())); + DataTypeIO.writeString(output, dimension, StandardCharsets.UTF_8); + DataTypeIO.writeString(output, worldName, StandardCharsets.UTF_8); + output.writeLong(hashedSeed); + output.writeByte((byte) gamemode.getId()); + output.writeByte((byte) gamemode.getId()); + output.writeBoolean(isDebug); + output.writeBoolean(isFlat); + output.writeBoolean(copyMetaData); + + return buffer.toByteArray(); + } + +} diff --git a/src/com/loohp/limbo/World/Schematic.java b/src/com/loohp/limbo/World/Schematic.java index 695db2a..1d5cbb1 100644 --- a/src/com/loohp/limbo/World/Schematic.java +++ b/src/com/loohp/limbo/World/Schematic.java @@ -5,6 +5,7 @@ import java.util.Iterator; import java.util.Map; import com.loohp.limbo.Utils.SchematicConvertionUtils; +import com.loohp.limbo.World.World.Environment; import net.querz.mca.Chunk; import net.querz.nbt.tag.CompoundTag; @@ -13,7 +14,7 @@ import net.querz.nbt.tag.ListTag; public class Schematic { - public static World toWorld(String name, CompoundTag nbt) { + public static World toWorld(String name, Environment environment, CompoundTag nbt) { short width = nbt.getShort("Width"); short length = nbt.getShort("Length"); short height = nbt.getShort("Height"); @@ -25,7 +26,7 @@ public class Schematic { mapping.put(palette.getInt(key), key); } - World world = new World(name, width, length); + World world = new World(name, width, length, environment); for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { for (int z = 0; z < length; z++) { diff --git a/src/com/loohp/limbo/World/World.java b/src/com/loohp/limbo/World/World.java index 9177bc7..07cd009 100644 --- a/src/com/loohp/limbo/World/World.java +++ b/src/com/loohp/limbo/World/World.java @@ -1,5 +1,6 @@ package com.loohp.limbo.World; +import com.loohp.limbo.Utils.NamespacedKey; import com.loohp.limbo.Utils.SchematicConvertionUtils; import net.querz.mca.Chunk; @@ -9,19 +10,31 @@ import net.querz.nbt.tag.ListTag; public class World { private String name; + private Environment environment; private Chunk[][] chunks; - public World(String name, int width, int length) { + public World(String name, int width, int length, Environment environment) { this.name = name; + this.environment = environment; this.chunks = new Chunk[(width >> 4) + 1][(length >> 4) + 1]; - + for (int x = 0; x < chunks.length; x++) { for (int z = 0; z < chunks[x].length; z++) { chunks[x][z] = Chunk.newChunk(); Chunk chunk = chunks[x][z]; chunk.cleanupPalettesAndBlockStates(); CompoundTag heightMap = new CompoundTag(); - heightMap.putLongArray("MOTION_BLOCKING", new long[] {1371773531765642314L,1389823183635651148L,1371738278539598925L,1389823183635388492L,1353688558756731469L,1389823114781694027L,1317765589597723213L,1371773531899860042L,1389823183635651149L,1371773462911685197L,1389823183635650636L,1353688626805119565L,1371773531900123211L,1335639250618849869L,1371738278674077258L,1389823114781694028L,1353723811310638154L,1371738278674077259L,1335674228429068364L,1335674228429067338L,1335674228698027594L,1317624576693539402L,1335709481520370249L,1299610178184057417L,1335638906349064264L,1299574993811968586L,1299574924958011464L,1299610178184056904L,1299574924958011464L,1299610109330100296L,1299574924958011464L,1299574924823793736L,1299574924958011465L,1281525273222484040L,1299574924958011464L,1281525273222484040L,9548107335L}); + heightMap.putLongArray("MOTION_BLOCKING", + new long[] { 1371773531765642314L, 1389823183635651148L, 1371738278539598925L, + 1389823183635388492L, 1353688558756731469L, 1389823114781694027L, 1317765589597723213L, + 1371773531899860042L, 1389823183635651149L, 1371773462911685197L, 1389823183635650636L, + 1353688626805119565L, 1371773531900123211L, 1335639250618849869L, 1371738278674077258L, + 1389823114781694028L, 1353723811310638154L, 1371738278674077259L, 1335674228429068364L, + 1335674228429067338L, 1335674228698027594L, 1317624576693539402L, 1335709481520370249L, + 1299610178184057417L, 1335638906349064264L, 1299574993811968586L, 1299574924958011464L, + 1299610178184056904L, 1299574924958011464L, 1299610109330100296L, 1299574924958011464L, + 1299574924823793736L, 1299574924958011465L, 1281525273222484040L, 1299574924958011464L, + 1281525273222484040L, 9548107335L }); chunk.setHeightMaps(heightMap); chunk.setBiomes(new int[256]); chunk.setTileEntities(new ListTag(CompoundTag.class)); @@ -50,4 +63,33 @@ public class World { public String getName() { return name; } + + public Environment getEnvironment() { + return environment; + } + + public enum Environment { + NORMAL(new NamespacedKey("minecraft:overworld")), + NETHER(new NamespacedKey("minecraft:the_nether")), + END(new NamespacedKey("minecraft:the_end")); + + NamespacedKey key; + + Environment(NamespacedKey key) { + this.key = key; + } + + public NamespacedKey getNamespacedKey() { + return key; + } + + public static Environment fromNamespacedKey(NamespacedKey key) { + for (Environment each : Environment.values()) { + if (each.getNamespacedKey().equals(key)) { + return each; + } + } + return null; + } + } } diff --git a/src/mapping.json b/src/mapping.json index 806e36e..80eb8f6 100644 --- a/src/mapping.json +++ b/src/mapping.json @@ -34,7 +34,9 @@ "PacketPlayOutDisconnect": "0x1A", "PacketPlayOutPluginMessaging": "0x17", "PacketPlayOutTabComplete": "0x10", - "PacketPlayOutDeclareCommands": "0x11" + "PacketPlayOutDeclareCommands": "0x11", + "PacketPlayOutRespawn": "0x3A", + "PacketPlayOutGameState": "0x1E" }, "StatusIn": { "0x01": "PacketStatusInPing", diff --git a/src/permission.yml b/src/permission.yml index 88d2981..662a2e5 100644 --- a/src/permission.yml +++ b/src/permission.yml @@ -3,6 +3,7 @@ groups: - limboserver.stop - limboserver.kick - limboserver.say + - limboserver.gamemode default: - limboserver.spawn