package com.bergerkiller.bukkit.common.bases;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import org.bukkit.World;
import org.bukkit.entity.Player;
import com.bergerkiller.bukkit.common.conversion.Conversion;
import com.bergerkiller.bukkit.common.internal.CommonNMS;
import com.bergerkiller.bukkit.common.reflection.classes.PlayerChunkMapRef;
import com.bergerkiller.bukkit.common.reflection.classes.PlayerChunkRef;
import net.minecraft.server.ChunkCoordIntPair;
import net.minecraft.server.EntityPlayer;
import net.minecraft.server.PlayerChunkMap;
import net.minecraft.server.WorldServer;
public class PlayerChunkMapBase extends PlayerChunkMap {
public PlayerChunkMapBase(World world, int viewDistace) {
super((WorldServer) Conversion.toWorldHandle.convert(world), viewDistace);
}
/**
* @deprecated use {@link #getWorld()} instead
*/
@Deprecated
@Override
public final WorldServer a() {
return CommonNMS.getNative(this.getWorld());
}
/**
* @deprecated use {@link #containsPlayer(Player, int, int) containsPlayer(player, x, z)} instead
*/
@Deprecated
@Override
public final boolean a(EntityPlayer entityplayer, int x, int z) {
return this.containsPlayer(CommonNMS.getPlayer(entityplayer), x, z);
}
/**
* @deprecated use {@link #addChunksToSend(Player)} instead
*/
@Deprecated
@Override
public final void b(EntityPlayer entityplayer) {
this.addChunksToSend(CommonNMS.getPlayer(entityplayer));
}
/**
* @deprecated use {@link #addPlayer(Player)} instead
*/
@Deprecated
@Override
public void addPlayer(EntityPlayer arg0) {
this.addPlayer(CommonNMS.getPlayer(arg0));
}
/**
* @deprecated use {@link #movePlayer(Player)} instead
*/
@Deprecated
@Override
public void movePlayer(EntityPlayer arg0) {
this.movePlayer(CommonNMS.getPlayer(arg0));
}
/**
* @deprecated use {@link #removePlayer(Player)} instead
*/
@Deprecated
@Override
public void removePlayer(EntityPlayer arg0) {
removePlayer(CommonNMS.getPlayer(arg0));
}
public Object getPlayerChunk(Object playerChunk) {
return playerChunk;
}
/**
* Updates player movement
*
* @param player to update
*/
@SuppressWarnings("unchecked")
public void movePlayer(Player player) {
EntityPlayer entityplayer = CommonNMS.getNative(player);
int i = (int) entityplayer.locX >> 4;
int j = (int) entityplayer.locZ >> 4;
double d0 = entityplayer.d - entityplayer.locX;
double d1 = entityplayer.e - entityplayer.locZ;
double d2 = d0 * d0 + d1 * d1;
if (d2 >= 64.0D) {
int k = (int) entityplayer.d >> 4;
int l = (int) entityplayer.e >> 4;
int i1 = PlayerChunkMapRef.radius.get(this);
int j1 = i - k;
int k1 = j - l;
List<ChunkCoordIntPair> chunksToLoad = new LinkedList<ChunkCoordIntPair>();
if ((j1 != 0) || (k1 != 0)) {
for (int l1 = i - i1; l1 <= i + i1; l1++) {
for (int i2 = j - i1; i2 <= j + i1; i2++) {
if(!PlayerChunkMapRef.shouldUnload.invoke(this, l1, i2, k, l, i1)) {
chunksToLoad.add(new ChunkCoordIntPair(l1, i2));
}
if(!PlayerChunkMapRef.shouldUnload.invoke(this, l1 - j1, i2 - k1, i, j, i1)) {
Object playerchunk = getPlayerChunk(PlayerChunkMapRef.getChunk.invoke(this, l1 - j1, i2 - k1, false));
if (playerchunk != null) {
PlayerChunkRef.unload.invoke(playerchunk, entityplayer);
}
}
}
}
b(entityplayer);
entityplayer.d = entityplayer.locX;
entityplayer.e = entityplayer.locZ;
Collections.sort(chunksToLoad, new ChunkCoordComparator(entityplayer));
for (ChunkCoordIntPair pair : chunksToLoad) {
Object playerchunk = PlayerChunkMapRef.getChunk.invoke(this, pair.x, pair.z, true);
PlayerChunkRef.load.invoke(playerchunk, entityplayer);
}
if ((j1 > 1) || (j1 < -1) || (k1 > 1) || (k1 < -1))
Collections.sort(entityplayer.chunkCoordIntPairQueue, new ChunkCoordComparator(entityplayer));
}
}
}
/**
* Adds a new player
*
* @param player to add
*/
public void addPlayer(Player player) {
super.addPlayer(CommonNMS.getNative(player));
}
/**
* Removes an existing player
*
* @param player to remove
*/
public void removePlayer(Player player) {
EntityPlayer entityplayer = CommonNMS.getNative(player);
int i = (int) entityplayer.d >> 4;
int j = (int) entityplayer.e >> 4;
int radius = PlayerChunkMapRef.radius.get(this);
for (int k = i - radius; k <= i + radius; k++) {
for (int l = j - radius; l <= j + radius; l++) {
Object playerchunk = getPlayerChunk(PlayerChunkMapRef.getChunk.invoke(this, k, l, false));
if (playerchunk != null) {
PlayerChunkRef.unload.invoke(playerchunk, entityplayer);
}
}
}
PlayerChunkMapRef.managedPlayers.get(this).remove(entityplayer);
}
/**
* Adds all chunks near a player to the chunk sending queue of a player
*
* @param player to add the chunks to send to
*/
public void addChunksToSend(Player player) {
super.b(CommonNMS.getNative(player));
}
/**
* Gets whether a player is registered for a Chunk.
* If this is the case, the player is liable for entity or block
* updates from entities or blocks in the chunk.
*
* @param player to check
* @param chunkX of the Chunk
* @param chunkZ of the Chunk
* @return True if the player is contained, False if not
*/
public boolean containsPlayer(Player player, int chunkX, int chunkZ) {
return super.a(CommonNMS.getNative(player), chunkX, chunkZ);
}
/**
* Gets the world from this PlayerManager<br>
* Is called by the PlayerChunkInstance initializer as well
*
* @return World
*/
public World getWorld() {
return Conversion.toWorld.convert(super.a());
}
/**
* This is nuts bro o,o
*/
private static class ChunkCoordComparator implements
Comparator<ChunkCoordIntPair> {
private int x;
private int z;
public ChunkCoordComparator(EntityPlayer entityplayer) {
this.x = ((int) entityplayer.locX >> 4);
this.z = ((int) entityplayer.locZ >> 4);
}
public int compare(ChunkCoordIntPair a, ChunkCoordIntPair b) {
if (a.equals(b)) {
return 0;
}
int ax = a.x - this.x;
int az = a.z - this.z;
int bx = b.x - this.x;
int bz = b.z - this.z;
int result = (ax - bx) * (ax + bx) + (az - bz) * (az + bz);
if (result != 0) {
return result;
}
if (ax < 0) {
if (bx < 0) {
return bz - az;
}
return -1;
}
if (bx < 0) {
return 1;
}
return az - bz;
}
}
}