From 1ed87eabbce2b55b337a5d9232082901a75c91cd Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Tue, 9 Aug 2016 14:32:51 +1000 Subject: [PATCH] Various Per world session history index when using disk Configurable clipboard/history save locations Fixed and optimized packet sending History caching optimizations (instant now) --- .../com/boydti/fawe/bukkit/FaweBukkit.java | 4 - .../boydti/fawe/bukkit/v0/BukkitQueue_0.java | 4 +- .../fawe/bukkit/v1_10/BukkitQueue_1_10.java | 95 ++----- .../fawe/bukkit/v1_7/BukkitQueue17.java | 64 ++--- .../fawe/bukkit/v1_8/BukkitQueue18R3.java | 76 ++---- .../fawe/bukkit/v1_9/BukkitQueue_1_9_R1.java | 103 +++---- core/src/main/java/com/boydti/fawe/Fawe.java | 6 +- .../main/java/com/boydti/fawe/FaweAPI.java | 2 +- .../java/com/boydti/fawe/config/Settings.java | 12 +- .../fawe/database/RollbackDatabase.java | 3 +- .../boydti/fawe/example/CharFaweChunk.java | 18 ++ .../fawe/example/NMSMappedFaweQueue.java | 4 +- .../com/boydti/fawe/example/NMSRelighter.java | 10 +- .../com/boydti/fawe/object/FaweChunk.java | 6 + .../com/boydti/fawe/object/FawePlayer.java | 64 +---- .../object/changeset/DiskStorageHistory.java | 142 +++++----- .../object/changeset/FaweStreamChangeSet.java | 4 + .../clipboard/DiskOptimizedClipboard.java | 4 +- .../java/com/sk89q/worldedit/EditSession.java | 6 +- .../com/sk89q/worldedit/LocalSession.java | 257 +++++++++++++++--- .../worldedit/command/HistoryCommands.java | 1 - .../worldedit/session/SessionManager.java | 119 +++----- core/src/main/java/com/test.das | 0 .../java/com/boydti/fawe/forge/ForgeMain.java | 5 - .../boydti/fawe/forge/v0/ForgeQueue_All.java | 93 ++----- .../java/com/boydti/fawe/forge/ForgeMain.java | 5 - .../boydti/fawe/forge/v0/ForgeQueue_All.java | 79 ++---- .../java/com/boydti/fawe/forge/ForgeMain.java | 5 - .../boydti/fawe/forge/v0/ForgeQueue_All.java | 78 ++---- .../java/com/boydti/fawe/forge/ForgeMain.java | 5 - .../boydti/fawe/forge/v0/ForgeQueue_All.java | 92 ++----- 31 files changed, 628 insertions(+), 738 deletions(-) delete mode 100644 core/src/main/java/com/test.das diff --git a/bukkit0/src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java b/bukkit0/src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java index 669c5a1c..f9da7546 100644 --- a/bukkit0/src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java +++ b/bukkit0/src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java @@ -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 diff --git a/bukkit0/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_0.java b/bukkit0/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_0.java index 427ce12b..9ffcf173 100644 --- a/bukkit0/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_0.java +++ b/bukkit0/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_0.java @@ -134,9 +134,7 @@ public abstract class BukkitQueue_0 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) { diff --git a/bukkit110/src/main/java/com/boydti/fawe/bukkit/v1_10/BukkitQueue_1_10.java b/bukkit110/src/main/java/com/boydti/fawe/bukkit/v1_10/BukkitQueue_1_10.java index 5eb9e51b..03d31ac6 100644 --- a/bukkit110/src/main/java/com/boydti/fawe/bukkit/v1_10/BukkitQueue_1_10.java +++ b/bukkit110/src/main/java/com/boydti/fawe/bukkit/v1_10/BukkitQueue_1_10.java @@ -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 set = new HashSet(playerChunk.c); - EntityTracker tracker = w.getTracker(); - // Get players - final HashSet 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 entities = new HashSet<>(); - Collection[] entitieSlices = (Collection[]) getEntitySlices.invoke(nmsChunk); - for (Collection 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 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[] entities = (Collection[]) getEntitySlices.invoke(nmsChunk); + for (int i = 0; i < entities.length; i++) { + Collection 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 clazzChunk = nmsChunk.getClass(); - final Field ef = clazzChunk.getDeclaredField("entitySlices"); - final Collection[] entities = (Collection[]) ef.get(nmsChunk); + final Collection[] entities = (Collection[]) getEntitySlices.invoke(nmsChunk); Map tiles = nmsChunk.getTileEntities(); // Remove entities for (int i = 0; i < entities.length; i++) { diff --git a/bukkit1710/src/main/java/com/boydti/fawe/bukkit/v1_7/BukkitQueue17.java b/bukkit1710/src/main/java/com/boydti/fawe/bukkit/v1_7/BukkitQueue17.java index 19029bd3..8e49f11a 100644 --- a/bukkit1710/src/main/java/com/boydti/fawe/bukkit/v1_7/BukkitQueue17.java +++ b/bukkit1710/src/main/java/com/boydti/fawe/bukkit/v1_7/BukkitQueue17.java @@ -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 entities = new HashSet<>(); - List[] entitieSlices = nmsChunk.entitySlices; - for (List 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 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) { diff --git a/bukkit18/src/main/java/com/boydti/fawe/bukkit/v1_8/BukkitQueue18R3.java b/bukkit18/src/main/java/com/boydti/fawe/bukkit/v1_8/BukkitQueue18R3.java index b55b2c5c..8cf8d20a 100644 --- a/bukkit18/src/main/java/com/boydti/fawe/bukkit/v1_8/BukkitQueue18R3.java +++ b/bukkit18/src/main/java/com/boydti/fawe/bukkit/v1_8/BukkitQueue18R3.java @@ -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 set = new HashSet(); - EntityTracker tracker = w.getTracker(); - // Get players - Field fieldChunkMap = chunkMap.getClass().getDeclaredField("d"); fieldChunkMap.setAccessible(true); LongHashMap map = (LongHashMap) fieldChunkMap.get(chunkMap); @@ -454,56 +448,38 @@ public class BukkitQueue18R3 extends BukkitQueue_0 players = new HashSet<>((Collection)fieldPlayers.get(playerChunk)); - if (players.size() == 0) { + Collection players = (Collection) fieldPlayers.get(playerChunk); + if (players.isEmpty()) { return; } - HashSet entities = new HashSet<>(); - List[] entitieSlices = nmsChunk.getEntitySlices(); - for (List 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 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) { diff --git a/bukkit19/src/main/java/com/boydti/fawe/bukkit/v1_9/BukkitQueue_1_9_R1.java b/bukkit19/src/main/java/com/boydti/fawe/bukkit/v1_9/BukkitQueue_1_9_R1.java index 85ee4689..9881ea78 100644 --- a/bukkit19/src/main/java/com/boydti/fawe/bukkit/v1_9/BukkitQueue_1_9_R1.java +++ b/bukkit19/src/main/java/com/boydti/fawe/bukkit/v1_9/BukkitQueue_1_9_R1.java @@ -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 set = new HashSet(playerChunk.c); - EntityTracker tracker = w.getTracker(); - // Get players - final HashSet 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 entities = new HashSet<>(); - List[] entitieSlices = playerChunk.chunk.getEntitySlices(); - for (List 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 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 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 diff --git a/core/src/main/java/com/boydti/fawe/Fawe.java b/core/src/main/java/com/boydti/fawe/Fawe.java index c9aa8d08..840394f6 100644 --- a/core/src/main/java/com/boydti/fawe/Fawe.java +++ b/core/src/main/java/com/boydti/fawe/Fawe.java @@ -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 diff --git a/core/src/main/java/com/boydti/fawe/FaweAPI.java b/core/src/main/java/com/boydti/fawe/FaweAPI.java index 48e95f17..2842b099 100644 --- a/core/src/main/java/com/boydti/fawe/FaweAPI.java +++ b/core/src/main/java/com/boydti/fawe/FaweAPI.java @@ -257,7 +257,7 @@ public class FaweAPI { * @return */ public static List 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<>(); } diff --git a/core/src/main/java/com/boydti/fawe/config/Settings.java b/core/src/main/java/com/boydti/fawe/config/Settings.java index c668361d..a1d226aa 100644 --- a/core/src/main/java/com/boydti/fawe/config/Settings.java +++ b/core/src/main/java/com/boydti/fawe/config/Settings.java @@ -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 = 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) { diff --git a/core/src/main/java/com/boydti/fawe/database/RollbackDatabase.java b/core/src/main/java/com/boydti/fawe/database/RollbackDatabase.java index efa88ad2..b6e221a5 100644 --- a/core/src/main/java/com/boydti/fawe/database/RollbackDatabase.java +++ b/core/src/main/java/com/boydti/fawe/database/RollbackDatabase.java @@ -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(?,?,?,?,?,?,?,?,?)"; diff --git a/core/src/main/java/com/boydti/fawe/example/CharFaweChunk.java b/core/src/main/java/com/boydti/fawe/example/CharFaweChunk.java index 0e9a3829..0310082c 100644 --- a/core/src/main/java/com/boydti/fawe/example/CharFaweChunk.java +++ b/core/src/main/java/com/boydti/fawe/example/CharFaweChunk.java @@ -22,6 +22,7 @@ public abstract class CharFaweChunk extends FaweChunk { public short[] air; public short[] relight; public int[][] biomes; + private int bitMask = -1; public T chunk; @@ -103,6 +104,23 @@ public abstract class CharFaweChunk extends FaweChunk { 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 diff --git a/core/src/main/java/com/boydti/fawe/example/NMSMappedFaweQueue.java b/core/src/main/java/com/boydti/fawe/example/NMSMappedFaweQueue.java index 2a78b660..040c54cf 100644 --- a/core/src/main/java/com/boydti/fawe/example/NMSMappedFaweQueue.java +++ b/core/src/main/java/com/boydti/fawe/example/NMSMappedFaweQueue.java @@ -66,7 +66,7 @@ public abstract class NMSMappedFaweQueue 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 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 createdEntities, boolean all) throws Exception; diff --git a/core/src/main/java/com/boydti/fawe/example/NMSRelighter.java b/core/src/main/java/com/boydti/fawe/example/NMSRelighter.java index d84b3721..67ede214 100644 --- a/core/src/main/java/com/boydti/fawe/example/NMSRelighter.java +++ b/core/src/main/java/com/boydti/fawe/example/NMSRelighter.java @@ -100,7 +100,15 @@ public class NMSRelighter { public void sendChunks() { for (Map.Entry 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); } } diff --git a/core/src/main/java/com/boydti/fawe/object/FaweChunk.java b/core/src/main/java/com/boydti/fawe/object/FaweChunk.java index 109ca682..58cae2fb 100644 --- a/core/src/main/java/com/boydti/fawe/object/FaweChunk.java +++ b/core/src/main/java/com/boydti/fawe/object/FaweChunk.java @@ -92,6 +92,12 @@ public abstract class FaweChunk { */ public abstract char[][] getCombinedIdArrays(); + /** + * The modified sections + * @return + */ + public abstract int getBitMask(); + /** * Get the combined block id at a location
* combined = (id <<<< 4) + data diff --git a/core/src/main/java/com/boydti/fawe/object/FawePlayer.java b/core/src/main/java/com/boydti/fawe/object/FawePlayer.java index 982d2e4d..fdce4d6e 100644 --- a/core/src/main/java/com/boydti/fawe/object/FawePlayer.java +++ b/core/src/main/java/com/boydti/fawe/object/FawePlayer.java @@ -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 { 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 { * - 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 { /** * Load all the undo EditSession's from disk for a world
- * - 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 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 { */ 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()); } diff --git a/core/src/main/java/com/boydti/fawe/object/changeset/DiskStorageHistory.java b/core/src/main/java/com/boydti/fawe/object/changeset/DiskStorageHistory.java index c3f0665a..4ff8d9cb 100644 --- a/core/src/main/java/com/boydti/fawe/object/changeset/DiskStorageHistory.java +++ b/core/src/main/java/com/boydti/fawe/object/changeset/DiskStorageHistory.java @@ -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() { diff --git a/core/src/main/java/com/boydti/fawe/object/changeset/FaweStreamChangeSet.java b/core/src/main/java/com/boydti/fawe/object/changeset/FaweStreamChangeSet.java index 9d630da0..c9f6c542 100644 --- a/core/src/main/java/com/boydti/fawe/object/changeset/FaweStreamChangeSet.java +++ b/core/src/main/java/com/boydti/fawe/object/changeset/FaweStreamChangeSet.java @@ -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; diff --git a/core/src/main/java/com/boydti/fawe/object/clipboard/DiskOptimizedClipboard.java b/core/src/main/java/com/boydti/fawe/object/clipboard/DiskOptimizedClipboard.java index e10ff24a..403a9ca0 100644 --- a/core/src/main/java/com/boydti/fawe/object/clipboard/DiskOptimizedClipboard.java +++ b/core/src/main/java/com/boydti/fawe/object/clipboard/DiskOptimizedClipboard.java @@ -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() { diff --git a/core/src/main/java/com/sk89q/worldedit/EditSession.java b/core/src/main/java/com/sk89q/worldedit/EditSession.java index 621296dc..452e36ca 100644 --- a/core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -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(); diff --git a/core/src/main/java/com/sk89q/worldedit/LocalSession.java b/core/src/main/java/com/sk89q/worldedit/LocalSession.java index e6065259..0f32e57b 100644 --- a/core/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/core/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -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 history = Collections.synchronizedList(new LinkedList()); - private transient volatile int historyPointer = 0; + private transient List history = Collections.synchronizedList(new LinkedList() { + @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 tools = new HashMap(); + private transient Map 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 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 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; } diff --git a/core/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java b/core/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java index 75507de2..c0d605f6 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java @@ -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() { @Override public void run(DiskStorageHistory edit) { diff --git a/core/src/main/java/com/sk89q/worldedit/session/SessionManager.java b/core/src/main/java/com/sk89q/worldedit/session/SessionManager.java index c43b0d6f..d087c6aa 100644 --- a/core/src/main/java/com/sk89q/worldedit/session/SessionManager.java +++ b/core/src/main/java/com/sk89q/worldedit/session/SessionManager.java @@ -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 sessions = new HashMap(); + private final Map sessions = new ConcurrentHashMap(); private SessionStore store = new VoidStore(); + private File path; + + // Added // + +// private final ConcurrentLinkedDeque 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 sessions) { - checkNotNull(sessions); - - if (sessions.isEmpty()) { - return Futures.immediateFuture(sessions); - } - - return executorService.submit(new Callable() { - @Override - public Object call() throws Exception { - Exception exception = null; - - for (Map.Entry 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 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 it = sessions.values().iterator(); - Map saveQueue = new HashMap(); - - 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; } + } \ No newline at end of file diff --git a/core/src/main/java/com/test.das b/core/src/main/java/com/test.das deleted file mode 100644 index e69de29b..00000000 diff --git a/forge110/src/main/java/com/boydti/fawe/forge/ForgeMain.java b/forge110/src/main/java/com/boydti/fawe/forge/ForgeMain.java index e478f99f..d408a41f 100644 --- a/forge110/src/main/java/com/boydti/fawe/forge/ForgeMain.java +++ b/forge110/src/main/java/com/boydti/fawe/forge/ForgeMain.java @@ -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()); - } } } } diff --git a/forge110/src/main/java/com/boydti/fawe/forge/v0/ForgeQueue_All.java b/forge110/src/main/java/com/boydti/fawe/forge/v0/ForgeQueue_All.java index 91774f74..acab27ce 100644 --- a/forge110/src/main/java/com/boydti/fawe/forge/v0/ForgeQueue_All.java +++ b/forge110/src/main/java/com/boydti/fawe/forge/v0/ForgeQueue_All.java @@ -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 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 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 entities = new HashSet<>(); - ClassInheritanceMultiMap[] entitieSlices = nmsChunk.getEntityLists(); - IntHashMap entries = null; - for (Field field : tracker.getClass().getDeclaredFields()) { - if (field.getType() == IntHashMap.class) { - field.setAccessible(true); - entries = (IntHashMap) field.get(tracker); - break; - } - } - for (ClassInheritanceMultiMap 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[] entities = nmsChunk.getEntityLists(); + for (int i = 0; i < entities.length; i++) { + ClassInheritanceMultiMap slice = entities[i]; + if (slice != null && !slice.isEmpty()) { + return true; + } + } + return false; + } + + @Override public FaweChunk getFaweChunk(int x, int z) { return new ForgeChunk_All(this, x, z); diff --git a/forge1710/src/main/java/com/boydti/fawe/forge/ForgeMain.java b/forge1710/src/main/java/com/boydti/fawe/forge/ForgeMain.java index b55802bc..24202b1a 100644 --- a/forge1710/src/main/java/com/boydti/fawe/forge/ForgeMain.java +++ b/forge1710/src/main/java/com/boydti/fawe/forge/ForgeMain.java @@ -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()); - } } } } diff --git a/forge1710/src/main/java/com/boydti/fawe/forge/v0/ForgeQueue_All.java b/forge1710/src/main/java/com/boydti/fawe/forge/v0/ForgeQueue_All.java index 0ee6c664..3c1dbd77 100644 --- a/forge1710/src/main/java/com/boydti/fawe/forge/v0/ForgeQueue_All.java +++ b/forge1710/src/main/java/com/boydti/fawe/forge/v0/ForgeQueue_All.java @@ -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 players = new HashSet<>(); + HashSet players = new HashSet<>(); for (EntityPlayer player : (List) w.playerEntities) { if (player instanceof EntityPlayerMP) { if (chunkMap.isPlayerWatchingChunk((EntityPlayerMP) player, x, z)) { @@ -241,60 +236,34 @@ public class ForgeQueue_All extends NMSMappedFaweQueue entities = new HashSet<>(); - Collection[] 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 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 changeTask) { ForgeChunk_All fs = (ForgeChunk_All) fc; diff --git a/forge189/src/main/java/com/boydti/fawe/forge/ForgeMain.java b/forge189/src/main/java/com/boydti/fawe/forge/ForgeMain.java index 730d635c..b319311c 100644 --- a/forge189/src/main/java/com/boydti/fawe/forge/ForgeMain.java +++ b/forge189/src/main/java/com/boydti/fawe/forge/ForgeMain.java @@ -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()); - } } } } diff --git a/forge189/src/main/java/com/boydti/fawe/forge/v0/ForgeQueue_All.java b/forge189/src/main/java/com/boydti/fawe/forge/v0/ForgeQueue_All.java index 3d0dd010..ef8ab125 100644 --- a/forge189/src/main/java/com/boydti/fawe/forge/v0/ForgeQueue_All.java +++ b/forge189/src/main/java/com/boydti/fawe/forge/v0/ForgeQueue_All.java @@ -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 players = new HashSet<>(); for (EntityPlayer player : w.playerEntities) { if (player instanceof EntityPlayerMP) { @@ -478,60 +473,35 @@ public class ForgeQueue_All extends NMSMappedFaweQueue entities = new HashSet<>(); - ClassInheritanceMultiMap[] entitieSlices = nmsChunk.getEntityLists(); - 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 (ClassInheritanceMultiMap 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[] entities = nmsChunk.getEntityLists(); + for (int i = 0; i < entities.length; i++) { + ClassInheritanceMultiMap slice = entities[i]; + if (slice != null && !slice.isEmpty()) { + return true; + } + } + return false; + } + + @Override public FaweChunk getFaweChunk(int x, int z) { return new ForgeChunk_All(this, x, z); diff --git a/forge194/src/main/java/com/boydti/fawe/forge/ForgeMain.java b/forge194/src/main/java/com/boydti/fawe/forge/ForgeMain.java index e478f99f..d408a41f 100644 --- a/forge194/src/main/java/com/boydti/fawe/forge/ForgeMain.java +++ b/forge194/src/main/java/com/boydti/fawe/forge/ForgeMain.java @@ -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()); - } } } } diff --git a/forge194/src/main/java/com/boydti/fawe/forge/v0/ForgeQueue_All.java b/forge194/src/main/java/com/boydti/fawe/forge/v0/ForgeQueue_All.java index 8883a8b3..46292fe9 100644 --- a/forge194/src/main/java/com/boydti/fawe/forge/v0/ForgeQueue_All.java +++ b/forge194/src/main/java/com/boydti/fawe/forge/v0/ForgeQueue_All.java @@ -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 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 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 entities = new HashSet<>(); - ClassInheritanceMultiMap[] entitieSlices = nmsChunk.getEntityLists(); - IntHashMap entries = null; - for (Field field : tracker.getClass().getDeclaredFields()) { - if (field.getType() == IntHashMap.class) { - field.setAccessible(true); - entries = (IntHashMap) field.get(tracker); - break; - } - } - for (ClassInheritanceMultiMap 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[] entities = nmsChunk.getEntityLists(); + for (int i = 0; i < entities.length; i++) { + ClassInheritanceMultiMap slice = entities[i]; + if (slice != null && !slice.isEmpty()) { + return true; + } + } + return false; + } + @Override public FaweChunk getFaweChunk(int x, int z) { return new ForgeChunk_All(this, x, z);