History on disk rollback command
Useful for undoing specific edits.
This commit is contained in:
parent
652a983907
commit
bf7d066520
@ -24,6 +24,9 @@ commands:
|
|||||||
wrg:
|
wrg:
|
||||||
description: (FAWE) Select your current WorldEdit Region.
|
description: (FAWE) Select your current WorldEdit Region.
|
||||||
aliases: [/wrg,wer,/wer,worldeditregion,/worldeditregion,/region]
|
aliases: [/wrg,wer,/wer,worldeditregion,/worldeditregion,/region]
|
||||||
|
frb:
|
||||||
|
description: (FAWE) Rollback an edit
|
||||||
|
aliases: [fawerollback,fawerb,/uu,/rb,/frb,/fawerollback,/fawerb]
|
||||||
permissions:
|
permissions:
|
||||||
fawe.bypass:
|
fawe.bypass:
|
||||||
default: false
|
default: false
|
||||||
|
@ -30,6 +30,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.ChatColor;
|
import org.bukkit.ChatColor;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
@ -315,4 +316,14 @@ public class FaweBukkit extends JavaPlugin implements IFawe, Listener {
|
|||||||
public String getPlatform() {
|
public String getPlatform() {
|
||||||
return "bukkit";
|
return "bukkit";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UUID getUUID(String name) {
|
||||||
|
return Bukkit.getOfflinePlayer(name).getUniqueId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName(UUID uuid) {
|
||||||
|
return Bukkit.getOfflinePlayer(uuid).getName();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,9 @@ commands:
|
|||||||
wrg:
|
wrg:
|
||||||
description: (FAWE) Select your current WorldEdit Region.
|
description: (FAWE) Select your current WorldEdit Region.
|
||||||
aliases: [/wrg,wer,/wer,worldeditregion,/worldeditregion,/region]
|
aliases: [/wrg,wer,/wer,worldeditregion,/worldeditregion,/region]
|
||||||
|
frb:
|
||||||
|
description: (FAWE) Rollback an edit
|
||||||
|
aliases: [fawerollback,fawerb,/uu,/rb,/frb,/fawerollback,/fawerb]
|
||||||
permissions:
|
permissions:
|
||||||
fawe.bypass:
|
fawe.bypass:
|
||||||
default: false
|
default: false
|
||||||
|
@ -2,6 +2,7 @@ package com.boydti.fawe;
|
|||||||
|
|
||||||
import com.boydti.fawe.command.FixLighting;
|
import com.boydti.fawe.command.FixLighting;
|
||||||
import com.boydti.fawe.command.Reload;
|
import com.boydti.fawe.command.Reload;
|
||||||
|
import com.boydti.fawe.command.Rollback;
|
||||||
import com.boydti.fawe.command.Stream;
|
import com.boydti.fawe.command.Stream;
|
||||||
import com.boydti.fawe.command.Wea;
|
import com.boydti.fawe.command.Wea;
|
||||||
import com.boydti.fawe.command.WorldEditRegion;
|
import com.boydti.fawe.command.WorldEditRegion;
|
||||||
@ -201,6 +202,7 @@ public class Fawe {
|
|||||||
this.IMP.setupCommand("stream", new Stream());
|
this.IMP.setupCommand("stream", new Stream());
|
||||||
this.IMP.setupCommand("wrg", new WorldEditRegion());
|
this.IMP.setupCommand("wrg", new WorldEditRegion());
|
||||||
this.IMP.setupCommand("fawe", new Reload());
|
this.IMP.setupCommand("fawe", new Reload());
|
||||||
|
this.IMP.setupCommand("frb", new Rollback());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setupConfigs() {
|
public void setupConfigs() {
|
||||||
|
@ -10,6 +10,7 @@ import com.sk89q.worldedit.EditSession;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
public interface IFawe {
|
public interface IFawe {
|
||||||
public void debug(final String s);
|
public void debug(final String s);
|
||||||
@ -39,4 +40,8 @@ public interface IFawe {
|
|||||||
public Set<FawePlayer> getPlayers();
|
public Set<FawePlayer> getPlayers();
|
||||||
|
|
||||||
public String getPlatform();
|
public String getPlatform();
|
||||||
|
|
||||||
|
public UUID getUUID(String name);
|
||||||
|
|
||||||
|
public String getName(UUID uuid);
|
||||||
}
|
}
|
||||||
|
160
core/src/main/java/com/boydti/fawe/command/Rollback.java
Normal file
160
core/src/main/java/com/boydti/fawe/command/Rollback.java
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
package com.boydti.fawe.command;
|
||||||
|
|
||||||
|
import com.boydti.fawe.Fawe;
|
||||||
|
import com.boydti.fawe.config.BBC;
|
||||||
|
import com.boydti.fawe.object.FaweCommand;
|
||||||
|
import com.boydti.fawe.object.FaweLocation;
|
||||||
|
import com.boydti.fawe.object.FawePlayer;
|
||||||
|
import com.boydti.fawe.object.RegionWrapper;
|
||||||
|
import com.boydti.fawe.object.RunnableVal;
|
||||||
|
import com.boydti.fawe.object.changeset.DiskStorageHistory;
|
||||||
|
import com.boydti.fawe.util.MainUtil;
|
||||||
|
import com.boydti.fawe.util.MathMan;
|
||||||
|
import com.boydti.fawe.util.SetQueue;
|
||||||
|
import com.boydti.fawe.util.TaskManager;
|
||||||
|
import com.sk89q.worldedit.EditSession;
|
||||||
|
import com.sk89q.worldedit.world.World;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class Rollback extends FaweCommand {
|
||||||
|
|
||||||
|
public Rollback() {
|
||||||
|
super("fawe.rollback");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean execute(final FawePlayer player, final String... args) {
|
||||||
|
if (args.length < 1) {
|
||||||
|
BBC.COMMAND_SYNTAX.send(player, "/frb <info|undo> u:<uuid> r:<radius> t:<time>");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
World world = player.getWorld();
|
||||||
|
switch (args[0]) {
|
||||||
|
default: {
|
||||||
|
BBC.COMMAND_SYNTAX.send(player, "/frb info u:<uuid> r:<radius> t:<time>");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case "i":
|
||||||
|
case "info": {
|
||||||
|
if (args.length < 2) {
|
||||||
|
BBC.COMMAND_SYNTAX.send(player, "/frb <info|undo> u:<uuid> r:<radius> t:<time>");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
player.deleteMeta("rollback");
|
||||||
|
final FaweLocation origin = player.getLocation();
|
||||||
|
rollback(player, Arrays.copyOfRange(args, 1, args.length), new RunnableVal<List<DiskStorageHistory>>() {
|
||||||
|
@Override
|
||||||
|
public void run(List<DiskStorageHistory> edits) {
|
||||||
|
long total = 0;
|
||||||
|
player.sendMessage("&d=== Edits ===");
|
||||||
|
for (DiskStorageHistory edit : edits) {
|
||||||
|
int[] headerAndFooter = edit.readHeaderAndFooter(new RegionWrapper(origin.x, origin.x, origin.z, origin.z));
|
||||||
|
RegionWrapper region = new RegionWrapper(headerAndFooter[0], headerAndFooter[2], headerAndFooter[1], headerAndFooter[3]);
|
||||||
|
int dx = region.distanceX(origin.x);
|
||||||
|
int dz = region.distanceZ(origin.z);
|
||||||
|
String name = Fawe.imp().getName(edit.getUUID());
|
||||||
|
long seconds = (System.currentTimeMillis() - edit.getBDFile().lastModified()) / 1000;
|
||||||
|
total += edit.getBDFile().length();
|
||||||
|
player.sendMessage(name + " : " + dx + "," + dz + " : " + MainUtil.secToTime(seconds));
|
||||||
|
}
|
||||||
|
player.sendMessage("&d=============");
|
||||||
|
player.sendMessage("&dSize: " + (((double) (total / 1024)) / 1000) + "MB");
|
||||||
|
player.sendMessage("&dTo rollback: /frb undo");
|
||||||
|
player.sendMessage("&d=============");
|
||||||
|
player.setMeta("rollback", edits);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "undo":
|
||||||
|
case "revert": {
|
||||||
|
final List<DiskStorageHistory> edits = (List<DiskStorageHistory>) player.getMeta("rollback");
|
||||||
|
player.deleteMeta("rollback");
|
||||||
|
if (edits == null) {
|
||||||
|
BBC.COMMAND_SYNTAX.send(player, "/frb info u:<uuid> r:<radius> t:<time>");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final Runnable task = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (edits.size() == 0) {
|
||||||
|
player.sendMessage("&d" + BBC.PREFIX.s() + " Rollback complete!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
DiskStorageHistory edit = edits.remove(0);
|
||||||
|
player.sendMessage("&d" + edit.getBDFile());
|
||||||
|
EditSession session = edit.toEditSession(null);
|
||||||
|
session.undo(session);
|
||||||
|
edit.deleteFiles();
|
||||||
|
SetQueue.IMP.addTask(this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
TaskManager.IMP.async(task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void rollback(final FawePlayer player, final String[] args, final RunnableVal<List<DiskStorageHistory>> result) {
|
||||||
|
TaskManager.IMP.async(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
UUID user = null;
|
||||||
|
int radius = Integer.MAX_VALUE;
|
||||||
|
long time = Long.MAX_VALUE;
|
||||||
|
for (int i = 0; i < args.length; i++) {
|
||||||
|
String[] split = args[i].split(":");
|
||||||
|
if (split.length != 2) {
|
||||||
|
BBC.COMMAND_SYNTAX.send(player, "/frb <info|undo> u:<uuid> r:<radius> t:<time>");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (split[0].toLowerCase()) {
|
||||||
|
case "username":
|
||||||
|
case "user":
|
||||||
|
case "u": {
|
||||||
|
try {
|
||||||
|
if (split[1].length() > 16) {
|
||||||
|
user = UUID.fromString(split[1]);
|
||||||
|
} else {
|
||||||
|
user = Fawe.imp().getUUID(split[1]);
|
||||||
|
}
|
||||||
|
} catch (IllegalArgumentException e) {}
|
||||||
|
if (user == null) {
|
||||||
|
player.sendMessage("&dInvalid user: " + split[1]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "r":
|
||||||
|
case "radius": {
|
||||||
|
if (!MathMan.isInteger(split[1])) {
|
||||||
|
player.sendMessage("&dInvalid radius: " + split[1]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
radius = Integer.parseInt(split[1]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "t":
|
||||||
|
case "time": {
|
||||||
|
time = MainUtil.timeToSec(split[1]) * 1000;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
BBC.COMMAND_SYNTAX.send(player, "/frb <info|undo> u:<uuid> r:<radius> t:<time>");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FaweLocation origin = player.getLocation();
|
||||||
|
List<DiskStorageHistory> edits = MainUtil.getBDFiles(origin, user, radius, time);
|
||||||
|
if (edits.size() == 0) {
|
||||||
|
player.sendMessage("No edits found!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
result.run(edits);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -1,16 +0,0 @@
|
|||||||
package com.boydti.fawe.command;
|
|
||||||
|
|
||||||
import com.boydti.fawe.object.FaweCommand;
|
|
||||||
import com.boydti.fawe.object.FawePlayer;
|
|
||||||
|
|
||||||
public class Undolist extends FaweCommand {
|
|
||||||
|
|
||||||
public Undolist() {
|
|
||||||
super("fawe.undolist");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean execute(final FawePlayer player, final String... args) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,5 +1,8 @@
|
|||||||
package com.boydti.fawe.object;
|
package com.boydti.fawe.object;
|
||||||
|
|
||||||
|
import com.sk89q.worldedit.WorldEdit;
|
||||||
|
import com.sk89q.worldedit.world.World;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
||||||
*/
|
*/
|
||||||
@ -32,6 +35,15 @@ public class FaweLocation {
|
|||||||
return ((this.x == other.x) && (this.y == other.y) && (this.z == other.z) && (this.world.equals(other.world)));
|
return ((this.x == other.x) && (this.y == other.y) && (this.z == other.z) && (this.world.equals(other.world)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public World getWorld() {
|
||||||
|
for (World world : WorldEdit.getInstance().getServer().getWorlds()) {
|
||||||
|
if (world.getName().equals(this.world)) {
|
||||||
|
return world;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return this.x << (8 + this.z) << (4 + this.y);
|
return this.x << (8 + this.z) << (4 + this.y);
|
||||||
|
@ -15,8 +15,10 @@ import com.sk89q.worldedit.regions.RegionSelector;
|
|||||||
import com.sk89q.worldedit.regions.selector.CuboidRegionSelector;
|
import com.sk89q.worldedit.regions.selector.CuboidRegionSelector;
|
||||||
import com.sk89q.worldedit.world.World;
|
import com.sk89q.worldedit.world.World;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
@ -30,7 +32,7 @@ public abstract class FawePlayer<T> {
|
|||||||
*/
|
*/
|
||||||
private volatile ConcurrentHashMap<String, Object> meta;
|
private volatile ConcurrentHashMap<String, Object> meta;
|
||||||
|
|
||||||
public static <T> FawePlayer<T> wrap(final Object obj) {
|
public static <V> FawePlayer<V> wrap(final Object obj) {
|
||||||
return Fawe.imp().wrap(obj);
|
return Fawe.imp().wrap(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,7 +73,7 @@ public abstract class FawePlayer<T> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
UUID uuid = getUUID();
|
UUID uuid = getUUID();
|
||||||
ArrayDeque<Integer> editIds = new ArrayDeque<>();
|
List<Integer> editIds = new ArrayList<>();
|
||||||
File folder = new File(Fawe.imp().getDirectory(), "history" + File.separator + world.getName() + File.separator + uuid);
|
File folder = new File(Fawe.imp().getDirectory(), "history" + File.separator + world.getName() + File.separator + uuid);
|
||||||
if (folder.isDirectory()) {
|
if (folder.isDirectory()) {
|
||||||
for (File file : folder.listFiles()) {
|
for (File file : folder.listFiles()) {
|
||||||
@ -81,6 +83,7 @@ public abstract class FawePlayer<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Collections.sort(editIds);
|
||||||
if (editIds.size() > 0) {
|
if (editIds.size() > 0) {
|
||||||
Fawe.debug(BBC.PREFIX.s() + " Indexing " + editIds.size() + " history objects for " + getName());
|
Fawe.debug(BBC.PREFIX.s() + " Indexing " + editIds.size() + " history objects for " + getName());
|
||||||
for (int index : editIds) {
|
for (int index : editIds) {
|
||||||
@ -169,20 +172,20 @@ public abstract class FawePlayer<T> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the metadata for a key.
|
* Get the metadata for a key.
|
||||||
* @param <T>
|
* @param <V>
|
||||||
* @param key
|
* @param key
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public <T> T getMeta(String key) {
|
public <V> V getMeta(String key) {
|
||||||
if (this.meta != null) {
|
if (this.meta != null) {
|
||||||
return (T) this.meta.get(key);
|
return (V) this.meta.get(key);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> T getMeta(String key, T def) {
|
public <V> V getMeta(String key, V def) {
|
||||||
if (this.meta != null) {
|
if (this.meta != null) {
|
||||||
T value = (T) this.meta.get(key);
|
V value = (V) this.meta.get(key);
|
||||||
return value == null ? def : value;
|
return value == null ? def : value;
|
||||||
}
|
}
|
||||||
return def;
|
return def;
|
||||||
|
@ -26,6 +26,45 @@ public class RegionWrapper {
|
|||||||
return ((x >= this.minX) && (x <= this.maxX) && (z >= this.minZ) && (z <= this.maxZ));
|
return ((x >= this.minX) && (x <= this.maxX) && (z >= this.minZ) && (z <= this.maxZ));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int distanceX(int x) {
|
||||||
|
if (x >= minX) {
|
||||||
|
if (x <= maxX) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return maxX - x;
|
||||||
|
}
|
||||||
|
return minX - x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int distanceZ(int z) {
|
||||||
|
if (z >= minZ) {
|
||||||
|
if (z <= maxZ) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return maxZ - z;
|
||||||
|
}
|
||||||
|
return minZ - z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int distance(int x, int z) {
|
||||||
|
if (isIn(x, z)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int dx1 = Math.abs(x - minX);
|
||||||
|
int dx2 = Math.abs(x - maxX);
|
||||||
|
int dz1 = Math.abs(z - minZ);
|
||||||
|
int dz2 = Math.abs(z - maxZ);
|
||||||
|
if (x >= minX && x <= maxX) {
|
||||||
|
return Math.min(dz1, dz2);
|
||||||
|
} else if (z >= minZ && z <= maxZ) {
|
||||||
|
return Math.min(dx1, dx2);
|
||||||
|
} else {
|
||||||
|
int dx = Math.min(dx1, dx2);
|
||||||
|
int dz = Math.min(dz1, dz2);
|
||||||
|
return (int) Math.sqrt(dx * dx + dz * dz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return this.minX + "," + this.minZ + "->" + this.maxX + "," + this.maxZ;
|
return this.minX + "," + this.minZ + "->" + this.maxX + "," + this.maxZ;
|
||||||
|
@ -4,6 +4,8 @@ import com.boydti.fawe.Fawe;
|
|||||||
import com.boydti.fawe.FaweCache;
|
import com.boydti.fawe.FaweCache;
|
||||||
import com.boydti.fawe.config.BBC;
|
import com.boydti.fawe.config.BBC;
|
||||||
import com.boydti.fawe.config.Settings;
|
import com.boydti.fawe.config.Settings;
|
||||||
|
import com.boydti.fawe.object.IntegerPair;
|
||||||
|
import com.boydti.fawe.object.RegionWrapper;
|
||||||
import com.boydti.fawe.util.MainUtil;
|
import com.boydti.fawe.util.MainUtil;
|
||||||
import com.boydti.fawe.util.ReflectionUtils;
|
import com.boydti.fawe.util.ReflectionUtils;
|
||||||
import com.sk89q.jnbt.CompoundTag;
|
import com.sk89q.jnbt.CompoundTag;
|
||||||
@ -52,6 +54,7 @@ import net.jpountz.lz4.LZ4OutputStream;
|
|||||||
*/
|
*/
|
||||||
public class DiskStorageHistory implements ChangeSet, FaweChangeSet {
|
public class DiskStorageHistory implements ChangeSet, FaweChangeSet {
|
||||||
|
|
||||||
|
private UUID uuid;
|
||||||
private File bdFile;
|
private File bdFile;
|
||||||
private File nbtfFile;
|
private File nbtfFile;
|
||||||
private File nbttFile;
|
private File nbttFile;
|
||||||
@ -95,6 +98,14 @@ public class DiskStorageHistory implements ChangeSet, FaweChangeSet {
|
|||||||
private AtomicInteger size = new AtomicInteger();
|
private AtomicInteger size = new AtomicInteger();
|
||||||
private World world;
|
private World world;
|
||||||
|
|
||||||
|
public void deleteFiles() {
|
||||||
|
bdFile.delete();
|
||||||
|
nbtfFile.delete();
|
||||||
|
nbttFile.delete();
|
||||||
|
entfFile.delete();
|
||||||
|
enttFile.delete();
|
||||||
|
}
|
||||||
|
|
||||||
public DiskStorageHistory(World world, UUID uuid) {
|
public DiskStorageHistory(World world, UUID uuid) {
|
||||||
size = new AtomicInteger();
|
size = new AtomicInteger();
|
||||||
String base = "history" + File.separator + world.getName() + File.separator + uuid;
|
String base = "history" + File.separator + world.getName() + File.separator + uuid;
|
||||||
@ -119,6 +130,7 @@ public class DiskStorageHistory implements ChangeSet, FaweChangeSet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void init(World world, UUID uuid, int i) {
|
public void init(World world, UUID uuid, int i) {
|
||||||
|
this.uuid = uuid;
|
||||||
this.world = world;
|
this.world = world;
|
||||||
String base = "history" + File.separator + world.getName() + File.separator + uuid;
|
String base = "history" + File.separator + world.getName() + File.separator + uuid;
|
||||||
base += File.separator + i;
|
base += File.separator + i;
|
||||||
@ -129,6 +141,14 @@ public class DiskStorageHistory implements ChangeSet, FaweChangeSet {
|
|||||||
bdFile = new File(Fawe.imp().getDirectory(), base + ".bd");
|
bdFile = new File(Fawe.imp().getDirectory(), base + ".bd");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public UUID getUUID() {
|
||||||
|
return uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getBDFile() {
|
||||||
|
return bdFile;
|
||||||
|
}
|
||||||
|
|
||||||
public EditSession toEditSession(Player player) {
|
public EditSession toEditSession(Player player) {
|
||||||
EditSessionFactory factory = WorldEdit.getInstance().getEditSessionFactory();
|
EditSessionFactory factory = WorldEdit.getInstance().getEditSessionFactory();
|
||||||
EditSession edit = factory.getEditSession(world, -1, null, player);
|
EditSession edit = factory.getEditSession(world, -1, null, player);
|
||||||
@ -335,6 +355,82 @@ public class DiskStorageHistory implements ChangeSet, FaweChangeSet {
|
|||||||
return osENTT;
|
return osENTT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int fx;
|
||||||
|
int fz;
|
||||||
|
|
||||||
|
public int[] readHeaderAndFooter(RegionWrapper requiredRegion) {
|
||||||
|
if (fx == 0 && fz == 0 && bdFile.exists()) {
|
||||||
|
if ((ox != 0 || oz != 0) && !requiredRegion.isIn(ox, oz)) {
|
||||||
|
return new int[] {ox, oz, ox, oz};
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
FileInputStream fis = new FileInputStream(bdFile);
|
||||||
|
LZ4Factory factory = LZ4Factory.fastestInstance();
|
||||||
|
LZ4Compressor compressor = factory.fastCompressor();
|
||||||
|
final InputStream gis;
|
||||||
|
if (Settings.COMPRESSION_LEVEL > 0) {
|
||||||
|
gis = new LZ4InputStream(new LZ4InputStream(fis));
|
||||||
|
} else {
|
||||||
|
gis = new LZ4InputStream(fis);
|
||||||
|
}
|
||||||
|
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));
|
||||||
|
if (!requiredRegion.isIn(ox, oz)) {
|
||||||
|
fis.close();
|
||||||
|
gis.close();
|
||||||
|
return new int[] {ox, oz, ox, oz};
|
||||||
|
}
|
||||||
|
byte[] even = new byte[9];
|
||||||
|
byte[] odd = new byte[9];
|
||||||
|
byte[] result = null;
|
||||||
|
int i = 0;
|
||||||
|
while (true) {
|
||||||
|
if ((i++ & 1) == 0) {
|
||||||
|
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();
|
||||||
|
gis.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new int[] {ox, oz, fx, fz};
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntegerPair readHeader() {
|
||||||
|
if (ox == 0 && oz == 0 && bdFile.exists()) {
|
||||||
|
try {
|
||||||
|
FileInputStream fis = new FileInputStream(bdFile);
|
||||||
|
LZ4Factory factory = LZ4Factory.fastestInstance();
|
||||||
|
LZ4Compressor compressor = factory.fastCompressor();
|
||||||
|
final InputStream gis;
|
||||||
|
if (Settings.COMPRESSION_LEVEL > 0) {
|
||||||
|
gis = new LZ4InputStream(new LZ4InputStream(fis));
|
||||||
|
} else {
|
||||||
|
gis = new LZ4InputStream(fis);
|
||||||
|
}
|
||||||
|
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));
|
||||||
|
fis.close();
|
||||||
|
gis.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new IntegerPair(ox, oz);
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("resource")
|
@SuppressWarnings("resource")
|
||||||
public Iterator<Change> getIterator(final boolean dir) {
|
public Iterator<Change> getIterator(final boolean dir) {
|
||||||
flush();
|
flush();
|
||||||
|
@ -2,15 +2,24 @@ package com.boydti.fawe.util;
|
|||||||
|
|
||||||
import com.boydti.fawe.Fawe;
|
import com.boydti.fawe.Fawe;
|
||||||
import com.boydti.fawe.config.BBC;
|
import com.boydti.fawe.config.BBC;
|
||||||
|
import com.boydti.fawe.object.FaweLocation;
|
||||||
import com.boydti.fawe.object.FawePlayer;
|
import com.boydti.fawe.object.FawePlayer;
|
||||||
|
import com.boydti.fawe.object.RegionWrapper;
|
||||||
import com.boydti.fawe.object.RunnableVal;
|
import com.boydti.fawe.object.RunnableVal;
|
||||||
|
import com.boydti.fawe.object.changeset.DiskStorageHistory;
|
||||||
import com.sk89q.jnbt.CompoundTag;
|
import com.sk89q.jnbt.CompoundTag;
|
||||||
import com.sk89q.jnbt.EndTag;
|
import com.sk89q.jnbt.EndTag;
|
||||||
import com.sk89q.jnbt.ListTag;
|
import com.sk89q.jnbt.ListTag;
|
||||||
import com.sk89q.jnbt.Tag;
|
import com.sk89q.jnbt.Tag;
|
||||||
|
import com.sk89q.worldedit.world.World;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
public class MainUtil {
|
public class MainUtil {
|
||||||
/*
|
/*
|
||||||
@ -50,6 +59,136 @@ public class MainUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String secToTime(long time) {
|
||||||
|
StringBuilder toreturn = new StringBuilder();
|
||||||
|
if (time>=33868800) {
|
||||||
|
int years = (int) (time/33868800);
|
||||||
|
time-=years*33868800;
|
||||||
|
toreturn.append(years+"y ");
|
||||||
|
}
|
||||||
|
if (time>=604800) {
|
||||||
|
int weeks = (int) (time/604800);
|
||||||
|
time-=weeks*604800;
|
||||||
|
toreturn.append(weeks+"w ");
|
||||||
|
}
|
||||||
|
if (time>=86400) {
|
||||||
|
int days = (int) (time/86400);
|
||||||
|
time-=days*86400;
|
||||||
|
toreturn.append(days+"d ");
|
||||||
|
}
|
||||||
|
if (time>=3600) {
|
||||||
|
int hours = (int) (time/3600);
|
||||||
|
time-=hours*3600;
|
||||||
|
toreturn.append(hours+"h ");
|
||||||
|
}
|
||||||
|
if (time>=60) {
|
||||||
|
int minutes = (int) (time/60);
|
||||||
|
time-=minutes*60;
|
||||||
|
toreturn.append(minutes+"m ");
|
||||||
|
}
|
||||||
|
if (toreturn.equals("")||time>0){
|
||||||
|
toreturn.append((time)+"s ");
|
||||||
|
}
|
||||||
|
return toreturn.toString().trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long timeToSec(String string) {
|
||||||
|
if (MathMan.isInteger(string)) {
|
||||||
|
return Long.parseLong(string);
|
||||||
|
}
|
||||||
|
string = string.toLowerCase().trim().toLowerCase();
|
||||||
|
if (string.equalsIgnoreCase("false")) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
String[] split = string.split(" ");
|
||||||
|
long time = 0;
|
||||||
|
for (String value : split) {
|
||||||
|
int nums = Integer.parseInt(value.replaceAll("[^\\d]", ""));
|
||||||
|
String letters = value.replaceAll("[^a-z]", "");
|
||||||
|
switch (letters) {
|
||||||
|
case "week":
|
||||||
|
case "weeks":
|
||||||
|
case "wks":
|
||||||
|
case "w":
|
||||||
|
|
||||||
|
time += 604800 * nums;
|
||||||
|
case "days":
|
||||||
|
case "day":
|
||||||
|
case "d":
|
||||||
|
time += 86400 * nums;
|
||||||
|
case "hour":
|
||||||
|
case "hr":
|
||||||
|
case "hrs":
|
||||||
|
case "hours":
|
||||||
|
case "h":
|
||||||
|
time += 3600 * nums;
|
||||||
|
case "minutes":
|
||||||
|
case "minute":
|
||||||
|
case "mins":
|
||||||
|
case "min":
|
||||||
|
case "m":
|
||||||
|
time += 60 * nums;
|
||||||
|
case "seconds":
|
||||||
|
case "second":
|
||||||
|
case "secs":
|
||||||
|
case "sec":
|
||||||
|
case "s":
|
||||||
|
time += nums;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<DiskStorageHistory> getBDFiles(FaweLocation origin, UUID user, int radius, long timediff) {
|
||||||
|
File history = new File(Fawe.imp().getDirectory(), "history" + File.separator + origin.world);
|
||||||
|
if (!history.exists()) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
ArrayList<File> files = new ArrayList<>();
|
||||||
|
for (File userFile : history.listFiles()) {
|
||||||
|
if (!userFile.isDirectory()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
UUID userUUID;
|
||||||
|
try {
|
||||||
|
userUUID = UUID.fromString(userFile.getName());
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (user != null && !userUUID.equals(user)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ArrayList<Integer> ids = new ArrayList<>();
|
||||||
|
for (File file : userFile.listFiles()) {
|
||||||
|
if (file.getName().endsWith(".bd")) {
|
||||||
|
if (timediff > Integer.MAX_VALUE || now - file.lastModified() <= timediff) {
|
||||||
|
files.add(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
World world = origin.getWorld();
|
||||||
|
Collections.sort(files, new Comparator<File>() {
|
||||||
|
@Override
|
||||||
|
public int compare(File a, File b) {
|
||||||
|
long value = a.lastModified() - b.lastModified();
|
||||||
|
return value == 0 ? 0 : value < 0 ? 1 : -1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
ArrayList<DiskStorageHistory> result = new ArrayList<>();
|
||||||
|
for (File file : files) {
|
||||||
|
UUID uuid = UUID.fromString(file.getParentFile().getName());
|
||||||
|
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));
|
||||||
|
RegionWrapper region = new RegionWrapper(headerAndFooter[0], headerAndFooter[2], headerAndFooter[1], headerAndFooter[3]);
|
||||||
|
if (region.distance(origin.x, origin.z) <= radius) {
|
||||||
|
result.add(dsh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public static void deleteOlder(File directory, final long timeDiff) {
|
public static void deleteOlder(File directory, final long timeDiff) {
|
||||||
final long now = System.currentTimeMillis();
|
final long now = System.currentTimeMillis();
|
||||||
iterateFiles(directory, new RunnableVal<File>() {
|
iterateFiles(directory, new RunnableVal<File>() {
|
||||||
|
194
core/src/main/java/com/boydti/fawe/util/MathMan.java
Normal file
194
core/src/main/java/com/boydti/fawe/util/MathMan.java
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
package com.boydti.fawe.util;
|
||||||
|
|
||||||
|
public class MathMan {
|
||||||
|
|
||||||
|
private static final int ATAN2_BITS = 7;
|
||||||
|
private static final int ATAN2_BITS2 = ATAN2_BITS << 1;
|
||||||
|
private static final int ATAN2_MASK = ~(-1 << ATAN2_BITS2);
|
||||||
|
private static final int ATAN2_COUNT = ATAN2_MASK + 1;
|
||||||
|
private static final int ATAN2_DIM = (int) Math.sqrt(ATAN2_COUNT);
|
||||||
|
private static final float INV_ATAN2_DIM_MINUS_1 = 1.0f / (ATAN2_DIM - 1);
|
||||||
|
private static final float[] atan2 = new float[ATAN2_COUNT];
|
||||||
|
|
||||||
|
static {
|
||||||
|
for (int i = 0; i < ATAN2_DIM; i++) {
|
||||||
|
for (int j = 0; j < ATAN2_DIM; j++) {
|
||||||
|
float x0 = (float) i / ATAN2_DIM;
|
||||||
|
float y0 = (float) j / ATAN2_DIM;
|
||||||
|
|
||||||
|
atan2[(j * ATAN2_DIM) + i] = (float) Math.atan2(y0, x0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double getMean(int[] array) {
|
||||||
|
double count = 0;
|
||||||
|
for (int i : array) {
|
||||||
|
count += i;
|
||||||
|
}
|
||||||
|
return count / array.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double getMean(double[] array) {
|
||||||
|
double count = 0;
|
||||||
|
for (double i : array) {
|
||||||
|
count += i;
|
||||||
|
}
|
||||||
|
return count / array.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int pair(short x, short y) {
|
||||||
|
return (x << 16) | (y & 0xFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static short unpairX(int hash) {
|
||||||
|
return (short) (hash >> 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static short unpairY(int hash) {
|
||||||
|
return (short) (hash & 0xFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns [x, y, z]
|
||||||
|
* @param yaw
|
||||||
|
* @param pitch
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static float[] getDirection(float yaw, float pitch) {
|
||||||
|
double pitch_sin = Math.sin(pitch);
|
||||||
|
return new float[]{(float) (pitch_sin * Math.cos(yaw)), (float) (pitch_sin * Math.sin(yaw)), (float) Math.cos(pitch)};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int roundInt(double value) {
|
||||||
|
return (int) (value < 0 ? (value == (int) value) ? value : value - 1 : value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns [ pitch, yaw ]
|
||||||
|
* @param x
|
||||||
|
* @param y
|
||||||
|
* @param z
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static float[] getPitchAndYaw(float x, float y, float z) {
|
||||||
|
float distance = sqrtApprox((z * z) + (x * x));
|
||||||
|
return new float[]{atan2(y, distance), atan2(x, z)};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final float atan2(float y, float x) {
|
||||||
|
float add, mul;
|
||||||
|
|
||||||
|
if (x < 0.0f) {
|
||||||
|
if (y < 0.0f) {
|
||||||
|
x = -x;
|
||||||
|
y = -y;
|
||||||
|
|
||||||
|
mul = 1.0f;
|
||||||
|
} else {
|
||||||
|
x = -x;
|
||||||
|
mul = -1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
add = -3.141592653f;
|
||||||
|
} else {
|
||||||
|
if (y < 0.0f) {
|
||||||
|
y = -y;
|
||||||
|
mul = -1.0f;
|
||||||
|
} else {
|
||||||
|
mul = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
add = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float invDiv = 1.0f / (((x < y) ? y : x) * INV_ATAN2_DIM_MINUS_1);
|
||||||
|
|
||||||
|
int xi = (int) (x * invDiv);
|
||||||
|
int yi = (int) (y * invDiv);
|
||||||
|
|
||||||
|
return (atan2[(yi * ATAN2_DIM) + xi] + add) * mul;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float sqrtApprox(float f) {
|
||||||
|
return f * Float.intBitsToFloat(0x5f375a86 - (Float.floatToIntBits(f) >> 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double sqrtApprox(double d) {
|
||||||
|
return Double.longBitsToDouble(((Double.doubleToLongBits(d) - (1l << 52)) >> 1) + (1l << 61));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float invSqrt(float x) {
|
||||||
|
float xhalf = 0.5f * x;
|
||||||
|
int i = Float.floatToIntBits(x);
|
||||||
|
i = 0x5f3759df - (i >> 1);
|
||||||
|
x = Float.intBitsToFloat(i);
|
||||||
|
x = x * (1.5f - (xhalf * x * x));
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getPositiveId(int i) {
|
||||||
|
if (i < 0) {
|
||||||
|
return (-i * 2) - 1;
|
||||||
|
}
|
||||||
|
return i * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isInteger(String str) {
|
||||||
|
if (str == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int length = str.length();
|
||||||
|
if (length == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int i = 0;
|
||||||
|
if (str.charAt(0) == '-') {
|
||||||
|
if (length == 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
i = 1;
|
||||||
|
}
|
||||||
|
for (; i < length; i++) {
|
||||||
|
char c = str.charAt(i);
|
||||||
|
if ((c <= '/') || (c >= ':')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double getSD(double[] array, double av) {
|
||||||
|
double sd = 0;
|
||||||
|
for (double element : array) {
|
||||||
|
sd += Math.pow(Math.abs(element - av), 2);
|
||||||
|
}
|
||||||
|
return Math.sqrt(sd / array.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double getSD(int[] array, double av) {
|
||||||
|
double sd = 0;
|
||||||
|
for (int element : array) {
|
||||||
|
sd += Math.pow(Math.abs(element - av), 2);
|
||||||
|
}
|
||||||
|
return Math.sqrt(sd / array.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int mod(int x, int y) {
|
||||||
|
if (isPowerOfTwo(y)) {
|
||||||
|
return x & (y - 1);
|
||||||
|
}
|
||||||
|
return x % y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int unsignedmod(int x, int y) {
|
||||||
|
if (isPowerOfTwo(y)) {
|
||||||
|
return x & (y - 1);
|
||||||
|
}
|
||||||
|
return x % y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isPowerOfTwo(int x) {
|
||||||
|
return (x & (x - 1)) == 0;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user