Anvil undo/region restrictions
This commit is contained in:
parent
d37e44e395
commit
7359100159
@ -107,9 +107,9 @@ public class BukkitQueue_All extends BukkitQueue_0<ChunkSnapshot, ChunkSnapshot,
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setMCA(int mcaX, int mcaZ, RegionWrapper allowed, Runnable whileLocked, boolean load) {
|
||||
public boolean setMCA(int mcaX, int mcaZ, RegionWrapper allowed, Runnable whileLocked, boolean saveChunks, boolean load) {
|
||||
if (classRegionFileCache == null) {
|
||||
return super.setMCA(mcaX, mcaZ, allowed, whileLocked, load);
|
||||
return super.setMCA(mcaX, mcaZ, allowed, whileLocked, saveChunks, load);
|
||||
}
|
||||
TaskManager.IMP.sync(new RunnableVal<Boolean>() {
|
||||
@Override
|
||||
@ -134,7 +134,7 @@ public class BukkitQueue_All extends BukkitQueue_0<ChunkSnapshot, ChunkSnapshot,
|
||||
int cz = chunk.getZ();
|
||||
if (cx >= bcx && cx <= tcx && cz >= bcz && cz <= tcz) {
|
||||
Object nmsChunk = methodGetHandleChunk.invoke(chunk);
|
||||
boolean mustSave = (boolean) methodNeedsSaving.invoke(nmsChunk, false);
|
||||
boolean mustSave = saveChunks && (boolean) methodNeedsSaving.invoke(nmsChunk, false);
|
||||
chunk.unload(mustSave, false);
|
||||
if (unloaded == null) unloaded = new ArrayDeque<Chunk>();
|
||||
unloaded.add(chunk);
|
||||
|
@ -402,7 +402,7 @@ public class BukkitQueue_1_10 extends BukkitQueue_0<net.minecraft.server.v1_10_R
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setMCA(final int mcaX, final int mcaZ, final RegionWrapper allowed, final Runnable whileLocked, final boolean load) {
|
||||
public boolean setMCA(final int mcaX, final int mcaZ, final RegionWrapper allowed, final Runnable whileLocked, final boolean saveChunks, final boolean load) {
|
||||
TaskManager.IMP.sync(new RunnableVal<Boolean>() {
|
||||
@Override
|
||||
public void run(Boolean value) {
|
||||
@ -423,7 +423,7 @@ public class BukkitQueue_1_10 extends BukkitQueue_0<net.minecraft.server.v1_10_R
|
||||
boolean isIn = allowed.isInChunk(chunk.locX, chunk.locZ);
|
||||
if (isIn) {
|
||||
if (!load) {
|
||||
if (chunk.a(false)) {
|
||||
if (saveChunks && chunk.a(false)) {
|
||||
mustSave = true;
|
||||
provider.saveChunk(chunk);
|
||||
provider.saveChunkNOP(chunk);
|
||||
@ -431,7 +431,7 @@ public class BukkitQueue_1_10 extends BukkitQueue_0<net.minecraft.server.v1_10_R
|
||||
continue;
|
||||
}
|
||||
iter.remove();
|
||||
boolean save = chunk.a(false);
|
||||
boolean save = saveChunks && chunk.a(false);
|
||||
mustSave |= save;
|
||||
if (save) {
|
||||
provider.unload(chunk);
|
||||
|
@ -260,7 +260,7 @@ public class BukkitQueue_1_11 extends BukkitQueue_0<net.minecraft.server.v1_11_R
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setMCA(final int mcaX, final int mcaZ, final RegionWrapper allowed, final Runnable whileLocked, final boolean load) {
|
||||
public boolean setMCA(final int mcaX, final int mcaZ, final RegionWrapper allowed, final Runnable whileLocked, final boolean saveChunks, final boolean load) {
|
||||
TaskManager.IMP.sync(new RunnableVal<Boolean>() {
|
||||
@Override
|
||||
public void run(Boolean value) {
|
||||
@ -281,7 +281,7 @@ public class BukkitQueue_1_11 extends BukkitQueue_0<net.minecraft.server.v1_11_R
|
||||
boolean isIn = allowed.isInChunk(chunk.locX, chunk.locZ);
|
||||
if (isIn) {
|
||||
if (!load) {
|
||||
if (chunk.a(false)) {
|
||||
if (saveChunks && chunk.a(false)) {
|
||||
mustSave = true;
|
||||
provider.saveChunk(chunk);
|
||||
provider.saveChunkNOP(chunk);
|
||||
@ -289,7 +289,7 @@ public class BukkitQueue_1_11 extends BukkitQueue_0<net.minecraft.server.v1_11_R
|
||||
continue;
|
||||
}
|
||||
iter.remove();
|
||||
boolean save = chunk.a(false);
|
||||
boolean save = saveChunks && chunk.a(false);
|
||||
mustSave |= save;
|
||||
provider.unloadChunk(chunk, save);
|
||||
if (chunksUnloaded == null) {
|
||||
|
@ -14,6 +14,7 @@ import com.boydti.fawe.object.visitor.FaweChunkVisitor;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.boydti.fawe.util.ReflectionUtils;
|
||||
import com.boydti.fawe.util.SetQueue;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
@ -293,7 +294,7 @@ public class BukkitQueue_1_12 extends BukkitQueue_0<net.minecraft.server.v1_12_R
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setMCA(final int mcaX, final int mcaZ, final RegionWrapper allowed, final Runnable whileLocked, final boolean load) {
|
||||
public boolean setMCA(final int mcaX, final int mcaZ, final RegionWrapper allowed, final Runnable whileLocked, final boolean saveChunks, final boolean load) {
|
||||
TaskManager.IMP.sync(new RunnableVal<Boolean>() {
|
||||
@Override
|
||||
public void run(Boolean value) {
|
||||
@ -314,11 +315,11 @@ public class BukkitQueue_1_12 extends BukkitQueue_0<net.minecraft.server.v1_12_R
|
||||
boolean isIn = allowed.isInChunk(chunk.locX, chunk.locZ);
|
||||
if (isIn) {
|
||||
if (!load) {
|
||||
mustSave |= save(chunk, provider);
|
||||
mustSave |= saveChunks && save(chunk, provider);
|
||||
continue;
|
||||
}
|
||||
iter.remove();
|
||||
boolean save = chunk.a(false);
|
||||
boolean save = saveChunks && chunk.a(false);
|
||||
mustSave |= save;
|
||||
provider.unloadChunk(chunk, save);
|
||||
if (chunksUnloaded == null) {
|
||||
@ -334,7 +335,9 @@ public class BukkitQueue_1_12 extends BukkitQueue_0<net.minecraft.server.v1_12_R
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mustSave) provider.c(); // TODO only the necessary chunks
|
||||
if (mustSave) {
|
||||
provider.c(); // TODO only the necessary chunks
|
||||
}
|
||||
|
||||
File unloadedRegion = null;
|
||||
if (load && !RegionFileCache.a.isEmpty()) {
|
||||
@ -378,9 +381,9 @@ public class BukkitQueue_1_12 extends BukkitQueue_0<net.minecraft.server.v1_12_R
|
||||
if (arr[z]) {
|
||||
int cx = bx + x;
|
||||
int cz = bz + z;
|
||||
TaskManager.IMP.sync(new RunnableVal<Object>() {
|
||||
SetQueue.IMP.addTask(new Runnable() {
|
||||
@Override
|
||||
public void run(Object value1) {
|
||||
public void run() {
|
||||
net.minecraft.server.v1_12_R1.Chunk chunk = provider.getChunkAt(cx, cz, null, false);
|
||||
if (chunk != null) {
|
||||
PlayerChunk pc = getPlayerChunk(nmsWorld, cx, cz);
|
||||
|
@ -130,7 +130,7 @@ public class BukkitQueue17 extends BukkitQueue_0<net.minecraft.server.v1_7_R4.Ch
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setMCA(final int mcaX, final int mcaZ, final RegionWrapper allowed, final Runnable whileLocked, final boolean load) {
|
||||
public boolean setMCA(final int mcaX, final int mcaZ, final RegionWrapper allowed, final Runnable whileLocked, boolean saveChunks, final boolean load) {
|
||||
TaskManager.IMP.sync(new RunnableVal<Boolean>() {
|
||||
@Override
|
||||
public void run(Boolean value) {
|
||||
@ -151,7 +151,7 @@ public class BukkitQueue17 extends BukkitQueue_0<net.minecraft.server.v1_7_R4.Ch
|
||||
boolean isIn = allowed.isInChunk(chunk.locX, chunk.locZ);
|
||||
if (isIn) {
|
||||
if (!load) {
|
||||
if (chunk.a(false)) {
|
||||
if (saveChunks && chunk.a(false)) {
|
||||
mustSave = true;
|
||||
provider.saveChunk(chunk);
|
||||
provider.saveChunkNOP(chunk);
|
||||
@ -159,7 +159,7 @@ public class BukkitQueue17 extends BukkitQueue_0<net.minecraft.server.v1_7_R4.Ch
|
||||
continue;
|
||||
}
|
||||
iter.remove();
|
||||
boolean save = chunk.a(false);
|
||||
boolean save = saveChunks && chunk.a(false);
|
||||
mustSave |= save;
|
||||
chunk.bukkitChunk.unload(save, false);
|
||||
if (chunksUnloaded == null) {
|
||||
|
@ -9,6 +9,7 @@ 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.SetQueue;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
@ -128,7 +129,7 @@ public class BukkitQueue18R3 extends BukkitQueue_0<net.minecraft.server.v1_8_R3.
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setMCA(final int mcaX, final int mcaZ, final RegionWrapper allowed, final Runnable whileLocked, final boolean load) {
|
||||
public boolean setMCA(final int mcaX, final int mcaZ, final RegionWrapper allowed, final Runnable whileLocked, final boolean saveChunks, final boolean load) {
|
||||
TaskManager.IMP.sync(new RunnableVal<Boolean>() {
|
||||
@Override
|
||||
public void run(Boolean value) {
|
||||
@ -149,7 +150,7 @@ public class BukkitQueue18R3 extends BukkitQueue_0<net.minecraft.server.v1_8_R3.
|
||||
boolean isIn = allowed.isInChunk(chunk.locX, chunk.locZ);
|
||||
if (isIn) {
|
||||
if (!load) {
|
||||
if (chunk.a(false)) {
|
||||
if (saveChunks && chunk.a(false)) {
|
||||
mustSave = true;
|
||||
provider.saveChunk(chunk);
|
||||
provider.saveChunkNOP(chunk);
|
||||
@ -157,7 +158,7 @@ public class BukkitQueue18R3 extends BukkitQueue_0<net.minecraft.server.v1_8_R3.
|
||||
continue;
|
||||
}
|
||||
iter.remove();
|
||||
boolean save = chunk.a(false);
|
||||
boolean save = saveChunks && chunk.a(false);
|
||||
mustSave |= save;
|
||||
chunk.bukkitChunk.unload(save, false);
|
||||
if (chunksUnloaded == null) {
|
||||
@ -217,9 +218,9 @@ public class BukkitQueue18R3 extends BukkitQueue_0<net.minecraft.server.v1_8_R3.
|
||||
if (arr[z]) {
|
||||
int cx = bx + x;
|
||||
int cz = bz + z;
|
||||
TaskManager.IMP.sync(new RunnableVal<Object>() {
|
||||
SetQueue.IMP.addTask(new Runnable() {
|
||||
@Override
|
||||
public void run(Object value1) {
|
||||
public void run() {
|
||||
net.minecraft.server.v1_8_R3.Chunk chunk = provider.getChunkAt(cx, cz, null);
|
||||
if (chunk != null) {
|
||||
if (nmsWorld.getPlayerChunkMap().isChunkInUse(cx, cz)) {
|
||||
|
@ -263,7 +263,7 @@ public class BukkitQueue_1_9_R1 extends BukkitQueue_0<net.minecraft.server.v1_9_
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setMCA(final int mcaX, final int mcaZ, final RegionWrapper allowed, final Runnable whileLocked, final boolean load) {
|
||||
public boolean setMCA(final int mcaX, final int mcaZ, final RegionWrapper allowed, final Runnable whileLocked, boolean saveChunks, final boolean load) {
|
||||
TaskManager.IMP.sync(new RunnableVal<Boolean>() {
|
||||
@Override
|
||||
public void run(Boolean value) {
|
||||
@ -284,7 +284,7 @@ public class BukkitQueue_1_9_R1 extends BukkitQueue_0<net.minecraft.server.v1_9_
|
||||
boolean isIn = allowed.isInChunk(chunk.locX, chunk.locZ);
|
||||
if (isIn) {
|
||||
if (!load) {
|
||||
if (chunk.a(false)) {
|
||||
if (saveChunks && chunk.a(false)) {
|
||||
mustSave = true;
|
||||
provider.saveChunk(chunk);
|
||||
provider.saveChunkNOP(chunk);
|
||||
@ -292,7 +292,7 @@ public class BukkitQueue_1_9_R1 extends BukkitQueue_0<net.minecraft.server.v1_9_
|
||||
continue;
|
||||
}
|
||||
iter.remove();
|
||||
boolean save = chunk.a(false);
|
||||
boolean save = saveChunks && chunk.a(false);
|
||||
mustSave |= save;
|
||||
if (save) {
|
||||
provider.unload(chunk);
|
||||
|
@ -23,11 +23,15 @@ import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.object.FaweQueue;
|
||||
import com.boydti.fawe.object.RegionWrapper;
|
||||
import com.boydti.fawe.object.RunnableVal4;
|
||||
import com.boydti.fawe.object.changeset.AnvilHistory;
|
||||
import com.boydti.fawe.object.clipboard.ClipboardRemapper;
|
||||
import com.boydti.fawe.object.exception.FaweException;
|
||||
import com.boydti.fawe.object.mask.FaweBlockMatcher;
|
||||
import com.boydti.fawe.regions.FaweMaskManager;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.boydti.fawe.util.SetQueue;
|
||||
import com.boydti.fawe.util.StringMan;
|
||||
import com.boydti.fawe.util.WEManager;
|
||||
import com.sk89q.minecraft.util.commands.Command;
|
||||
import com.sk89q.minecraft.util.commands.CommandPermissions;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
@ -48,8 +52,10 @@ import com.sk89q.worldedit.util.command.parametric.Optional;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@ -122,7 +128,23 @@ public class AnvilCommands {
|
||||
String worldName = Fawe.imp().getWorldName(editSession.getWorld());
|
||||
FaweQueue tmp = SetQueue.IMP.getNewQueue(worldName, true, false);
|
||||
MCAQueue queue = new MCAQueue(tmp);
|
||||
queue.filterCopy(filter, wrappedRegion);
|
||||
FawePlayer<Object> fp = FawePlayer.wrap(player);
|
||||
LocalSession session = fp.getSession();
|
||||
if (session == null || session.hasFastMode()) {
|
||||
queue.filterCopy(filter, wrappedRegion);
|
||||
} else {
|
||||
RegionWrapper[] allowed = WEManager.IMP.getMask(fp, FaweMaskManager.MaskType.OWNER);
|
||||
HashSet<RegionWrapper> allowedSet = new HashSet<>(Arrays.asList(allowed));
|
||||
RegionWrapper wrappedSelection = new RegionWrapper(selection.getMinimumPoint(), selection.getMaximumPoint());
|
||||
if (allowed.length == 0) {
|
||||
throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_NO_REGION);
|
||||
} else if (!WEManager.IMP.regionContains(wrappedSelection, allowedSet)) {
|
||||
throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_FAILS);
|
||||
}
|
||||
AnvilHistory history = new AnvilHistory(worldName, player.getUniqueId());
|
||||
queue.filterCopy(filter, wrappedRegion, history);
|
||||
session.remember(player, editSession.getWorld(), history, fp.getLimit());
|
||||
}
|
||||
return filter;
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,8 @@ import com.boydti.fawe.example.CharFaweChunk;
|
||||
import com.boydti.fawe.example.NMSMappedFaweQueue;
|
||||
import com.boydti.fawe.example.NullFaweChunk;
|
||||
import com.boydti.fawe.jnbt.anvil.filters.DelegateMCAFilter;
|
||||
import com.boydti.fawe.jnbt.anvil.history.IAnvilHistory;
|
||||
import com.boydti.fawe.jnbt.anvil.history.NullAnvilHistory;
|
||||
import com.boydti.fawe.object.FaweChunk;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.object.FaweQueue;
|
||||
@ -147,9 +149,9 @@ public class MCAQueue extends NMSMappedFaweQueue<FaweQueue, FaweChunk, FaweChunk
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setMCA(int mcaX, int mcaZ, RegionWrapper region, Runnable whileLocked, boolean unload) {
|
||||
if (parent != null) return parent.setMCA(mcaX, mcaZ, region, whileLocked, unload);
|
||||
return super.setMCA(mcaX, mcaZ, region, whileLocked, unload);
|
||||
public boolean setMCA(int mcaX, int mcaZ, RegionWrapper region, Runnable whileLocked, boolean save, boolean unload) {
|
||||
if (parent != null) return parent.setMCA(mcaX, mcaZ, region, whileLocked, save, unload);
|
||||
return super.setMCA(mcaX, mcaZ, region, whileLocked, save, unload);
|
||||
}
|
||||
|
||||
public void pasteRegion(MCAQueue from, final RegionWrapper regionFrom, Vector offset) throws IOException {
|
||||
@ -279,27 +281,30 @@ public class MCAQueue extends NMSMappedFaweQueue<FaweQueue, FaweChunk, FaweChunk
|
||||
from.clear();
|
||||
}
|
||||
|
||||
private void performCopy(MCAFile original, MCAFile copy, RegionWrapper region, ForkJoinPool pool) {
|
||||
private void performCopy(MCAFile original, MCAFile copy, RegionWrapper region, IAnvilHistory task, ForkJoinPool pool) {
|
||||
original.clear();
|
||||
File originalFile = original.getFile();
|
||||
File copyFile = copy.getFile();
|
||||
if (copy.isModified()) {
|
||||
if (copy.isDeleted()) {
|
||||
if (originalFile.delete()) return;
|
||||
setMCA(original.getX(), original.getZ(), region, () -> originalFile.delete(), true);
|
||||
if (task.addFileChange(originalFile)) return;
|
||||
setMCA(original.getX(), original.getZ(), region, () -> task.addFileChange(originalFile), true, true);
|
||||
return;
|
||||
} else if (copyFile.exists()) {
|
||||
try {
|
||||
copy.close(pool);
|
||||
Files.move(copyFile.toPath(), originalFile.toPath(), StandardCopyOption.ATOMIC_MOVE);
|
||||
} catch (IOException e) {
|
||||
setMCA(original.getX(), original.getZ(), region, () -> {
|
||||
originalFile.delete();
|
||||
if (!copyFile.renameTo(originalFile)) {
|
||||
Fawe.debug("Failed to copy (2)");
|
||||
}
|
||||
}, true);
|
||||
// If the task is the normal delete task, we can do a normal file move
|
||||
copy.close(pool);
|
||||
if (task.getClass() == NullAnvilHistory.class) {
|
||||
try {
|
||||
Files.move(copyFile.toPath(), originalFile.toPath(), StandardCopyOption.ATOMIC_MOVE);
|
||||
return;
|
||||
} catch (IOException ignore) {}
|
||||
}
|
||||
setMCA(original.getX(), original.getZ(), region, () -> {
|
||||
task.addFileChange(originalFile);
|
||||
if (!copyFile.renameTo(originalFile)) {
|
||||
Fawe.debug("Failed to copy (2)");
|
||||
}
|
||||
}, true, true);
|
||||
}
|
||||
}
|
||||
copy.clear();
|
||||
@ -307,6 +312,11 @@ public class MCAQueue extends NMSMappedFaweQueue<FaweQueue, FaweChunk, FaweChunk
|
||||
}
|
||||
|
||||
public <G, T extends MCAFilter<G>> T filterCopy(final T filter, RegionWrapper region) {
|
||||
return filterCopy(filter, region, new NullAnvilHistory());
|
||||
}
|
||||
|
||||
|
||||
public <G, T extends MCAFilter<G>> T filterCopy(final T filter, RegionWrapper region, IAnvilHistory task) {
|
||||
DelegateMCAFilter<G> delegate = new DelegateMCAFilter<G>(filter) {
|
||||
MCAFile original;
|
||||
MCAFile copy;
|
||||
@ -330,11 +340,11 @@ public class MCAQueue extends NMSMappedFaweQueue<FaweQueue, FaweChunk, FaweChunk
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}, false);
|
||||
}, true, false);
|
||||
this.copy = new MCAFile(original.getParent(), copyDest);
|
||||
MCAFile result = filter.applyFile(copy);
|
||||
if (result == null) {
|
||||
performCopy(original, copy, region, pool);
|
||||
performCopy(original, copy, region, task, pool);
|
||||
}
|
||||
if (result == null || !copy.getFile().equals(result.getFile())) {
|
||||
copy.clear();
|
||||
@ -345,7 +355,7 @@ public class MCAQueue extends NMSMappedFaweQueue<FaweQueue, FaweChunk, FaweChunk
|
||||
|
||||
@Override
|
||||
public void finishFile(MCAFile newRegion, G cache) {
|
||||
performCopy(original, newRegion, region, pool);
|
||||
performCopy(original, newRegion, region, task, pool);
|
||||
}
|
||||
};
|
||||
if (region == RegionWrapper.GLOBAL()) {
|
||||
|
@ -51,7 +51,7 @@ public class MCAQueueMap implements IFaweQueueMap {
|
||||
lastFile = tmp = mcaFileMap.get(pair);
|
||||
if (lastFile == null) {
|
||||
try {
|
||||
queue.setMCA(lastFileX, lastFileZ, RegionWrapper.GLOBAL(), null, false);
|
||||
queue.setMCA(lastFileX, lastFileZ, RegionWrapper.GLOBAL(), null, true, false);
|
||||
lastFile = tmp = new MCAFile(queue, lastFileX, lastFileZ);
|
||||
} catch (FaweException.FaweChunkLoadException ignore) {
|
||||
lastFile = null;
|
||||
@ -184,7 +184,7 @@ public class MCAQueueMap implements IFaweQueueMap {
|
||||
public void run() {
|
||||
file.close(SetQueue.IMP.getForkJoinPool());
|
||||
}
|
||||
}, true);
|
||||
}, true, true);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
@ -0,0 +1,9 @@
|
||||
package com.boydti.fawe.jnbt.anvil.history;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public interface IAnvilHistory {
|
||||
default boolean addFileChange(File originalMCAFile) {
|
||||
return originalMCAFile.delete();
|
||||
}
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
package com.boydti.fawe.jnbt.anvil.history;
|
||||
|
||||
public class NullAnvilHistory implements IAnvilHistory {
|
||||
}
|
@ -289,7 +289,7 @@ public abstract class FaweQueue implements HasFaweQueue, Extent {
|
||||
|
||||
public abstract Collection<FaweChunk> getFaweChunks();
|
||||
|
||||
public boolean setMCA(int mcaX, int mcaZ, RegionWrapper region, Runnable whileLocked, boolean load) {
|
||||
public boolean setMCA(int mcaX, int mcaZ, RegionWrapper region, Runnable whileLocked, boolean save, boolean load) {
|
||||
if (whileLocked != null) whileLocked.run();
|
||||
return true;
|
||||
}
|
||||
|
@ -0,0 +1,105 @@
|
||||
package com.boydti.fawe.object.changeset;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.jnbt.anvil.history.IAnvilHistory;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Iterators;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.history.change.Change;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class AnvilHistory extends FaweChangeSet implements IAnvilHistory {
|
||||
private final File folder;
|
||||
private int size;
|
||||
|
||||
public AnvilHistory(String world, File folder) {
|
||||
super(world);
|
||||
this.folder = folder;
|
||||
size = -1;
|
||||
}
|
||||
|
||||
public AnvilHistory(String world, UUID uuid) {
|
||||
super(world);
|
||||
File history = MainUtil.getFile(Fawe.imp().getDirectory(), Settings.IMP.PATHS.HISTORY + File.separator + world + File.separator + uuid);
|
||||
File destFolder = new File(history, Integer.toString(MainUtil.getMaxFileId(history)));
|
||||
if (!destFolder.exists()) {
|
||||
destFolder.mkdirs();
|
||||
}
|
||||
this.folder = destFolder;
|
||||
this.size = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addFileChange(File originalMCAFile) {
|
||||
try {
|
||||
Files.move(originalMCAFile.toPath(), Paths.get(folder.getPath(), originalMCAFile.getName()), StandardCopyOption.ATOMIC_MOVE);
|
||||
if (size != -1) size++;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
originalMCAFile.delete();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(int x, int y, int z, int combinedFrom, int combinedTo) {
|
||||
throw new UnsupportedOperationException("Only anvil operations are supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTileCreate(CompoundTag tag) {
|
||||
throw new UnsupportedOperationException("Only anvil operations are supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTileRemove(CompoundTag tag) {
|
||||
throw new UnsupportedOperationException("Only anvil operations are supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addEntityRemove(CompoundTag tag) {
|
||||
throw new UnsupportedOperationException("Only anvil operations are supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addEntityCreate(CompoundTag tag) {
|
||||
throw new UnsupportedOperationException("Only anvil operations are supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBiomeChange(int x, int z, BaseBiome from, BaseBiome to) {
|
||||
throw new UnsupportedOperationException("Only anvil operations are supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Change> getIterator(boolean redo) {
|
||||
if (redo) throw new UnsupportedOperationException("Only undo operations are supported");
|
||||
List<File> files = Arrays.asList(folder.listFiles());
|
||||
final MutableAnvilChange change = new MutableAnvilChange();
|
||||
return Iterators.transform(files.iterator(), new Function<File, MutableAnvilChange>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public MutableAnvilChange apply(@Nullable File input) {
|
||||
change.setSource(input.toPath());
|
||||
return change;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return size == -1 ? folder.listFiles().length : size;
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
package com.boydti.fawe.object.changeset;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.object.FaweQueue;
|
||||
import com.boydti.fawe.object.HasFaweQueue;
|
||||
import com.boydti.fawe.object.RegionWrapper;
|
||||
import com.boydti.fawe.util.ExtentTraverser;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.history.UndoContext;
|
||||
import com.sk89q.worldedit.history.change.Change;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
|
||||
public class MutableAnvilChange implements Change {
|
||||
private Path source;
|
||||
private Path destDir;
|
||||
|
||||
public void setSource(Path source) {
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
private FaweQueue queue;
|
||||
private boolean checkedQueue;
|
||||
|
||||
@Override
|
||||
public void undo(UndoContext context) throws WorldEditException {
|
||||
if (queue != null) {
|
||||
perform(queue);
|
||||
}
|
||||
if (!checkedQueue) {
|
||||
checkedQueue = true;
|
||||
Extent extent = context.getExtent();
|
||||
ExtentTraverser found = new ExtentTraverser(extent).find(HasFaweQueue.class);
|
||||
if (found != null) {
|
||||
queue = ((HasFaweQueue) found.get()).getQueue();
|
||||
destDir = queue.getSaveFolder().toPath();
|
||||
perform(queue);
|
||||
} else {
|
||||
Fawe.debug("FAWE does not support: " + extent + " for " + getClass() + " (bug Empire92)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void perform(FaweQueue queue) {
|
||||
Path dest = destDir.resolve(source.getFileName());
|
||||
try {
|
||||
Files.move(source, dest, StandardCopyOption.ATOMIC_MOVE);
|
||||
} catch (IOException ignore) {
|
||||
int[] coords = MainUtil.regionNameToCoords(source.toString());
|
||||
queue.setMCA(coords[0], coords[1], RegionWrapper.GLOBAL(), new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Files.move(source, dest, StandardCopyOption.ATOMIC_MOVE);
|
||||
} catch (IOException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
}, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void redo(UndoContext context) throws WorldEditException {
|
||||
throw new UnsupportedOperationException("Redo not supported");
|
||||
}
|
||||
}
|
@ -47,8 +47,8 @@ public class DelegateFaweQueue extends FaweQueue {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setMCA(int mcaX, int mcaZ, RegionWrapper region, Runnable whileLocked, boolean load) {
|
||||
return parent.setMCA(mcaX, mcaZ, region, whileLocked, load);
|
||||
public boolean setMCA(int mcaX, int mcaZ, RegionWrapper region, Runnable whileLocked, boolean save, boolean load) {
|
||||
return parent.setMCA(mcaX, mcaZ, region, whileLocked, save, load);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -30,6 +30,7 @@ import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
@ -61,7 +62,6 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.zip.DataFormatException;
|
||||
import java.util.zip.Deflater;
|
||||
@ -220,27 +220,23 @@ public class MainUtil {
|
||||
}
|
||||
|
||||
public static int getMaxFileId(File folder) {
|
||||
final AtomicInteger max = new AtomicInteger();
|
||||
if (folder.exists()) {
|
||||
MainUtil.traverse(folder.toPath(), new RunnableVal2<Path, BasicFileAttributes>() {
|
||||
@Override
|
||||
public void run(Path path, BasicFileAttributes attr) {
|
||||
try {
|
||||
String file = path.getFileName().toString();
|
||||
int index = file.indexOf('.');
|
||||
if (index == -1) {
|
||||
return;
|
||||
}
|
||||
int id = Integer.parseInt(file.substring(0, index));
|
||||
if (id > max.get()) {
|
||||
max.set(id);
|
||||
}
|
||||
} catch (NumberFormatException ignore) {
|
||||
}
|
||||
final int[] max = new int[1];
|
||||
folder.listFiles(new FileFilter() {
|
||||
@Override
|
||||
public boolean accept(File pathname) {
|
||||
String name = pathname.getName();
|
||||
Integer val = null;
|
||||
if (pathname.isDirectory()) {
|
||||
val = StringMan.toInteger(name, 0, name.length());
|
||||
} else {
|
||||
int i = name.lastIndexOf('.');
|
||||
if (i != -1) val = StringMan.toInteger(name, 0, i);
|
||||
}
|
||||
});
|
||||
}
|
||||
return max.get() + 1;
|
||||
if (val != null && val > max[0]) max[0] = val;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
return max[0] + 1;
|
||||
}
|
||||
|
||||
public static File getFile(File base, String path) {
|
||||
|
@ -80,24 +80,50 @@ public class SetQueue {
|
||||
public void run() {
|
||||
try {
|
||||
long now = System.currentTimeMillis();
|
||||
targetTPS = 18 - Math.max(Settings.IMP.QUEUE.EXTRA_TIME_MS * 0.05, 0);
|
||||
do {
|
||||
Runnable task = tasks.poll();
|
||||
if (task != null) {
|
||||
task.run();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} while (Fawe.get().getTimer().isAbove(targetTPS));
|
||||
if (inactiveQueues.isEmpty() && activeQueues.isEmpty()) {
|
||||
last = lastSuccess = now;
|
||||
boolean empty = (inactiveQueues.isEmpty() && activeQueues.isEmpty());
|
||||
boolean emptyTasks = tasks.isEmpty();
|
||||
if (emptyTasks && empty) {
|
||||
last = now;
|
||||
runEmptyTasks();
|
||||
return;
|
||||
}
|
||||
|
||||
targetTPS = 18 - Math.max(Settings.IMP.QUEUE.EXTRA_TIME_MS * 0.05, 0);
|
||||
|
||||
long diff = (50 + SetQueue.this.last) - (SetQueue.this.last = now);
|
||||
long absDiff = Math.abs(diff);
|
||||
if (diff == 0) {
|
||||
allocate = Math.min(50, allocate + 1);
|
||||
} else if (diff < 0) {
|
||||
allocate = Math.max(5, allocate + diff);
|
||||
} else if (!Fawe.get().getTimer().isAbove(targetTPS)) {
|
||||
allocate = Math.max(5, allocate - 1);
|
||||
}
|
||||
|
||||
long currentAllocate = allocate - absDiff;
|
||||
|
||||
if (!emptyTasks) {
|
||||
long taskAllocate = empty ? currentAllocate : currentAllocate >> 1;
|
||||
long used = 0;
|
||||
do {
|
||||
Runnable task = tasks.poll();
|
||||
if (task != null) {
|
||||
task.run();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} while ((used = System.currentTimeMillis() - now) < taskAllocate);
|
||||
currentAllocate -= used;
|
||||
}
|
||||
|
||||
if (empty) {
|
||||
runEmptyTasks();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!MemUtil.isMemoryFree()) {
|
||||
final int mem = MemUtil.calculateMemory();
|
||||
if (mem != Integer.MAX_VALUE) {
|
||||
last = now;
|
||||
allocate = Math.max(5, allocate - 1);
|
||||
if ((mem <= 1) && Settings.IMP.PREVENT_CRASHES) {
|
||||
for (FaweQueue queue : getAllQueues()) {
|
||||
@ -113,27 +139,13 @@ public class SetQueue {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
FaweQueue queue = getNextQueue();
|
||||
if (queue == null) {
|
||||
last = now;
|
||||
return;
|
||||
}
|
||||
if (!Fawe.get().getTimer().isAbove(targetTPS)) {
|
||||
allocate = Math.max(5, allocate - 1);
|
||||
last = now;
|
||||
return;
|
||||
}
|
||||
if (Thread.currentThread() != Fawe.get().getMainThread()) {
|
||||
throw new IllegalStateException("This shouldn't be possible for placement to occur off the main thread");
|
||||
}
|
||||
long diff = (50 + SetQueue.this.last) - (SetQueue.this.last = now);
|
||||
long absDiff = Math.abs(diff);
|
||||
if (diff == 0) {
|
||||
allocate = Math.min(50, allocate + 1);
|
||||
} else if (diff < 0) {
|
||||
allocate = Math.max(5, allocate + diff);
|
||||
}
|
||||
long time = Settings.IMP.QUEUE.EXTRA_TIME_MS + allocate - absDiff - System.currentTimeMillis() + now;
|
||||
|
||||
long time = Settings.IMP.QUEUE.EXTRA_TIME_MS + currentAllocate - System.currentTimeMillis() + now;
|
||||
// Disable the async catcher as it can't discern async vs parallel
|
||||
boolean parallel = Settings.IMP.QUEUE.PARALLEL_THREADS > 1;
|
||||
queue.startSet(parallel);
|
||||
|
@ -313,6 +313,37 @@ public class StringMan {
|
||||
}
|
||||
}
|
||||
|
||||
public static Integer toInteger(String string, int start, int end) {
|
||||
int value = 0;
|
||||
char char0 = string.charAt(0);
|
||||
boolean negative;
|
||||
if (char0 == '-') {
|
||||
negative = true;
|
||||
start++;
|
||||
}
|
||||
else negative = false;
|
||||
for (int i = start; i < end; i++) {
|
||||
char c = string.charAt(i);
|
||||
switch (c) {
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
value = value * 10 + c - '0';
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return negative ? -value : value;
|
||||
}
|
||||
|
||||
public static String join(final int[] array, final String delimiter) {
|
||||
final Integer[] wrapped = new Integer[array.length];
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
|
@ -208,7 +208,7 @@ public class PlayerWrapper extends AbstractPlayerActor {
|
||||
edit.flushQueue();
|
||||
LocalSession session = Fawe.get().getWorldEdit().getSession(this);
|
||||
if (session != null) {
|
||||
session.remember(edit, true, false, FawePlayer.wrap(this).getLimit().MAX_HISTORY);
|
||||
session.remember(edit, true, FawePlayer.wrap(this).getLimit().MAX_HISTORY);
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
caught = e;
|
||||
|
@ -2934,7 +2934,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
|
||||
int yv = (int) (y.getValue() * unit.getY() + zero2.getY());
|
||||
int zv = (int) (z.getValue() * unit.getZ() + zero2.getZ());
|
||||
// read block from world
|
||||
BaseBlock material = getLazyBlock(xv, yv, zv);
|
||||
BaseBlock material = FaweCache.CACHE_BLOCK[queue.getCombinedId4DataDebug(xv, yv, zv, 0, EditSession.this)];
|
||||
// queue operation
|
||||
return setBlockFast(position, material);
|
||||
} catch (EvaluationException e) {
|
||||
|
@ -23,14 +23,17 @@ import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.FaweInputStream;
|
||||
import com.boydti.fawe.object.FaweLimit;
|
||||
import com.boydti.fawe.object.FaweOutputStream;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.object.RunnableVal2;
|
||||
import com.boydti.fawe.object.changeset.AnvilHistory;
|
||||
import com.boydti.fawe.object.changeset.DiskStorageHistory;
|
||||
import com.boydti.fawe.object.changeset.FaweChangeSet;
|
||||
import com.boydti.fawe.object.collection.SparseBitSet;
|
||||
import com.boydti.fawe.object.extent.ResettableExtent;
|
||||
import com.boydti.fawe.util.EditSessionBuilder;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.boydti.fawe.util.StringMan;
|
||||
import com.boydti.fawe.wrappers.WorldWrapper;
|
||||
import com.sk89q.jchronic.Chronic;
|
||||
import com.sk89q.jchronic.Options;
|
||||
@ -47,6 +50,7 @@ import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import com.sk89q.worldedit.extent.inventory.BlockBag;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.function.mask.Masks;
|
||||
import com.sk89q.worldedit.history.changeset.ChangeSet;
|
||||
import com.sk89q.worldedit.internal.cui.CUIEvent;
|
||||
import com.sk89q.worldedit.internal.cui.CUIRegion;
|
||||
import com.sk89q.worldedit.internal.cui.SelectionShapeEvent;
|
||||
@ -63,11 +67,6 @@ import java.io.FileFilter;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
@ -78,9 +77,7 @@ import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.swing.filechooser.FileNameExtensionFilter;
|
||||
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
@ -207,84 +204,35 @@ public class LocalSession {
|
||||
}
|
||||
|
||||
private boolean loadHistoryChangeSets(UUID uuid, World world) {
|
||||
final List<Integer> editIds = new ArrayList<>();
|
||||
SparseBitSet set = new SparseBitSet();
|
||||
final File folder = MainUtil.getFile(Fawe.imp().getDirectory(), Settings.IMP.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);
|
||||
Integer val = null;
|
||||
if (pathname.isDirectory()) {
|
||||
val = StringMan.toInteger(name, 0, name.length());
|
||||
|
||||
} else {
|
||||
int i = name.lastIndexOf('.');
|
||||
if (i != -1) val = StringMan.toInteger(name, 0, i);
|
||||
}
|
||||
if (val != null) set.set(val);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (editIds.size() > 0) {
|
||||
if (!set.isEmpty()) {
|
||||
historySize = MainUtil.getTotalSize(folder.toPath());
|
||||
Collections.sort(editIds);
|
||||
for (int index : editIds) {
|
||||
for (int index = set.nextSetBit(0); index != -1; index = set.nextSetBit(index + 1)) {
|
||||
history.add(index);
|
||||
}
|
||||
} else {
|
||||
historySize = 0;
|
||||
}
|
||||
return editIds.size() > 0;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
private void deleteOldFiles(UUID uuid, World world, long maxBytes) throws IOException {
|
||||
final File folder = MainUtil.getFile(Fawe.imp().getDirectory(), Settings.IMP.PATHS.HISTORY + File.separator + Fawe.imp().getWorldName(world) + File.separator + uuid);
|
||||
|
||||
final ArrayList<Integer> ids = new ArrayList<Integer>();
|
||||
final HashMap<Integer, ArrayDeque<Path>> paths = new HashMap<>();
|
||||
final HashMap<Integer, AtomicLong> sizes = new HashMap<>();
|
||||
final AtomicLong totalSize = new AtomicLong();
|
||||
|
||||
MainUtil.traverse(folder.toPath(), new RunnableVal2<Path, BasicFileAttributes>() {
|
||||
@Override
|
||||
public void run(Path path, BasicFileAttributes attr) {
|
||||
try {
|
||||
String file = path.getFileName().toString();
|
||||
int index = file.indexOf('.');
|
||||
if (index == -1) {
|
||||
return;
|
||||
}
|
||||
int id = Integer.parseInt(file.substring(0, index));
|
||||
long size = attr.size();
|
||||
totalSize.addAndGet(size);
|
||||
ArrayDeque<Path> existingPaths = paths.get(id);
|
||||
if (existingPaths == null) {
|
||||
existingPaths = new ArrayDeque<Path>();
|
||||
paths.put(id, existingPaths);
|
||||
}
|
||||
existingPaths.add(path);
|
||||
AtomicLong existingSize = sizes.get(id);
|
||||
if (existingSize == null) {
|
||||
existingSize = new AtomicLong();
|
||||
sizes.put(id, existingSize);
|
||||
}
|
||||
existingSize.addAndGet(size);
|
||||
} catch (NumberFormatException ignore) {
|
||||
}
|
||||
}
|
||||
});
|
||||
if (totalSize.get() < maxBytes) {
|
||||
return;
|
||||
}
|
||||
Collections.sort(ids);
|
||||
long total = totalSize.get();
|
||||
for (int i = 0; i < ids.size() && total > maxBytes; i++) {
|
||||
int id = ids.get(i);
|
||||
for (Path path : paths.get(id)) {
|
||||
Files.delete(path);
|
||||
}
|
||||
total -= sizes.get(id).get();
|
||||
}
|
||||
return !set.isEmpty();
|
||||
}
|
||||
|
||||
private void loadHistoryNegativeIndex(UUID uuid, World world) {
|
||||
@ -414,7 +362,7 @@ public class LocalSession {
|
||||
public void remember(EditSession editSession) {
|
||||
FawePlayer fp = editSession.getPlayer();
|
||||
int limit = fp == null ? Integer.MAX_VALUE : fp.getLimit().MAX_HISTORY;
|
||||
remember(editSession, true, false, limit);
|
||||
remember(editSession, true, limit);
|
||||
}
|
||||
|
||||
private FaweChangeSet getChangeSet(Object o) {
|
||||
@ -424,12 +372,62 @@ public class LocalSession {
|
||||
return cs;
|
||||
}
|
||||
if (o instanceof Integer) {
|
||||
return new DiskStorageHistory(currentWorld, this.uuid, (Integer) o);
|
||||
File folder = MainUtil.getFile(Fawe.imp().getDirectory(), Settings.IMP.PATHS.HISTORY + File.separator + Fawe.imp().getWorldName(currentWorld) + File.separator + uuid);
|
||||
File specific = new File(folder, o.toString());
|
||||
if (specific.isDirectory()) {
|
||||
return new AnvilHistory(Fawe.imp().getWorldName(currentWorld), specific);
|
||||
} else {
|
||||
return new DiskStorageHistory(currentWorld, this.uuid, (Integer) o);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public synchronized void remember(final EditSession editSession, final boolean append, final boolean sendMessage, int limitMb) {
|
||||
public synchronized void remember(Player player, World world, ChangeSet changeSet, FaweLimit limit) {
|
||||
if (Settings.IMP.HISTORY.USE_DISK) {
|
||||
LocalSession.MAX_HISTORY_SIZE = Integer.MAX_VALUE;
|
||||
}
|
||||
if (changeSet.size() == 0) {
|
||||
return;
|
||||
}
|
||||
loadSessionHistoryFromDisk(player.getUniqueId(), world);
|
||||
if (changeSet instanceof FaweChangeSet) {
|
||||
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) {
|
||||
FaweChangeSet oldChangeSet;
|
||||
if (item instanceof FaweChangeSet) {
|
||||
oldChangeSet = (FaweChangeSet) item;
|
||||
} else {
|
||||
oldChangeSet = getChangeSet(item);
|
||||
}
|
||||
historySize -= MainUtil.getSize(oldChangeSet);
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
historySize += MainUtil.getSize(changeSet);
|
||||
history.add(changeSet);
|
||||
if (getHistoryNegativeIndex() != 0) {
|
||||
setDirty();
|
||||
historyNegativeIndex = 0;
|
||||
}
|
||||
if (limit != null) {
|
||||
int limitMb = limit.MAX_HISTORY;
|
||||
while (((!Settings.IMP.HISTORY.USE_DISK && history.size() > MAX_HISTORY_SIZE) || (historySize >> 20) > limitMb) && history.size() > 1) {
|
||||
FaweChangeSet item = (FaweChangeSet) history.remove(0);
|
||||
item.delete();
|
||||
long size = MainUtil.getSize(item);
|
||||
historySize -= size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void remember(final EditSession editSession, final boolean append, int limitMb) {
|
||||
if (Settings.IMP.HISTORY.USE_DISK) {
|
||||
LocalSession.MAX_HISTORY_SIZE = Integer.MAX_VALUE;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user