Revamp of the packet sending code, added possibility to have listeners for outgoing packets

This commit is contained in:
themode 2020-11-13 07:43:35 +01:00
parent 3c2c7acb0b
commit c60f625c55
28 changed files with 204 additions and 408 deletions

View File

@ -31,7 +31,6 @@ import net.minestom.server.item.Material;
import net.minestom.server.listener.manager.PacketListenerManager;
import net.minestom.server.network.ConnectionManager;
import net.minestom.server.network.PacketProcessor;
import net.minestom.server.network.PacketWriterUtils;
import net.minestom.server.network.netty.NettyServer;
import net.minestom.server.network.packet.server.play.PluginMessagePacket;
import net.minestom.server.network.packet.server.play.ServerDifficultyPacket;
@ -49,6 +48,7 @@ import net.minestom.server.storage.StorageLocation;
import net.minestom.server.storage.StorageManager;
import net.minestom.server.timer.SchedulerManager;
import net.minestom.server.utils.MathUtils;
import net.minestom.server.utils.PacketUtils;
import net.minestom.server.utils.thread.MinestomThread;
import net.minestom.server.utils.validate.Check;
import net.minestom.server.world.Difficulty;
@ -242,8 +242,7 @@ public final class MinecraftServer {
Check.notNull(brandName, "The brand name cannot be null");
MinecraftServer.brandName = brandName;
PluginMessagePacket brandMessage = PluginMessagePacket.getBrandPacket();
PacketWriterUtils.writeAndSend(connectionManager.getOnlinePlayers(), brandMessage);
PacketUtils.sendGroupedPacket(connectionManager.getOnlinePlayers(), PluginMessagePacket.getBrandPacket());
}
/**
@ -301,12 +300,11 @@ public final class MinecraftServer {
Check.notNull(difficulty, "The server difficulty cannot be null.");
MinecraftServer.difficulty = difficulty;
// The difficulty packet
// Send the packet to all online players
ServerDifficultyPacket serverDifficultyPacket = new ServerDifficultyPacket();
serverDifficultyPacket.difficulty = difficulty;
serverDifficultyPacket.locked = true; // Can only be modified on single-player
// Send the packet to all online players
PacketWriterUtils.writeAndSend(connectionManager.getOnlinePlayers(), serverDifficultyPacket);
PacketUtils.sendGroupedPacket(connectionManager.getOnlinePlayers(), serverDifficultyPacket);
}
/**
@ -468,14 +466,16 @@ public final class MinecraftServer {
"The chunk view distance must be between 2 and 32");
MinecraftServer.chunkViewDistance = chunkViewDistance;
if (started) {
UpdateViewDistancePacket updateViewDistancePacket = new UpdateViewDistancePacket();
updateViewDistancePacket.viewDistance = chunkViewDistance;
final Collection<Player> players = connectionManager.getOnlinePlayers();
PacketWriterUtils.writeAndSend(players, updateViewDistancePacket);
UpdateViewDistancePacket updateViewDistancePacket = new UpdateViewDistancePacket();
updateViewDistancePacket.viewDistance = chunkViewDistance;
connectionManager.getOnlinePlayers().forEach(player -> {
// Send packet to all online players
PacketUtils.sendGroupedPacket(players, updateViewDistancePacket);
players.forEach(player -> {
final Chunk playerChunk = player.getChunk();
if (playerChunk != null) {
player.refreshVisibleChunks(playerChunk);

View File

@ -71,10 +71,10 @@ public final class UpdateManager {
final long tickTime = System.nanoTime() - currentTime;
// Tick end callbacks
doTickCallback(tickEndCallbacks, tickTime / 1000000);
doTickCallback(tickEndCallbacks, tickTime / 1000000L);
// Sleep until next tick
final long sleepTime = Math.max(1, (tickDistance - tickTime) / 1000000);
final long sleepTime = Math.max(1, (tickDistance - tickTime) / 1000000L);
try {
Thread.sleep(sleepTime);

View File

@ -1,11 +1,10 @@
package net.minestom.server;
import net.minestom.server.entity.Player;
import net.minestom.server.network.PacketWriterUtils;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.utils.PacketUtils;
import org.jetbrains.annotations.NotNull;
import java.util.HashSet;
import java.util.Set;
/**
@ -56,7 +55,7 @@ public interface Viewable {
* @param packet the packet to send to all viewers
*/
default void sendPacketToViewers(@NotNull ServerPacket packet) {
PacketWriterUtils.writeAndSend(getViewers(), packet);
PacketUtils.sendGroupedPacket(getViewers(), packet);
}
/**
@ -69,40 +68,22 @@ public interface Viewable {
*/
default void sendPacketsToViewers(@NotNull ServerPacket... packets) {
for (ServerPacket packet : packets) {
PacketWriterUtils.writeAndSend(getViewers(), packet);
PacketUtils.sendGroupedPacket(getViewers(), packet);
}
}
/**
* Sends a packet to all viewers and the viewable element if it is a player.
* <p>
* If 'this' isn't a player, then {@link #sendPacketToViewers(ServerPacket)} is called instead.
* If 'this' isn't a player, then {only @link #sendPacketToViewers(ServerPacket)} is called.
*
* @param packet the packet to send
*/
default void sendPacketToViewersAndSelf(@NotNull ServerPacket packet) {
if (this instanceof Player) {
if (getViewers().isEmpty()) {
PacketWriterUtils.writeAndSend((Player) this, packet);
} else {
UNSAFE_sendPacketToViewersAndSelf(packet);
}
} else {
sendPacketToViewers(packet);
((Player) this).getPlayerConnection().sendPacket(packet);
}
}
/**
* Sends a packet to all the viewers and 'this'.
* <p>
* Unsafe because of a cast to {@link Player} without any check beforehand.
*
* @param packet the packet to send
*/
private void UNSAFE_sendPacketToViewersAndSelf(@NotNull ServerPacket packet) {
Set<Player> recipients = new HashSet<>(getViewers());
recipients.add((Player) this);
PacketWriterUtils.writeAndSend(recipients, packet);
sendPacketToViewers(packet);
}
}

View File

