Various
Per world session history index when using disk Configurable clipboard/history save locations Fixed and optimized packet sending History caching optimizations (instant now)
This commit is contained in:
parent
97ca92eedf
commit
1ed87eabbc
@ -314,10 +314,6 @@ public class FaweBukkit implements IFawe, Listener {
|
||||
public void onPlayerChangedWorld(PlayerChangedWorldEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
FawePlayer fp = FawePlayer.wrap(player);
|
||||
if (Settings.HISTORY.USE_DISK) {
|
||||
fp.getSession().clearHistory();
|
||||
fp.loadSessionsFromDisk(fp.getWorld());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -134,9 +134,7 @@ public abstract class BukkitQueue_0<CHUNK, CHUNKSECTIONS, SECTION> extends NMSMa
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refreshChunk(World world, CHUNK chunk) {
|
||||
return;
|
||||
}
|
||||
public void refreshChunk(FaweChunk fs) {}
|
||||
|
||||
@Override
|
||||
public boolean regenerateChunk(World world, int x, int z) {
|
||||
|
@ -34,15 +34,12 @@ import java.util.UUID;
|
||||
import net.minecraft.server.v1_10_R1.Block;
|
||||
import net.minecraft.server.v1_10_R1.BlockPosition;
|
||||
import net.minecraft.server.v1_10_R1.Blocks;
|
||||
import net.minecraft.server.v1_10_R1.ChunkCoordIntPair;
|
||||
import net.minecraft.server.v1_10_R1.ChunkSection;
|
||||
import net.minecraft.server.v1_10_R1.DataBits;
|
||||
import net.minecraft.server.v1_10_R1.DataPaletteBlock;
|
||||
import net.minecraft.server.v1_10_R1.Entity;
|
||||
import net.minecraft.server.v1_10_R1.EntityHuman;
|
||||
import net.minecraft.server.v1_10_R1.EntityPlayer;
|
||||
import net.minecraft.server.v1_10_R1.EntityTracker;
|
||||
import net.minecraft.server.v1_10_R1.EntityTrackerEntry;
|
||||
import net.minecraft.server.v1_10_R1.EntityTypes;
|
||||
import net.minecraft.server.v1_10_R1.EnumDifficulty;
|
||||
import net.minecraft.server.v1_10_R1.EnumGamemode;
|
||||
@ -52,7 +49,6 @@ import net.minecraft.server.v1_10_R1.IDataManager;
|
||||
import net.minecraft.server.v1_10_R1.MinecraftServer;
|
||||
import net.minecraft.server.v1_10_R1.NBTTagCompound;
|
||||
import net.minecraft.server.v1_10_R1.NibbleArray;
|
||||
import net.minecraft.server.v1_10_R1.PacketPlayOutEntityDestroy;
|
||||
import net.minecraft.server.v1_10_R1.PacketPlayOutMapChunk;
|
||||
import net.minecraft.server.v1_10_R1.PlayerChunk;
|
||||
import net.minecraft.server.v1_10_R1.PlayerChunkMap;
|
||||
@ -246,86 +242,54 @@ public class BukkitQueue_1_10 extends BukkitQueue_0<Chunk, ChunkSection[], Chunk
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refreshChunk(World world, Chunk chunk) {
|
||||
public void refreshChunk(FaweChunk fc) {
|
||||
BukkitChunk_1_10 fs = (BukkitChunk_1_10) fc;
|
||||
Chunk chunk = fs.getChunk();
|
||||
if (!chunk.isLoaded()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
net.minecraft.server.v1_10_R1.Chunk nmsChunk = ((CraftChunk) chunk).getHandle();
|
||||
ChunkCoordIntPair pos = nmsChunk.k(); // getPosition()
|
||||
WorldServer w = (WorldServer) nmsChunk.getWorld();
|
||||
PlayerChunkMap chunkMap = w.getPlayerChunkMap();
|
||||
PlayerChunk playerChunk = chunkMap.getChunk(pos.x, pos.z);
|
||||
PlayerChunk playerChunk = chunkMap.getChunk(nmsChunk.locX, nmsChunk.locZ);
|
||||
if (playerChunk == null) {
|
||||
return;
|
||||
}
|
||||
HashSet<EntityPlayer> set = new HashSet<EntityPlayer>(playerChunk.c);
|
||||
EntityTracker tracker = w.getTracker();
|
||||
// Get players
|
||||
final HashSet<EntityPlayer> players = new HashSet<>();
|
||||
for (EntityHuman human : w.players) {
|
||||
if (set.contains(human)) {
|
||||
players.add((EntityPlayer) human);
|
||||
}
|
||||
}
|
||||
if (players.size() == 0) {
|
||||
if (playerChunk.c.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
HashSet<EntityTrackerEntry> entities = new HashSet<>();
|
||||
Collection<Entity>[] entitieSlices = (Collection<Entity>[]) getEntitySlices.invoke(nmsChunk);
|
||||
for (Collection<Entity> slice : entitieSlices) {
|
||||
if (slice == null) {
|
||||
continue;
|
||||
}
|
||||
for (Entity ent : slice) {
|
||||
EntityTrackerEntry entry = tracker.trackedEntities.get(ent.getId());
|
||||
if (entry == null) {
|
||||
continue;
|
||||
}
|
||||
entities.add(entry);
|
||||
PacketPlayOutEntityDestroy packet = new PacketPlayOutEntityDestroy(ent.getId());
|
||||
for (EntityPlayer player : players) {
|
||||
player.playerConnection.sendPacket(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Send chunks
|
||||
PacketPlayOutMapChunk packet = new PacketPlayOutMapChunk(nmsChunk, 65535);
|
||||
for (EntityPlayer player : players) {
|
||||
player.playerConnection.sendPacket(packet);
|
||||
int mask = fc.getBitMask();
|
||||
if (mask == 65535 && hasEntities(nmsChunk)) {
|
||||
PacketPlayOutMapChunk packet = new PacketPlayOutMapChunk(nmsChunk, 65280);
|
||||
for (EntityPlayer player : playerChunk.c) {
|
||||
player.playerConnection.sendPacket(packet);
|
||||
}
|
||||
mask = 255;
|
||||
}
|
||||
// send ents
|
||||
for (Collection<Entity> slice : entitieSlices) {
|
||||
if (slice == null) {
|
||||
continue;
|
||||
}
|
||||
for (final Entity ent : slice) {
|
||||
final EntityTrackerEntry entry = tracker.trackedEntities.get(ent.getId());
|
||||
if (entry == null) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
TaskManager.IMP.later(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (EntityPlayer player : players) {
|
||||
boolean result = entry.trackedPlayers.remove(player);
|
||||
if (result && ent != player) {
|
||||
entry.updatePlayer(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 2);
|
||||
} catch (Throwable e) {
|
||||
MainUtil.handleError(e);
|
||||
}
|
||||
}
|
||||
PacketPlayOutMapChunk packet = new PacketPlayOutMapChunk(nmsChunk, mask);
|
||||
for (EntityPlayer player : playerChunk.c) {
|
||||
player.playerConnection.sendPacket(packet);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasEntities(net.minecraft.server.v1_10_R1.Chunk nmsChunk) {
|
||||
try {
|
||||
final Collection<Entity>[] entities = (Collection<Entity>[]) getEntitySlices.invoke(nmsChunk);
|
||||
for (int i = 0; i < entities.length; i++) {
|
||||
Collection<Entity> slice = entities[i];
|
||||
if (slice != null && !slice.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (Throwable ignore) {}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeLighting(ChunkSection[] sections, RelightMode mode, boolean sky) {
|
||||
if (mode != RelightMode.NONE) {
|
||||
@ -548,8 +512,7 @@ public class BukkitQueue_1_10 extends BukkitQueue_0<Chunk, ChunkSection[], Chunk
|
||||
net.minecraft.server.v1_10_R1.World nmsWorld = nmsChunk.world;
|
||||
ChunkSection[] sections = nmsChunk.getSections();
|
||||
Class<? extends net.minecraft.server.v1_10_R1.Chunk> clazzChunk = nmsChunk.getClass();
|
||||
final Field ef = clazzChunk.getDeclaredField("entitySlices");
|
||||
final Collection<Entity>[] entities = (Collection<Entity>[]) ef.get(nmsChunk);
|
||||
final Collection<Entity>[] entities = (Collection<Entity>[]) getEntitySlices.invoke(nmsChunk);
|
||||
Map<BlockPosition, TileEntity> tiles = nmsChunk.getTileEntities();
|
||||
// Remove entities
|
||||
for (int i = 0; i < entities.length; i++) {
|
||||
|
@ -35,7 +35,6 @@ import net.minecraft.server.v1_7_R4.ChunkSection;
|
||||
import net.minecraft.server.v1_7_R4.Entity;
|
||||
import net.minecraft.server.v1_7_R4.EntityPlayer;
|
||||
import net.minecraft.server.v1_7_R4.EntityTracker;
|
||||
import net.minecraft.server.v1_7_R4.EntityTrackerEntry;
|
||||
import net.minecraft.server.v1_7_R4.EntityTypes;
|
||||
import net.minecraft.server.v1_7_R4.EnumDifficulty;
|
||||
import net.minecraft.server.v1_7_R4.EnumGamemode;
|
||||
@ -44,7 +43,6 @@ import net.minecraft.server.v1_7_R4.LongHashMap;
|
||||
import net.minecraft.server.v1_7_R4.MinecraftServer;
|
||||
import net.minecraft.server.v1_7_R4.NBTTagCompound;
|
||||
import net.minecraft.server.v1_7_R4.NibbleArray;
|
||||
import net.minecraft.server.v1_7_R4.PacketPlayOutEntityDestroy;
|
||||
import net.minecraft.server.v1_7_R4.PacketPlayOutMapChunk;
|
||||
import net.minecraft.server.v1_7_R4.PlayerChunkMap;
|
||||
import net.minecraft.server.v1_7_R4.ServerNBTManager;
|
||||
@ -453,8 +451,12 @@ public class BukkitQueue17 extends BukkitQueue_0<Chunk, ChunkSection[], ChunkSec
|
||||
fieldNonEmptyBlockCount.set(section, nonEmptyBlockCount);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void refreshChunk(World world, Chunk chunk) {
|
||||
public void refreshChunk(FaweChunk fc) {
|
||||
BukkitChunk_1_7 fs = (BukkitChunk_1_7) fc;
|
||||
Chunk chunk = fs.getChunk();
|
||||
if (!chunk.isLoaded()) {
|
||||
return;
|
||||
}
|
||||
@ -483,52 +485,34 @@ public class BukkitQueue17 extends BukkitQueue_0<Chunk, ChunkSection[], ChunkSec
|
||||
if (players.size() == 0) {
|
||||
return;
|
||||
}
|
||||
HashSet<EntityTrackerEntry> entities = new HashSet<>();
|
||||
List<Entity>[] entitieSlices = nmsChunk.entitySlices;
|
||||
for (List<Entity> slice : entitieSlices) {
|
||||
if (slice == null) {
|
||||
continue;
|
||||
}
|
||||
for (Entity ent : slice) {
|
||||
EntityTrackerEntry entry = (EntityTrackerEntry) tracker.trackedEntities.get(ent.getId());
|
||||
if (entry == null) {
|
||||
continue;
|
||||
}
|
||||
entities.add(entry);
|
||||
PacketPlayOutEntityDestroy packet = new PacketPlayOutEntityDestroy(ent.getId());
|
||||
for (EntityPlayer player : players) {
|
||||
player.playerConnection.sendPacket(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Send chunks
|
||||
PacketPlayOutMapChunk packet = new PacketPlayOutMapChunk(nmsChunk, false, 65535, 25);
|
||||
int mask = fc.getBitMask();
|
||||
if (mask == 65535 && hasEntities(nmsChunk)) {
|
||||
PacketPlayOutMapChunk packet = new PacketPlayOutMapChunk(nmsChunk, false, 65280, 25);
|
||||
for (EntityPlayer player : players) {
|
||||
player.playerConnection.sendPacket(packet);
|
||||
}
|
||||
mask = 255;
|
||||
}
|
||||
PacketPlayOutMapChunk packet = new PacketPlayOutMapChunk(nmsChunk, false, mask, 25);
|
||||
for (EntityPlayer player : players) {
|
||||
player.playerConnection.sendPacket(packet);
|
||||
}
|
||||
// send ents
|
||||
for (final EntityTrackerEntry entry : entities) {
|
||||
try {
|
||||
TaskManager.IMP.later(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (EntityPlayer player : players) {
|
||||
boolean result = entry.trackedPlayers.remove(player);
|
||||
if (result && entry.tracker != player) {
|
||||
entry.updatePlayer(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 2);
|
||||
} catch (Throwable e) {
|
||||
MainUtil.handleError(e);
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
MainUtil.handleError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasEntities(net.minecraft.server.v1_7_R4.Chunk nmsChunk) {
|
||||
for (int i = 0; i < nmsChunk.entitySlices.length; i++) {
|
||||
List<Entity> slice = nmsChunk.entitySlices[i];
|
||||
if (slice != null && !slice.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeLighting(ChunkSection[] sections, RelightMode mode, boolean sky) {
|
||||
if (mode == RelightMode.ALL) {
|
||||
|
@ -30,12 +30,10 @@ import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import net.minecraft.server.v1_8_R3.Block;
|
||||
import net.minecraft.server.v1_8_R3.BlockPosition;
|
||||
import net.minecraft.server.v1_8_R3.ChunkCoordIntPair;
|
||||
import net.minecraft.server.v1_8_R3.ChunkSection;
|
||||
import net.minecraft.server.v1_8_R3.Entity;
|
||||
import net.minecraft.server.v1_8_R3.EntityPlayer;
|
||||
import net.minecraft.server.v1_8_R3.EntityTracker;
|
||||
import net.minecraft.server.v1_8_R3.EntityTrackerEntry;
|
||||
import net.minecraft.server.v1_8_R3.EntityTypes;
|
||||
import net.minecraft.server.v1_8_R3.EnumDifficulty;
|
||||
import net.minecraft.server.v1_8_R3.EnumSkyBlock;
|
||||
@ -43,7 +41,6 @@ import net.minecraft.server.v1_8_R3.LongHashMap;
|
||||
import net.minecraft.server.v1_8_R3.MinecraftServer;
|
||||
import net.minecraft.server.v1_8_R3.NBTTagCompound;
|
||||
import net.minecraft.server.v1_8_R3.NibbleArray;
|
||||
import net.minecraft.server.v1_8_R3.PacketPlayOutEntityDestroy;
|
||||
import net.minecraft.server.v1_8_R3.PacketPlayOutMapChunk;
|
||||
import net.minecraft.server.v1_8_R3.PlayerChunkMap;
|
||||
import net.minecraft.server.v1_8_R3.ServerNBTManager;
|
||||
@ -429,24 +426,21 @@ public class BukkitQueue18R3 extends BukkitQueue_0<Chunk, ChunkSection[], ChunkS
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refreshChunk(World world, Chunk chunk) {
|
||||
public void refreshChunk(FaweChunk fc) {
|
||||
BukkitChunk_1_8 fs = (BukkitChunk_1_8) fc;
|
||||
Chunk chunk = fs.getChunk();
|
||||
if (!chunk.isLoaded()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
net.minecraft.server.v1_8_R3.Chunk nmsChunk = ((CraftChunk) chunk).getHandle();
|
||||
ChunkCoordIntPair pos = nmsChunk.j(); // getPosition()
|
||||
WorldServer w = (WorldServer) nmsChunk.getWorld();
|
||||
PlayerChunkMap chunkMap = w.getPlayerChunkMap();
|
||||
int x = pos.x;
|
||||
int z = pos.z;
|
||||
int x = nmsChunk.locX;
|
||||
int z = nmsChunk.locZ;
|
||||
if (!chunkMap.isChunkInUse(x, z)) {
|
||||
return;
|
||||
}
|
||||
HashSet<EntityPlayer> set = new HashSet<EntityPlayer>();
|
||||
EntityTracker tracker = w.getTracker();
|
||||
// Get players
|
||||
|
||||
Field fieldChunkMap = chunkMap.getClass().getDeclaredField("d");
|
||||
fieldChunkMap.setAccessible(true);
|
||||
LongHashMap<Object> map = (LongHashMap<Object>) fieldChunkMap.get(chunkMap);
|
||||
@ -454,56 +448,38 @@ public class BukkitQueue18R3 extends BukkitQueue_0<Chunk, ChunkSection[], ChunkS
|
||||
Object playerChunk = map.getEntry(pair);
|
||||
Field fieldPlayers = playerChunk.getClass().getDeclaredField("b");
|
||||
fieldPlayers.setAccessible(true);
|
||||
final HashSet<EntityPlayer> players = new HashSet<>((Collection<EntityPlayer>)fieldPlayers.get(playerChunk));
|
||||
if (players.size() == 0) {
|
||||
Collection<EntityPlayer> players = (Collection<EntityPlayer>) fieldPlayers.get(playerChunk);
|
||||
if (players.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
HashSet<EntityTrackerEntry> entities = new HashSet<>();
|
||||
List<Entity>[] entitieSlices = nmsChunk.getEntitySlices();
|
||||
for (List<Entity> slice : entitieSlices) {
|
||||
if (slice == null) {
|
||||
continue;
|
||||
}
|
||||
for (Entity ent : slice) {
|
||||
EntityTrackerEntry entry = tracker.trackedEntities.get(ent.getId());
|
||||
if (entry == null) {
|
||||
continue;
|
||||
}
|
||||
entities.add(entry);
|
||||
PacketPlayOutEntityDestroy packet = new PacketPlayOutEntityDestroy(ent.getId());
|
||||
for (EntityPlayer player : players) {
|
||||
player.playerConnection.sendPacket(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Send chunks
|
||||
PacketPlayOutMapChunk packet = new PacketPlayOutMapChunk(nmsChunk, false, 65535);
|
||||
int mask = fc.getBitMask();
|
||||
if (mask == 65535 && hasEntities(nmsChunk)) {
|
||||
PacketPlayOutMapChunk packet = new PacketPlayOutMapChunk(nmsChunk, false, 65280);
|
||||
for (EntityPlayer player : players) {
|
||||
player.playerConnection.sendPacket(packet);
|
||||
}
|
||||
mask = 255;
|
||||
}
|
||||
PacketPlayOutMapChunk packet = new PacketPlayOutMapChunk(nmsChunk, false, mask);
|
||||
for (EntityPlayer player : players) {
|
||||
player.playerConnection.sendPacket(packet);
|
||||
}
|
||||
// send ents
|
||||
for (final EntityTrackerEntry entry : entities) {
|
||||
try {
|
||||
TaskManager.IMP.later(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (EntityPlayer player : players) {
|
||||
boolean result = entry.trackedPlayers.remove(player);
|
||||
if (result && entry.tracker != player) {
|
||||
entry.updatePlayer(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 2);
|
||||
} catch (Throwable e) {
|
||||
MainUtil.handleError(e);
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
MainUtil.handleError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasEntities(net.minecraft.server.v1_8_R3.Chunk nmsChunk) {
|
||||
for (int i = 0; i < nmsChunk.entitySlices.length; i++) {
|
||||
List<Entity> slice = nmsChunk.entitySlices[i];
|
||||
if (slice != null && !slice.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeLighting(ChunkSection[] sections, RelightMode mode, boolean sky) {
|
||||
if (mode == RelightMode.ALL) {
|
||||
|
@ -34,16 +34,13 @@ import java.util.UUID;
|
||||
import net.minecraft.server.v1_9_R2.Block;
|
||||
import net.minecraft.server.v1_9_R2.BlockPosition;
|
||||
import net.minecraft.server.v1_9_R2.Blocks;
|
||||
import net.minecraft.server.v1_9_R2.ChunkCoordIntPair;
|
||||
import net.minecraft.server.v1_9_R2.ChunkSection;
|
||||
import net.minecraft.server.v1_9_R2.DataBits;
|
||||
import net.minecraft.server.v1_9_R2.DataPalette;
|
||||
import net.minecraft.server.v1_9_R2.DataPaletteBlock;
|
||||
import net.minecraft.server.v1_9_R2.Entity;
|
||||
import net.minecraft.server.v1_9_R2.EntityHuman;
|
||||
import net.minecraft.server.v1_9_R2.EntityPlayer;
|
||||
import net.minecraft.server.v1_9_R2.EntityTracker;
|
||||
import net.minecraft.server.v1_9_R2.EntityTrackerEntry;
|
||||
import net.minecraft.server.v1_9_R2.EntityTypes;
|
||||
import net.minecraft.server.v1_9_R2.EnumDifficulty;
|
||||
import net.minecraft.server.v1_9_R2.EnumSkyBlock;
|
||||
@ -52,7 +49,6 @@ import net.minecraft.server.v1_9_R2.IDataManager;
|
||||
import net.minecraft.server.v1_9_R2.MinecraftServer;
|
||||
import net.minecraft.server.v1_9_R2.NBTTagCompound;
|
||||
import net.minecraft.server.v1_9_R2.NibbleArray;
|
||||
import net.minecraft.server.v1_9_R2.PacketPlayOutEntityDestroy;
|
||||
import net.minecraft.server.v1_9_R2.PacketPlayOutMapChunk;
|
||||
import net.minecraft.server.v1_9_R2.PlayerChunk;
|
||||
import net.minecraft.server.v1_9_R2.PlayerChunkMap;
|
||||
@ -128,80 +124,49 @@ public class BukkitQueue_1_9_R1 extends BukkitQueue_0<Chunk, ChunkSection[], Chu
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refreshChunk(World world, Chunk chunk) {
|
||||
public void refreshChunk(FaweChunk fc) {
|
||||
BukkitChunk_1_9 fs = (BukkitChunk_1_9) fc;
|
||||
Chunk chunk = fs.getChunk();
|
||||
if (!chunk.isLoaded()) {
|
||||
return;
|
||||
}
|
||||
net.minecraft.server.v1_9_R2.Chunk nmsChunk = ((CraftChunk) chunk).getHandle();
|
||||
ChunkCoordIntPair pos = nmsChunk.k(); // getPosition()
|
||||
WorldServer w = (WorldServer) nmsChunk.getWorld();
|
||||
PlayerChunkMap chunkMap = w.getPlayerChunkMap();
|
||||
PlayerChunk playerChunk = chunkMap.getChunk(pos.x, pos.z);
|
||||
if (playerChunk == null) {
|
||||
return;
|
||||
}
|
||||
HashSet<EntityPlayer> set = new HashSet<EntityPlayer>(playerChunk.c);
|
||||
EntityTracker tracker = w.getTracker();
|
||||
// Get players
|
||||
final HashSet<EntityPlayer> players = new HashSet<>();
|
||||
for (EntityHuman human : w.players) {
|
||||
if (set.contains(human)) {
|
||||
players.add((EntityPlayer) human);
|
||||
try {
|
||||
net.minecraft.server.v1_9_R2.Chunk nmsChunk = ((CraftChunk) chunk).getHandle();
|
||||
WorldServer w = (WorldServer) nmsChunk.getWorld();
|
||||
PlayerChunkMap chunkMap = w.getPlayerChunkMap();
|
||||
PlayerChunk playerChunk = chunkMap.getChunk(nmsChunk.locX, nmsChunk.locZ);
|
||||
if (playerChunk == null) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (players.size() == 0) {
|
||||
return;
|
||||
}
|
||||
HashSet<EntityTrackerEntry> entities = new HashSet<>();
|
||||
List<Entity>[] entitieSlices = playerChunk.chunk.getEntitySlices();
|
||||
for (List<Entity> slice : entitieSlices) {
|
||||
if (slice == null) {
|
||||
continue;
|
||||
if (playerChunk.c.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
for (Entity ent : slice) {
|
||||
EntityTrackerEntry entry = tracker.trackedEntities.get(ent.getId());
|
||||
if (entry == null) {
|
||||
continue;
|
||||
}
|
||||
entities.add(entry);
|
||||
PacketPlayOutEntityDestroy packet = new PacketPlayOutEntityDestroy(ent.getId());
|
||||
for (EntityPlayer player : players) {
|
||||
// Send chunks
|
||||
int mask = fc.getBitMask();
|
||||
if (mask == 65535 && hasEntities(nmsChunk)) {
|
||||
PacketPlayOutMapChunk packet = new PacketPlayOutMapChunk(nmsChunk, 65280);
|
||||
for (EntityPlayer player : playerChunk.c) {
|
||||
player.playerConnection.sendPacket(packet);
|
||||
}
|
||||
mask = 255;
|
||||
}
|
||||
PacketPlayOutMapChunk packet = new PacketPlayOutMapChunk(nmsChunk, mask);
|
||||
for (EntityPlayer player : playerChunk.c) {
|
||||
player.playerConnection.sendPacket(packet);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasEntities(net.minecraft.server.v1_9_R2.Chunk nmsChunk) {
|
||||
for (int i = 0; i < nmsChunk.entitySlices.length; i++) {
|
||||
List<Entity> slice = nmsChunk.entitySlices[i];
|
||||
if (slice != null && !slice.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// Send chunks
|
||||
PacketPlayOutMapChunk packet = new PacketPlayOutMapChunk(playerChunk.chunk, 65535);
|
||||
for (EntityPlayer player : players) {
|
||||
player.playerConnection.sendPacket(packet);
|
||||
}
|
||||
// send ents
|
||||
for (List<Entity> slice : entitieSlices) {
|
||||
if (slice == null) {
|
||||
continue;
|
||||
}
|
||||
for (final Entity ent : slice) {
|
||||
final EntityTrackerEntry entry = tracker.trackedEntities.get(ent.getId());
|
||||
if (entry == null) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
TaskManager.IMP.later(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (EntityPlayer player : players) {
|
||||
boolean result = entry.trackedPlayers.remove(player);
|
||||
if (result && ent != player) {
|
||||
entry.updatePlayer(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 2);
|
||||
} catch (Throwable e) {
|
||||
MainUtil.handleError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -55,6 +55,7 @@ import com.sk89q.worldedit.history.change.EntityCreate;
|
||||
import com.sk89q.worldedit.history.change.EntityRemove;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.regions.selector.CuboidRegionSelector;
|
||||
import com.sk89q.worldedit.session.SessionManager;
|
||||
import com.sk89q.worldedit.util.command.parametric.ParametricBuilder;
|
||||
import com.sk89q.worldedit.world.registry.BundledBlockData;
|
||||
import java.io.File;
|
||||
@ -179,8 +180,8 @@ public class Fawe {
|
||||
* Implementation dependent stuff
|
||||
*/
|
||||
this.setupConfigs();
|
||||
MainUtil.deleteOlder(new File(IMP.getDirectory(), "history"), TimeUnit.DAYS.toMillis(Settings.HISTORY.DELETE_AFTER_DAYS));
|
||||
MainUtil.deleteOlder(new File(IMP.getDirectory(), "clipboard"), TimeUnit.DAYS.toMillis(Settings.CLIPBOARD.DELETE_AFTER_DAYS));
|
||||
MainUtil.deleteOlder(MainUtil.getFile(IMP.getDirectory(), Settings.PATHS.HISTORY), TimeUnit.DAYS.toMillis(Settings.HISTORY.DELETE_AFTER_DAYS));
|
||||
MainUtil.deleteOlder(MainUtil.getFile(IMP.getDirectory(), Settings.PATHS.CLIPBOARD), TimeUnit.DAYS.toMillis(Settings.CLIPBOARD.DELETE_AFTER_DAYS));
|
||||
|
||||
TaskManager.IMP = this.IMP.getTaskManager();
|
||||
TaskManager.IMP.repeat(timer = new FaweTimer(), 1);
|
||||
@ -276,6 +277,7 @@ public class Fawe {
|
||||
EditSession.inject(); // Custom block placer + optimizations
|
||||
EditSessionEvent.inject(); // Add EditSession to event
|
||||
LocalSession.inject(); // Add remember order / queue flushing
|
||||
SessionManager.inject(); // Custom session saving
|
||||
// Commands
|
||||
BrushCommands.inject(); // Translations + heightmap
|
||||
ToolCommands.inject(); // Translations + inspect
|
||||
|
@ -257,7 +257,7 @@ public class FaweAPI {
|
||||
* @return
|
||||
*/
|
||||
public static List<DiskStorageHistory> getBDFiles(FaweLocation origin, UUID user, int radius, long timediff, boolean shallow) {
|
||||
File history = new File(Fawe.imp().getDirectory(), "history" + File.separator + origin.world);
|
||||
File history = MainUtil.getFile(Fawe.imp().getDirectory(), Settings.PATHS.HISTORY + File.separator + origin.world);
|
||||
if (!history.exists()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
@ -37,6 +37,13 @@ public class Settings extends Config {
|
||||
})
|
||||
public static int MAX_MEMORY_PERCENT = 95;
|
||||
|
||||
@Comment("Paths for various directories")
|
||||
public static final class PATHS {
|
||||
public static String HISTORY = "history";
|
||||
public static String CLIPBOARD = "clipboard";
|
||||
}
|
||||
|
||||
|
||||
@Create // This value will be generated automatically
|
||||
public static ConfigBlock<LIMITS> LIMITS = null;
|
||||
|
||||
@ -129,7 +136,8 @@ public class Settings extends Config {
|
||||
public static int CHUNK_WAIT_MS = 100;
|
||||
@Comment("Delete history on disk after a number of days")
|
||||
public static int DELETE_AFTER_DAYS = 7;
|
||||
@Comment("Delete history in memory on logout (does not effect disk)")
|
||||
@Comment("Delete history in memory on logout (does not effect disk) (BROKEN, USE DISK INSTEAD)")
|
||||
@Final // Deprecated
|
||||
public static boolean DELETE_ON_LOGOUT = true;
|
||||
@Comment({
|
||||
"If history should be enabled by default for plugins using WorldEdit:",
|
||||
@ -227,7 +235,7 @@ public class Settings extends Config {
|
||||
" - 1 = Optimal (Relight changed light sources and changed blocks)",
|
||||
" - 2 = All (Slowly relight every blocks)"
|
||||
})
|
||||
public static int MODE = 2;
|
||||
public static int MODE = 1;
|
||||
}
|
||||
|
||||
public static void save(File file) {
|
||||
|
@ -6,6 +6,7 @@ import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.logging.rollback.RollbackOptimizedHistory;
|
||||
import com.boydti.fawe.object.RunnableVal;
|
||||
import com.boydti.fawe.object.changeset.DiskStorageHistory;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
@ -42,7 +43,7 @@ public class RollbackDatabase {
|
||||
public RollbackDatabase(final String world) throws SQLException, ClassNotFoundException {
|
||||
this.prefix = "";
|
||||
this.world = world;
|
||||
this.dbLocation = new File(Fawe.imp().getDirectory(), "history" + File.separator + world + File.separator + "summary.db");
|
||||
this.dbLocation = MainUtil.getFile(Fawe.imp().getDirectory(), Settings.PATHS.HISTORY + File.separator + world + File.separator + "summary.db");
|
||||
connection = openConnection();
|
||||
CREATE_TABLE = "CREATE TABLE IF NOT EXISTS `" + prefix + "edits` (`player` BLOB(16) NOT NULL,`id` INT NOT NULL,`x1` INT NOT NULL,`y1` INT NOT NULL,`z1` INT NOT NULL,`x2` INT NOT NULL,`y2` INT NOT NULL,`z2` INT NOT NULL,`time` INT NOT NULL, PRIMARY KEY (player, id))";
|
||||
INSERT_EDIT = "INSERT INTO `" + prefix + "edits` (`player`,`id`,`x1`,`y1`,`z1`,`x2`,`y2`,`z2`,`time`) VALUES(?,?,?,?,?,?,?,?,?)";
|
||||
|
@ -22,6 +22,7 @@ public abstract class CharFaweChunk<T> extends FaweChunk<T> {
|
||||
public short[] air;
|
||||
public short[] relight;
|
||||
public int[][] biomes;
|
||||
private int bitMask = -1;
|
||||
|
||||
public T chunk;
|
||||
|
||||
@ -103,6 +104,23 @@ public abstract class CharFaweChunk<T> extends FaweChunk<T> {
|
||||
return total;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBitMask() {
|
||||
if (bitMask == -1) {
|
||||
this.bitMask = 0;
|
||||
for (int section = 0; section < ids.length; section++) {
|
||||
if (ids[section] != null) {
|
||||
bitMask += 1 << section;
|
||||
}
|
||||
}
|
||||
}
|
||||
return bitMask;
|
||||
}
|
||||
|
||||
public void setBitMask(int value) {
|
||||
this.bitMask = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the raw data for a section
|
||||
* @param i
|
||||
|
@ -66,7 +66,7 @@ public abstract class NMSMappedFaweQueue<WORLD, CHUNK, CHUNKSECTION, SECTION> ex
|
||||
|
||||
@Override
|
||||
public void sendChunk(final FaweChunk fc) {
|
||||
refreshChunk(getWorld(), (CHUNK) fc.getChunk());
|
||||
refreshChunk(fc);
|
||||
}
|
||||
|
||||
public abstract void setFullbright(CHUNKSECTION sections);
|
||||
@ -159,7 +159,7 @@ public abstract class NMSMappedFaweQueue<WORLD, CHUNK, CHUNKSECTION, SECTION> ex
|
||||
|
||||
public abstract void setBlockLight(SECTION section, int x, int y, int z, int value);
|
||||
|
||||
public abstract void refreshChunk(WORLD world, CHUNK chunk);
|
||||
public abstract void refreshChunk(FaweChunk fs);
|
||||
|
||||
public abstract CharFaweChunk getPrevious(CharFaweChunk fs, CHUNKSECTION sections, Map<?, ?> tiles, Collection<?>[] entities, Set<UUID> createdEntities, boolean all) throws Exception;
|
||||
|
||||
|
@ -100,7 +100,15 @@ public class NMSRelighter {
|
||||
public void sendChunks() {
|
||||
for (Map.Entry<Long, RelightSkyEntry> entry : skyToRelight.entrySet()) {
|
||||
RelightSkyEntry chunk = entry.getValue();
|
||||
queue.sendChunk(queue.getFaweChunk(chunk.x, chunk.z));
|
||||
CharFaweChunk fc = (CharFaweChunk) queue.getFaweChunk(chunk.x, chunk.z);
|
||||
int mask = 0;
|
||||
for (int y = 0; y < chunk.fix.length; y++) {
|
||||
if (chunk.fix[y]) {
|
||||
mask += 1 << y;
|
||||
}
|
||||
}
|
||||
fc.setBitMask(mask);
|
||||
queue.sendChunk(fc);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -92,6 +92,12 @@ public abstract class FaweChunk<T> {
|
||||
*/
|
||||
public abstract char[][] getCombinedIdArrays();
|
||||
|
||||
/**
|
||||
* The modified sections
|
||||
* @return
|
||||
*/
|
||||
public abstract int getBitMask();
|
||||
|
||||
/**
|
||||
* Get the combined block id at a location<br>
|
||||
* combined = (id <<<< 4) + data
|
||||
|
@ -4,8 +4,6 @@ import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweAPI;
|
||||
import com.boydti.fawe.config.BBC;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.changeset.DiskStorageHistory;
|
||||
import com.boydti.fawe.object.changeset.FaweStreamChangeSet;
|
||||
import com.boydti.fawe.object.clipboard.DiskOptimizedClipboard;
|
||||
import com.boydti.fawe.object.exception.FaweException;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
@ -30,9 +28,6 @@ import com.sk89q.worldedit.world.World;
|
||||
import com.sk89q.worldedit.world.registry.WorldData;
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
@ -111,23 +106,6 @@ public abstract class FawePlayer<T> {
|
||||
if (Settings.CLIPBOARD.USE_DISK) {
|
||||
loadClipboardFromDisk();
|
||||
}
|
||||
if (getSession() == null || getPlayer() == null || session.getSize() != 0 || !Settings.HISTORY.USE_DISK) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
UUID uuid = getUUID();
|
||||
String currentWorldName = getLocation().world;
|
||||
World world = getWorld();
|
||||
if (world != null) {
|
||||
if (Fawe.imp().getWorldName(world).equals(currentWorldName)) {
|
||||
getSession().clearHistory();
|
||||
loadSessionsFromDisk(world);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
MainUtil.handleError(e);
|
||||
Fawe.debug("Failed to load history for: " + getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -135,7 +113,7 @@ public abstract class FawePlayer<T> {
|
||||
* - Should already be called if history on disk is enabled
|
||||
*/
|
||||
public void loadClipboardFromDisk() {
|
||||
File file = new File(Fawe.imp().getDirectory(), "clipboard" + File.separator + getUUID() + ".bd");
|
||||
File file = MainUtil.getFile(Fawe.imp().getDirectory(), Settings.PATHS.CLIPBOARD + File.separator + getUUID() + ".bd");
|
||||
try {
|
||||
if (file.exists() && file.length() > 5) {
|
||||
DiskOptimizedClipboard doc = new DiskOptimizedClipboard(file);
|
||||
@ -174,45 +152,14 @@ public abstract class FawePlayer<T> {
|
||||
|
||||
/**
|
||||
* Load all the undo EditSession's from disk for a world <br>
|
||||
* - Usually already called when a player joins or changes world
|
||||
* - Usually already called when necessary
|
||||
* @param world
|
||||
*/
|
||||
public void loadSessionsFromDisk(final World world) {
|
||||
if (world == null) {
|
||||
return;
|
||||
}
|
||||
final long start = System.currentTimeMillis();
|
||||
final UUID uuid = getUUID();
|
||||
final List<Integer> editIds = new ArrayList<>();
|
||||
final File folder = new File(Fawe.imp().getDirectory(), "history" + File.separator + Fawe.imp().getWorldName(world) + File.separator + uuid);
|
||||
if (folder.isDirectory()) {
|
||||
for (File file : folder.listFiles()) {
|
||||
if (file.getName().endsWith(".bd")) {
|
||||
int index = Integer.parseInt(file.getName().split("\\.")[0]);
|
||||
editIds.add(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (editIds.size() > 0) {
|
||||
BBC.INDEXING_HISTORY.send(this, editIds.size());
|
||||
TaskManager.IMP.async(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Collections.sort(editIds);
|
||||
for (int i = editIds.size() - 1; i >= 0; i--) {
|
||||
int index = editIds.get(i);
|
||||
FaweStreamChangeSet set = new DiskStorageHistory(world, uuid, index);
|
||||
EditSession edit = set.toEditSession(FawePlayer.this);
|
||||
if (world.equals(getWorld())) {
|
||||
session.remember(edit, false, false, Integer.MAX_VALUE);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
BBC.INDEXING_COMPLETE.send(FawePlayer.this, (System.currentTimeMillis() - start) / 1000d);
|
||||
}
|
||||
});
|
||||
}
|
||||
getSession().loadSessionHistoryFromDisk(getUUID(), world);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -417,9 +364,10 @@ public abstract class FawePlayer<T> {
|
||||
*/
|
||||
public void unregister() {
|
||||
if (Settings.HISTORY.DELETE_ON_LOGOUT) {
|
||||
getSession().setClipboard(null);
|
||||
getSession().clearHistory();
|
||||
session = getSession();
|
||||
WorldEdit.getInstance().removeSession(getPlayer());
|
||||
session.setClipboard(null);
|
||||
session.clearHistory();
|
||||
}
|
||||
Fawe.get().unregister(getName());
|
||||
}
|
||||
|
@ -35,11 +35,6 @@ public class DiskStorageHistory extends FaweStreamChangeSet {
|
||||
private File entfFile;
|
||||
private File enttFile;
|
||||
|
||||
/**
|
||||
* Summary of this change (not accurate for larger edits)
|
||||
*/
|
||||
private DiskStorageSummary summary;
|
||||
|
||||
/*
|
||||
* Block data
|
||||
*
|
||||
@ -50,33 +45,20 @@ public class DiskStorageHistory extends FaweStreamChangeSet {
|
||||
* { short rel x, short rel z, unsigned byte y, short combinedFrom, short combinedTo }
|
||||
*/
|
||||
private OutputStream osBD;
|
||||
|
||||
// NBT From
|
||||
private NBTOutputStream osNBTF;
|
||||
|
||||
// NBT To
|
||||
private NBTOutputStream osNBTT;
|
||||
|
||||
// Entity Create From
|
||||
private NBTOutputStream osENTCF;
|
||||
|
||||
// Entity Create To
|
||||
private NBTOutputStream osENTCT;
|
||||
|
||||
private int index;
|
||||
|
||||
public void deleteFiles() {
|
||||
bdFile.delete();
|
||||
nbtfFile.delete();
|
||||
nbttFile.delete();
|
||||
entfFile.delete();
|
||||
enttFile.delete();
|
||||
}
|
||||
|
||||
public DiskStorageHistory(World world, UUID uuid) {
|
||||
super(world);
|
||||
String base = "history" + File.separator + Fawe.imp().getWorldName(world) + File.separator + uuid;
|
||||
File folder = new File(Fawe.imp().getDirectory(), base);
|
||||
File folder = MainUtil.getFile(Fawe.imp().getDirectory(), Settings.PATHS.HISTORY + File.separator + Fawe.imp().getWorldName(world) + File.separator + uuid);
|
||||
int max = 0;
|
||||
if (folder.exists()) {
|
||||
for (File file : folder.listFiles()) {
|
||||
@ -97,16 +79,34 @@ public class DiskStorageHistory extends FaweStreamChangeSet {
|
||||
init(uuid, index);
|
||||
}
|
||||
|
||||
public DiskStorageHistory(File folder, World world, UUID uuid, int i) {
|
||||
super(world);
|
||||
this.uuid = uuid;
|
||||
this.index = i;
|
||||
initFiles(folder);
|
||||
}
|
||||
|
||||
private void initFiles(File folder) {
|
||||
nbtfFile = new File(folder, index + ".nbtf");
|
||||
nbttFile = new File(folder, index + ".nbtt");
|
||||
entfFile = new File(folder, index + ".entf");
|
||||
enttFile = new File(folder, index + ".entt");
|
||||
bdFile = new File(folder, index + ".bd");
|
||||
}
|
||||
|
||||
private void init(UUID uuid, int i) {
|
||||
this.uuid = uuid;
|
||||
this.index = i;
|
||||
String base = "history" + File.separator + Fawe.imp().getWorldName(getWorld()) + File.separator + uuid;
|
||||
base += File.separator + i;
|
||||
nbtfFile = new File(Fawe.imp().getDirectory(), base + ".nbtf");
|
||||
nbttFile = new File(Fawe.imp().getDirectory(), base + ".nbtt");
|
||||
entfFile = new File(Fawe.imp().getDirectory(), base + ".entf");
|
||||
enttFile = new File(Fawe.imp().getDirectory(), base + ".entt");
|
||||
bdFile = new File(Fawe.imp().getDirectory(), base + ".bd");
|
||||
File folder = MainUtil.getFile(Fawe.imp().getDirectory(), Settings.PATHS.HISTORY + File.separator + Fawe.imp().getWorldName(getWorld()) + File.separator + uuid);
|
||||
initFiles(folder);
|
||||
}
|
||||
|
||||
public void deleteFiles() {
|
||||
bdFile.delete();
|
||||
nbtfFile.delete();
|
||||
nbttFile.delete();
|
||||
entfFile.delete();
|
||||
enttFile.delete();
|
||||
}
|
||||
|
||||
public UUID getUUID() {
|
||||
@ -162,6 +162,27 @@ public class DiskStorageHistory extends FaweStreamChangeSet {
|
||||
return 80;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getSizeOnDisk() {
|
||||
int total = 0;
|
||||
if (bdFile.exists()) {
|
||||
total += bdFile.getTotalSpace();
|
||||
}
|
||||
if (nbtfFile.exists()) {
|
||||
total += entfFile.getTotalSpace();
|
||||
}
|
||||
if (nbttFile.exists()) {
|
||||
total += entfFile.getTotalSpace();
|
||||
}
|
||||
if (entfFile.exists()) {
|
||||
total += entfFile.getTotalSpace();
|
||||
}
|
||||
if (enttFile.exists()) {
|
||||
total += entfFile.getTotalSpace();
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream getBlockOS(int x, int y, int z) throws IOException {
|
||||
if (osBD != null) {
|
||||
@ -281,49 +302,46 @@ public class DiskStorageHistory extends FaweStreamChangeSet {
|
||||
}
|
||||
|
||||
public DiskStorageSummary summarize(RegionWrapper requiredRegion, boolean shallow) {
|
||||
if (summary != null) {
|
||||
return summary;
|
||||
}
|
||||
if (bdFile.exists()) {
|
||||
int ox = getOriginX();
|
||||
int oz = getOriginZ();
|
||||
if ((ox != 0 || oz != 0) && !requiredRegion.isIn(ox, oz)) {
|
||||
return summary = new DiskStorageSummary(ox, oz);
|
||||
if (bdFile.exists()) {
|
||||
int ox = getOriginX();
|
||||
int oz = getOriginZ();
|
||||
if ((ox != 0 || oz != 0) && !requiredRegion.isIn(ox, oz)) {
|
||||
return new DiskStorageSummary(ox, oz);
|
||||
}
|
||||
try (FileInputStream fis = new FileInputStream(bdFile)) {
|
||||
FaweInputStream gis = MainUtil.getCompressedIS(fis);
|
||||
// skip mode
|
||||
gis.skip(1);
|
||||
// origin
|
||||
ox = ((gis.read() << 24) + (gis.read() << 16) + (gis.read() << 8) + (gis.read() << 0));
|
||||
oz = ((gis.read() << 24) + (gis.read() << 16) + (gis.read() << 8) + (gis.read() << 0));
|
||||
setOrigin(ox, oz);
|
||||
DiskStorageSummary summary = new DiskStorageSummary(ox, oz);
|
||||
if (!requiredRegion.isIn(ox, oz)) {
|
||||
fis.close();
|
||||
gis.close();
|
||||
return summary;
|
||||
}
|
||||
try (FileInputStream fis = new FileInputStream(bdFile)) {
|
||||
FaweInputStream gis = MainUtil.getCompressedIS(fis);
|
||||
// skip mode
|
||||
gis.skip(1);
|
||||
// origin
|
||||
ox = ((gis.read() << 24) + (gis.read() << 16) + (gis.read() << 8) + (gis.read() << 0));
|
||||
oz = ((gis.read() << 24) + (gis.read() << 16) + (gis.read() << 8) + (gis.read() << 0));
|
||||
setOrigin(ox, oz);
|
||||
summary = new DiskStorageSummary(ox, oz);
|
||||
if (!requiredRegion.isIn(ox, oz)) {
|
||||
byte[] buffer = new byte[9];
|
||||
int i = 0;
|
||||
int amount = (Settings.HISTORY.BUFFER_SIZE - HEADER_SIZE) / 9;
|
||||
while (!shallow && ++i < amount) {
|
||||
if (gis.read(buffer) == -1) {
|
||||
fis.close();
|
||||
gis.close();
|
||||
return summary;
|
||||
}
|
||||
byte[] buffer = new byte[9];
|
||||
int i = 0;
|
||||
int amount = (Settings.HISTORY.BUFFER_SIZE - HEADER_SIZE) / 9;
|
||||
while (!shallow && ++i < amount) {
|
||||
if (gis.read(buffer) == -1) {
|
||||
fis.close();
|
||||
gis.close();
|
||||
return summary;
|
||||
}
|
||||
int x = ((byte) buffer[0] & 0xFF) + ((byte) buffer[1] << 8) + ox;
|
||||
int z = ((byte) buffer[2] & 0xFF) + ((byte) buffer[3] << 8) + oz;
|
||||
int combined1 = buffer[7] & 0xFF;
|
||||
int combined2 = buffer[8] & 0xFF;
|
||||
summary.add(x, z, ((combined2 << 4) + (combined1 >> 4)));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
MainUtil.handleError(e);
|
||||
int x = ((byte) buffer[0] & 0xFF) + ((byte) buffer[1] << 8) + ox;
|
||||
int z = ((byte) buffer[2] & 0xFF) + ((byte) buffer[3] << 8) + oz;
|
||||
int combined1 = buffer[7] & 0xFF;
|
||||
int combined2 = buffer[8] & 0xFF;
|
||||
summary.add(x, z, ((combined2 << 4) + (combined1 >> 4)));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
MainUtil.handleError(e);
|
||||
}
|
||||
return summary;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public IntegerPair readHeader() {
|
||||
|
@ -50,6 +50,10 @@ public abstract class FaweStreamChangeSet extends FaweChangeSet {
|
||||
|
||||
public abstract long getSizeInMemory();
|
||||
|
||||
public long getSizeOnDisk() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public abstract OutputStream getBlockOS(int x, int y, int z) throws IOException;
|
||||
public abstract NBTOutputStream getEntityCreateOS() throws IOException;
|
||||
public abstract NBTOutputStream getEntityRemoveOS() throws IOException;
|
||||
|
@ -56,7 +56,7 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable {
|
||||
private int last;
|
||||
|
||||
public DiskOptimizedClipboard(int width, int height, int length, UUID uuid) {
|
||||
this(width, height, length, new File(Fawe.imp().getDirectory(), "clipboard" + File.separator + uuid + ".bd"));
|
||||
this(width, height, length, MainUtil.getFile(Fawe.imp().getDirectory(), Settings.PATHS.CLIPBOARD + File.separator + uuid + ".bd"));
|
||||
}
|
||||
|
||||
public DiskOptimizedClipboard(File file) throws IOException {
|
||||
@ -176,7 +176,7 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable {
|
||||
}
|
||||
|
||||
public DiskOptimizedClipboard(int width, int height, int length) {
|
||||
this(width, height, length, new File(Fawe.imp().getDirectory(), "clipboard" + File.separator + UUID.randomUUID()));
|
||||
this(width, height, length, MainUtil.getFile(Fawe.imp().getDirectory(), Settings.PATHS.CLIPBOARD + File.separator + UUID.randomUUID() + ".bd"));
|
||||
}
|
||||
|
||||
public void close() {
|
||||
|
@ -1028,8 +1028,9 @@ public class EditSession implements Extent {
|
||||
public void undo(final EditSession editSession) {
|
||||
final UndoContext context = new UndoContext();
|
||||
context.setExtent(editSession.bypassAll);
|
||||
ChangeSet changeSet = getChangeSet();
|
||||
editSession.getQueue().setChangeTask(null);
|
||||
Operations.completeSmart(ChangeSetExecutor.createUndo(getChangeSet(), context), new Runnable() {
|
||||
Operations.completeSmart(ChangeSetExecutor.createUndo(changeSet, context), new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
editSession.flushQueue();
|
||||
@ -1046,8 +1047,9 @@ public class EditSession implements Extent {
|
||||
public void redo(final EditSession editSession) {
|
||||
final UndoContext context = new UndoContext();
|
||||
context.setExtent(editSession.bypassAll);
|
||||
ChangeSet changeSet = getChangeSet();
|
||||
editSession.getQueue().setChangeTask(null);
|
||||
Operations.completeSmart(ChangeSetExecutor.createRedo(getChangeSet(), context), new Runnable() {
|
||||
Operations.completeSmart(ChangeSetExecutor.createRedo(changeSet, context), new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
editSession.flushQueue();
|
||||
|
@ -19,7 +19,13 @@
|
||||
|
||||
package com.sk89q.worldedit;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.FaweInputStream;
|
||||
import com.boydti.fawe.object.FaweOutputStream;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.object.changeset.DiskStorageHistory;
|
||||
import com.boydti.fawe.object.changeset.FaweChangeSet;
|
||||
import com.boydti.fawe.object.clipboard.DiskOptimizedClipboard;
|
||||
import com.boydti.fawe.util.EditSessionBuilder;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
@ -50,15 +56,24 @@ import com.sk89q.worldedit.session.ClipboardHolder;
|
||||
import com.sk89q.worldedit.session.request.Request;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import com.sk89q.worldedit.world.snapshot.Snapshot;
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.swing.filechooser.FileNameExtensionFilter;
|
||||
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
@ -78,14 +93,37 @@ public class LocalSession {
|
||||
// Session related
|
||||
private transient RegionSelector selector = new CuboidRegionSelector();
|
||||
private transient boolean placeAtPos1 = false;
|
||||
private transient List<EditSession> history = Collections.synchronizedList(new LinkedList<EditSession>());
|
||||
private transient volatile int historyPointer = 0;
|
||||
private transient List<Object> history = Collections.synchronizedList(new LinkedList<Object>() {
|
||||
@Override
|
||||
public void add(int index, Object element) { // Integer = Lazy evaluated FaweChangeSet
|
||||
if (element instanceof Integer || element instanceof FaweChangeSet) {
|
||||
super.add(index, element);
|
||||
} else {
|
||||
throw new ClassCastException("Must add either Integer (index) or FaweChangeSet");
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public Object get(int index) {
|
||||
Object value = super.get(index);
|
||||
if (value instanceof Integer) {
|
||||
value = getChangeSet(value);
|
||||
set(index, value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object remove(int index) {
|
||||
return getChangeSet(super.remove(index));
|
||||
}
|
||||
});
|
||||
private transient volatile Integer historyNegativeIndex;
|
||||
private transient volatile long historySize = 0;
|
||||
private transient ClipboardHolder clipboard;
|
||||
private transient boolean toolControl = true;
|
||||
private transient boolean superPickaxe = false;
|
||||
private transient BlockTool pickaxeMode = new SinglePickaxe();
|
||||
private transient Map<Integer, Tool> tools = new HashMap<Integer, Tool>();
|
||||
private transient Map<Integer, Tool> tools = new HashMap<>();
|
||||
private transient int maxBlocksChanged = -1;
|
||||
private transient boolean useInventory;
|
||||
private transient Snapshot snapshot;
|
||||
@ -95,6 +133,10 @@ public class LocalSession {
|
||||
private transient Mask mask;
|
||||
private transient TimeZone timezone = TimeZone.getDefault();
|
||||
|
||||
// May be null
|
||||
private transient World currentWorld;
|
||||
private transient UUID uuid;
|
||||
|
||||
// Saved properties
|
||||
private String lastScript;
|
||||
private RegionSelectorType defaultSelector;
|
||||
@ -136,6 +178,97 @@ public class LocalSession {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param uuid
|
||||
* @param world
|
||||
* @return If any loading occured
|
||||
*/
|
||||
public boolean loadSessionHistoryFromDisk(UUID uuid, World world) {
|
||||
if (world == null || uuid == null) {
|
||||
return false;
|
||||
}
|
||||
if (!world.equals(currentWorld)) {
|
||||
this.uuid = uuid;
|
||||
// Save history
|
||||
saveHistoryNegativeIndex(uuid, currentWorld);
|
||||
history.clear();
|
||||
currentWorld = world;
|
||||
// Load history
|
||||
if (loadHistoryChangeSets(uuid, currentWorld)) {
|
||||
loadHistoryNegativeIndex(uuid, currentWorld);
|
||||
return true;
|
||||
}
|
||||
historyNegativeIndex = 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean loadHistoryChangeSets(UUID uuid, World world) {
|
||||
final List<Integer> editIds = new ArrayList<>();
|
||||
final File folder = MainUtil.getFile(Fawe.imp().getDirectory(), Settings.PATHS.HISTORY + File.separator + Fawe.imp().getWorldName(world) + File.separator + uuid);
|
||||
if (folder.isDirectory()) {
|
||||
final FileNameExtensionFilter filter = new FileNameExtensionFilter("BlockData files","bd");
|
||||
folder.listFiles(new FileFilter() {
|
||||
@Override
|
||||
public boolean accept(File pathname) {
|
||||
String name = pathname.getName();
|
||||
int i = name.lastIndexOf('.');
|
||||
if ((name.length() == i + 3) && (name.charAt(i + 1) == 'b' && name.charAt(i + 2) == 'd')) {
|
||||
int index = Integer.parseInt(name.substring(0, i));
|
||||
editIds.add(index);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
historySize = 0;
|
||||
if (editIds.size() > 0) {
|
||||
Collections.sort(editIds);
|
||||
for (int index : editIds) {
|
||||
history.add(index);
|
||||
}
|
||||
}
|
||||
return editIds.size() > 0;
|
||||
}
|
||||
|
||||
private void loadHistoryNegativeIndex(UUID uuid, World world) {
|
||||
File file = MainUtil.getFile(Fawe.imp().getDirectory(), Settings.PATHS.HISTORY + File.separator + Fawe.imp().getWorldName(world) + File.separator + uuid + File.separator + "index");
|
||||
if (file.exists()) {
|
||||
try {
|
||||
FaweInputStream is = new FaweInputStream(new FileInputStream(file));
|
||||
historyNegativeIndex = Math.min(Math.max(0, is.readInt()), history.size());
|
||||
is.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
historyNegativeIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void saveHistoryNegativeIndex(UUID uuid, World world) {
|
||||
if (world == null) {
|
||||
return;
|
||||
}
|
||||
File file = MainUtil.getFile(Fawe.imp().getDirectory(), Settings.PATHS.HISTORY + File.separator + Fawe.imp().getWorldName(world) + File.separator + uuid + File.separator + "index");
|
||||
if (getHistoryNegativeIndex() != 0) {
|
||||
try {
|
||||
if (file.exists()) {
|
||||
file.getParentFile().mkdirs();
|
||||
file.createNewFile();
|
||||
}
|
||||
FaweOutputStream os = new FaweOutputStream(new FileOutputStream(file));
|
||||
os.writeInt(getHistoryNegativeIndex());
|
||||
os.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else if (file.exists()) {
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether this session is "dirty" and has changes that needs to
|
||||
* be committed.
|
||||
@ -153,6 +286,29 @@ public class LocalSession {
|
||||
dirty.set(true);
|
||||
}
|
||||
|
||||
public int getHistoryIndex() {
|
||||
return history.size() - 1 - (historyNegativeIndex == null ? 0 : historyNegativeIndex);
|
||||
}
|
||||
|
||||
public int getHistoryNegativeIndex() {
|
||||
return (historyNegativeIndex == null ? historyNegativeIndex = 0 : historyNegativeIndex);
|
||||
}
|
||||
|
||||
public void setHistoryIndex(int value) {
|
||||
historyNegativeIndex = history.size() - value - 1;
|
||||
}
|
||||
|
||||
public boolean save() {
|
||||
saveHistoryNegativeIndex(uuid, currentWorld);
|
||||
if (defaultSelector == RegionSelectorType.CUBOID) {
|
||||
defaultSelector = null;
|
||||
}
|
||||
if (lastScript != null || defaultSelector != null) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether this session is "dirty" and has changes that needs to
|
||||
* be committed, and reset it to {@code false}.
|
||||
@ -187,7 +343,7 @@ public class LocalSession {
|
||||
*/
|
||||
public void clearHistory() {
|
||||
history.clear();
|
||||
historyPointer = 0;
|
||||
historyNegativeIndex = 0;
|
||||
historySize = 0;
|
||||
}
|
||||
|
||||
@ -203,6 +359,16 @@ public class LocalSession {
|
||||
remember(editSession, true, false, limit);
|
||||
}
|
||||
|
||||
private FaweChangeSet getChangeSet(Object o) {
|
||||
if (o instanceof FaweChangeSet) {
|
||||
return (FaweChangeSet) o;
|
||||
}
|
||||
if (o instanceof Integer) {
|
||||
return new DiskStorageHistory(currentWorld, this.uuid, (Integer) o);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void remember(final EditSession editSession, final boolean append, final boolean sendMessage, int limitMb) {
|
||||
if (editSession == null || editSession.getChangeSet() == null || limitMb == 0 || ((historySize >> 20) > limitMb && !append)) {
|
||||
return;
|
||||
@ -213,27 +379,41 @@ public class LocalSession {
|
||||
if (editSession.size() == 0 || editSession.hasFastMode()) {
|
||||
return;
|
||||
}
|
||||
FawePlayer fp = editSession.getPlayer();
|
||||
if (fp != null) {
|
||||
loadSessionHistoryFromDisk(fp.getUUID(), editSession.getWorld());
|
||||
}
|
||||
// Destroy any sessions after this undo point
|
||||
if (append) {
|
||||
while (historyPointer < history.size()) {
|
||||
EditSession item = history.get(historyPointer);
|
||||
historySize -= MainUtil.getSizeInMemory(item.getChangeSet());
|
||||
history.remove(historyPointer);
|
||||
int size = getHistoryNegativeIndex();
|
||||
ListIterator<Object> iter = history.listIterator();
|
||||
int i = 0;
|
||||
int cutoffIndex = history.size() - getHistoryNegativeIndex();
|
||||
while (iter.hasNext()) {
|
||||
Object item = iter.next();
|
||||
if (++i > cutoffIndex) {
|
||||
if (item instanceof FaweChangeSet) {
|
||||
FaweChangeSet changeSet = (FaweChangeSet) item;
|
||||
historySize -= MainUtil.getSizeInMemory(changeSet);
|
||||
}
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
historySize += MainUtil.getSizeInMemory(editSession.getChangeSet());
|
||||
FaweChangeSet changeSet = (FaweChangeSet) editSession.getChangeSet();
|
||||
historySize += MainUtil.getSizeInMemory(changeSet);
|
||||
if (append) {
|
||||
history.add(editSession);
|
||||
historyPointer = history.size();
|
||||
history.add(changeSet);
|
||||
if (getHistoryNegativeIndex() != 0) {
|
||||
setDirty();
|
||||
historyNegativeIndex = 0;
|
||||
}
|
||||
} else {
|
||||
history.add(0, editSession);
|
||||
historyPointer++;
|
||||
history.add(0, changeSet);
|
||||
}
|
||||
while ((history.size() > MAX_HISTORY_SIZE || (historySize >> 20) > limitMb) && history.size() > 1) {
|
||||
EditSession item = history.get(0);
|
||||
historySize -= MainUtil.getSizeInMemory(item.getChangeSet());
|
||||
history.remove(0);
|
||||
historyPointer--;
|
||||
FaweChangeSet item = (FaweChangeSet) history.remove(0);
|
||||
historySize -= MainUtil.getSizeInMemory(item);
|
||||
}
|
||||
}
|
||||
|
||||
@ -257,20 +437,26 @@ public class LocalSession {
|
||||
*/
|
||||
public EditSession undo(@Nullable BlockBag newBlockBag, Player player) {
|
||||
checkNotNull(player);
|
||||
--historyPointer;
|
||||
if (historyPointer >= 0) {
|
||||
EditSession editSession = history.get(historyPointer);
|
||||
EditSession newEditSession = new EditSessionBuilder(editSession.getWorld())
|
||||
loadSessionHistoryFromDisk(player.getUniqueId(), player.getWorld());
|
||||
if (getHistoryNegativeIndex() < history.size()) {
|
||||
FaweChangeSet changeSet = (FaweChangeSet) history.get(getHistoryIndex());
|
||||
EditSession newEditSession = new EditSessionBuilder(changeSet.getWorld())
|
||||
.allowedRegionsEverywhere()
|
||||
.checkMemory(false)
|
||||
.changeSetNull()
|
||||
.fastmode(true)
|
||||
.changeSet(changeSet)
|
||||
.fastmode(false)
|
||||
.limitUnlimited()
|
||||
.build();
|
||||
editSession.undo(newEditSession);
|
||||
return editSession;
|
||||
newEditSession.undo(newEditSession);
|
||||
setDirty();
|
||||
historyNegativeIndex++;
|
||||
return newEditSession;
|
||||
} else {
|
||||
historyPointer = 0;
|
||||
int size = history.size();
|
||||
if (getHistoryNegativeIndex() != size) {
|
||||
historyNegativeIndex = history.size();
|
||||
setDirty();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -295,20 +481,21 @@ public class LocalSession {
|
||||
*/
|
||||
public EditSession redo(@Nullable BlockBag newBlockBag, Player player) {
|
||||
checkNotNull(player);
|
||||
if (historyPointer < history.size()) {
|
||||
EditSession editSession = history.get(historyPointer);
|
||||
EditSession newEditSession = new EditSessionBuilder(editSession.getWorld())
|
||||
loadSessionHistoryFromDisk(player.getUniqueId(), player.getWorld());
|
||||
if (getHistoryNegativeIndex() > 0) {
|
||||
setDirty();
|
||||
historyNegativeIndex--;
|
||||
FaweChangeSet changeSet = (FaweChangeSet) history.get(getHistoryIndex());
|
||||
EditSession newEditSession = new EditSessionBuilder(changeSet.getWorld())
|
||||
.allowedRegionsEverywhere()
|
||||
.checkMemory(false)
|
||||
.changeSetNull()
|
||||
.fastmode(true)
|
||||
.changeSet(changeSet)
|
||||
.fastmode(false)
|
||||
.limitUnlimited()
|
||||
.build();
|
||||
editSession.redo(newEditSession);
|
||||
++historyPointer;
|
||||
return editSession;
|
||||
newEditSession.redo(newEditSession);
|
||||
return newEditSession;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -91,7 +91,6 @@ public class HistoryCommands {
|
||||
Vector top = origin.add(radius, radius, radius);
|
||||
RollbackDatabase database = DBHandler.IMP.getDatabase(Fawe.imp().getWorldName(world));
|
||||
final AtomicInteger count = new AtomicInteger();
|
||||
System.out.println("ROLLING BACK");
|
||||
database.getPotentialEdits(other, System.currentTimeMillis() - timeDiff, bot, top, new RunnableVal<DiskStorageHistory>() {
|
||||
@Override
|
||||
public void run(DiskStorageHistory edit) {
|
||||
|
@ -19,8 +19,6 @@
|
||||
|
||||
package com.sk89q.worldedit.session;
|
||||
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.common.util.concurrent.ListeningExecutorService;
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
import com.sk89q.worldedit.LocalConfiguration;
|
||||
@ -33,19 +31,16 @@ import com.sk89q.worldedit.session.storage.SessionStore;
|
||||
import com.sk89q.worldedit.session.storage.VoidStore;
|
||||
import com.sk89q.worldedit.util.concurrency.EvenMoreExecutors;
|
||||
import com.sk89q.worldedit.util.eventbus.Subscribe;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
@ -58,14 +53,22 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
||||
*/
|
||||
public class SessionManager {
|
||||
|
||||
@Deprecated
|
||||
public static int EXPIRATION_GRACE = 600000;
|
||||
private static final int FLUSH_PERIOD = 1000 * 30;
|
||||
|
||||
private static final ListeningExecutorService executorService = MoreExecutors.listeningDecorator(EvenMoreExecutors.newBoundedCachedThreadPool(0, 1, 5));
|
||||
private static final Logger log = Logger.getLogger(SessionManager.class.getCanonicalName());
|
||||
private final Timer timer = new Timer();
|
||||
private final WorldEdit worldEdit;
|
||||
private final Map<UUID, SessionHolder> sessions = new HashMap<UUID, SessionHolder>();
|
||||
private final Map<UUID, SessionHolder> sessions = new ConcurrentHashMap<UUID, SessionHolder>();
|
||||
private SessionStore store = new VoidStore();
|
||||
private File path;
|
||||
|
||||
// Added //
|
||||
|
||||
// private final ConcurrentLinkedDeque<SessionHolder> toSave = new ConcurrentLinkedDeque<>();
|
||||
///////////
|
||||
|
||||
|
||||
/**
|
||||
* Create a new session manager.
|
||||
@ -77,7 +80,6 @@ public class SessionManager {
|
||||
this.worldEdit = worldEdit;
|
||||
|
||||
worldEdit.getEventBus().register(this);
|
||||
timer.schedule(new SessionTracker(), FLUSH_PERIOD, FLUSH_PERIOD);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -191,44 +193,26 @@ public class SessionManager {
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save a map of sessions to disk.
|
||||
*
|
||||
* @param sessions a map of sessions to save
|
||||
* @return a future that completes on save or error
|
||||
*/
|
||||
private ListenableFuture<?> commit(final Map<SessionKey, LocalSession> sessions) {
|
||||
checkNotNull(sessions);
|
||||
|
||||
if (sessions.isEmpty()) {
|
||||
return Futures.immediateFuture(sessions);
|
||||
}
|
||||
|
||||
return executorService.submit(new Callable<Object>() {
|
||||
@Override
|
||||
public Object call() throws Exception {
|
||||
Exception exception = null;
|
||||
|
||||
for (Map.Entry<SessionKey, LocalSession> entry : sessions.entrySet()) {
|
||||
SessionKey key = entry.getKey();
|
||||
|
||||
if (key.isPersistent()) {
|
||||
try {
|
||||
store.save(getKey(key), entry.getValue());
|
||||
} catch (IOException e) {
|
||||
log.log(Level.WARNING, "Failed to write session for UUID " + getKey(key), e);
|
||||
exception = e;
|
||||
private void save(SessionHolder holder) {
|
||||
SessionKey key = holder.key;
|
||||
if (key.isPersistent()) {
|
||||
try {
|
||||
if (holder.session.compareAndResetDirty()) {
|
||||
if (holder.session.save()) {
|
||||
store.save(getKey(key), holder.session);
|
||||
} else if (path != null) {
|
||||
File file = new File(path, getKey(key) + ".json");
|
||||
if (file.exists()) {
|
||||
if (!file.delete()) {
|
||||
file.deleteOnExit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (exception != null) {
|
||||
throw exception;
|
||||
}
|
||||
|
||||
return sessions;
|
||||
} catch (IOException e) {
|
||||
log.log(Level.WARNING, "Failed to write session for UUID " + getKey(key), e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -264,13 +248,16 @@ public class SessionManager {
|
||||
*/
|
||||
public synchronized void remove(SessionOwner owner) {
|
||||
checkNotNull(owner);
|
||||
sessions.remove(getKey(owner));
|
||||
save(sessions.remove(getKey(owner)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all sessions.
|
||||
*/
|
||||
public synchronized void clear() {
|
||||
for (Map.Entry<UUID, SessionHolder> entry : sessions.entrySet()) {
|
||||
save(entry.getValue());
|
||||
}
|
||||
sessions.clear();
|
||||
}
|
||||
|
||||
@ -279,6 +266,7 @@ public class SessionManager {
|
||||
LocalConfiguration config = event.getConfiguration();
|
||||
File dir = new File(config.getWorkingDirectory(), "sessions");
|
||||
store = new JsonFileSessionStore(dir);
|
||||
this.path = dir;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -295,42 +283,9 @@ public class SessionManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes inactive sessions after they have been inactive for a period
|
||||
* of time. Commits them as well.
|
||||
*/
|
||||
private class SessionTracker extends TimerTask {
|
||||
@Override
|
||||
public void run() {
|
||||
synchronized (SessionManager.this) {
|
||||
long now = System.currentTimeMillis();
|
||||
Iterator<SessionHolder> it = sessions.values().iterator();
|
||||
Map<SessionKey, LocalSession> saveQueue = new HashMap<SessionKey, LocalSession>();
|
||||
|
||||
while (it.hasNext()) {
|
||||
SessionHolder stored = it.next();
|
||||
if (stored.key.isActive()) {
|
||||
stored.lastActive = now;
|
||||
|
||||
if (stored.session.compareAndResetDirty()) {
|
||||
saveQueue.put(stored.key, stored.session);
|
||||
}
|
||||
} else {
|
||||
if (now - stored.lastActive > EXPIRATION_GRACE) {
|
||||
if (stored.session.compareAndResetDirty()) {
|
||||
saveQueue.put(stored.key, stored.session);
|
||||
}
|
||||
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!saveQueue.isEmpty()) {
|
||||
commit(saveQueue);
|
||||
}
|
||||
}
|
||||
}
|
||||
public static Class<?> inject() {
|
||||
return SessionManager.class;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
package com.boydti.fawe.forge;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
@ -72,10 +71,6 @@ public class ForgeMain {
|
||||
FawePlayer fp = FawePlayer.wrap(player);
|
||||
if (fp.getMeta("lastWorld") != event.getWorld()) {
|
||||
fp.setMeta("lastWorld", event.getWorld());
|
||||
if (Settings.HISTORY.USE_DISK) {
|
||||
fp.getSession().clearHistory();
|
||||
fp.loadSessionsFromDisk(fp.getWorld());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ import com.boydti.fawe.object.RunnableVal;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.boydti.fawe.util.ReflectionUtils;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.ListTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
@ -18,6 +17,7 @@ import com.sk89q.jnbt.Tag;
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
@ -31,20 +31,16 @@ import net.minecraft.block.Block;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityList;
|
||||
import net.minecraft.entity.EntityTracker;
|
||||
import net.minecraft.entity.EntityTrackerEntry;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.nbt.NBTBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.network.play.server.SPacketChunkData;
|
||||
import net.minecraft.network.play.server.SPacketDestroyEntities;
|
||||
import net.minecraft.server.management.PlayerChunkMap;
|
||||
import net.minecraft.server.management.PlayerChunkMapEntry;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.ClassInheritanceMultiMap;
|
||||
import net.minecraft.util.IntHashMap;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
import net.minecraft.world.EnumSkyBlock;
|
||||
@ -513,7 +509,9 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refreshChunk(World world, net.minecraft.world.chunk.Chunk nmsChunk) {
|
||||
public void refreshChunk(FaweChunk fc) {
|
||||
ForgeChunk_All fs = (ForgeChunk_All) fc;
|
||||
Chunk nmsChunk = fs.getChunk();
|
||||
if (!nmsChunk.isLoaded()) {
|
||||
return;
|
||||
}
|
||||
@ -523,75 +521,44 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
|
||||
PlayerChunkMap chunkMap = w.getPlayerChunkMap();
|
||||
int x = pos.chunkXPos;
|
||||
int z = pos.chunkZPos;
|
||||
if (!chunkMap.contains(x, z)) {
|
||||
PlayerChunkMapEntry chunkMapEntry = chunkMap.getEntry(x, z);
|
||||
if (chunkMapEntry == null) {
|
||||
return;
|
||||
}
|
||||
EntityTracker tracker = w.getEntityTracker();
|
||||
HashSet<EntityPlayerMP> players = new HashSet<>();
|
||||
for (EntityPlayer player : w.playerEntities) {
|
||||
if (player instanceof EntityPlayerMP) {
|
||||
if (chunkMap.isPlayerWatchingChunk((EntityPlayerMP) player, x, z)) {
|
||||
players.add((EntityPlayerMP) player);
|
||||
}
|
||||
final ArrayDeque<EntityPlayerMP> players = new ArrayDeque<>();
|
||||
chunkMapEntry.hasPlayerMatching(input -> {
|
||||
players.add(input);
|
||||
return false;
|
||||
});
|
||||
int mask = fc.getBitMask();
|
||||
if (mask == 65535 && hasEntities(nmsChunk)) {
|
||||
SPacketChunkData packet = new SPacketChunkData(nmsChunk, 65280);
|
||||
for (EntityPlayerMP player : players) {
|
||||
player.connection.sendPacket(packet);
|
||||
}
|
||||
mask = 255;
|
||||
}
|
||||
if (players.size() == 0) {
|
||||
return;
|
||||
}
|
||||
HashSet<EntityTrackerEntry> entities = new HashSet<>();
|
||||
ClassInheritanceMultiMap<Entity>[] entitieSlices = nmsChunk.getEntityLists();
|
||||
IntHashMap<EntityTrackerEntry> entries = null;
|
||||
for (Field field : tracker.getClass().getDeclaredFields()) {
|
||||
if (field.getType() == IntHashMap.class) {
|
||||
field.setAccessible(true);
|
||||
entries = (IntHashMap<EntityTrackerEntry>) field.get(tracker);
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (ClassInheritanceMultiMap<Entity> slice : entitieSlices) {
|
||||
if (slice == null) {
|
||||
continue;
|
||||
}
|
||||
for (Entity ent : slice) {
|
||||
EntityTrackerEntry entry = entries != null ? entries.lookup(ent.getEntityId()) : null;
|
||||
if (entry == null) {
|
||||
continue;
|
||||
}
|
||||
entities.add(entry);
|
||||
SPacketDestroyEntities packet = new SPacketDestroyEntities(ent.getEntityId());
|
||||
for (EntityPlayerMP player : players) {
|
||||
player.connection.sendPacket(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Send chunks
|
||||
SPacketChunkData packet = new SPacketChunkData(nmsChunk, 65535);
|
||||
SPacketChunkData packet = new SPacketChunkData(nmsChunk, mask);
|
||||
for (EntityPlayerMP player : players) {
|
||||
player.connection.sendPacket(packet);
|
||||
}
|
||||
// send ents
|
||||
for (EntityTrackerEntry entry : entities) {
|
||||
try {
|
||||
TaskManager.IMP.later(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (EntityPlayerMP player : players) {
|
||||
boolean result = entry.trackingPlayers.remove(player);
|
||||
if (result && entry.getTrackedEntity() != player) {
|
||||
entry.updatePlayerEntity(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 2);
|
||||
} catch (Throwable e) {
|
||||
MainUtil.handleError(e);
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
MainUtil.handleError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasEntities(Chunk nmsChunk) {
|
||||
ClassInheritanceMultiMap<Entity>[] entities = nmsChunk.getEntityLists();
|
||||
for (int i = 0; i < entities.length; i++) {
|
||||
ClassInheritanceMultiMap<Entity> slice = entities[i];
|
||||
if (slice != null && !slice.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public FaweChunk<Chunk> getFaweChunk(int x, int z) {
|
||||
return new ForgeChunk_All(this, x, z);
|
||||
|
@ -1,7 +1,6 @@
|
||||
package com.boydti.fawe.forge;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import cpw.mods.fml.common.FMLCommonHandler;
|
||||
import cpw.mods.fml.common.Mod;
|
||||
@ -73,10 +72,6 @@ public class ForgeMain {
|
||||
FawePlayer fp = FawePlayer.wrap(player);
|
||||
if (fp.getMeta("lastWorld") != event.world) {
|
||||
fp.setMeta("lastWorld", event.world);
|
||||
if (Settings.HISTORY.USE_DISK) {
|
||||
fp.getSession().clearHistory();
|
||||
fp.loadSessionsFromDisk(fp.getWorld());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,6 @@ import com.boydti.fawe.object.RunnableVal;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.boydti.fawe.util.ReflectionUtils;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.ListTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
@ -31,17 +30,13 @@ import java.util.UUID;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityList;
|
||||
import net.minecraft.entity.EntityTracker;
|
||||
import net.minecraft.entity.EntityTrackerEntry;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.nbt.NBTBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.network.play.server.S13PacketDestroyEntities;
|
||||
import net.minecraft.network.play.server.S21PacketChunkData;
|
||||
import net.minecraft.server.management.PlayerManager;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.IntHashMap;
|
||||
import net.minecraft.util.LongHashMap;
|
||||
import net.minecraft.world.ChunkCoordIntPair;
|
||||
import net.minecraft.world.ChunkPosition;
|
||||
@ -216,21 +211,21 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
|
||||
};
|
||||
|
||||
@Override
|
||||
public void refreshChunk(World world, net.minecraft.world.chunk.Chunk nmsChunk) {
|
||||
public void refreshChunk(FaweChunk fc) {
|
||||
ForgeChunk_All fs = (ForgeChunk_All) fc;
|
||||
Chunk nmsChunk = fs.getChunk();
|
||||
if (!nmsChunk.isChunkLoaded) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
ChunkCoordIntPair pos = nmsChunk.getChunkCoordIntPair();
|
||||
WorldServer w = (WorldServer) nmsChunk.worldObj;
|
||||
PlayerManager chunkMap = w.getPlayerManager();
|
||||
int x = pos.chunkXPos;
|
||||
int z = pos.chunkZPos;
|
||||
int x = nmsChunk.xPosition;
|
||||
int z = nmsChunk.zPosition;
|
||||
if (!chunkMap.func_152621_a(x, z)) {
|
||||
return;
|
||||
}
|
||||
EntityTracker tracker = w.getEntityTracker();
|
||||
final HashSet<EntityPlayerMP> players = new HashSet<>();
|
||||
HashSet<EntityPlayerMP> players = new HashSet<>();
|
||||
for (EntityPlayer player : (List<EntityPlayer>) w.playerEntities) {
|
||||
if (player instanceof EntityPlayerMP) {
|
||||
if (chunkMap.isPlayerWatchingChunk((EntityPlayerMP) player, x, z)) {
|
||||
@ -241,60 +236,34 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
|
||||
if (players.size() == 0) {
|
||||
return;
|
||||
}
|
||||
HashSet<EntityTrackerEntry> entities = new HashSet<>();
|
||||
Collection<Entity>[] entitieSlices = nmsChunk.entityLists;
|
||||
IntHashMap entries = null;
|
||||
for (Field field : tracker.getClass().getDeclaredFields()) {
|
||||
if (field.getType() == IntHashMap.class) {
|
||||
field.setAccessible(true);
|
||||
entries = (IntHashMap) field.get(tracker);
|
||||
break;
|
||||
int mask = fc.getBitMask();
|
||||
if (mask == 65535 && hasEntities(nmsChunk)) {
|
||||
S21PacketChunkData packet = new S21PacketChunkData(nmsChunk, false, 65280);
|
||||
for (EntityPlayerMP player : players) {
|
||||
player.playerNetServerHandler.sendPacket(packet);
|
||||
}
|
||||
mask = 255;
|
||||
}
|
||||
for (Collection<Entity> slice : entitieSlices) {
|
||||
if (slice == null) {
|
||||
continue;
|
||||
}
|
||||
for (Entity ent : slice) {
|
||||
EntityTrackerEntry entry = entries != null ? (EntityTrackerEntry) entries.lookup(ent.getEntityId()) : null;
|
||||
if (entry == null) {
|
||||
continue;
|
||||
}
|
||||
entities.add(entry);
|
||||
S13PacketDestroyEntities packet = new S13PacketDestroyEntities(ent.getEntityId());
|
||||
for (EntityPlayerMP player : players) {
|
||||
player.playerNetServerHandler.sendPacket(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Send chunks
|
||||
S21PacketChunkData packet = new S21PacketChunkData(nmsChunk, false, 65535);
|
||||
S21PacketChunkData packet = new S21PacketChunkData(nmsChunk, false, mask);
|
||||
for (EntityPlayerMP player : players) {
|
||||
player.playerNetServerHandler.sendPacket(packet);
|
||||
}
|
||||
// send ents
|
||||
for (final EntityTrackerEntry entry : entities) {
|
||||
try {
|
||||
TaskManager.IMP.later(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (EntityPlayerMP player : players) {
|
||||
boolean result = entry.trackingPlayers.remove(player);
|
||||
if (result && entry.myEntity != player) {
|
||||
entry.tryStartWachingThis(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 2);
|
||||
} catch (Throwable e) {
|
||||
MainUtil.handleError(e);
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
MainUtil.handleError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasEntities(Chunk nmsChunk) {
|
||||
for (int i = 0; i < nmsChunk.entityLists.length; i++) {
|
||||
List slice = nmsChunk.entityLists[i];
|
||||
if (slice != null && !slice.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean setComponents(FaweChunk fc, RunnableVal<FaweChunk> changeTask) {
|
||||
ForgeChunk_All fs = (ForgeChunk_All) fc;
|
||||
|
@ -1,7 +1,6 @@
|
||||
package com.boydti.fawe.forge;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
@ -73,10 +72,6 @@ public class ForgeMain {
|
||||
FawePlayer fp = FawePlayer.wrap(player);
|
||||
if (fp.getMeta("lastWorld") != event.world) {
|
||||
fp.setMeta("lastWorld", event.world);
|
||||
if (Settings.HISTORY.USE_DISK) {
|
||||
fp.getSession().clearHistory();
|
||||
fp.loadSessionsFromDisk(fp.getWorld());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ import com.boydti.fawe.object.RunnableVal;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.boydti.fawe.util.ReflectionUtils;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.ListTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
@ -29,19 +28,15 @@ import java.util.UUID;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityList;
|
||||
import net.minecraft.entity.EntityTracker;
|
||||
import net.minecraft.entity.EntityTrackerEntry;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.nbt.NBTBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.network.play.server.S13PacketDestroyEntities;
|
||||
import net.minecraft.network.play.server.S21PacketChunkData;
|
||||
import net.minecraft.server.management.PlayerManager;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.BlockPos;
|
||||
import net.minecraft.util.ClassInheritanceMultiMap;
|
||||
import net.minecraft.util.IntHashMap;
|
||||
import net.minecraft.world.ChunkCoordIntPair;
|
||||
import net.minecraft.world.EnumSkyBlock;
|
||||
import net.minecraft.world.World;
|
||||
@ -453,20 +448,20 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refreshChunk(World world, net.minecraft.world.chunk.Chunk nmsChunk) {
|
||||
public void refreshChunk(FaweChunk fc) {
|
||||
ForgeChunk_All fs = (ForgeChunk_All) fc;
|
||||
Chunk nmsChunk = fs.getChunk();
|
||||
if (!nmsChunk.isLoaded()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
ChunkCoordIntPair pos = nmsChunk.getChunkCoordIntPair();
|
||||
WorldServer w = (WorldServer) nmsChunk.getWorld();
|
||||
PlayerManager chunkMap = w.getPlayerManager();
|
||||
int x = pos.chunkXPos;
|
||||
int z = pos.chunkZPos;
|
||||
int x = nmsChunk.xPosition;
|
||||
int z = nmsChunk.zPosition;
|
||||
if (!chunkMap.hasPlayerInstance(x, z)) {
|
||||
return;
|
||||
}
|
||||
EntityTracker tracker = w.getEntityTracker();
|
||||
HashSet<EntityPlayerMP> players = new HashSet<>();
|
||||
for (EntityPlayer player : w.playerEntities) {
|
||||
if (player instanceof EntityPlayerMP) {
|
||||
@ -478,60 +473,35 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
|
||||
if (players.size() == 0) {
|
||||
return;
|
||||
}
|
||||
HashSet<EntityTrackerEntry> entities = new HashSet<>();
|
||||
ClassInheritanceMultiMap<Entity>[] entitieSlices = nmsChunk.getEntityLists();
|
||||
IntHashMap<EntityTrackerEntry> entries = null;
|
||||
for (Field field : tracker.getClass().getDeclaredFields()) {
|
||||
if (field.getType() == IntHashMap.class) {
|
||||
field.setAccessible(true);
|
||||
entries = (IntHashMap<EntityTrackerEntry>) field.get(tracker);
|
||||
break;
|
||||
int mask = fc.getBitMask();
|
||||
if (mask == 65535 && hasEntities(nmsChunk)) {
|
||||
S21PacketChunkData packet = new S21PacketChunkData(nmsChunk, false, 65280);
|
||||
for (EntityPlayerMP player : players) {
|
||||
player.playerNetServerHandler.sendPacket(packet);
|
||||
}
|
||||
mask = 255;
|
||||
}
|
||||
for (ClassInheritanceMultiMap<Entity> slice : entitieSlices) {
|
||||
if (slice == null) {
|
||||
continue;
|
||||
}
|
||||
for (Entity ent : slice) {
|
||||
EntityTrackerEntry entry = entries != null ? entries.lookup(ent.getEntityId()) : null;
|
||||
if (entry == null) {
|
||||
continue;
|
||||
}
|
||||
entities.add(entry);
|
||||
S13PacketDestroyEntities packet = new S13PacketDestroyEntities(ent.getEntityId());
|
||||
for (EntityPlayerMP player : players) {
|
||||
player.playerNetServerHandler.sendPacket(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Send chunks
|
||||
S21PacketChunkData packet = new S21PacketChunkData(nmsChunk, false, 65535);
|
||||
S21PacketChunkData packet = new S21PacketChunkData(nmsChunk, false, mask);
|
||||
for (EntityPlayerMP player : players) {
|
||||
player.playerNetServerHandler.sendPacket(packet);
|
||||
}
|
||||
// send ents
|
||||
for (EntityTrackerEntry entry : entities) {
|
||||
try {
|
||||
TaskManager.IMP.later(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (EntityPlayerMP player : players) {
|
||||
boolean result = entry.trackingPlayers.remove(player);
|
||||
if (result && entry.trackedEntity != player) {
|
||||
entry.updatePlayerEntity(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 2);
|
||||
} catch (Throwable e) {
|
||||
MainUtil.handleError(e);
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
MainUtil.handleError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasEntities(Chunk nmsChunk) {
|
||||
ClassInheritanceMultiMap<Entity>[] entities = nmsChunk.getEntityLists();
|
||||
for (int i = 0; i < entities.length; i++) {
|
||||
ClassInheritanceMultiMap<Entity> slice = entities[i];
|
||||
if (slice != null && !slice.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public FaweChunk<Chunk> getFaweChunk(int x, int z) {
|
||||
return new ForgeChunk_All(this, x, z);
|
||||
|
@ -1,7 +1,6 @@
|
||||
package com.boydti.fawe.forge;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
@ -72,10 +71,6 @@ public class ForgeMain {
|
||||
FawePlayer fp = FawePlayer.wrap(player);
|
||||
if (fp.getMeta("lastWorld") != event.getWorld()) {
|
||||
fp.setMeta("lastWorld", event.getWorld());
|
||||
if (Settings.HISTORY.USE_DISK) {
|
||||
fp.getSession().clearHistory();
|
||||
fp.loadSessionsFromDisk(fp.getWorld());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ import com.boydti.fawe.object.RunnableVal;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.boydti.fawe.util.ReflectionUtils;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.ListTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
@ -18,6 +17,7 @@ import com.sk89q.jnbt.Tag;
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
@ -31,20 +31,16 @@ import net.minecraft.block.Block;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityList;
|
||||
import net.minecraft.entity.EntityTracker;
|
||||
import net.minecraft.entity.EntityTrackerEntry;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.nbt.NBTBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.network.play.server.SPacketChunkData;
|
||||
import net.minecraft.network.play.server.SPacketDestroyEntities;
|
||||
import net.minecraft.server.management.PlayerChunkMap;
|
||||
import net.minecraft.server.management.PlayerChunkMapEntry;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.ClassInheritanceMultiMap;
|
||||
import net.minecraft.util.IntHashMap;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
import net.minecraft.world.EnumSkyBlock;
|
||||
@ -513,7 +509,9 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refreshChunk(World world, net.minecraft.world.chunk.Chunk nmsChunk) {
|
||||
public void refreshChunk(FaweChunk fc) {
|
||||
ForgeChunk_All fs = (ForgeChunk_All) fc;
|
||||
Chunk nmsChunk = fs.getChunk();
|
||||
if (!nmsChunk.isLoaded()) {
|
||||
return;
|
||||
}
|
||||
@ -523,75 +521,43 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
|
||||
PlayerChunkMap chunkMap = w.getPlayerChunkMap();
|
||||
int x = pos.chunkXPos;
|
||||
int z = pos.chunkZPos;
|
||||
if (!chunkMap.contains(x, z)) {
|
||||
PlayerChunkMapEntry chunkMapEntry = chunkMap.getEntry(x, z);
|
||||
if (chunkMapEntry == null) {
|
||||
return;
|
||||
}
|
||||
EntityTracker tracker = w.getEntityTracker();
|
||||
HashSet<EntityPlayerMP> players = new HashSet<>();
|
||||
for (EntityPlayer player : w.playerEntities) {
|
||||
if (player instanceof EntityPlayerMP) {
|
||||
if (chunkMap.isPlayerWatchingChunk((EntityPlayerMP) player, x, z)) {
|
||||
players.add((EntityPlayerMP) player);
|
||||
}
|
||||
final ArrayDeque<EntityPlayerMP> players = new ArrayDeque<>();
|
||||
chunkMapEntry.hasPlayerMatching(input -> {
|
||||
players.add(input);
|
||||
return false;
|
||||
});
|
||||
int mask = fc.getBitMask();
|
||||
if (mask == 65535 && hasEntities(nmsChunk)) {
|
||||
SPacketChunkData packet = new SPacketChunkData(nmsChunk, 65280);
|
||||
for (EntityPlayerMP player : players) {
|
||||
player.connection.sendPacket(packet);
|
||||
}
|
||||
mask = 255;
|
||||
}
|
||||
if (players.size() == 0) {
|
||||
return;
|
||||
}
|
||||
HashSet<EntityTrackerEntry> entities = new HashSet<>();
|
||||
ClassInheritanceMultiMap<Entity>[] entitieSlices = nmsChunk.getEntityLists();
|
||||
IntHashMap<EntityTrackerEntry> entries = null;
|
||||
for (Field field : tracker.getClass().getDeclaredFields()) {
|
||||
if (field.getType() == IntHashMap.class) {
|
||||
field.setAccessible(true);
|
||||
entries = (IntHashMap<EntityTrackerEntry>) field.get(tracker);
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (ClassInheritanceMultiMap<Entity> slice : entitieSlices) {
|
||||
if (slice == null) {
|
||||
continue;
|
||||
}
|
||||
for (Entity ent : slice) {
|
||||
EntityTrackerEntry entry = entries != null ? entries.lookup(ent.getEntityId()) : null;
|
||||
if (entry == null) {
|
||||
continue;
|
||||
}
|
||||
entities.add(entry);
|
||||
SPacketDestroyEntities packet = new SPacketDestroyEntities(ent.getEntityId());
|
||||
for (EntityPlayerMP player : players) {
|
||||
player.connection.sendPacket(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Send chunks
|
||||
SPacketChunkData packet = new SPacketChunkData(nmsChunk, 65535);
|
||||
SPacketChunkData packet = new SPacketChunkData(nmsChunk, mask);
|
||||
for (EntityPlayerMP player : players) {
|
||||
player.connection.sendPacket(packet);
|
||||
}
|
||||
// send ents
|
||||
for (EntityTrackerEntry entry : entities) {
|
||||
try {
|
||||
TaskManager.IMP.later(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (EntityPlayerMP player : players) {
|
||||
boolean result = entry.trackingPlayers.remove(player);
|
||||
if (result && entry.getTrackedEntity() != player) {
|
||||
entry.updatePlayerEntity(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 2);
|
||||
} catch (Throwable e) {
|
||||
MainUtil.handleError(e);
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
MainUtil.handleError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasEntities(Chunk nmsChunk) {
|
||||
ClassInheritanceMultiMap<Entity>[] entities = nmsChunk.getEntityLists();
|
||||
for (int i = 0; i < entities.length; i++) {
|
||||
ClassInheritanceMultiMap<Entity> slice = entities[i];
|
||||
if (slice != null && !slice.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FaweChunk<Chunk> getFaweChunk(int x, int z) {
|
||||
return new ForgeChunk_All(this, x, z);
|
||||
|
Loading…
Reference in New Issue
Block a user