diff --git a/pom.xml b/pom.xml index dbd4049..17d6cfc 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ com.loohp Limbo Limbo - 0.7.15-ALPHA + 0.7.16-ALPHA Standalone Limbo Minecraft Server. https://github.com/LOOHP/Limbo diff --git a/src/main/java/com/loohp/limbo/Limbo.java b/src/main/java/com/loohp/limbo/Limbo.java index 80c86ac..05cfc96 100644 --- a/src/main/java/com/loohp/limbo/Limbo.java +++ b/src/main/java/com/loohp/limbo/Limbo.java @@ -41,6 +41,7 @@ import com.loohp.limbo.player.Player; import com.loohp.limbo.plugins.LimboPlugin; import com.loohp.limbo.plugins.PluginManager; import com.loohp.limbo.scheduler.LimboScheduler; +import com.loohp.limbo.scheduler.LimboTask; import com.loohp.limbo.scheduler.Tick; import com.loohp.limbo.utils.CustomStringUtils; import com.loohp.limbo.utils.ImageUtils; @@ -542,4 +543,31 @@ public final class Limbo { } } + public void transferAll(String host, int port, int batchDelayTicks, int batchSize) { + if (batchDelayTicks <= 0 || batchSize <= 0) { + for (Player player : getPlayers()) { + player.transfer(host, port); + } + } else { + long totalDelay = 0; + Set currentBatch = new HashSet<>(); + List players = new ArrayList<>(getPlayers()); + + for (int i = 0; i < players.size(); i++) { + currentBatch.add(players.get(i)); + if (currentBatch.size() < batchSize && i != players.size() - 1) { + continue; + } + Set batch = new HashSet<>(currentBatch); + LimboTask task = () -> { + for (Player p : batch) { + p.transfer(host, port); + } + }; + Limbo.getInstance().getScheduler().runTaskLater(null, task, totalDelay); + totalDelay += batchDelayTicks; + currentBatch.clear(); + } + } + } } diff --git a/src/main/java/com/loohp/limbo/commands/DefaultCommands.java b/src/main/java/com/loohp/limbo/commands/DefaultCommands.java index ce42507..03778ef 100644 --- a/src/main/java/com/loohp/limbo/commands/DefaultCommands.java +++ b/src/main/java/com/loohp/limbo/commands/DefaultCommands.java @@ -180,6 +180,77 @@ public class DefaultCommands implements CommandExecutor, TabCompletor { } return; } + + if (args[0].equalsIgnoreCase("transfer")) { + if (sender.hasPermission("limboserver.transfer")) { + if (args.length == 4) { + Player player = Limbo.getInstance().getPlayer(args[1]); + if (player != null) { + String host = args[2]; + int port; + try { + port = Integer.parseInt(args[3]); + } catch (NumberFormatException e) { + sender.sendMessage(ChatColor.RED + "Invalid port number!"); + return; + } + player.transfer(host, port); + sender.sendMessage(ChatColor.GOLD + "Transferred " + player.getName() + " to " + host + ":" + port); + } else { + sender.sendMessage(ChatColor.RED + "Player is not online!"); + } + } else { + sender.sendMessage(ChatColor.RED + "Invalid usage! Use: /transfer "); + } + } else { + sender.sendMessage(ChatColor.RED + "You do not have permission to use that command!"); + } + return; + } + + if (args[0].equalsIgnoreCase("transferall")) { + if (sender.hasPermission("limboserver.transfer")) { + if (args.length >= 3 && args.length <= 5) { + String host = args[1]; + int port; + int batchDelay; + int batchSize; + try { + port = Integer.parseInt(args[2]); + } catch (NumberFormatException e) { + sender.sendMessage(ChatColor.RED + "Invalid port!"); + return; + } + if (args.length == 4) { + try { + batchDelay = Integer.parseInt(args[3]); + } catch (NumberFormatException e) { + sender.sendMessage(ChatColor.RED + "Invalid batch delay ticks!"); + return; + } + batchSize = 1; + } else if (args.length == 5) { + try { + batchDelay = Integer.parseInt(args[3]); + batchSize = Integer.parseInt(args[4]); + } catch (NumberFormatException e) { + sender.sendMessage(ChatColor.RED + "Invalid batch delay ticks or size!"); + return; + } + } else { + batchDelay = 1; + batchSize = 10; + } + Limbo.getInstance().transferAll(host, port, batchDelay, batchSize); + sender.sendMessage(ChatColor.GOLD + "Transferred all players to " + host + ":" + port); + } else { + sender.sendMessage(ChatColor.RED + "Invalid usage! Use: /transferall [ ]"); + } + } else { + sender.sendMessage(ChatColor.RED + "You do not have permission to use that command!"); + } + return; + } } @Override @@ -202,6 +273,10 @@ public class DefaultCommands implements CommandExecutor, TabCompletor { if (sender.hasPermission("limboserver.gamemode")) { tab.add("gamemode"); } + if (sender.hasPermission("limboserver.transfer")) { + tab.add("transfer"); + tab.add("transferall"); + } break; case 1: if (sender.hasPermission("limboserver.spawn")) { @@ -229,6 +304,14 @@ public class DefaultCommands implements CommandExecutor, TabCompletor { tab.add("gamemode"); } } + if (sender.hasPermission("limboserver.transfer")) { + if ("transfer".startsWith(args[0].toLowerCase())) { + tab.add("transfer"); + } + if ("transferall".startsWith(args[0].toLowerCase())) { + tab.add("transferall"); + } + } break; case 2: if (sender.hasPermission("limboserver.kick")) { @@ -249,6 +332,15 @@ public class DefaultCommands implements CommandExecutor, TabCompletor { } } } + if (sender.hasPermission("limboserver.transfer")) { + if (args[0].equalsIgnoreCase("transfer")) { + for (Player player : Limbo.getInstance().getPlayers()) { + if (player.getName().toLowerCase().startsWith(args[1].toLowerCase())) { + tab.add(player.getName()); + } + } + } + } break; case 3: if (sender.hasPermission("limboserver.gamemode")) { diff --git a/src/main/java/com/loohp/limbo/network/protocol/packets/ClientboundTransferPacket.java b/src/main/java/com/loohp/limbo/network/protocol/packets/ClientboundTransferPacket.java new file mode 100644 index 0000000..95ed6e6 --- /dev/null +++ b/src/main/java/com/loohp/limbo/network/protocol/packets/ClientboundTransferPacket.java @@ -0,0 +1,59 @@ +/* + * This file is part of Limbo. + * + * Copyright (C) 2022. LoohpJames + * 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.registry.PacketRegistry; +import com.loohp.limbo.utils.DataTypeIO; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +public class ClientboundTransferPacket extends PacketOut { + + private final String host; + private final int port; + + public ClientboundTransferPacket(String host, int port) { + this.host = host; + this.port = port; + } + + public String getHost() { + return host; + } + + public int getPort() { + return port; + } + + @Override + public byte[] serializePacket() throws IOException { + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + + DataOutputStream output = new DataOutputStream(buffer); + output.writeByte(PacketRegistry.getPacketId(getClass())); + DataTypeIO.writeString(output, host, StandardCharsets.UTF_8); + DataTypeIO.writeVarInt(output, port); + + return buffer.toByteArray(); + } +} diff --git a/src/main/java/com/loohp/limbo/player/Player.java b/src/main/java/com/loohp/limbo/player/Player.java index a3885f4..fe3db32 100644 --- a/src/main/java/com/loohp/limbo/player/Player.java +++ b/src/main/java/com/loohp/limbo/player/Player.java @@ -45,6 +45,7 @@ import com.loohp.limbo.network.protocol.packets.ClientboundSetSubtitleTextPacket import com.loohp.limbo.network.protocol.packets.ClientboundSetTitleTextPacket; import com.loohp.limbo.network.protocol.packets.ClientboundSetTitlesAnimationPacket; import com.loohp.limbo.network.protocol.packets.ClientboundSystemChatPacket; +import com.loohp.limbo.network.protocol.packets.ClientboundTransferPacket; import com.loohp.limbo.network.protocol.packets.PacketOut; import com.loohp.limbo.network.protocol.packets.PacketPlayOutCloseWindow; import com.loohp.limbo.network.protocol.packets.PacketPlayOutGameStateChange; @@ -650,4 +651,13 @@ public class Player extends LivingEntity implements CommandSender, InventoryHold public InventoryHolder getHolder() { return this; } + + public void transfer(String host, int port) { + try { + ClientboundTransferPacket transferPacket = new ClientboundTransferPacket(host, port); + clientConnection.sendPacket(transferPacket); + } catch (IOException e) { + e.printStackTrace(); + } + } } diff --git a/src/main/java/com/loohp/limbo/registry/PacketRegistry.java b/src/main/java/com/loohp/limbo/registry/PacketRegistry.java index 89a0c02..ddcd346 100644 --- a/src/main/java/com/loohp/limbo/registry/PacketRegistry.java +++ b/src/main/java/com/loohp/limbo/registry/PacketRegistry.java @@ -35,6 +35,7 @@ import com.loohp.limbo.network.protocol.packets.ClientboundSetSubtitleTextPacket import com.loohp.limbo.network.protocol.packets.ClientboundSetTitleTextPacket; import com.loohp.limbo.network.protocol.packets.ClientboundSetTitlesAnimationPacket; import com.loohp.limbo.network.protocol.packets.ClientboundSystemChatPacket; +import com.loohp.limbo.network.protocol.packets.ClientboundTransferPacket; import com.loohp.limbo.network.protocol.packets.Packet; import com.loohp.limbo.network.protocol.packets.PacketHandshakingIn; import com.loohp.limbo.network.protocol.packets.PacketLoginInLoginStart; @@ -220,6 +221,7 @@ public class PacketRegistry { registerClass(PacketPlayOutWindowData.class, "minecraft:container_set_data", NetworkPhase.PLAY, PacketBound.CLIENTBOUND); registerClass(ClientboundChunkBatchFinishedPacket.class, "minecraft:chunk_batch_finished", NetworkPhase.PLAY, PacketBound.CLIENTBOUND); registerClass(ClientboundChunkBatchStartPacket.class, "minecraft:chunk_batch_start", NetworkPhase.PLAY, PacketBound.CLIENTBOUND); + registerClass(ClientboundTransferPacket.class, "minecraft:transfer", NetworkPhase.PLAY, PacketBound.CLIENTBOUND); } private static void registerClass(Class packetClass, String key, NetworkPhase networkPhase, PacketBound packetBound) { diff --git a/src/main/resources/permission.yml b/src/main/resources/permission.yml index b6b2334..1dc025e 100644 --- a/src/main/resources/permission.yml +++ b/src/main/resources/permission.yml @@ -4,6 +4,7 @@ groups: - limboserver.kick - limboserver.say - limboserver.gamemode + - limboserver.transfer default: - limboserver.spawn - limboserver.chat