diff --git a/src/main/java/com/loohp/limbo/events/player/PlayerResourcePackStatusEvent.java b/src/main/java/com/loohp/limbo/events/player/PlayerResourcePackStatusEvent.java new file mode 100644 index 0000000..0c41004 --- /dev/null +++ b/src/main/java/com/loohp/limbo/events/player/PlayerResourcePackStatusEvent.java @@ -0,0 +1,22 @@ +package com.loohp.limbo.events.player; + +import com.loohp.limbo.player.Player; +import com.loohp.limbo.server.packets.PacketPlayInResourcePackStatus.EnumResourcePackStatus; + +public class PlayerResourcePackStatusEvent extends PlayerEvent { + + private Player player; + private EnumResourcePackStatus status; + + public PlayerResourcePackStatusEvent(Player player, EnumResourcePackStatus status) { + super(player); + } + + public Player getPlayer() { + return player; + } + + public EnumResourcePackStatus getStatus() { + return status; + } +} diff --git a/src/main/java/com/loohp/limbo/file/ServerProperties.java b/src/main/java/com/loohp/limbo/file/ServerProperties.java index 85da867..c16cc40 100644 --- a/src/main/java/com/loohp/limbo/file/ServerProperties.java +++ b/src/main/java/com/loohp/limbo/file/ServerProperties.java @@ -50,6 +50,11 @@ public class ServerProperties { private double ticksPerSecond; private boolean handshakeVerbose; + private String resourcePackSHA; + private String resourcePackLink; + private boolean resourcePackRequired; + private String resourcePackPrompt; + Optional favicon; public ServerProperties(File file) throws IOException { @@ -122,6 +127,11 @@ public class ServerProperties { viewDistance = Integer.parseInt(prop.getProperty("view-distance")); ticksPerSecond = Double.parseDouble(prop.getProperty("ticks-per-second")); handshakeVerbose = Boolean.parseBoolean(prop.getProperty("handshake-verbose")); + + resourcePackLink = prop.getProperty("resource-pack"); + resourcePackSHA = prop.getProperty("resource-pack-sha1"); + resourcePackRequired = Boolean.parseBoolean(prop.getProperty("required-resource-pack")); + resourcePackPrompt = prop.getProperty("resource-pack-prompt"); File png = new File("server-icon.png"); if (png.exists()) { @@ -242,5 +252,21 @@ public class ServerProperties { public boolean handshakeVerboseEnabled() { return handshakeVerbose; } + + public String getResourcePackLink() { + return resourcePackLink; + } + + public String getResourcePackSHA() { + return resourcePackSHA; + } + + public boolean getResourcePackRequired() { + return resourcePackRequired; + } + + public String getResourcePackPrompt() { + return resourcePackPrompt; + } } diff --git a/src/main/java/com/loohp/limbo/player/Player.java b/src/main/java/com/loohp/limbo/player/Player.java index ff34b48..71ab2d1 100644 --- a/src/main/java/com/loohp/limbo/player/Player.java +++ b/src/main/java/com/loohp/limbo/player/Player.java @@ -18,6 +18,7 @@ import com.loohp.limbo.server.packets.PacketPlayOutChat; import com.loohp.limbo.server.packets.PacketPlayOutGameState; import com.loohp.limbo.server.packets.PacketPlayOutHeldItemChange; import com.loohp.limbo.server.packets.PacketPlayOutPositionAndLook; +import com.loohp.limbo.server.packets.PacketPlayOutResourcePackSend; import com.loohp.limbo.server.packets.PacketPlayOutRespawn; import com.loohp.limbo.utils.GameMode; @@ -259,5 +260,17 @@ public class Player extends LivingEntity implements CommandSender { } } } + + + public void setResourcePack(String url, String hash, boolean forced, BaseComponent[] promptmessage) { + try { + PacketPlayOutResourcePackSend packsend = new PacketPlayOutResourcePackSend(url, hash, forced, + (promptmessage != null || !ComponentSerializer.toString(promptmessage).equalsIgnoreCase("")) ? true : false, + ComponentSerializer.toString(promptmessage)); + clientConnection.sendPacket(packsend); + } catch (IOException e) { + e.printStackTrace(); + } + } } diff --git a/src/main/java/com/loohp/limbo/server/ClientConnection.java b/src/main/java/com/loohp/limbo/server/ClientConnection.java index 93f6b67..e9d31b7 100644 --- a/src/main/java/com/loohp/limbo/server/ClientConnection.java +++ b/src/main/java/com/loohp/limbo/server/ClientConnection.java @@ -26,6 +26,7 @@ import com.loohp.limbo.events.player.PlayerJoinEvent; import com.loohp.limbo.events.player.PlayerLoginEvent; import com.loohp.limbo.events.player.PlayerMoveEvent; import com.loohp.limbo.events.player.PlayerQuitEvent; +import com.loohp.limbo.events.player.PlayerResourcePackStatusEvent; import com.loohp.limbo.events.player.PlayerSelectedSlotChangeEvent; import com.loohp.limbo.events.status.StatusPingEvent; import com.loohp.limbo.file.ServerProperties; @@ -45,6 +46,7 @@ import com.loohp.limbo.server.packets.PacketPlayInHeldItemChange; 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.PacketPlayInResourcePackStatus; import com.loohp.limbo.server.packets.PacketPlayInRotation; import com.loohp.limbo.server.packets.PacketPlayInTabComplete; import com.loohp.limbo.server.packets.PacketPlayOutDeclareCommands; @@ -417,6 +419,20 @@ public class ClientConnection extends Thread { sendPacket(state); } + if (properties.getResourcePackLink() != null && !properties.getResourcePackLink().equalsIgnoreCase("")) { + if (properties.getResourcePackSHA() != null && !properties.getResourcePackSHA().equalsIgnoreCase("")) { + //SEND RESOURCEPACK + player.setResourcePack(properties.getResourcePackLink(), + properties.getResourcePackSHA(), properties.getResourcePackRequired(), + ComponentSerializer.parse(properties.getResourcePackPrompt())); + } else { + //NO SHA + Limbo.getInstance().getConsole().sendMessage("ResourcePacks require SHA1s"); + } + } else { + //RESOURCEPACK NOT ENABLED + } + ready = true; while (client_socket.isConnected()) { @@ -510,6 +526,11 @@ public class ClientConnection extends Thread { } else { Limbo.getInstance().getUnsafe().setSelectedSlotSilently(player, event.getSlot()); } + + } else if (packetType.equals(PacketPlayInResourcePackStatus.class)) { + PacketPlayInResourcePackStatus rpcheck = new PacketPlayInResourcePackStatus(input); + // Pass on result to the events + Limbo.getInstance().getEventsManager().callEvent(new PlayerResourcePackStatusEvent(player, rpcheck.getLoadedValue())); } else { input.skipBytes(size - DataTypeIO.getVarIntLength(packetId)); } diff --git a/src/main/java/com/loohp/limbo/server/packets/PacketPlayInResourcePackStatus.java b/src/main/java/com/loohp/limbo/server/packets/PacketPlayInResourcePackStatus.java new file mode 100644 index 0000000..1f98a6d --- /dev/null +++ b/src/main/java/com/loohp/limbo/server/packets/PacketPlayInResourcePackStatus.java @@ -0,0 +1,42 @@ +package com.loohp.limbo.server.packets; + +import java.io.DataInputStream; +import java.io.IOException; + +import com.loohp.limbo.utils.DataTypeIO; + +public class PacketPlayInResourcePackStatus extends PacketIn { + + + public enum EnumResourcePackStatus { + SUCCESS, + DECLINED, + FAILED, + ACCEPTED; + } + + private int loaded; + + public PacketPlayInResourcePackStatus(int loaded) { + this.loaded = loaded; + } + + public PacketPlayInResourcePackStatus(DataInputStream in) throws IOException { + this(DataTypeIO.readVarInt(in)); + } + + public EnumResourcePackStatus getLoadedValue() { + switch (loaded) { + case 0: return EnumResourcePackStatus.SUCCESS; + case 1: return EnumResourcePackStatus.DECLINED; + case 2: return EnumResourcePackStatus.FAILED; + case 3: return EnumResourcePackStatus.ACCEPTED; + default: return EnumResourcePackStatus.FAILED; + } + } + + public boolean isLoadedValue(EnumResourcePackStatus status) { + return getLoadedValue() == status; + } + +} diff --git a/src/main/java/com/loohp/limbo/server/packets/PacketPlayOutResourcePackSend.java b/src/main/java/com/loohp/limbo/server/packets/PacketPlayOutResourcePackSend.java new file mode 100644 index 0000000..f0e2bd9 --- /dev/null +++ b/src/main/java/com/loohp/limbo/server/packets/PacketPlayOutResourcePackSend.java @@ -0,0 +1,62 @@ +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 PacketPlayOutResourcePackSend extends PacketOut { + + private String url; + private String hash; + private boolean isForced; + private boolean hasPromptMessage; + private String promptMessage; + + public PacketPlayOutResourcePackSend(String url, String hash, boolean isForced, boolean hasPromptMessage, String promptMessage) { + this.url = url; + this.hash = hash; + this.isForced = isForced; + this.hasPromptMessage = hasPromptMessage; + this.promptMessage = promptMessage; + } + + public String getURL() { + return url; + } + + public String getHash() { + return hash; + } + + public boolean isForced() { + return isForced; + } + + public boolean hasPromptMessage() { + return hasPromptMessage; + } + + public String getPromptMessage() { + return promptMessage; + } + + @Override + public byte[] serializePacket() throws IOException { + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + + DataOutputStream output = new DataOutputStream(buffer); + output.writeByte(Packet.getPlayOut().get(getClass())); + DataTypeIO.writeString(output, url, StandardCharsets.UTF_8); + DataTypeIO.writeString(output, hash, StandardCharsets.UTF_8); + output.writeBoolean(isForced); + output.writeBoolean(hasPromptMessage); + if (hasPromptMessage) { + DataTypeIO.writeString(output, promptMessage, StandardCharsets.UTF_8); + } + return buffer.toByteArray(); + } + +}