PlotSquared/Bukkit/src/main/java/com/plotsquared/bukkit/util/SendChunk.java

152 lines
6.4 KiB
Java
Raw Normal View History

2016-02-23 05:11:28 +01:00
package com.plotsquared.bukkit.util;
2016-03-23 02:41:37 +01:00
import static com.intellectualcrafters.plot.util.ReflectionUtils.getRefClass;
2016-02-23 05:11:28 +01:00
import com.intellectualcrafters.plot.PS;
import com.intellectualcrafters.plot.object.ChunkLoc;
import com.intellectualcrafters.plot.object.Location;
import com.intellectualcrafters.plot.object.Plot;
import com.intellectualcrafters.plot.object.PlotPlayer;
import com.intellectualcrafters.plot.util.ReflectionUtils.RefClass;
import com.intellectualcrafters.plot.util.ReflectionUtils.RefConstructor;
import com.intellectualcrafters.plot.util.ReflectionUtils.RefField;
import com.intellectualcrafters.plot.util.ReflectionUtils.RefMethod;
import com.intellectualcrafters.plot.util.TaskManager;
import com.intellectualcrafters.plot.util.UUIDHandler;
import com.plotsquared.bukkit.object.BukkitPlayer;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.World;
import org.bukkit.entity.Player;
2016-03-23 02:41:37 +01:00
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
2016-02-23 05:11:28 +01:00
import java.util.Map.Entry;
/**
* An utility that can be used to send chunks, rather than using bukkit code to do so (uses heavy NMS)
*
*/
public class SendChunk {
private final RefMethod methodGetHandlePlayer;
private final RefMethod methodGetHandleChunk;
2016-03-23 02:41:37 +01:00
private final RefConstructor mapChunk;
2016-02-23 05:11:28 +01:00
private final RefField connection;
private final RefMethod send;
private final RefMethod methodInitLighting;
/**
* Constructor
*/
2016-04-30 00:14:12 +02:00
public SendChunk() throws ClassNotFoundException, NoSuchMethodException, NoSuchFieldException {
2016-03-23 02:41:37 +01:00
RefClass classCraftPlayer = getRefClass("{cb}.entity.CraftPlayer");
this.methodGetHandlePlayer = classCraftPlayer.getMethod("getHandle");
RefClass classCraftChunk = getRefClass("{cb}.CraftChunk");
this.methodGetHandleChunk = classCraftChunk.getMethod("getHandle");
RefClass classChunk = getRefClass("{nms}.Chunk");
this.methodInitLighting = classChunk.getMethod("initLighting");
RefClass classMapChunk = getRefClass("{nms}.PacketPlayOutMapChunk");
2016-04-02 07:30:26 +02:00
//TODO in 1.7.10 this is PacketPlayOutMapChunk(Chunk chunk, boolean flag, int i, int version)
2016-03-23 02:41:37 +01:00
this.mapChunk = classMapChunk.getConstructor(classChunk.getRealClass(), boolean.class, int.class);
2016-05-11 17:16:38 +02:00
if (PS.get().checkVersion(PS.get().IMP.getServerVersion(), 1, 9, 4)) {
2016-05-11 18:11:46 +02:00
this.mapChunk = classMapChunk.getConstructor(classChunk.getRealClass(),int.class);
2016-05-11 17:16:38 +02:00
} else {
this.mapChunk = classMapChunk.getConstructor(classChunk.getRealClass(), boolean.class, int.class);
}
2016-03-23 02:41:37 +01:00
RefClass classEntityPlayer = getRefClass("{nms}.EntityPlayer");
this.connection = classEntityPlayer.getField("playerConnection");
RefClass classPacket = getRefClass("{nms}.Packet");
RefClass classConnection = getRefClass("{nms}.PlayerConnection");
this.send = classConnection.getMethod("sendPacket", classPacket.getRealClass());
2016-02-23 05:11:28 +01:00
}
2016-03-23 02:41:37 +01:00
public void sendChunk(Collection<Chunk> input) {
HashSet<Chunk> chunks = new HashSet<Chunk>(input);
HashMap<String, ArrayList<Chunk>> map = new HashMap<>();
int view = Bukkit.getServer().getViewDistance();
for (Chunk chunk : chunks) {
String world = chunk.getWorld().getName();
2016-02-23 05:11:28 +01:00
ArrayList<Chunk> list = map.get(world);
if (list == null) {
list = new ArrayList<>();
map.put(world, list);
}
list.add(chunk);
2016-03-23 02:41:37 +01:00
Object c = this.methodGetHandleChunk.of(chunk).call();
this.methodInitLighting.of(c).call();
2016-02-23 05:11:28 +01:00
}
for (Entry<String, PlotPlayer> entry : UUIDHandler.getPlayers().entrySet()) {
PlotPlayer pp = entry.getValue();
2016-03-23 02:41:37 +01:00
Plot plot = pp.getCurrentPlot();
2016-02-23 05:11:28 +01:00
Location loc = null;
String world;
if (plot != null) {
world = plot.getArea().worldname;
} else {
loc = pp.getLocation();
world = loc.getWorld();
}
2016-03-23 02:41:37 +01:00
ArrayList<Chunk> list = map.get(world);
2016-02-23 05:11:28 +01:00
if (list == null) {
continue;
}
if (loc == null) {
loc = pp.getLocation();
}
2016-03-23 02:41:37 +01:00
int cx = loc.getX() >> 4;
int cz = loc.getZ() >> 4;
Player player = ((BukkitPlayer) pp).player;
Object entity = this.methodGetHandlePlayer.of(player).call();
2016-02-23 05:11:28 +01:00
2016-03-23 02:41:37 +01:00
for (Chunk chunk : list) {
int dx = Math.abs(cx - chunk.getX());
int dz = Math.abs(cz - chunk.getZ());
2016-02-23 05:11:28 +01:00
if ((dx > view) || (dz > view)) {
continue;
}
2016-03-23 02:41:37 +01:00
Object c = this.methodGetHandleChunk.of(chunk).call();
2016-02-23 05:11:28 +01:00
chunks.remove(chunk);
2016-03-23 02:41:37 +01:00
Object con = this.connection.of(entity).get();
2016-05-11 17:16:38 +02:00
Object packet;
if (PS.get().checkVersion(PS.get().IMP.getServerVersion(), 1, 9, 4)) {
2016-05-11 18:11:46 +02:00
packet = this.mapChunk.create(c,65535);
2016-05-11 17:16:38 +02:00
} else {
packet = this.mapChunk.create(c, true, 65535);
}
2016-03-23 02:41:37 +01:00
this.send.of(con).call(packet);
2016-02-23 05:11:28 +01:00
}
}
for (final Chunk chunk : chunks) {
TaskManager.runTask(new Runnable() {
@Override
public void run() {
try {
chunk.unload(true, false);
2016-03-23 02:41:37 +01:00
} catch (Throwable e) {
2016-03-29 21:47:59 +02:00
String worldName = chunk.getWorld().getName();
PS.debug("$4Could not save chunk: " + worldName + ";" + chunk.getX() + ";" + chunk.getZ());
2016-02-23 05:11:28 +01:00
PS.debug("$3 - $4File may be open in another process (e.g. MCEdit)");
2016-03-29 21:47:59 +02:00
PS.debug("$3 - $4" + worldName + "/level.dat or " + worldName
2016-02-23 05:11:28 +01:00
+ "/level_old.dat may be corrupt (try repairing or removing these)");
}
}
});
}
}
2016-03-29 21:47:59 +02:00
public void sendChunk(String worldName, Collection<ChunkLoc> chunkLocations) {
World myWorld = Bukkit.getWorld(worldName);
2016-03-23 02:41:37 +01:00
ArrayList<Chunk> chunks = new ArrayList<>();
2016-03-29 21:47:59 +02:00
for (ChunkLoc loc : chunkLocations) {
if (myWorld.isChunkLoaded(loc.x, loc.z)) {
chunks.add(myWorld.getChunkAt(loc.x, loc.z));
}
2016-02-23 05:11:28 +01:00
}
sendChunk(chunks);
}
}