mirror of
https://github.com/boy0001/FastAsyncWorldedit.git
synced 2024-12-29 12:37:53 +01:00
Various
Rename Favs jar and print error on failed load LocalSession history on disk size limit per player (in MB) Possible fix for ForgeEssentials incompatibility
This commit is contained in:
parent
3ec42144e7
commit
d0b5dab2a0
@ -71,8 +71,11 @@ public class Settings extends Config {
|
||||
"NoteBlock, Sign, Skull, Structure"
|
||||
})
|
||||
public int MAX_BLOCKSTATES = 1337;
|
||||
@Comment("Maximum size of the player's history in Megabytes")
|
||||
public int MAX_HISTORY_MB = 200;
|
||||
@Comment({
|
||||
"Maximum size of the player's history in Megabytes:",
|
||||
" - History on disk or memory will be deleted",
|
||||
})
|
||||
public int MAX_HISTORY_MB = -1;
|
||||
}
|
||||
|
||||
public static class HISTORY {
|
||||
@ -266,7 +269,7 @@ public class Settings extends Config {
|
||||
limit.MAX_ENTITIES = Math.max(limit.MAX_ENTITIES, newLimit.MAX_ENTITIES != -1 ? newLimit.MAX_ENTITIES : Integer.MAX_VALUE);
|
||||
limit.MAX_FAILS = Math.max(limit.MAX_FAILS, newLimit.MAX_FAILS != -1 ? newLimit.MAX_FAILS : Integer.MAX_VALUE);
|
||||
limit.MAX_ITERATIONS = Math.max(limit.MAX_ITERATIONS, newLimit.MAX_ITERATIONS != -1 ? newLimit.MAX_ITERATIONS : Integer.MAX_VALUE);
|
||||
limit.MAX_HISTORY = HISTORY.USE_DISK ? Integer.MAX_VALUE : Math.max(limit.MAX_HISTORY, newLimit.MAX_HISTORY_MB != -1 ? newLimit.MAX_HISTORY_MB : Integer.MAX_VALUE);
|
||||
limit.MAX_HISTORY = Math.max(limit.MAX_HISTORY, newLimit.MAX_HISTORY_MB != -1 ? newLimit.MAX_HISTORY_MB : Integer.MAX_VALUE);
|
||||
}
|
||||
}
|
||||
return limit;
|
||||
|
@ -35,6 +35,7 @@ public class RollbackDatabase {
|
||||
private String GET_EDITS;
|
||||
private String GET_EDITS_USER;
|
||||
private String DELETE_EDITS_USER;
|
||||
private String DELETE_EDIT_USER;
|
||||
private String PURGE;
|
||||
|
||||
private ConcurrentLinkedQueue<RollbackOptimizedHistory> historyChanges = new ConcurrentLinkedQueue<>();
|
||||
@ -52,6 +53,7 @@ public class RollbackDatabase {
|
||||
GET_EDITS = "SELECT `player`,`id` FROM `" + prefix + "edits` WHERE `x2`>=? AND `x1`<=? AND `y2`>=? AND `y1`<=? AND `z2`>=? AND `z1`<=? AND `time`>? ORDER BY `time` DESC, `id` DESC";
|
||||
GET_EDITS_USER = "SELECT `player`,`id` FROM `" + prefix + "edits` WHERE `x2`>=? AND `x1`<=? AND `y2`>=? AND `y1`<=? AND `z2`>=? AND `z1`<=? AND `time`>? AND `player`=? ORDER BY `time` DESC, `id` DESC";
|
||||
DELETE_EDITS_USER = "DELETE FROM `" + prefix + "edits` WHERE `x2`>=? AND `x1`<=? AND `y2`>=? AND `y1`<=? AND `z2`>=? AND `z1`<=? AND `time`>? AND `player`=?";
|
||||
DELETE_EDIT_USER = "DELETE FROM `" + prefix + "edits` WHERE `player`=? AND `id`=?";
|
||||
init();
|
||||
purge((int) TimeUnit.DAYS.toMillis(Settings.HISTORY.DELETE_AFTER_DAYS));
|
||||
TaskManager.IMP.async(new Runnable() {
|
||||
@ -90,6 +92,21 @@ public class RollbackDatabase {
|
||||
notify.add(run);
|
||||
}
|
||||
|
||||
public void delete(final UUID uuid, final int id) {
|
||||
addTask(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try (PreparedStatement stmt = connection.prepareStatement(DELETE_EDIT_USER)) {
|
||||
byte[] uuidBytes = ByteBuffer.allocate(16).putLong(uuid.getMostSignificantBits()).putLong(uuid.getLeastSignificantBits()).array();
|
||||
stmt.setBytes(1, uuidBytes);
|
||||
stmt.setInt(2, id);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void purge(int diff) {
|
||||
long now = System.currentTimeMillis() / 1000;
|
||||
final int then = (int) (now - diff);
|
||||
|
@ -47,7 +47,7 @@ public class FaweLimit {
|
||||
MAX.MAX_ITERATIONS = Integer.MAX_VALUE;
|
||||
MAX.MAX_BLOCKSTATES = Integer.MAX_VALUE;
|
||||
MAX.MAX_ENTITIES = Integer.MAX_VALUE;
|
||||
MAX.MAX_HISTORY = 15;
|
||||
MAX.MAX_HISTORY = Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
public boolean MAX_CHANGES() {
|
||||
|
@ -2,6 +2,8 @@ package com.boydti.fawe.object.changeset;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.database.DBHandler;
|
||||
import com.boydti.fawe.database.RollbackDatabase;
|
||||
import com.boydti.fawe.object.FaweInputStream;
|
||||
import com.boydti.fawe.object.IntegerPair;
|
||||
import com.boydti.fawe.object.RegionWrapper;
|
||||
@ -101,6 +103,15 @@ public class DiskStorageHistory extends FaweStreamChangeSet {
|
||||
initFiles(folder);
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
Fawe.debug("Deleting history: " + Fawe.imp().getWorldName(getWorld()) + "/" + uuid + "/" + index);
|
||||
deleteFiles();
|
||||
if (Settings.HISTORY.USE_DATABASE) {
|
||||
RollbackDatabase db = DBHandler.IMP.getDatabase(Fawe.imp().getWorldName(getWorld()));
|
||||
db.delete(uuid, index);
|
||||
}
|
||||
}
|
||||
|
||||
public void deleteFiles() {
|
||||
bdFile.delete();
|
||||
nbtfFile.delete();
|
||||
@ -166,19 +177,19 @@ public class DiskStorageHistory extends FaweStreamChangeSet {
|
||||
public long getSizeOnDisk() {
|
||||
int total = 0;
|
||||
if (bdFile.exists()) {
|
||||
total += bdFile.getTotalSpace();
|
||||
total += bdFile.length();
|
||||
}
|
||||
if (nbtfFile.exists()) {
|
||||
total += entfFile.getTotalSpace();
|
||||
total += entfFile.length();
|
||||
}
|
||||
if (nbttFile.exists()) {
|
||||
total += entfFile.getTotalSpace();
|
||||
total += entfFile.length();
|
||||
}
|
||||
if (entfFile.exists()) {
|
||||
total += entfFile.getTotalSpace();
|
||||
total += entfFile.length();
|
||||
}
|
||||
if (enttFile.exists()) {
|
||||
total += entfFile.getTotalSpace();
|
||||
total += entfFile.length();
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
@ -80,6 +80,8 @@ public abstract class FaweChangeSet implements ChangeSet {
|
||||
public abstract void addEntityCreate(CompoundTag tag);
|
||||
public abstract Iterator<Change> getIterator(boolean redo);
|
||||
|
||||
public void delete() {};
|
||||
|
||||
public EditSession toEditSession(FawePlayer player) {
|
||||
EditSession editSession = new EditSessionBuilder(world).player(player).autoQueue(false).fastmode(false).checkMemory(false).changeSet(this).allowedRegions(RegionWrapper.GLOBAL().toArray()).build();
|
||||
editSession.setSize(1);
|
||||
|
@ -8,6 +8,7 @@ import com.boydti.fawe.object.FaweOutputStream;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.object.RegionWrapper;
|
||||
import com.boydti.fawe.object.RunnableVal;
|
||||
import com.boydti.fawe.object.RunnableVal2;
|
||||
import com.boydti.fawe.object.changeset.CPUOptimizedChangeSet;
|
||||
import com.boydti.fawe.object.changeset.FaweStreamChangeSet;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
@ -38,12 +39,18 @@ import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.FileVisitResult;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.SimpleFileVisitor;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
import java.util.zip.ZipEntry;
|
||||
@ -78,6 +85,42 @@ public class MainUtil {
|
||||
Fawe.debug(s);
|
||||
}
|
||||
|
||||
public static long getTotalSize(Path path) {
|
||||
final AtomicLong size = new AtomicLong(0);
|
||||
traverse(path, new RunnableVal2<Path, BasicFileAttributes>() {
|
||||
@Override
|
||||
public void run(Path path, BasicFileAttributes attrs) {
|
||||
size.addAndGet (attrs.size());
|
||||
}
|
||||
});
|
||||
return size.get();
|
||||
}
|
||||
|
||||
public static long traverse(Path path, final RunnableVal2<Path, BasicFileAttributes> onEach) {
|
||||
final AtomicLong size = new AtomicLong(0);
|
||||
try {
|
||||
Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
|
||||
@Override public FileVisitResult
|
||||
visitFile(Path file, BasicFileAttributes attrs) {
|
||||
onEach.run(file, attrs);
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
@Override public FileVisitResult
|
||||
visitFileFailed(Path file, IOException exc) {
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
@Override public FileVisitResult
|
||||
postVisitDirectory (Path dir, IOException exc) {
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new AssertionError ("walkFileTree will not throw IOException if the FileVisitor does not");
|
||||
}
|
||||
return size.get();
|
||||
}
|
||||
|
||||
public static File getFile(File base, String path) {
|
||||
if (Paths.get(path).isAbsolute()) {
|
||||
return new File(path);
|
||||
@ -93,9 +136,10 @@ public class MainUtil {
|
||||
return getCompressedOS(os, Settings.HISTORY.COMPRESSION_LEVEL);
|
||||
}
|
||||
|
||||
public static long getSizeInMemory(ChangeSet changeSet) {
|
||||
public static long getSize(ChangeSet changeSet) {
|
||||
if (changeSet instanceof FaweStreamChangeSet){
|
||||
return 92 + ((FaweStreamChangeSet) changeSet).getSizeInMemory();
|
||||
FaweStreamChangeSet fscs = (FaweStreamChangeSet) changeSet;
|
||||
return fscs.getSizeOnDisk() + fscs.getSizeInMemory();
|
||||
} else if (changeSet instanceof CPUOptimizedChangeSet) {
|
||||
return changeSet.size() + 32;
|
||||
} else if (changeSet != null) {
|
||||
|
@ -24,11 +24,13 @@ 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.RunnableVal2;
|
||||
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;
|
||||
import com.boydti.fawe.wrappers.WorldWrapper;
|
||||
import com.sk89q.jchronic.Chronic;
|
||||
import com.sk89q.jchronic.Options;
|
||||
import com.sk89q.jchronic.utils.Span;
|
||||
@ -61,6 +63,10 @@ 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;
|
||||
@ -72,6 +78,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;
|
||||
|
||||
@ -118,7 +125,6 @@ public class LocalSession {
|
||||
}
|
||||
});
|
||||
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;
|
||||
@ -133,9 +139,9 @@ public class LocalSession {
|
||||
private transient Mask mask;
|
||||
private transient TimeZone timezone = TimeZone.getDefault();
|
||||
|
||||
// May be null
|
||||
private transient World currentWorld;
|
||||
private transient UUID uuid;
|
||||
private transient volatile long historySize = 0;
|
||||
|
||||
// Saved properties
|
||||
private String lastScript;
|
||||
@ -222,16 +228,70 @@ public class LocalSession {
|
||||
}
|
||||
});
|
||||
}
|
||||
historySize = 0;
|
||||
if (editIds.size() > 0) {
|
||||
historySize = MainUtil.getTotalSize(folder.toPath());
|
||||
Collections.sort(editIds);
|
||||
for (int index : editIds) {
|
||||
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.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){
|
||||
ignore.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
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()) {
|
||||
@ -392,16 +452,19 @@ public class LocalSession {
|
||||
while (iter.hasNext()) {
|
||||
Object item = iter.next();
|
||||
if (++i > cutoffIndex) {
|
||||
FaweChangeSet changeSet;
|
||||
if (item instanceof FaweChangeSet) {
|
||||
FaweChangeSet changeSet = (FaweChangeSet) item;
|
||||
historySize -= MainUtil.getSizeInMemory(changeSet);
|
||||
changeSet = (FaweChangeSet) item;
|
||||
} else {
|
||||
changeSet = getChangeSet(item);
|
||||
}
|
||||
historySize -= MainUtil.getSize(changeSet);
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
FaweChangeSet changeSet = (FaweChangeSet) editSession.getChangeSet();
|
||||
historySize += MainUtil.getSizeInMemory(changeSet);
|
||||
historySize += MainUtil.getSize(changeSet);
|
||||
if (append) {
|
||||
history.add(changeSet);
|
||||
if (getHistoryNegativeIndex() != 0) {
|
||||
@ -413,7 +476,8 @@ public class LocalSession {
|
||||
}
|
||||
while ((history.size() > MAX_HISTORY_SIZE || (historySize >> 20) > limitMb) && history.size() > 1) {
|
||||
FaweChangeSet item = (FaweChangeSet) history.remove(0);
|
||||
historySize -= MainUtil.getSizeInMemory(item);
|
||||
item.delete();
|
||||
historySize -= MainUtil.getSize(item);
|
||||
}
|
||||
}
|
||||
|
||||
@ -648,7 +712,11 @@ public class LocalSession {
|
||||
* @return the the world of the selection
|
||||
*/
|
||||
public World getSelectionWorld() {
|
||||
return selector.getIncompleteRegion().getWorld();
|
||||
World world = selector.getIncompleteRegion().getWorld();
|
||||
if (world instanceof WorldWrapper) {
|
||||
return ((WorldWrapper) world).getParent();
|
||||
}
|
||||
return world;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -14,4 +14,4 @@ processResources {
|
||||
}
|
||||
|
||||
jar.destinationDir = file '../target'
|
||||
jar.archiveName = "${parent.name}-${project.name}-${parent.version}.jar"
|
||||
jar.archiveName = "FastAsyncVoxelSniper-${project.name}-${parent.version}.jar"
|
@ -45,6 +45,8 @@ public class Favs extends JavaPlugin {
|
||||
}
|
||||
});
|
||||
Fawe.debug("Injected VoxelSniper classes");
|
||||
} catch (Throwable ignore) {}
|
||||
} catch (Throwable ignore) {
|
||||
ignore.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user