Rollback optimizations / features
This commit is contained in:
parent
63ad22a021
commit
d38db03600
@ -23,7 +23,7 @@ public class BukkitCommand implements CommandExecutor {
|
|||||||
BBC.NO_PERM.send(plr, this.cmd.getPerm());
|
BBC.NO_PERM.send(plr, this.cmd.getPerm());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
this.cmd.execute(plr, args);
|
this.cmd.executeSafe(plr, args);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,9 +13,11 @@ import com.boydti.fawe.util.MathMan;
|
|||||||
import com.boydti.fawe.util.SetQueue;
|
import com.boydti.fawe.util.SetQueue;
|
||||||
import com.boydti.fawe.util.TaskManager;
|
import com.boydti.fawe.util.TaskManager;
|
||||||
import com.sk89q.worldedit.EditSession;
|
import com.sk89q.worldedit.EditSession;
|
||||||
|
import com.sk89q.worldedit.blocks.ItemType;
|
||||||
import com.sk89q.worldedit.world.World;
|
import com.sk89q.worldedit.world.World;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public class Rollback extends FaweCommand {
|
public class Rollback extends FaweCommand {
|
||||||
@ -44,25 +46,33 @@ public class Rollback extends FaweCommand {
|
|||||||
}
|
}
|
||||||
player.deleteMeta("rollback");
|
player.deleteMeta("rollback");
|
||||||
final FaweLocation origin = player.getLocation();
|
final FaweLocation origin = player.getLocation();
|
||||||
rollback(player, Arrays.copyOfRange(args, 1, args.length), new RunnableVal<List<DiskStorageHistory>>() {
|
rollback(player, !player.hasPermission("fawe.rollback.deep"), Arrays.copyOfRange(args, 1, args.length), new RunnableVal<List<DiskStorageHistory>>() {
|
||||||
@Override
|
@Override
|
||||||
public void run(List<DiskStorageHistory> edits) {
|
public void run(List<DiskStorageHistory> edits) {
|
||||||
long total = 0;
|
long total = 0;
|
||||||
player.sendMessage("&d=== Edits ===");
|
player.sendMessage("&d=| Username | Bounds | Distance | Changes | Age |=");
|
||||||
for (DiskStorageHistory edit : edits) {
|
for (DiskStorageHistory edit : edits) {
|
||||||
int[] headerAndFooter = edit.readHeaderAndFooter(new RegionWrapper(origin.x, origin.x, origin.z, origin.z));
|
DiskStorageHistory.DiskStorageSummary summary = edit.summarize(new RegionWrapper(origin.x, origin.x, origin.z, origin.z), !player.hasPermission("fawe.rollback.deep"));
|
||||||
RegionWrapper region = new RegionWrapper(headerAndFooter[0], headerAndFooter[2], headerAndFooter[1], headerAndFooter[3]);
|
RegionWrapper region = new RegionWrapper(summary.minX, summary.maxX, summary.minZ, summary.maxZ);
|
||||||
int dx = region.distanceX(origin.x);
|
int distance = region.distance(origin.x, origin.z);
|
||||||
int dz = region.distanceZ(origin.z);
|
|
||||||
String name = Fawe.imp().getName(edit.getUUID());
|
String name = Fawe.imp().getName(edit.getUUID());
|
||||||
long seconds = (System.currentTimeMillis() - edit.getBDFile().lastModified()) / 1000;
|
long seconds = (System.currentTimeMillis() - edit.getBDFile().lastModified()) / 1000;
|
||||||
total += edit.getBDFile().length();
|
total += edit.getBDFile().length();
|
||||||
player.sendMessage(name + " : " + dx + "," + dz + " : " + MainUtil.secToTime(seconds));
|
int size = summary.getSize();
|
||||||
|
Map<Integer, Double> percents = summary.getPercents();
|
||||||
|
StringBuilder percentString = new StringBuilder();
|
||||||
|
String prefix = "";
|
||||||
|
for (Map.Entry<Integer, Double> entry : percents.entrySet()) {
|
||||||
|
percentString.append(prefix).append(entry.getValue()).append("% ").append(ItemType.toName(entry.getKey()));
|
||||||
|
prefix = ", ";
|
||||||
}
|
}
|
||||||
player.sendMessage("&d=============");
|
player.sendMessage("&c" + name + " | " + region + " | " + distance + "m | " + size + " | " + MainUtil.secToTime(seconds));
|
||||||
|
player.sendMessage("&8 - &7(" + percentString + ")");
|
||||||
|
}
|
||||||
|
player.sendMessage("&d==================================================");
|
||||||
player.sendMessage("&dSize: " + (((double) (total / 1024)) / 1000) + "MB");
|
player.sendMessage("&dSize: " + (((double) (total / 1024)) / 1000) + "MB");
|
||||||
player.sendMessage("&dTo rollback: /frb undo");
|
player.sendMessage("&dTo rollback: /frb undo");
|
||||||
player.sendMessage("&d=============");
|
player.sendMessage("&d==================================================");
|
||||||
player.setMeta("rollback", edits);
|
player.setMeta("rollback", edits);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -70,6 +80,10 @@ public class Rollback extends FaweCommand {
|
|||||||
}
|
}
|
||||||
case "undo":
|
case "undo":
|
||||||
case "revert": {
|
case "revert": {
|
||||||
|
if (!player.hasPermission("fawe.rollback.perform")) {
|
||||||
|
BBC.NO_PERM.send(player, "fawe.rollback.perform");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
final List<DiskStorageHistory> edits = (List<DiskStorageHistory>) player.getMeta("rollback");
|
final List<DiskStorageHistory> edits = (List<DiskStorageHistory>) player.getMeta("rollback");
|
||||||
player.deleteMeta("rollback");
|
player.deleteMeta("rollback");
|
||||||
if (edits == null) {
|
if (edits == null) {
|
||||||
@ -97,7 +111,7 @@ public class Rollback extends FaweCommand {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void rollback(final FawePlayer player, final String[] args, final RunnableVal<List<DiskStorageHistory>> result) {
|
public void rollback(final FawePlayer player, final boolean shallow, final String[] args, final RunnableVal<List<DiskStorageHistory>> result) {
|
||||||
TaskManager.IMP.async(new Runnable() {
|
TaskManager.IMP.async(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@ -148,9 +162,13 @@ public class Rollback extends FaweCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
FaweLocation origin = player.getLocation();
|
FaweLocation origin = player.getLocation();
|
||||||
List<DiskStorageHistory> edits = MainUtil.getBDFiles(origin, user, radius, time);
|
List<DiskStorageHistory> edits = MainUtil.getBDFiles(origin, user, radius, time, shallow);
|
||||||
|
if (edits == null) {
|
||||||
|
player.sendMessage("&cToo broad, try refining your search!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (edits.size() == 0) {
|
if (edits.size() == 0) {
|
||||||
player.sendMessage("No edits found!");
|
player.sendMessage("&cNo edits found!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
result.run(edits);
|
result.run(edits);
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package com.boydti.fawe.object;
|
package com.boydti.fawe.object;
|
||||||
|
|
||||||
|
import com.boydti.fawe.config.BBC;
|
||||||
|
|
||||||
public abstract class FaweCommand<T> {
|
public abstract class FaweCommand<T> {
|
||||||
public final String perm;
|
public final String perm;
|
||||||
|
|
||||||
@ -11,5 +13,21 @@ public abstract class FaweCommand<T> {
|
|||||||
return this.perm;
|
return this.perm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean executeSafe(final FawePlayer<T> player, final String... args) {
|
||||||
|
if (player == null) {
|
||||||
|
execute(player, args);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
if (player.getMeta("fawe_action") != null) {
|
||||||
|
BBC.WORLDEDIT_COMMAND_LIMIT.send(player);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
player.setMeta("fawe_action", true);
|
||||||
|
boolean result = execute(player, args);
|
||||||
|
player.deleteMeta("fawe_action");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public abstract boolean execute(final FawePlayer<T> player, final String... args);
|
public abstract boolean execute(final FawePlayer<T> player, final String... args);
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,7 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@ -355,19 +356,21 @@ public class DiskStorageHistory implements ChangeSet, FaweChangeSet {
|
|||||||
return osENTT;
|
return osENTT;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fx;
|
|
||||||
int fz;
|
|
||||||
|
|
||||||
public int[] readHeaderAndFooter(RegionWrapper requiredRegion) {
|
private DiskStorageSummary summary;
|
||||||
if (fx == 0 && fz == 0 && bdFile.exists()) {
|
|
||||||
if ((ox != 0 || oz != 0) && !requiredRegion.isIn(ox, oz)) {
|
public DiskStorageSummary summarize(RegionWrapper requiredRegion, boolean shallow) {
|
||||||
return new int[] {ox, oz, ox, oz};
|
if (summary != null) {
|
||||||
|
return summary;
|
||||||
}
|
}
|
||||||
try {
|
if (bdFile.exists()) {
|
||||||
FileInputStream fis = new FileInputStream(bdFile);
|
if ((ox != 0 || oz != 0) && !requiredRegion.isIn(ox, oz)) {
|
||||||
|
return summary = new DiskStorageSummary(ox, oz);
|
||||||
|
}
|
||||||
|
try (FileInputStream fis = new FileInputStream(bdFile)) {
|
||||||
LZ4Factory factory = LZ4Factory.fastestInstance();
|
LZ4Factory factory = LZ4Factory.fastestInstance();
|
||||||
LZ4Compressor compressor = factory.fastCompressor();
|
LZ4Compressor compressor = factory.fastCompressor();
|
||||||
final InputStream gis;
|
final LZ4InputStream gis;
|
||||||
if (Settings.COMPRESSION_LEVEL > 0) {
|
if (Settings.COMPRESSION_LEVEL > 0) {
|
||||||
gis = new LZ4InputStream(new LZ4InputStream(fis));
|
gis = new LZ4InputStream(new LZ4InputStream(fis));
|
||||||
} else {
|
} else {
|
||||||
@ -375,37 +378,31 @@ public class DiskStorageHistory implements ChangeSet, FaweChangeSet {
|
|||||||
}
|
}
|
||||||
ox = ((gis.read() << 24) + (gis.read() << 16) + (gis.read() << 8) + (gis.read() << 0));
|
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));
|
oz = ((gis.read() << 24) + (gis.read() << 16) + (gis.read() << 8) + (gis.read() << 0));
|
||||||
|
summary = new DiskStorageSummary(ox, oz);
|
||||||
if (!requiredRegion.isIn(ox, oz)) {
|
if (!requiredRegion.isIn(ox, oz)) {
|
||||||
fis.close();
|
fis.close();
|
||||||
gis.close();
|
gis.close();
|
||||||
return new int[] {ox, oz, ox, oz};
|
return summary;
|
||||||
}
|
}
|
||||||
byte[] even = new byte[9];
|
byte[] buffer = new byte[9];
|
||||||
byte[] odd = new byte[9];
|
|
||||||
byte[] result = null;
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while (true) {
|
while (!shallow || gis.hasBytesAvailableInDecompressedBuffer(9)) {
|
||||||
if ((i++ & 1) == 0) {
|
if (gis.read(buffer) == -1) {
|
||||||
if (gis.read(even) == -1) {
|
|
||||||
result = odd;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (gis.read(odd) == -1) {
|
|
||||||
result = even;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fx = ((byte) result[0] & 0xFF) + ((byte) result[1] << 8) + ox;
|
|
||||||
fz = ((byte) result[2] & 0xFF) + ((byte) result[3] << 8) + oz;
|
|
||||||
fis.close();
|
fis.close();
|
||||||
gis.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];
|
||||||
|
int combined2 = buffer[8];
|
||||||
|
summary.add(x, z, ((combined2 << 4) + (combined1 >> 4)));
|
||||||
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new int[] {ox, oz, fx, fz};
|
return summary;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IntegerPair readHeader() {
|
public IntegerPair readHeader() {
|
||||||
@ -555,4 +552,72 @@ public class DiskStorageHistory implements ChangeSet, FaweChangeSet {
|
|||||||
flush();
|
flush();
|
||||||
return size.get();
|
return size.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class DiskStorageSummary {
|
||||||
|
|
||||||
|
private final int z;
|
||||||
|
private final int x;
|
||||||
|
public int[] blocks;
|
||||||
|
|
||||||
|
public int minX;
|
||||||
|
public int minZ;
|
||||||
|
|
||||||
|
public int maxX;
|
||||||
|
public int maxZ;
|
||||||
|
|
||||||
|
public DiskStorageSummary(int x, int z) {
|
||||||
|
blocks = new int[256];
|
||||||
|
this.x = x;
|
||||||
|
this.z = z;
|
||||||
|
minX = x;
|
||||||
|
maxX = x;
|
||||||
|
minZ = z;
|
||||||
|
maxZ = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void add(int x, int z, int id) {
|
||||||
|
blocks[id]++;
|
||||||
|
if (x < minX) {
|
||||||
|
minX = x;
|
||||||
|
} else if (x > maxX) {
|
||||||
|
maxX = x;
|
||||||
|
}
|
||||||
|
if (z < minZ) {
|
||||||
|
minZ = z;
|
||||||
|
} else if (z > maxZ) {
|
||||||
|
maxZ = z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public HashMap<Integer, Integer> getBlocks() {
|
||||||
|
HashMap<Integer, Integer> map = new HashMap<>();
|
||||||
|
for (int i = 0; i < blocks.length; i++) {
|
||||||
|
if (blocks[i] != 0) {
|
||||||
|
map.put(i, blocks[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<Integer, Double> getPercents() {
|
||||||
|
HashMap<Integer, Integer> map = getBlocks();
|
||||||
|
int count = getSize();
|
||||||
|
HashMap<Integer, Double> newMap = new HashMap<Integer, Double>();
|
||||||
|
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
|
||||||
|
int id = entry.getKey();
|
||||||
|
int changes = entry.getValue();
|
||||||
|
double percent = ((changes * 1000l) / count) / 10d;
|
||||||
|
newMap.put(id, percent);
|
||||||
|
}
|
||||||
|
return newMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSize() {
|
||||||
|
int count = 0;
|
||||||
|
for (int i = 0; i < blocks.length; i++) {
|
||||||
|
count += blocks[i];
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -139,7 +139,7 @@ public class MainUtil {
|
|||||||
return time;
|
return time;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<DiskStorageHistory> getBDFiles(FaweLocation origin, UUID user, int radius, long timediff) {
|
public static List<DiskStorageHistory> getBDFiles(FaweLocation origin, UUID user, int radius, long timediff, boolean shallow) {
|
||||||
File history = new File(Fawe.imp().getDirectory(), "history" + File.separator + origin.world);
|
File history = new File(Fawe.imp().getDirectory(), "history" + File.separator + origin.world);
|
||||||
if (!history.exists()) {
|
if (!history.exists()) {
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
@ -168,6 +168,9 @@ public class MainUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (files.size() > 512) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
World world = origin.getWorld();
|
World world = origin.getWorld();
|
||||||
Collections.sort(files, new Comparator<File>() {
|
Collections.sort(files, new Comparator<File>() {
|
||||||
@Override
|
@Override
|
||||||
@ -180,11 +183,12 @@ public class MainUtil {
|
|||||||
for (File file : files) {
|
for (File file : files) {
|
||||||
UUID uuid = UUID.fromString(file.getParentFile().getName());
|
UUID uuid = UUID.fromString(file.getParentFile().getName());
|
||||||
DiskStorageHistory dsh = new DiskStorageHistory(world, uuid, Integer.parseInt(file.getName().split("\\.")[0]));
|
DiskStorageHistory dsh = new DiskStorageHistory(world, uuid, Integer.parseInt(file.getName().split("\\.")[0]));
|
||||||
int[] headerAndFooter = dsh.readHeaderAndFooter(new RegionWrapper(origin.x - 512, origin.x + 512, origin.z - 512, origin.z + 512));
|
DiskStorageHistory.DiskStorageSummary summary = dsh.summarize(new RegionWrapper(origin.x - 512, origin.x + 512, origin.z - 512, origin.z + 512), shallow);
|
||||||
RegionWrapper region = new RegionWrapper(headerAndFooter[0], headerAndFooter[2], headerAndFooter[1], headerAndFooter[3]);
|
RegionWrapper region = new RegionWrapper(summary.minX, summary.maxX, summary.minZ, summary.maxZ);
|
||||||
if (region.distance(origin.x, origin.z) <= radius) {
|
if (region.distance(origin.x, origin.z) <= radius) {
|
||||||
result.add(dsh);
|
result.add(dsh);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -75,6 +75,10 @@ public class LZ4InputStream extends InputStream {
|
|||||||
return n - numBytesRemainingToSkip;
|
return n - numBytesRemainingToSkip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasBytesAvailableInDecompressedBuffer(int bytes) {
|
||||||
|
return decompressedBufferPosition + bytes <= decompressedBufferLength;
|
||||||
|
}
|
||||||
|
|
||||||
private boolean ensureBytesAvailableInDecompressedBuffer() throws IOException {
|
private boolean ensureBytesAvailableInDecompressedBuffer() throws IOException {
|
||||||
while (decompressedBufferPosition >= decompressedBufferLength) {
|
while (decompressedBufferPosition >= decompressedBufferLength) {
|
||||||
if (!fillBuffer()) {
|
if (!fillBuffer()) {
|
||||||
|
@ -30,7 +30,7 @@ public class SpongeCommand implements CommandCallable {
|
|||||||
BBC.NO_PERM.send(plr, this.cmd.getPerm());
|
BBC.NO_PERM.send(plr, this.cmd.getPerm());
|
||||||
return CommandResult.success();
|
return CommandResult.success();
|
||||||
}
|
}
|
||||||
this.cmd.execute(plr, args.split(" "));
|
this.cmd.executeSafe(plr, args.split(" "));
|
||||||
return CommandResult.success();
|
return CommandResult.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user