package de.take_weiland.mods.commons.net;
import de.take_weiland.mods.commons.internal.SevenCommons;
import de.take_weiland.mods.commons.util.Players;
import de.take_weiland.mods.commons.util.SCReflector;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.ICrafting;
import net.minecraft.network.packet.Packet;
import net.minecraft.server.management.PlayerInstance;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraft.world.chunk.Chunk;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.List;
/**
* <p>Utility class for sending Packets around.</p>
*/
@ParametersAreNonnullByDefault
public final class Packets {
/**
* <p>Send the given packet to the Server.</p>
* @param packet the packet
*/
public static void sendToServer(Packet packet) {
SevenCommons.proxy.sendPacketToServer(packet);
}
/**
* <p>Send the given packet to the given player.</p>
* @param packet the packet
* @param player the player
*/
public static void sendTo(Packet packet, EntityPlayer player) {
checkNotClient(player).playerNetServerHandler.sendPacketToPlayer(packet);
}
/**
* <p>Send the given packet to the given players.</p>
* @param packet the packet
* @param players the players
*/
public static void sendTo(Packet packet, Iterable<? extends EntityPlayer> players) {
for (EntityPlayer player : players) {
checkNotClient(player).playerNetServerHandler.sendPacketToPlayer(packet);
}
}
/**
* <p>Send the given packet to the given players.</p>
* @param packet the packet
* @param players the players
*/
public static void sendTo(Packet packet, EntityPlayer... players) {
for (EntityPlayer player : players) {
checkNotClient(player).playerNetServerHandler.sendPacketToPlayer(packet);
}
}
/**
* <p>Send the given packet to all players currently on the server.</p>
* @param packet the packet
*/
public static void sendToAll(Packet packet) {
sendToList(packet, Players.getAll());
}
/**
* <p>Send the given packet to all players currently in the given world.</p>
* @param packet the packet
* @param world the world
*/
public static void sendToAllIn(Packet packet, World world) {
sendToList(packet, Players.allIn(checkNotClient(world)));
}
@SuppressWarnings("ForLoopReplaceableByForEach")
private static void sendToList(Packet packet, List<EntityPlayerMP> players) {
for (int i = 0, len = players.size(); i < len; i++) {
players.get(i).playerNetServerHandler.sendPacketToPlayer(packet);
}
}
/**
* <p>Send the given packet to all players tracking the given entity. If the entity is a player, does not include the player itself.</p>
* @param packet the packet
* @param entity the entity
*/
public static void sendToAllTracking(Packet packet, Entity entity) {
checkNotClient(entity.worldObj).getEntityTracker().sendPacketToAllPlayersTrackingEntity(entity, packet);
}
/**
* <p>Send the given packet to all players tracking the given entity, including the player itself if the entity is a player.</p>
* @param packet the packet
* @param entity the entity
*/
public static void sendToAllAssociated(Packet packet, Entity entity) {
checkNotClient(entity.worldObj).getEntityTracker().sendPacketToAllAssociatedPlayers(entity, packet);
}
/**
* <p>Send the given packet to all players tracking the given TileEntity, that is tracking the chunk it is in.</p>
* @param packet the packet
* @param te the TileEntity
*/
public static void sendToAllTracking(Packet packet, TileEntity te) {
sendToAllTrackingChunk(packet, te.worldObj, te.xCoord >> 4, te.zCoord >> 4);
}
/**
* <p>Send the given packet to all players tracking the Chunk at the given coordinates in the given world.</p>
* @param packet the packet
* @param world the world
* @param chunkX the chunk x coordinate
* @param chunkZ the chunk z coordinate
*/
public static void sendToAllTrackingChunk(Packet packet, World world, int chunkX, int chunkZ) {
PlayerInstance pi = checkNotClient(world).getPlayerManager().getOrCreateChunkWatcher(chunkX, chunkZ, false);
if (pi != null) {
pi.sendToAllPlayersWatchingChunk(packet);
}
}
/**
* <p>Send the given packet to all players tracking the given chunk.</p>
* @param packet the packet
* @param chunk the chunk
*/
public static void sendToAllTracking(Packet packet, Chunk chunk) {
sendToAllTrackingChunk(packet, chunk.worldObj, chunk.xPosition, chunk.zPosition);
}
/**
* <p>Send the given packet to the player using the given Container.</p>
* <p><b>Warning</b>: Due to Minecraft's internal design a new Container gets created for every player, even if they are watching the same inventory.
* This method does <i>not</i> check for players viewing the inventory. As in: this method sends the packet to only one player.</p>
*/
public static void sendToViewing(Packet packet, Container container) {
List<ICrafting> crafters = SCReflector.instance.getCrafters(container);
for (int i = 0, len = crafters.size(); i < len; ++i) {
ICrafting crafter = crafters.get(i);
if (crafter instanceof EntityPlayerMP) {
((EntityPlayerMP) crafter).playerNetServerHandler.sendPacketToPlayer(packet);
break;
}
}
}
/**
* <p>Send the given packet to all players within the given radius around the given coordinates.</p>
* @param packet the packet
* @param world the world
* @param x the x coordinate
* @param y the y coordinate
* @param z the z coordinate
* @param radius the radius
*/
public static void sendToAllNear(Packet packet, World world, double x, double y, double z, double radius) {
List<EntityPlayerMP> players = Players.allIn(checkNotClient(world));
radius *= radius;
//noinspection ForLoopReplaceableByForEach
for (int i = 0, len = players.size(); i < len; ++i) {
EntityPlayerMP player = players.get(i);
double dx = x - player.posX;
double dy = y - player.posY;
double dz = z - player.posZ;
if (dx * dx + dy * dy + dz * dz < radius) {
player.playerNetServerHandler.sendPacketToPlayer(packet);
}
}
}
/**
* <p>Send the given packet to all players within the given radius around the given entity.</p>
* @param packet the packet
* @param entity the entity
* @param radius the radius
*/
public static void sendToAllNear(Packet packet, Entity entity, double radius) {
sendToAllNear(packet, entity.worldObj, entity.posX, entity.posY, entity.posZ, radius);
}
/**
* <p>Send the given packet to all players within the given radius around the given TileEntity.</p>
* @param packet the packet
* @param te the TileEntity
* @param radius the radius
*/
public static void sendToAllNear(Packet packet, TileEntity te, double radius) {
sendToAllNear(packet, te.worldObj, te.xCoord, te.yCoord, te.zCoord, radius);
}
private static EntityPlayerMP checkNotClient(EntityPlayer player) {
if (player.worldObj.isRemote) {
throw new IllegalArgumentException("Tried to send packet using a client side player");
}
return (EntityPlayerMP) player;
}
private static WorldServer checkNotClient(World world) {
if (world.isRemote) {
throw new IllegalArgumentException("Tried to send packet using a client world");
}
return (WorldServer) world;
}
private Packets() { }
}