@ -1,15 +1,16 @@
package net.minestom.server.advancements;
import io.netty.buffer.ByteBuf;
import net.minestom.server.chat.ColoredText;
import net.minestom.server.entity.Player;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import net.minestom.server.network.packet.server.play.AdvancementsPacket;
import net.minestom.server.network.player.PlayerConnection;
import net.minestom.server.utils.PacketUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Date;
import java.util.Set;
/**
* Represents an advancement located in an {@link AdvancementTab}.
@ -373,17 +374,11 @@ public class Advancement {
updateCriteria();
if (tab != null) {
// Update the tab cached packet
tab.updatePacket();
final Set<Player> viewers = tab.getViewers();
AdvancementsPacket createPacket = tab.createPacket();
final ByteBuf createBuffer = tab.createBuffer;
final ByteBuf removeBuffer = tab.removeBuffer;
tab.getViewers().forEach(player -> {
final PlayerConnection playerConnection = player.getPlayerConnection();
// Receive order is important
playerConnection.sendPacket(removeBuffer, true);
playerConnection.sendPacket(createBuffer, true);
});
PacketUtils.sendGroupedPacket(viewers, tab.removePacket);
PacketUtils.sendGroupedPacket(viewers, createPacket);
}
}

View File

@ -1,11 +1,9 @@
package net.minestom.server.advancements;
import io.netty.buffer.ByteBuf;
import net.minestom.server.Viewable;
import net.minestom.server.entity.Player;
import net.minestom.server.network.packet.server.play.AdvancementsPacket;
import net.minestom.server.network.player.PlayerConnection;
import net.minestom.server.utils.PacketUtils;
import net.minestom.server.utils.advancement.AdvancementUtils;
import net.minestom.server.utils.validate.Check;
import org.jetbrains.annotations.NotNull;
@ -33,19 +31,16 @@ public class AdvancementTab implements Viewable {
// Advancement -> its parent
private final Map<Advancement, Advancement> advancementMap = new HashMap<>();
// Packet cache, updated every time the tab changes
protected ByteBuf createBuffer;
// the packet used to clear the tab (used to remove it and to update an advancement)
// will never change (since the root identifier is always the same)
protected final ByteBuf removeBuffer;
protected final AdvancementsPacket removePacket;
protected AdvancementTab(@NotNull String rootIdentifier, @NotNull AdvancementRoot root) {
this.root = root;
cacheAdvancement(rootIdentifier, root, null);
final AdvancementsPacket removePacket = AdvancementUtils.getRemovePacket(new String[]{rootIdentifier});
this.removeBuffer = PacketUtils.writePacket(removePacket);
this.removePacket = AdvancementUtils.getRemovePacket(new String[]{rootIdentifier});
}
/**
@ -88,13 +83,6 @@ public class AdvancementTab implements Viewable {
}
/**
* Updates the packet buffer.
*/
protected void updatePacket() {
this.createBuffer = PacketUtils.writePacket(createPacket());
}
/**
* Builds the packet which build the whole advancement tab.
*
@ -135,8 +123,6 @@ public class AdvancementTab implements Viewable {
advancement.setParent(parent);
advancement.updateCriteria();
this.advancementMap.put(advancement, parent);
updatePacket();
}
@Override
@ -149,7 +135,7 @@ public class AdvancementTab implements Viewable {
final PlayerConnection playerConnection = player.getPlayerConnection();
// Send the tab to the player
playerConnection.sendPacket(createBuffer, true);
playerConnection.sendPacket(createPacket());
addPlayer(player);
@ -166,7 +152,7 @@ public class AdvancementTab implements Viewable {
// Remove the tab
if (!player.isRemoved()) {
playerConnection.sendPacket(removeBuffer, true);
playerConnection.sendPacket(removePacket);
}
removePlayer(player);

View File

@ -291,9 +291,6 @@ public class Player extends LivingEntity implements CommandSender {
@Override
public void update(long time) {
// Flush all pending packets
playerConnection.flush();
playerConnection.updateStats();
// Process received packets
@ -1687,7 +1684,7 @@ public class Player extends LivingEntity implements CommandSender {
public void setTeam(Team team) {
super.setTeam(team);
if (team != null)
getPlayerConnection().sendPacket(team.getTeamsCreationPacket());
getPlayerConnection().sendPacket(team.createTeamsCreationPacket());
}
/**
@ -2338,7 +2335,7 @@ public class Player extends LivingEntity implements CommandSender {
// Team
if (this.getTeam() != null)
connection.sendPacket(this.getTeam().getTeamsCreationPacket());
connection.sendPacket(this.getTeam().createTeamsCreationPacket());
EntityHeadLookPacket entityHeadLookPacket = new EntityHeadLookPacket();
entityHeadLookPacket.entityId = getEntityId();

View File

@ -13,7 +13,6 @@ import net.minestom.server.instance.batch.ChunkBatch;
import net.minestom.server.instance.block.Block;
import net.minestom.server.instance.block.BlockManager;
import net.minestom.server.instance.block.CustomBlock;
import net.minestom.server.network.PacketWriterUtils;
import net.minestom.server.network.packet.server.play.ChunkDataPacket;
import net.minestom.server.network.packet.server.play.UpdateLightPacket;
import net.minestom.server.network.player.PlayerConnection;
@ -464,7 +463,8 @@ public abstract class Chunk implements Viewable, DataContainer {
}
updateLightPacket.skyLight = temp;
updateLightPacket.blockLight = temp2;
PacketWriterUtils.writeAndSend(player, updateLightPacket);
playerConnection.sendPacket(updateLightPacket);
}
}
@ -496,6 +496,7 @@ public abstract class Chunk implements Viewable, DataContainer {
*
* @param section the section to update
* @param player the player to send the packet to
* @throws IllegalArgumentException if {@code section} is not a valid section
*/
public void sendChunkSectionUpdate(int section, @NotNull Player player) {
if (!PlayerUtils.isNettyClient(player))
@ -503,7 +504,7 @@ public abstract class Chunk implements Viewable, DataContainer {
Check.argCondition(!MathUtils.isBetween(section, 0, CHUNK_SECTION_COUNT),
"The chunk section " + section + " does not exist");
PacketWriterUtils.writeAndSend(player, getChunkSectionUpdatePacket(section));
player.getPlayerConnection().sendPacket(createChunkSectionUpdatePacket(section));
}
/**
@ -513,7 +514,7 @@ public abstract class Chunk implements Viewable, DataContainer {
* @return the {@link ChunkDataPacket} to update a single chunk section
*/
@NotNull
protected ChunkDataPacket getChunkSectionUpdatePacket(int section) {
protected ChunkDataPacket createChunkSectionUpdatePacket(int section) {
ChunkDataPacket chunkDataPacket = getFreshPartialDataPacket();
chunkDataPacket.fullChunk = false;
int[] sections = new int[CHUNK_SECTION_COUNT];

View File

@ -1,9 +1,10 @@
package net.minestom.server.instance;
import net.minestom.server.instance.block.Block;
import net.minestom.server.network.PacketWriterUtils;
import net.minestom.server.network.packet.server.play.ExplosionPacket;
import net.minestom.server.utils.BlockPosition;
import net.minestom.server.utils.PacketUtils;
import org.jetbrains.annotations.NotNull;
import java.util.List;
@ -54,7 +55,7 @@ public abstract class Explosion {
*
* @param instance instance to perform this explosion in
*/
public void apply(Instance instance) {
public void apply(@NotNull Instance instance) {
List<BlockPosition> blocks = prepare(instance);
ExplosionPacket packet = new ExplosionPacket();
packet.x = getCenterX();
@ -80,7 +81,7 @@ public abstract class Explosion {
postExplosion(instance, blocks, packet);
// TODO send only to close players
PacketWriterUtils.writeAndSend(instance.getPlayers(), packet);
PacketUtils.sendGroupedPacket(instance.getPlayers(), packet);
postSend(instance, blocks);
}

View File

@ -16,12 +16,12 @@ import net.minestom.server.instance.batch.ChunkBatch;
import net.minestom.server.instance.block.Block;
import net.minestom.server.instance.block.BlockManager;
import net.minestom.server.instance.block.CustomBlock;
import net.minestom.server.network.PacketWriterUtils;
import net.minestom.server.network.packet.server.play.BlockActionPacket;
import net.minestom.server.network.packet.server.play.TimeUpdatePacket;
import net.minestom.server.storage.StorageLocation;
import net.minestom.server.thread.ThreadProvider;
import net.minestom.server.utils.BlockPosition;
import net.minestom.server.utils.PacketUtils;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.chunk.ChunkCallback;
import net.minestom.server.utils.chunk.ChunkUtils;
@ -369,7 +369,7 @@ public abstract class Instance implements BlockModifier, EventHandler, DataConta
*/
public void setTime(long time) {
this.time = time;
PacketWriterUtils.writeAndSend(getPlayers(), getTimePacket());
PacketUtils.sendGroupedPacket(getPlayers(), createTimePacket());
}
/**
@ -417,12 +417,12 @@ public abstract class Instance implements BlockModifier, EventHandler, DataConta
}
/**
* Gets a {@link TimeUpdatePacket} with the current age and time of this instance
* Creates a {@link TimeUpdatePacket} with the current age and time of this instance
*
* @return the {@link TimeUpdatePacket} with this instance data
*/
@NotNull
private TimeUpdatePacket getTimePacket() {
private TimeUpdatePacket createTimePacket() {
TimeUpdatePacket timeUpdatePacket = new TimeUpdatePacket();
timeUpdatePacket.worldAge = worldAge;
timeUpdatePacket.timeOfDay = time;
@ -996,7 +996,7 @@ public abstract class Instance implements BlockModifier, EventHandler, DataConta
// time needs to be send to players
if (timeUpdate != null && !CooldownUtils.hasCooldown(time, lastTimeUpdate, timeUpdate)) {
PacketWriterUtils.writeAndSend(getPlayers(), getTimePacket());
PacketUtils.sendGroupedPacket(getPlayers(), createTimePacket());
this.lastTimeUpdate = time;
}

View File

@ -2,8 +2,8 @@ package net.minestom.server.instance;
import net.minestom.server.entity.Entity;
import net.minestom.server.entity.Player;
import net.minestom.server.network.PacketWriterUtils;
import net.minestom.server.network.packet.server.play.WorldBorderPacket;
import net.minestom.server.utils.PacketUtils;
import net.minestom.server.utils.Position;
import org.jetbrains.annotations.NotNull;
@ -100,6 +100,7 @@ public class WorldBorder {
*/
public void setWarningTime(int warningTime) {
this.warningTime = warningTime;
WorldBorderPacket worldBorderPacket = new WorldBorderPacket();
worldBorderPacket.action = WorldBorderPacket.Action.SET_WARNING_TIME;
worldBorderPacket.wbAction = new WorldBorderPacket.WBSetWarningTime(warningTime);
@ -115,6 +116,7 @@ public class WorldBorder {
*/
public void setWarningBlocks(int warningBlocks) {
this.warningBlocks = warningBlocks;
WorldBorderPacket worldBorderPacket = new WorldBorderPacket();
worldBorderPacket.action = WorldBorderPacket.Action.SET_WARNING_BLOCKS;
worldBorderPacket.wbAction = new WorldBorderPacket.WBSetWarningBlocks(warningBlocks);
@ -137,6 +139,7 @@ public class WorldBorder {
this.speed = speed;
this.lerpStartTime = System.currentTimeMillis();
WorldBorderPacket worldBorderPacket = new WorldBorderPacket();
worldBorderPacket.action = WorldBorderPacket.Action.LERP_SIZE;
worldBorderPacket.wbAction = new WorldBorderPacket.WBLerpSize(oldDiameter, newDiameter, speed);
@ -270,10 +273,10 @@ public class WorldBorder {
/**
* Sends a {@link WorldBorderPacket} to all the instance players.
*
* @param worldBorderPacket the packet to send
* @param packet the packet to send
*/
private void sendPacket(@NotNull WorldBorderPacket worldBorderPacket) {
PacketWriterUtils.writeAndSend(instance.getPlayers(), worldBorderPacket);
private void sendPacket(@NotNull WorldBorderPacket packet) {
PacketUtils.sendGroupedPacket(instance.getPlayers(), packet);
}
public enum CollisionAxis {

View File

@ -13,7 +13,6 @@ import net.minestom.server.inventory.click.InventoryClickResult;
import net.minestom.server.inventory.condition.InventoryCondition;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.StackingRule;
import net.minestom.server.network.PacketWriterUtils;
import net.minestom.server.network.packet.server.play.EntityEquipmentPacket;
import net.minestom.server.network.packet.server.play.SetSlotPacket;
import net.minestom.server.network.packet.server.play.WindowItemsPacket;
@ -214,7 +213,7 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler
* the inventory items
*/
public void update() {
PacketWriterUtils.writeAndSend(player, createWindowItemsPacket());
player.getPlayerConnection().sendPacket(createWindowItemsPacket());
}
/**

View File

@ -9,9 +9,9 @@ import net.minestom.server.command.CommandManager;
import net.minestom.server.entity.Player;
import net.minestom.server.event.player.PlayerChatEvent;
import net.minestom.server.network.ConnectionManager;
import net.minestom.server.network.PacketWriterUtils;
import net.minestom.server.network.packet.client.play.ClientChatMessagePacket;
import net.minestom.server.network.packet.server.play.ChatMessagePacket;
import net.minestom.server.utils.PacketUtils;
import java.util.Collection;
import java.util.function.Function;
@ -62,7 +62,7 @@ public class ChatMessageListener {
ChatMessagePacket chatMessagePacket =
new ChatMessagePacket(jsonMessage, ChatMessagePacket.Position.CHAT, player.getUuid());
PacketWriterUtils.writeAndSend(recipients, chatMessagePacket);
PacketUtils.sendGroupedPacket(recipients, chatMessagePacket);
}
});

View File

@ -1,21 +1,24 @@
package net.minestom.server.listener.manager;
import net.minestom.server.entity.Player;
import net.minestom.server.network.packet.client.ClientPlayPacket;
import net.minestom.server.network.ConnectionManager;
import org.jetbrains.annotations.NotNull;
/**
* Interface used to add a listener for incoming packets with {@link net.minestom.server.network.ConnectionManager#onPacketReceive(PacketConsumer)}.
* Interface used to add a listener for incoming/outgoing packets with
* {@link ConnectionManager#onPacketReceive(PacketConsumer)} and {@link ConnectionManager#onPacketSend(PacketConsumer)}.
*
* @param <T> the packet type
*/
@FunctionalInterface
public interface PacketConsumer {
public interface PacketConsumer<T> {
/**
* Called when a packet is received from the client.
* Called when a packet is received/sent from/to a client.
*
* @param player the player who sent the packet
* @param packetController the packet controller, used to cancel or control which listener will be called
* @param packet the received packet
* @param player the player concerned by the packet
* @param packetController the packet controller, can be used to cancel the packet
* @param packet the packet
*/
void accept(@NotNull Player player, @NotNull PacketController packetController, @NotNull ClientPlayPacket packet);
void accept(@NotNull Player player, @NotNull PacketController packetController, @NotNull T packet);
}

View File

@ -1,19 +1,15 @@
package net.minestom.server.listener.manager;
import net.minestom.server.entity.Player;
import net.minestom.server.network.packet.client.ClientPlayPacket;
import org.jetbrains.annotations.Nullable;
/**
* Used to control the output of a packet in {@link PacketConsumer#accept(Player, PacketController, ClientPlayPacket)}.
* Used to control the output of a packet in {@link PacketConsumer#accept(Player, PacketController, Object)}.
*/
public class PacketController {
private boolean cancel;
private PacketListenerConsumer packetListenerConsumer;
protected PacketController(@Nullable PacketListenerConsumer packetListenerConsumer) {
this.packetListenerConsumer = packetListenerConsumer;
protected PacketController() {
}
/**
@ -33,25 +29,4 @@ public class PacketController {
public void setCancel(boolean cancel) {
this.cancel = cancel;
}
/**
* Gets the listener associated with the packet.
*
* @return the packet's listener, null if not present
*/
@Nullable
public PacketListenerConsumer getPacketListenerConsumer() {
return packetListenerConsumer;
}
/**
* Changes the packet listener, setting it to null cancel the listener.
* <p>
* WARNING: this will overwrite the default minestom listener, be sure to know what you are doing.
*
* @param packetListenerConsumer the new packet listener, can be null
*/
public void setPacketListenerConsumer(@Nullable PacketListenerConsumer packetListenerConsumer) {
this.packetListenerConsumer = packetListenerConsumer;
}
}

View File

@ -6,13 +6,17 @@ import net.minestom.server.listener.*;
import net.minestom.server.network.ConnectionManager;
import net.minestom.server.network.packet.client.ClientPlayPacket;
import net.minestom.server.network.packet.client.play.*;
import net.minestom.server.network.packet.server.ServerPacket;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public final class PacketListenerManager {
public final static Logger LOGGER = LoggerFactory.getLogger(PacketListenerManager.class);
private static final ConnectionManager CONNECTION_MANAGER = MinecraftServer.getConnectionManager();
private final Map<Class<? extends ClientPlayPacket>, PacketListenerConsumer> listeners = new ConcurrentHashMap<>();
@ -56,7 +60,7 @@ public final class PacketListenerManager {
* @param player the player who sent the packet
* @param <T> the packet type
*/
public <T extends ClientPlayPacket> void process(@NotNull T packet, @NotNull Player player) {
public <T extends ClientPlayPacket> void processClientPacket(@NotNull T packet, @NotNull Player player) {
final Class clazz = packet.getClass();
@ -64,26 +68,29 @@ public final class PacketListenerManager {
// Listener can be null if none has been set before, call PacketConsumer anyway
if (packetListenerConsumer == null) {
System.err.println("Packet " + clazz + " does not have any default listener! (The issue comes from Minestom)");
LOGGER.error("Packet " + clazz + " does not have any default listener! (The issue comes from Minestom)");
return;
}
final PacketController packetController = new PacketController(packetListenerConsumer);
for (PacketConsumer packetConsumer : CONNECTION_MANAGER.getReceivePacketConsumers()) {
final PacketController packetController = new PacketController();
for (PacketConsumer<ClientPlayPacket> packetConsumer : CONNECTION_MANAGER.getReceivePacketConsumers()) {
packetConsumer.accept(player, packetController, packet);
}
if (packetController.isCancel())
return;
// Get the new listener (or the same) from the packet controller
packetListenerConsumer = packetController.getPacketListenerConsumer();
// Finally execute the listener
packetListenerConsumer.accept(packet, player);
}
// Call the listener if not null
// (can be null because no listener is set, or because it has been changed by the controller)
if (packetListenerConsumer != null) {
packetListenerConsumer.accept(packet, player);
public <T extends ServerPacket> boolean processServerPacket(@NotNull T packet, @NotNull Player player) {
final PacketController packetController = new PacketController();
for (PacketConsumer<ServerPacket> packetConsumer : CONNECTION_MANAGER.getSendPacketConsumers()) {
packetConsumer.accept(player, packetController, packet);
}
return !packetController.isCancel();
}
/**

View File

@ -4,10 +4,13 @@ import net.minestom.server.chat.JsonMessage;
import net.minestom.server.entity.Player;
import net.minestom.server.entity.fakeplayer.FakePlayer;
import net.minestom.server.listener.manager.PacketConsumer;
import net.minestom.server.network.packet.client.ClientPlayPacket;
import net.minestom.server.network.packet.client.login.LoginStartPacket;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.login.LoginSuccessPacket;
import net.minestom.server.network.packet.server.play.ChatMessagePacket;
import net.minestom.server.network.player.PlayerConnection;
import net.minestom.server.utils.PacketUtils;
import net.minestom.server.utils.callback.validator.PlayerValidator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -26,7 +29,9 @@ public final class ConnectionManager {
private final Map<PlayerConnection, Player> connectionPlayerMap = Collections.synchronizedMap(new HashMap<>());
// All the consumers to call once a packet is received
private final List<PacketConsumer> receivePacketConsumers = new CopyOnWriteArrayList<>();
private final List<PacketConsumer<ClientPlayPacket>> receivePacketConsumers = new CopyOnWriteArrayList<>();
// All the consumers to call once a packet is sent
private final List<PacketConsumer<ServerPacket>> sendPacketConsumers = new CopyOnWriteArrayList<>();
// The uuid provider once a player login
private UuidProvider uuidProvider;
// The player provider to have your own Player implementation
@ -115,7 +120,8 @@ public final class ConnectionManager {
private void broadcastJson(@NotNull String json, @NotNull Collection<Player> recipients) {
ChatMessagePacket chatMessagePacket =
new ChatMessagePacket(json, ChatMessagePacket.Position.SYSTEM_MESSAGE);
PacketWriterUtils.writeAndSend(recipients, chatMessagePacket);
PacketUtils.sendGroupedPacket(recipients, chatMessagePacket);
}
private Collection<Player> getRecipients(@Nullable PlayerValidator condition) {
@ -142,7 +148,7 @@ public final class ConnectionManager {
* @return an unmodifiable list of packet's consumers
*/
@NotNull
public List<PacketConsumer> getReceivePacketConsumers() {
public List<PacketConsumer<ClientPlayPacket>> getReceivePacketConsumers() {
return Collections.unmodifiableList(receivePacketConsumers);
}
@ -151,10 +157,29 @@ public final class ConnectionManager {
*
* @param packetConsumer the packet consumer
*/
public void onPacketReceive(@NotNull PacketConsumer packetConsumer) {
public void onPacketReceive(@NotNull PacketConsumer<ClientPlayPacket> packetConsumer) {
this.receivePacketConsumers.add(packetConsumer);
}
/**
* Gets all the listeners which are called for each packet sent.
*
* @return an unmodifiable list of packet's consumers
*/
@NotNull
public List<PacketConsumer<ServerPacket>> getSendPacketConsumers() {
return Collections.unmodifiableList(sendPacketConsumers);
}
/**
* Adds a consumer to call once a packet is sent.
*
* @param packetConsumer the packet consumer
*/
public void onPacketSend(@NotNull PacketConsumer<ServerPacket> packetConsumer) {
this.sendPacketConsumers.add(packetConsumer);
}
/**
* Changes how {@link UUID} are attributed to players.
* <p>

View File

@ -1,101 +0,0 @@
package net.minestom.server.network;
import io.netty.buffer.ByteBuf;
import net.minestom.server.MinecraftServer;
import net.minestom.server.entity.Player;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.player.PlayerConnection;
import net.minestom.server.utils.PacketUtils;
import net.minestom.server.utils.player.PlayerUtils;
import net.minestom.server.utils.thread.MinestomThread;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.concurrent.ExecutorService;
import java.util.function.Consumer;
/**
* Utils class used to write {@link ServerPacket} in the appropriate thread pool.
* <p>
* WARNING: those methods do not guarantee a receive order.
*/
public final class PacketWriterUtils {
private static final ExecutorService PACKET_WRITER_POOL = new MinestomThread(MinecraftServer.THREAD_COUNT_PACKET_WRITER, MinecraftServer.THREAD_NAME_PACKET_WRITER);
/**
* Writes the {@link ServerPacket} in the writer thread pool.
* <p>
* WARNING: should not be used if the packet receive order is important
*
* @param serverPacket the packet to write
* @param consumer the consumer called once the packet has been written
*/
public static void writeCallbackPacket(@NotNull ServerPacket serverPacket, @NotNull Consumer<ByteBuf> consumer) {
PACKET_WRITER_POOL.execute(() -> {
final ByteBuf buffer = PacketUtils.writePacket(serverPacket);
consumer.accept(buffer);
});
}
/**
* Writes a {@link ServerPacket} in the writer thread pool and send it to every players in {@code players}.
* <p>
* WARNING: should not be used if the packet receive order is important
*
* @param players the players list to send the packet to
* @param serverPacket the packet to write and send
*/
public static void writeAndSend(@NotNull Collection<Player> players, @NotNull ServerPacket serverPacket) {
PACKET_WRITER_POOL.execute(() -> {
if (players.isEmpty())
return;
final ByteBuf buffer = PacketUtils.writePacket(serverPacket);
for (Player player : players) {
final PlayerConnection playerConnection = player.getPlayerConnection();
if (PlayerUtils.isNettyClient(player)) {
playerConnection.writePacket(buffer, true);
} else {
playerConnection.sendPacket(serverPacket);
}
}
buffer.release();
});
}
/**
* Writes a {@link ServerPacket} and send it to a {@link PlayerConnection}.
* <p>
* WARNING: should not be used if the packet receive order is important
*
* @param playerConnection the connection to send the packet to
* @param serverPacket the packet to write and send
*/
public static void writeAndSend(@NotNull PlayerConnection playerConnection, @NotNull ServerPacket serverPacket) {
PACKET_WRITER_POOL.execute(() -> {
if (PlayerUtils.isNettyClient(playerConnection)) {
final ByteBuf buffer = PacketUtils.writePacket(serverPacket);
buffer.retain();
playerConnection.writePacket(buffer, false);
buffer.release();
} else {
playerConnection.sendPacket(serverPacket);
}
});
}
/**
* Writes a {@link ServerPacket} and send it to a {@link Player}.
* <p>
* WARNING: should not be used if the packet receive order is important
*
* @param player the player to send the packet to
* @param serverPacket the packet to write and send
*/
public static void writeAndSend(@NotNull Player player, @NotNull ServerPacket serverPacket) {
final PlayerConnection playerConnection = player.getPlayerConnection();
writeAndSend(playerConnection, serverPacket);
}
}

View File

@ -17,7 +17,7 @@ public abstract class ClientPlayPacket implements ClientPacket {
* @param player the player who sent the packet
*/
public void process(@NotNull Player player) {
PACKET_LISTENER_MANAGER.process(this, player);
PACKET_LISTENER_MANAGER.processClientPacket(this, player);
}
}

View File

@ -34,8 +34,9 @@ public class PluginMessagePacket implements ServerPacket {
PluginMessagePacket brandMessage = new PluginMessagePacket();
brandMessage.channel = "minecraft:brand";
BinaryWriter writer = new BinaryWriter();
writer.writeSizedString(MinecraftServer.getBrandName());
final String brandName = MinecraftServer.getBrandName();
BinaryWriter writer = new BinaryWriter(4 + brandName.length());
writer.writeSizedString(brandName);
brandMessage.data = writer.toByteArray();

View File

@ -1,5 +1,6 @@
package net.minestom.server.network.packet.server.play;
import net.minestom.server.chat.JsonMessage;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
import net.minestom.server.utils.binary.BinaryWriter;
@ -22,7 +23,7 @@ public class TeamsPacket implements ServerPacket {
/**
* The display name for the team
*/
public String teamDisplayName;
public JsonMessage teamDisplayName;
/**
* The friendly flags to
*/
@ -42,11 +43,11 @@ public class TeamsPacket implements ServerPacket {
/**
* The prefix of the team
*/
public String teamPrefix;
public JsonMessage teamPrefix;
/**
* The suffix of the team
*/
public String teamSuffix;
public JsonMessage teamSuffix;
/**
* An array with all entities in the team
*/
@ -65,13 +66,13 @@ public class TeamsPacket implements ServerPacket {
switch (action) {
case CREATE_TEAM:
case UPDATE_TEAM_INFO:
writer.writeSizedString(this.teamDisplayName);
writer.writeSizedString(this.teamDisplayName.toString());
writer.writeByte(this.friendlyFlags);
writer.writeSizedString(this.nameTagVisibility.getIdentifier());
writer.writeSizedString(this.collisionRule.getIdentifier());
writer.writeVarInt(this.teamColor);
writer.writeSizedString(this.teamPrefix);
writer.writeSizedString(this.teamSuffix);
writer.writeSizedString(this.teamPrefix.toString());
writer.writeSizedString(this.teamSuffix.toString());
break;
case REMOVE_TEAM:

View File

@ -1,6 +1,5 @@
package net.minestom.server.network.player;
import io.netty.buffer.ByteBuf;
import net.minestom.server.MinecraftServer;
import net.minestom.server.entity.Player;
import net.minestom.server.entity.fakeplayer.FakePlayer;
@ -13,24 +12,11 @@ import java.net.SocketAddress;
public class FakePlayerConnection extends PlayerConnection {
@Override
public void sendPacket(@NotNull ByteBuf buffer, boolean copy) {
throw new UnsupportedOperationException("FakePlayer cannot read Bytebuf");
}
@Override
public void writePacket(@NotNull ByteBuf buffer, boolean copy) {
throw new UnsupportedOperationException("FakePlayer cannot write to Bytebuf");
}
@Override
public void sendPacket(@NotNull ServerPacket serverPacket) {
getFakePlayer().getController().consumePacket(serverPacket);
}
@Override
public void flush() {
// Does nothing
if (shouldSendPacket(serverPacket)) {
getFakePlayer().getController().consumePacket(serverPacket);
}
}
@NotNull

View File

@ -1,6 +1,5 @@
package net.minestom.server.network.player;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.socket.SocketChannel;
import lombok.Getter;
@ -81,38 +80,11 @@ public class NettyPlayerConnection extends PlayerConnection {
channel.pipeline().addAfter("framer", "compressor", new PacketCompressor(threshold));
}
@Override
public void sendPacket(@NotNull ByteBuf buffer, boolean copy) {
if (copy) {
buffer = buffer.copy();
buffer.retain();
channel.writeAndFlush(buffer);
buffer.release();
} else {
channel.writeAndFlush(buffer);
}
}
@Override
public void writePacket(@NotNull ByteBuf buffer, boolean copy) {
if (copy) {
buffer = buffer.copy();
buffer.retain();
channel.write(buffer);
buffer.release();
} else {
channel.write(buffer);
}
}
@Override
public void sendPacket(@NotNull ServerPacket serverPacket) {
channel.writeAndFlush(serverPacket);
}
@Override
public void flush() {
getChannel().flush();
if (shouldSendPacket(serverPacket)) {
channel.writeAndFlush(serverPacket);
}
}
@NotNull

View File

@ -1,16 +1,18 @@
package net.minestom.server.network.player;
import io.netty.buffer.ByteBuf;
import lombok.Getter;
import net.minestom.server.MinecraftServer;
import net.minestom.server.chat.ChatColor;
import net.minestom.server.chat.ColoredText;
import net.minestom.server.entity.Player;
import net.minestom.server.listener.manager.PacketListenerManager;
import net.minestom.server.network.ConnectionManager;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.login.LoginDisconnectPacket;
import net.minestom.server.network.packet.server.play.DisconnectPacket;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.net.SocketAddress;
import java.util.concurrent.atomic.AtomicInteger;
@ -21,6 +23,8 @@ import java.util.concurrent.atomic.AtomicInteger;
*/
public abstract class PlayerConnection {
protected static final PacketListenerManager PACKET_LISTENER_MANAGER = MinecraftServer.getPacketListenerManager();
private Player player;
private ConnectionState connectionState;
private boolean online;
@ -68,33 +72,19 @@ public abstract class PlayerConnection {
}
}
/**
* Sends a raw {@link ByteBuf} to the client.
*
* @param buffer The buffer to send.
* @param copy Should be true unless your only using the ByteBuf once.
*/
public abstract void sendPacket(@NotNull ByteBuf buffer, boolean copy);
/**
* Writes a raw {@link ByteBuf} to the client.
*
* @param buffer The buffer to send.
* @param copy Should be true unless your only using the ByteBuf once.
*/
public abstract void writePacket(@NotNull ByteBuf buffer, boolean copy);
/**
* Serializes the packet and send it to the client.
* <p>
* Also responsible for executing {@link ConnectionManager#getSendPacketConsumers()} consumers.
*
* @param serverPacket the packet to send
* @see #shouldSendPacket(ServerPacket)
*/
public abstract void sendPacket(@NotNull ServerPacket serverPacket);
/**
* Flush all waiting packets.
*/
public abstract void flush();
protected boolean shouldSendPacket(@NotNull ServerPacket serverPacket) {
return player == null || PACKET_LISTENER_MANAGER.processServerPacket(serverPacket, player);
}
/**
* Gets the remote address of the client.
@ -112,8 +102,9 @@ public abstract class PlayerConnection {
/**
* Gets the player linked to this connection.
*
* @return the player
* @return the player, can be null if not initialized yet
*/
@Nullable
public Player getPlayer() {
return player;
}

View File

@ -401,13 +401,13 @@ public class Sidebar implements Scoreboard {
TeamsPacket teamsPacket = new TeamsPacket();
teamsPacket.teamName = teamName;
teamsPacket.action = TeamsPacket.Action.CREATE_TEAM;
teamsPacket.teamDisplayName = teamDisplayName.toString();
teamsPacket.teamDisplayName = teamDisplayName;
teamsPacket.friendlyFlags = friendlyFlags;
teamsPacket.nameTagVisibility = nameTagVisibility;
teamsPacket.collisionRule = collisionRule;
teamsPacket.teamColor = teamColor;
teamsPacket.teamPrefix = prefix.toString();
teamsPacket.teamSuffix = suffix.toString();
teamsPacket.teamPrefix = prefix;
teamsPacket.teamSuffix = suffix;
teamsPacket.entities = new String[]{entityName};
return teamsPacket;
}
@ -434,13 +434,13 @@ public class Sidebar implements Scoreboard {
TeamsPacket teamsPacket = new TeamsPacket();
teamsPacket.teamName = teamName;
teamsPacket.action = TeamsPacket.Action.UPDATE_TEAM_INFO;
teamsPacket.teamDisplayName = teamDisplayName.toString();
teamsPacket.teamDisplayName = teamDisplayName;
teamsPacket.friendlyFlags = friendlyFlags;
teamsPacket.nameTagVisibility = nameTagVisibility;
teamsPacket.collisionRule = collisionRule;
teamsPacket.teamColor = teamColor;
teamsPacket.teamPrefix = prefix.toString();
teamsPacket.teamSuffix = suffix.toString();
teamsPacket.teamPrefix = prefix;
teamsPacket.teamSuffix = suffix;
return teamsPacket;
}

View File

@ -1,12 +1,11 @@
package net.minestom.server.scoreboard;
import io.netty.buffer.ByteBuf;
import net.minestom.server.MinecraftServer;
import net.minestom.server.chat.ChatColor;
import net.minestom.server.chat.ColoredText;
import net.minestom.server.entity.LivingEntity;
import net.minestom.server.entity.Player;
import net.minestom.server.network.PacketWriterUtils;
import net.minestom.server.network.ConnectionManager;
import net.minestom.server.network.packet.server.play.TeamsPacket;
import net.minestom.server.network.packet.server.play.TeamsPacket.CollisionRule;
import net.minestom.server.network.packet.server.play.TeamsPacket.NameTagVisibility;
@ -21,18 +20,12 @@ import java.util.concurrent.CopyOnWriteArraySet;
*/
public class Team {
private static final ConnectionManager CONNECTION_MANAGER = MinecraftServer.getConnectionManager();
/**
* A collection of all registered entities who are on the team
*/
private final Set<String> members;
/**
* Creation packet for the team to create
*/
private final TeamsPacket teamsCreationPacket;
/**
* A byte buf to destroy the team
*/
private final ByteBuf teamsDestroyPacket;
/**
* The registry name of the team
@ -94,22 +87,6 @@ public class Team {
this.entities = new String[0];
this.members = new CopyOnWriteArraySet<>();
// Initializes creation packet
this.teamsCreationPacket = new TeamsPacket();
this.teamsCreationPacket.teamName = teamName;
this.teamsCreationPacket.action = TeamsPacket.Action.CREATE_TEAM;
this.teamsCreationPacket.teamDisplayName = this.teamDisplayName.toString();
this.teamsCreationPacket.friendlyFlags = this.friendlyFlags;
this.teamsCreationPacket.nameTagVisibility = this.nameTagVisibility;
this.teamsCreationPacket.collisionRule = this.collisionRule;
this.teamsCreationPacket.teamColor = this.teamColor.getId();
this.teamsCreationPacket.teamPrefix = this.prefix.toString();
this.teamsCreationPacket.teamSuffix = this.suffix.toString();
this.teamsCreationPacket.entities = this.entities;
// Directly write packet since it will not change
this.teamsDestroyPacket = PacketUtils.writePacket(this.createTeamDestructionPacket());
}
/**
@ -124,7 +101,6 @@ public class Team {
System.arraycopy(this.entities, 0, entitiesCache, 0, this.entities.length);
entitiesCache[this.entities.length] = member;
this.entities = entitiesCache;
this.teamsCreationPacket.entities = this.entities;
// Adds a new member to the team
this.members.add(member);
@ -134,8 +110,9 @@ public class Team {
addPlayerPacket.teamName = this.teamName;
addPlayerPacket.action = TeamsPacket.Action.ADD_PLAYERS_TEAM;
addPlayerPacket.entities = new String[]{member};
// Sends to all online players the add player packet
PacketWriterUtils.writeAndSend(MinecraftServer.getConnectionManager().getOnlinePlayers(), addPlayerPacket);
PacketUtils.sendGroupedPacket(CONNECTION_MANAGER.getOnlinePlayers(), addPlayerPacket);
}
/**
@ -150,7 +127,7 @@ public class Team {
removePlayerPacket.action = TeamsPacket.Action.REMOVE_PLAYERS_TEAM;
removePlayerPacket.entities = new String[]{member};
// Sends to all online player teh remove player packet
PacketWriterUtils.writeAndSend(MinecraftServer.getConnectionManager().getOnlinePlayers(), removePlayerPacket);
PacketUtils.sendGroupedPacket(CONNECTION_MANAGER.getOnlinePlayers(), removePlayerPacket);
// Removes the player from the
this.members.remove(member);
@ -161,7 +138,6 @@ public class Team {
entitiesCache[count++] = teamMember;
}
this.entities = entitiesCache;
this.teamsCreationPacket.entities = this.entities;
}
/**
@ -173,7 +149,6 @@ public class Team {
*/
public void setTeamDisplayName(ColoredText teamDisplayName) {
this.teamDisplayName = teamDisplayName;
this.teamsCreationPacket.teamDisplayName = teamDisplayName.toString();
}
/**
@ -195,7 +170,6 @@ public class Team {
*/
public void setNameTagVisibility(NameTagVisibility visibility) {
this.nameTagVisibility = visibility;
this.teamsCreationPacket.nameTagVisibility = visibility;
}
/**
@ -217,7 +191,6 @@ public class Team {
*/
public void setCollisionRule(CollisionRule rule) {
this.collisionRule = rule;
this.teamsCreationPacket.collisionRule = rule;
}
/**
@ -239,7 +212,6 @@ public class Team {
*/
public void setTeamColor(ChatColor color) {
this.teamColor = color;
this.teamsCreationPacket.teamColor = color.getId();
}
/**
@ -261,7 +233,6 @@ public class Team {
*/
public void setPrefix(ColoredText prefix) {
this.prefix = prefix;
this.teamsCreationPacket.teamPrefix = prefix.toString();
}
/**
@ -283,7 +254,6 @@ public class Team {
*/
public void setSuffix(ColoredText suffix) {
this.suffix = suffix;
this.teamsCreationPacket.teamSuffix = suffix.toString();
}
/**
@ -305,7 +275,6 @@ public class Team {
*/
public void setFriendlyFlags(byte flag) {
this.friendlyFlags = flag;
this.teamsCreationPacket.friendlyFlags = flag;
}
/**
@ -328,16 +297,24 @@ public class Team {
}
/**
* Gets the creation packet to add a team.
* Creates the creation packet to add a team.
*
* @return the packet to add the team
*/
public TeamsPacket getTeamsCreationPacket() {
return teamsCreationPacket;
}
public TeamsPacket createTeamsCreationPacket() {
TeamsPacket teamsCreationPacket = new TeamsPacket();
teamsCreationPacket.teamName = teamName;
teamsCreationPacket.action = TeamsPacket.Action.CREATE_TEAM;
teamsCreationPacket.teamDisplayName = this.teamDisplayName;
teamsCreationPacket.friendlyFlags = this.friendlyFlags;
teamsCreationPacket.nameTagVisibility = this.nameTagVisibility;
teamsCreationPacket.collisionRule = this.collisionRule;
teamsCreationPacket.teamColor = this.teamColor.getId();
teamsCreationPacket.teamPrefix = this.prefix;
teamsCreationPacket.teamSuffix = this.suffix;
teamsCreationPacket.entities = this.entities;
public ByteBuf getTeamsDestroyPacket() {
return teamsDestroyPacket;
return teamsCreationPacket;
}
/**
@ -435,16 +412,14 @@ public class Team {
final TeamsPacket updatePacket = new TeamsPacket();
updatePacket.teamName = this.teamName;
updatePacket.action = TeamsPacket.Action.UPDATE_TEAM_INFO;
updatePacket.teamDisplayName = this.teamDisplayName.toString();
updatePacket.teamDisplayName = this.teamDisplayName;
updatePacket.friendlyFlags = this.friendlyFlags;
updatePacket.nameTagVisibility = this.nameTagVisibility;
updatePacket.collisionRule = this.collisionRule;
updatePacket.teamColor = this.teamColor.getId();
updatePacket.teamPrefix = this.prefix.toString();
updatePacket.teamSuffix = this.suffix.toString();
ByteBuf buffer = PacketUtils.writePacket(updatePacket);
for (Player onlinePlayer : MinecraftServer.getConnectionManager().getOnlinePlayers()) {
onlinePlayer.getPlayerConnection().sendPacket(buffer, true);
}
updatePacket.teamPrefix = this.prefix;
updatePacket.teamSuffix = this.suffix;
PacketUtils.sendGroupedPacket(MinecraftServer.getConnectionManager().getOnlinePlayers(), updatePacket);
}
}

View File

@ -1,14 +1,14 @@
package net.minestom.server.scoreboard;
import io.netty.buffer.ByteBuf;
import net.minestom.server.MinecraftServer;
import net.minestom.server.chat.ChatColor;
import net.minestom.server.chat.ColoredText;
import net.minestom.server.entity.LivingEntity;
import net.minestom.server.entity.Player;
import net.minestom.server.network.PacketWriterUtils;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.ConnectionManager;
import net.minestom.server.utils.PacketUtils;
import net.minestom.server.utils.UniqueIdUtils;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
@ -20,6 +20,8 @@ import java.util.concurrent.CopyOnWriteArraySet;
*/
public final class TeamManager {
private static final ConnectionManager CONNECTION_MANAGER = MinecraftServer.getConnectionManager();
/**
* Represents all registered teams
*/
@ -37,9 +39,10 @@ public final class TeamManager {
*
* @param team The team to be registered
*/
protected void registerNewTeam(Team team) {
protected void registerNewTeam(@NotNull Team team) {
this.teams.add(team);
this.broadcastPacket(team.getTeamsCreationPacket());
PacketUtils.sendGroupedPacket(MinecraftServer.getConnectionManager().getOnlinePlayers(), team.createTeamsCreationPacket());
}
/**
@ -48,7 +51,7 @@ public final class TeamManager {
* @param registryName The registry name of team
* @return {@code true} if the team was deleted, otherwise {@code false}
*/
public boolean deleteTeam(String registryName) {
public boolean deleteTeam(@NotNull String registryName) {
Team team = this.getTeam(registryName);
if (team == null) return false;
return this.deleteTeam(team);
@ -60,9 +63,9 @@ public final class TeamManager {
* @param team The team to be deleted
* @return {@code true} if the team was deleted, otherwise {@code false}
*/
public boolean deleteTeam(Team team) {
public boolean deleteTeam(@NotNull Team team) {
// Sends to all online players a team destroy packet
this.broadcastBuffer(team.getTeamsDestroyPacket());
PacketUtils.sendGroupedPacket(CONNECTION_MANAGER.getOnlinePlayers(), team.createTeamDestructionPacket());
return this.teams.remove(team);
}
@ -72,7 +75,7 @@ public final class TeamManager {
* @param name The registry name of the team
* @return the team builder
*/
public TeamBuilder createBuilder(String name) {
public TeamBuilder createBuilder(@NotNull String name) {
return new TeamBuilder(name, this);
}
@ -82,7 +85,7 @@ public final class TeamManager {
* @param name The registry name
* @return the created {@link Team}
*/
public Team createTeam(String name) {
public Team createTeam(@NotNull String name) {
return this.createBuilder(name).build();
}
@ -193,24 +196,4 @@ public final class TeamManager {
public Set<Team> getTeams() {
return this.teams;
}
/**
* Broadcasts to all online {@link Player}'s a {@link ServerPacket}
*
* @param packet The packet to broadcast
*/
private void broadcastPacket(ServerPacket packet) {
PacketWriterUtils.writeAndSend(MinecraftServer.getConnectionManager().getOnlinePlayers(), packet);
}
/**
* Broadcasts to all online {@link Player}'s a buffer
*
* @param buffer The buffer to broadcast
*/
private void broadcastBuffer(ByteBuf buffer) {
for (Player onlinePlayer : MinecraftServer.getConnectionManager().getOnlinePlayers()) {
onlinePlayer.getPlayerConnection().sendPacket(buffer, true);
}
}
}

View File

@ -2,10 +2,13 @@ package net.minestom.server.utils;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import net.minestom.server.entity.Player;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.utils.binary.BinaryWriter;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
/**
* Class used to write packets.
*/
@ -15,6 +18,12 @@ public final class PacketUtils {
}
public static void sendGroupedPacket(Collection<Player> players, ServerPacket packet) {
for (Player player : players) {
player.getPlayerConnection().sendPacket(packet);
}
}
/**
* Writes a {@link ServerPacket} into a {@link ByteBuf}.
*

View File

@ -83,6 +83,12 @@ public class PlayerInit {
packetController.setCancel(false);
});
connectionManager.onPacketSend((player, packetController, packet) -> {
// Listen to all sent packet
System.out.println("PACKET: " + packet.getClass().getSimpleName());
packetController.setCancel(false);
});
connectionManager.addPlayerInitialization(player -> {
player.addEventCallback(EntityAttackEvent.class, event -> {