geforkt von Mirrors/FastAsyncWorldEdit
Various major
Add regen Add //history [find|restore|rollback|summary|clear] - history commands are interactable - inspect brush info is interactable Commands are now logged to a searchable database Fix some cases of id/ordinal mismatch
Dieser Commit ist enthalten in:
Ursprung
edcaeb6cfe
Commit
1844d4dba7
@ -1,56 +0,0 @@
|
||||
package com.boydti.fawe.bukkit;
|
||||
|
||||
import com.sk89q.worldedit.util.formatting.text.TextComponent;
|
||||
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
|
||||
import com.boydti.fawe.object.FaweCommand;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.BukkitBlockCommandSender;
|
||||
import com.sk89q.worldedit.bukkit.BukkitCommandSender;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import org.bukkit.command.BlockCommandSender;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class BukkitCommand implements CommandExecutor {
|
||||
|
||||
private final FaweCommand cmd;
|
||||
|
||||
public BukkitCommand(FaweCommand cmd) {
|
||||
this.cmd = cmd;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(@NotNull CommandSender sender, Command cmd, String label, String[] args) {
|
||||
final Actor plr = wrapCommandSender(sender);
|
||||
if (!sender.hasPermission(this.cmd.getPerm()) && !sender.isOp()) {
|
||||
plr.printError(TranslatableComponent.of("fawe.error.no.perm", TextComponent.of(this.cmd.getPerm())));
|
||||
return true;
|
||||
}
|
||||
this.cmd.executeSafe(plr, args);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to wrap a Bukkit Player as a WorldEdit Player.
|
||||
*
|
||||
* @param player a player
|
||||
* @return a wrapped player
|
||||
*/
|
||||
public com.sk89q.worldedit.bukkit.BukkitPlayer wrapPlayer(Player player) {
|
||||
return BukkitAdapter.adapt(player);
|
||||
}
|
||||
|
||||
public Actor wrapCommandSender(CommandSender sender) {
|
||||
if (sender instanceof Player) {
|
||||
return wrapPlayer((Player) sender);
|
||||
} else if (sender instanceof BlockCommandSender) {
|
||||
return new BukkitBlockCommandSender(WorldEditPlugin.getInstance(), (BlockCommandSender) sender);
|
||||
}
|
||||
|
||||
return new BukkitCommandSender(WorldEditPlugin.getInstance(), sender);
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@ package com.boydti.fawe.bukkit.adapter.mc1_14;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static org.slf4j.LoggerFactory.getLogger;
|
||||
|
||||
import com.bekvon.bukkit.residence.commands.set;
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
@ -67,26 +68,18 @@ import org.jetbrains.annotations.NotNull;
|
||||
public class BukkitGetBlocks_1_14 extends CharGetBlocks {
|
||||
public ChunkSection[] sections;
|
||||
public Chunk nmsChunk;
|
||||
public CraftWorld world;
|
||||
public WorldServer world;
|
||||
public int X, Z;
|
||||
// private boolean forceLoad;
|
||||
|
||||
public BukkitGetBlocks_1_14(World world, int X, int Z, boolean forceLoad) {
|
||||
this.world = (CraftWorld) world;
|
||||
this.X = X;
|
||||
this.Z = Z;
|
||||
// if (forceLoad) {
|
||||
// this.world.getHandle().setForceLoaded(X, Z, this.forceLoad = true);
|
||||
// }
|
||||
public BukkitGetBlocks_1_14(World world, int X, int Z) {
|
||||
this(((CraftWorld) world).getHandle(), X, Z);
|
||||
}
|
||||
|
||||
// @Override
|
||||
// protected void finalize() {
|
||||
// if (forceLoad) {
|
||||
// this.world.getHandle().setForceLoaded(X, Z, forceLoad = false);
|
||||
// }
|
||||
// }
|
||||
|
||||
public BukkitGetBlocks_1_14(WorldServer world, int X, int Z) {
|
||||
this.world = world;
|
||||
this.X = X;
|
||||
this.Z = Z;
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
return X;
|
||||
@ -133,14 +126,16 @@ public class BukkitGetBlocks_1_14 extends CharGetBlocks {
|
||||
|
||||
@Override
|
||||
public CompoundTag getEntity(UUID uuid) {
|
||||
org.bukkit.entity.Entity bukkitEnt = world.getEntity(uuid);
|
||||
if (bukkitEnt != null) {
|
||||
Entity entity = world.getEntity(uuid);
|
||||
if (entity != null) {
|
||||
org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity();
|
||||
return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData();
|
||||
}
|
||||
for (List<Entity> entry : getChunk().getEntitySlices()) {
|
||||
if (entry != null) {
|
||||
for (Entity entity : entry) {
|
||||
if (uuid.equals(entity.getUniqueID())) {
|
||||
for (Entity ent : entry) {
|
||||
if (uuid.equals(ent.getUniqueID())) {
|
||||
org.bukkit.entity.Entity bukkitEnt = ent.getBukkitEntity();
|
||||
return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData();
|
||||
}
|
||||
}
|
||||
@ -235,7 +230,7 @@ public class BukkitGetBlocks_1_14 extends CharGetBlocks {
|
||||
@Override
|
||||
public <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
|
||||
try {
|
||||
WorldServer nmsWorld = world.getHandle();
|
||||
WorldServer nmsWorld = world;
|
||||
Chunk nmsChunk = BukkitAdapter_1_14.ensureLoaded(nmsWorld, X, Z);
|
||||
|
||||
// Remove existing tiles
|
||||
@ -633,7 +628,7 @@ public class BukkitGetBlocks_1_14 extends CharGetBlocks {
|
||||
synchronized (this) {
|
||||
tmp = nmsChunk;
|
||||
if (tmp == null) {
|
||||
nmsChunk = tmp = BukkitAdapter_1_14.ensureLoaded(this.world.getHandle(), X, Z);
|
||||
nmsChunk = tmp = BukkitAdapter_1_14.ensureLoaded(this.world, X, Z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import org.bukkit.World;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Collection;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
@ -19,10 +20,10 @@ public class GriefPreventionFilter extends CuboidRegionFilter {
|
||||
|
||||
public GriefPreventionFilter(World world) {
|
||||
checkNotNull(world);
|
||||
this.claims = TaskManager.IMP.sync(new RunnableVal<Collection<Claim>>() {
|
||||
this.claims = TaskManager.IMP.sync(new Supplier<Collection<Claim>>() {
|
||||
@Override
|
||||
public void run(Collection<Claim> claims) {
|
||||
this.value = new ArrayDeque<>(GriefPrevention.instance.dataStore.getClaims());
|
||||
public Collection<Claim> get() {
|
||||
return new ArrayDeque<>(GriefPrevention.instance.dataStore.getClaims());
|
||||
}
|
||||
});
|
||||
this.world = world;
|
||||
|
@ -3,6 +3,7 @@ package com.boydti.fawe.bukkit.filter;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static org.slf4j.LoggerFactory.getLogger;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweAPI;
|
||||
import com.boydti.fawe.object.RunnableVal;
|
||||
import com.boydti.fawe.regions.general.CuboidRegionFilter;
|
||||
@ -26,20 +27,17 @@ public class WorldGuardFilter extends CuboidRegionFilter {
|
||||
}
|
||||
@Override
|
||||
public void calculateRegions() {
|
||||
TaskManager.IMP.sync(new RunnableVal<Object>() {
|
||||
@Override
|
||||
public void run(Object value) {
|
||||
WorldGuardFilter.this.manager = WorldGuard.getInstance().getPlatform().getRegionContainer().get(FaweAPI.getWorld(world.getName()));
|
||||
for (ProtectedRegion region : manager.getRegions().values()) {
|
||||
BlockVector3 min = region.getMinimumPoint();
|
||||
BlockVector3 max = region.getMaximumPoint();
|
||||
if (max.getBlockX() - min.getBlockX() > 1024 || max.getBlockZ() - min.getBlockZ() > 1024) {
|
||||
getLogger(WorldGuardFilter.class).debug("Large or complex region shapes cannot be optimized. Filtering will be slower");
|
||||
large = true;
|
||||
break;
|
||||
}
|
||||
add(min.toBlockVector2(), max.toBlockVector2());
|
||||
Fawe.get().getQueueHandler().sync(() -> {
|
||||
WorldGuardFilter.this.manager = WorldGuard.getInstance().getPlatform().getRegionContainer().get(FaweAPI.getWorld(world.getName()));
|
||||
for (ProtectedRegion region : manager.getRegions().values()) {
|
||||
BlockVector3 min = region.getMinimumPoint();
|
||||
BlockVector3 max = region.getMaximumPoint();
|
||||
if (max.getBlockX() - min.getBlockX() > 1024 || max.getBlockZ() - min.getBlockZ() > 1024) {
|
||||
getLogger(WorldGuardFilter.class).debug("Large or complex region shapes cannot be optimized. Filtering will be slower");
|
||||
large = true;
|
||||
break;
|
||||
}
|
||||
add(min.toBlockVector2(), max.toBlockVector2());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -74,27 +74,6 @@ public class BukkitBlockCommandSender extends AbstractNonPlayerActor implements
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void print(String msg) {
|
||||
for (String part : msg.split("\n")) {
|
||||
print(TextComponent.of(part, TextColor.GRAY));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void printDebug(String msg) {
|
||||
for (String part : msg.split("\n")) {
|
||||
print(TextComponent.of(part, TextColor.GRAY));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void printError(String msg) {
|
||||
for (String part : msg.split("\n")) {
|
||||
print(TextComponent.of(part, TextColor.RED));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void print(Component component) {
|
||||
TextAdapter.sendComponent(sender, WorldEditText.format(component, getLocale()));
|
||||
|
@ -74,27 +74,6 @@ public class BukkitCommandSender extends AbstractNonPlayerActor {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void print(String msg) {
|
||||
for (String part : msg.split("\n")) {
|
||||
sender.sendMessage("\u00A7d" + part);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void printDebug(String msg) {
|
||||
for (String part : msg.split("\n")) {
|
||||
sender.sendMessage("\u00A77" + part);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void printError(String msg) {
|
||||
for (String part : msg.split("\n")) {
|
||||
sender.sendMessage("\u00A7c" + part);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void print(Component component) {
|
||||
TextAdapter.sendComponent(sender, WorldEditText.format(component, getLocale()));
|
||||
|
@ -190,6 +190,10 @@ public class BukkitWorld extends AbstractWorld {
|
||||
|
||||
@Override
|
||||
public boolean regenerate(Region region, EditSession editSession) {
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
if (adapter != null) {
|
||||
return adapter.regenerate(this, region, editSession);
|
||||
}
|
||||
/*
|
||||
BaseBlock[] history = new BaseBlock[16 * 16 * (getMaxY() + 1)];
|
||||
|
||||
@ -560,7 +564,7 @@ public class BukkitWorld extends AbstractWorld {
|
||||
|
||||
@Override
|
||||
public IChunkGet get(int chunkX, int chunkZ) {
|
||||
return new BukkitGetBlocks_1_14(getWorldChecked(), chunkX, chunkZ, Settings.IMP.QUEUE.POOL);
|
||||
return new BukkitGetBlocks_1_14(getWorldChecked(), chunkX, chunkZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -24,11 +24,13 @@ import com.boydti.fawe.beta.implementation.packet.ChunkPacket;
|
||||
import com.boydti.fawe.bukkit.FaweBukkit;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.blocks.BaseItem;
|
||||
import com.sk89q.worldedit.blocks.BaseItemStack;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.registry.state.Property;
|
||||
import com.sk89q.worldedit.util.Direction;
|
||||
import com.sk89q.worldedit.world.DataFixer;
|
||||
@ -232,4 +234,8 @@ public interface BukkitImplAdapter<T> extends IBukkitAdapter {
|
||||
default void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket packet) {
|
||||
throw new UnsupportedOperationException("Cannot send fake chunks");
|
||||
}
|
||||
|
||||
default boolean regenerate(com.sk89q.worldedit.world.World world, Region region, EditSession editSession) {
|
||||
return editSession.regenerate(region);
|
||||
}
|
||||
}
|
@ -20,23 +20,35 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl;
|
||||
|
||||
import com.bekvon.bukkit.residence.commands.material;
|
||||
import com.bekvon.bukkit.residence.commands.server;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.implementation.packet.ChunkPacket;
|
||||
import com.boydti.fawe.beta.implementation.queue.SingleThreadQueueExtent;
|
||||
import com.boydti.fawe.bukkit.adapter.BukkitQueueHandler;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_14.BlockMaterial_1_14;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_14.BukkitAdapter_1_14;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_14.BukkitGetBlocks_1_14;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_14.MapChunkUtil_1_14;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_14.nbt.LazyCompoundTag_1_14;
|
||||
import com.google.common.io.Files;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.MaxChangedBlocksException;
|
||||
import com.sk89q.worldedit.blocks.BaseItemStack;
|
||||
import com.sk89q.worldedit.blocks.TileEntityBlock;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.BukkitWorld;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.CachedBukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.IDelegateBukkitImplAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.Spigot_v1_14_R4;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.entity.LazyBaseEntity;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.registry.state.Property;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
@ -50,6 +62,7 @@ import net.minecraft.server.v1_14_R1.Block;
|
||||
import net.minecraft.server.v1_14_R1.BlockPosition;
|
||||
import net.minecraft.server.v1_14_R1.Chunk;
|
||||
import net.minecraft.server.v1_14_R1.ChunkCoordIntPair;
|
||||
import net.minecraft.server.v1_14_R1.ChunkProviderServer;
|
||||
import net.minecraft.server.v1_14_R1.ChunkSection;
|
||||
import net.minecraft.server.v1_14_R1.Entity;
|
||||
import net.minecraft.server.v1_14_R1.EntityPlayer;
|
||||
@ -58,6 +71,7 @@ import net.minecraft.server.v1_14_R1.IBlockData;
|
||||
import net.minecraft.server.v1_14_R1.IRegistry;
|
||||
import net.minecraft.server.v1_14_R1.ItemStack;
|
||||
import net.minecraft.server.v1_14_R1.MinecraftKey;
|
||||
import net.minecraft.server.v1_14_R1.MinecraftServer;
|
||||
import net.minecraft.server.v1_14_R1.NBTBase;
|
||||
import net.minecraft.server.v1_14_R1.NBTTagCompound;
|
||||
import net.minecraft.server.v1_14_R1.NBTTagInt;
|
||||
@ -65,11 +79,13 @@ import net.minecraft.server.v1_14_R1.PacketPlayOutMapChunk;
|
||||
import net.minecraft.server.v1_14_R1.PlayerChunk;
|
||||
import net.minecraft.server.v1_14_R1.TileEntity;
|
||||
import net.minecraft.server.v1_14_R1.World;
|
||||
import net.minecraft.server.v1_14_R1.WorldNBTStorage;
|
||||
import net.minecraft.server.v1_14_R1.WorldServer;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.craftbukkit.v1_14_R1.CraftChunk;
|
||||
import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_14_R1.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_14_R1.block.data.CraftBlockData;
|
||||
import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
|
||||
@ -80,6 +96,8 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.OptionalInt;
|
||||
@ -358,4 +376,53 @@ public final class FAWE_Spigot_v1_14_R4 extends CachedBukkitAdapter implements I
|
||||
}
|
||||
return parent.fromNative(foreign);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean regenerate(com.sk89q.worldedit.world.World world, Region region, EditSession editSession) {
|
||||
WorldServer originalWorld = ((CraftWorld) world).getHandle();
|
||||
ChunkProviderServer provider = originalWorld.getChunkProvider();
|
||||
if (!(provider instanceof ChunkProviderServer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
File saveFolder = Files.createTempDir();
|
||||
// register this just in case something goes wrong
|
||||
// normally it should be deleted at the end of this method
|
||||
saveFolder.deleteOnExit();
|
||||
try {
|
||||
CraftServer server = originalWorld.getServer();
|
||||
WorldNBTStorage originalDataManager = originalWorld.getDataManager();
|
||||
WorldNBTStorage saveHandler = new WorldNBTStorage(saveFolder, originalDataManager.getDirectory().getName(), server.getServer(), originalDataManager.getDataFixer());
|
||||
try (WorldServer freshWorld = new WorldServer(server.getServer(),
|
||||
server.getServer().executorService, saveHandler,
|
||||
originalWorld.worldData,
|
||||
originalWorld.worldProvider.getDimensionManager(),
|
||||
originalWorld.getMethodProfiler(),
|
||||
server.getServer().worldLoadListenerFactory.create(11),
|
||||
((CraftWorld) world).getEnvironment(),
|
||||
server.getGenerator(world.getName()))) {
|
||||
|
||||
// Pre-gen all the chunks
|
||||
// We need to also pull one more chunk in every direction
|
||||
CuboidRegion expandedPreGen = new CuboidRegion(region.getMinimumPoint().subtract(16, 0, 16), region.getMaximumPoint().add(16, 0, 16));
|
||||
for (BlockVector2 chunk : expandedPreGen.getChunks()) {
|
||||
freshWorld.getChunkAt(chunk.getBlockX(), chunk.getBlockZ());
|
||||
}
|
||||
|
||||
// TODO optimize
|
||||
SingleThreadQueueExtent extent = new SingleThreadQueueExtent();
|
||||
extent.init(null, (x, z) -> new BukkitGetBlocks_1_14(freshWorld, x, z), null);
|
||||
for (BlockVector3 vec : region) {
|
||||
editSession.setBlock(vec, extent.getFullBlock(vec));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} catch (MaxChangedBlocksException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
saveFolder.delete();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -1,184 +0,0 @@
|
||||
package com.boydti.fawe.command;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweAPI;
|
||||
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.FaweCommand;
|
||||
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.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import com.sk89q.worldedit.util.Location;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
public class Rollback extends FaweCommand {
|
||||
|
||||
public Rollback() {
|
||||
super("fawe.rollback");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(Actor actor, String... args) {
|
||||
if (!(actor.isPlayer() && actor instanceof Player)) {
|
||||
return false;
|
||||
}
|
||||
Player player = (Player) actor;
|
||||
if (!Settings.IMP.HISTORY.USE_DATABASE) {
|
||||
player.print(TranslatableComponent.of("fawe.error.setting.disable" , "history.use-database (Import with /frb #import )"));
|
||||
return false;
|
||||
}
|
||||
if (args.length != 3) {
|
||||
player.print(TranslatableComponent.of("fawe.error.command.syntax" , "/frb u:<uuid> r:<radius> t:<time>"));
|
||||
return false;
|
||||
}
|
||||
switch (args[0]) {
|
||||
case "i":
|
||||
case "info":
|
||||
case "undo":
|
||||
case "revert":
|
||||
player.print(TranslatableComponent.of("fawe.error.command.syntax" , "/frb u:<uuid> r:<radius> t:<time>"));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (args.length < 1) {
|
||||
player.print(TranslatableComponent.of("fawe.error.command.syntax" , "/frb <info|undo> u:<uuid> r:<radius> t:<time>"));
|
||||
return false;
|
||||
}
|
||||
World world = player.getWorld();
|
||||
switch (args[0]) {
|
||||
case "i":
|
||||
case "info":
|
||||
if (args.length < 2) {
|
||||
player.print(TranslatableComponent.of("fawe.error.command.syntax" , "/frb <info|undo> u:<uuid> r:<radius> t:<time>"));
|
||||
return false;
|
||||
}
|
||||
player.deleteMeta(Player.METADATA_KEYS.ROLLBACK);
|
||||
Location origin = player.getLocation();
|
||||
rollback(player, !player.hasPermission("fawe.rollback.deep"), Arrays.copyOfRange(args, 1, args.length), new RunnableVal<List<DiskStorageHistory>>() {
|
||||
@Override
|
||||
public void run(List<DiskStorageHistory> edits) {
|
||||
long total = 0;
|
||||
player.print("&d=| Username | Bounds | Distance | Changes | Age |=");
|
||||
for (DiskStorageHistory edit : edits) {
|
||||
DiskStorageHistory.DiskStorageSummary summary = edit.summarize(new RegionWrapper(origin.getBlockX(), origin.getBlockX(), origin.getBlockZ(), origin.getBlockZ()), !player.hasPermission("fawe.rollback.deep"));
|
||||
RegionWrapper region = new RegionWrapper(summary.minX, summary.maxX, summary.minZ, summary.maxZ);
|
||||
int distance = region.distance(origin.getBlockX(), origin.getBlockZ());
|
||||
String name = Fawe.imp().getName(edit.getUUID());
|
||||
long seconds = (System.currentTimeMillis() - edit.getBDFile().lastModified()) / 1000;
|
||||
total += edit.getBDFile().length();
|
||||
int size = summary.getSize();
|
||||
Map<BlockState, Double> percents = summary.getPercents();
|
||||
StringBuilder percentString = new StringBuilder();
|
||||
String prefix = "";
|
||||
for (Map.Entry<BlockState, Double> entry : percents.entrySet()) {
|
||||
BlockState state = entry.getKey();
|
||||
String itemName = "#" + state;
|
||||
percentString.append(prefix).append(entry.getValue()).append("% ").append(itemName);
|
||||
prefix = ", ";
|
||||
}
|
||||
player.print("&c" + name + " | " + region + " | " + distance + "m | " + size + " | " + MainUtil.secToTime(seconds));
|
||||
player.print("&8 - &7(" + percentString + ")");
|
||||
}
|
||||
player.print("&d==================================================");
|
||||
player.print("&dSize: " + (double) (total / 1024) / 1000 + "MB");
|
||||
player.print("&dTo rollback: /frb undo");
|
||||
player.print("&d==================================================");
|
||||
player.setMeta(Player.METADATA_KEYS.ROLLBACK, edits);
|
||||
}
|
||||
});
|
||||
break;
|
||||
case "undo":
|
||||
case "revert":
|
||||
if (!player.hasPermission("fawe.rollback.perform")) {
|
||||
player.print(TranslatableComponent.of("fawe.error.no.perm", "fawe.rollback.perform"));
|
||||
return false;
|
||||
}
|
||||
final List<DiskStorageHistory> edits = player.getMeta(Player.METADATA_KEYS.ROLLBACK);
|
||||
player.deleteMeta(Player.METADATA_KEYS.ROLLBACK);
|
||||
if (edits == null) {
|
||||
player.print(TranslatableComponent.of("fawe.error.command.syntax" , "/frb info u:<uuid> r:<radius> t:<time>"));
|
||||
return false;
|
||||
}
|
||||
for (DiskStorageHistory edit : edits) {
|
||||
player.print("&d" + edit.getBDFile());
|
||||
EditSession session = edit.toEditSession(null);
|
||||
session.undo(session);
|
||||
edit.deleteFiles();
|
||||
session.flushQueue();
|
||||
}
|
||||
player.print("Rollback complete!");
|
||||
default:
|
||||
player.print(TranslatableComponent.of("fawe.error.command.syntax" , "/frb info u:<uuid> r:<radius> t:<time>"));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void rollback(Player player, boolean shallow, String[] args, RunnableVal<List<DiskStorageHistory>> result) {
|
||||
UUID user = null;
|
||||
int radius = Integer.MAX_VALUE;
|
||||
long time = Long.MAX_VALUE;
|
||||
for (String arg : args) {
|
||||
String[] split = arg.split(":");
|
||||
if (split.length != 2) {
|
||||
player.print(TranslatableComponent.of("fawe.error.command.syntax" , "/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 ignored) {
|
||||
}
|
||||
if (user == null) {
|
||||
player.print("&dInvalid user: " + split[1]);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case "r":
|
||||
case "radius":
|
||||
if (!MathMan.isInteger(split[1])) {
|
||||
player.print("&dInvalid radius: " + split[1]);
|
||||
return;
|
||||
}
|
||||
radius = Integer.parseInt(split[1]);
|
||||
break;
|
||||
case "t":
|
||||
case "time":
|
||||
time = MainUtil.timeToSec(split[1]) * 1000;
|
||||
break;
|
||||
default:
|
||||
player.print(TranslatableComponent.of("fawe.error.command.syntax" , "/frb <info|undo> u:<uuid> r:<radius> t:<time>"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
Location origin = player.getLocation();
|
||||
List<DiskStorageHistory> edits = FaweAPI.getBDFiles(origin, user, radius, time, shallow);
|
||||
if (edits == null) {
|
||||
player.print("&cToo broad, try refining your search!");
|
||||
return;
|
||||
}
|
||||
if (edits.size() == 0) {
|
||||
player.print("&cNo edits found!");
|
||||
return;
|
||||
}
|
||||
result.run(edits);
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package com.boydti.fawe.config;
|
||||
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.util.formatting.WorldEditText;
|
||||
import com.sk89q.worldedit.util.formatting.text.Component;
|
||||
import com.sk89q.worldedit.util.formatting.text.TextComponent;
|
||||
@ -11,6 +12,14 @@ import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class Caption {
|
||||
public static String toString(Component component) {
|
||||
return toString(component, WorldEdit.getInstance().getTranslationManager().getDefaultLocale());
|
||||
}
|
||||
|
||||
public static String toString(Component component, Locale locale) {
|
||||
return WorldEditText.reduceToText(color(component), locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Colorize a component with legacy color codes
|
||||
* @param parent
|
||||
|
@ -6,10 +6,13 @@ import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.logging.rollback.RollbackOptimizedHistory;
|
||||
import com.boydti.fawe.object.RunnableVal;
|
||||
import com.boydti.fawe.object.changeset.DiskStorageHistory;
|
||||
import com.boydti.fawe.object.collection.YieldIterable;
|
||||
import com.boydti.fawe.object.task.AsyncNotifyQueue;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@ -19,10 +22,21 @@ import java.sql.DriverManager;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import org.intellij.lang.annotations.Language;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -36,217 +50,240 @@ public class RollbackDatabase extends AsyncNotifyQueue {
|
||||
private final World world;
|
||||
private Connection connection;
|
||||
|
||||
private String INSERT_EDIT;
|
||||
private String CREATE_TABLE;
|
||||
// private String GET_EDITS_POINT;
|
||||
private String GET_EDITS;
|
||||
private String GET_EDITS_USER;
|
||||
private String GET_EDITS_ASC;
|
||||
private String GET_EDITS_USER_ASC;
|
||||
private String DELETE_EDITS_USER;
|
||||
private String DELETE_EDIT_USER;
|
||||
private String PURGE;
|
||||
private @Language("sql") String CREATE_TABLE = "CREATE TABLE IF NOT EXISTS `{0}edits` (`player` BLOB(16) NOT NULL,`id` INT NOT NULL, `time` INT NOT NULL,`x1` INT NOT NULL,`x2` INT NOT NULL,`z1` INT NOT NULL,`z2` INT NOT NULL,`y1` INT NOT NULL, `y2` INT NOT NULL, `size` INT NOT NULL, `command` VARCHAR, PRIMARY KEY (player, id))";
|
||||
private @Language("sql") String UPDATE_TABLE = "ALTER TABLE `{0}edits` ADD `command` VARCHAR, ADD `size` INT NOT NULL";
|
||||
private @Language("sql") String INSERT_EDIT = "INSERT OR REPLACE INTO `{0}edits` (`player`,`id`,`time`,`x1`,`x2`,`z1`,`z2`,`y1`,`y2`,`command`,`size`) VALUES(?,?,?,?,?,?,?,?,?,?,?)";
|
||||
private @Language("sql") String PURGE = "DELETE FROM `{0}edits` WHERE `time`<?";
|
||||
private @Language("sql") String GET_EDITS_USER = "SELECT * FROM `{0}edits` WHERE `time`>? AND `x2`>=? AND `x1`<=? AND `z2`>=? AND `z1`<=? AND `y2`>=? AND `y1`<=? AND `player`=? ORDER BY `time` DESC, `id` DESC";
|
||||
private @Language("sql") String GET_EDITS_USER_ASC = "SELECT * FROM `{0}edits` WHERE `time`>? AND `x2`>=? AND `x1`<=? AND `z2`>=? AND `z1`<=? AND `y2`>=? AND `y1`<=? AND `player`=? ORDER BY `time` ASC, `id` ASC";
|
||||
private @Language("sql") String GET_EDITS = "SELECT * FROM `{0}edits` WHERE `time`>? AND `x2`>=? AND `x1`<=? AND `z2`>=? AND `z1`<=? AND `y2`>=? AND `y1`<=? ORDER BY `time` DESC, `id` DESC";
|
||||
private @Language("sql") String GET_EDITS_ASC = "SELECT * FROM `{0}edits` WHERE `time`>? AND `x2`>=? AND `x1`<=? AND `z2`>=? AND `z1`<=? AND `y2`>=? AND `y1`<=? ORDER BY `time` ASC, `id` ASC";
|
||||
private @Language("sql") String GET_EDIT_USER = "SELECT * FROM `{0}edits` WHERE `player`=? AND `id`=?";
|
||||
|
||||
private @Language("sql") String DELETE_EDITS_USER = "DELETE FROM `{0}edits` WHERE `player`=? AND `time`>? AND `x2`>=? AND `x1`<=? AND `y2`>=? AND `y1`<=? AND `z2`>=? AND `z1`<=?";
|
||||
private @Language("sql") String DELETE_EDIT_USER = "DELETE FROM `{0}edits` WHERE `player`=? AND `id`=?";
|
||||
|
||||
private ConcurrentLinkedQueue<RollbackOptimizedHistory> historyChanges = new ConcurrentLinkedQueue<>();
|
||||
private final ConcurrentLinkedQueue<Runnable> tasks = new ConcurrentLinkedQueue<>();
|
||||
|
||||
public RollbackDatabase(String world) throws SQLException, ClassNotFoundException {
|
||||
this(FaweAPI.getWorld(world));
|
||||
}
|
||||
|
||||
public RollbackDatabase(World world) throws SQLException, ClassNotFoundException {
|
||||
super((t, e) -> e.printStackTrace());
|
||||
this.prefix = "";
|
||||
this.worldName = world.getName();
|
||||
this.world = world;
|
||||
this.dbLocation = MainUtil.getFile(Fawe.imp().getDirectory(), Settings.IMP.PATHS.HISTORY + File.separator + world.getName() + File.separator + "summary.db");
|
||||
connection = openConnection();
|
||||
CREATE_TABLE = "CREATE TABLE IF NOT EXISTS `" + prefix + "edits` (`player` BLOB(16) NOT NULL,`id` INT NOT NULL,`x1` INT NOT NULL,`y1` INT NOT NULL,`z1` INT NOT NULL,`x2` INT NOT NULL,`y2` INT NOT NULL,`z2` INT NOT NULL,`time` INT NOT NULL, PRIMARY KEY (player, id))";
|
||||
INSERT_EDIT = "INSERT OR REPLACE INTO `" + prefix + "edits` (`player`,`id`,`x1`,`y1`,`z1`,`x2`,`y2`,`z2`,`time`) VALUES(?,?,?,?,?,?,?,?,?)";
|
||||
PURGE = "DELETE FROM `" + prefix + "edits` WHERE `time`<?";
|
||||
// GET_EDITS_POINT = "SELECT `player`,`id` FROM `" + prefix + "edits` WHERE `x2`>=? AND `x1`<=? AND `y2`>=? AND `y1`<=? AND `z2`>=? AND `z1`<=?";
|
||||
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";
|
||||
GET_EDITS_ASC = "SELECT `player`,`id` FROM `" + prefix + "edits` WHERE `x2`>=? AND `x1`<=? AND `y2`>=? AND `y1`<=? AND `z2`>=? AND `z1`<=? AND `time`>? ORDER BY `time` ASC, `id` ASC";
|
||||
GET_EDITS_USER_ASC = "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` ASC, `id` ASC";
|
||||
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.IMP.HISTORY.DELETE_AFTER_DAYS));
|
||||
}
|
||||
|
||||
// update vars
|
||||
CREATE_TABLE = CREATE_TABLE.replace("{0}", prefix);
|
||||
UPDATE_TABLE = UPDATE_TABLE.replace("{0}", prefix);
|
||||
INSERT_EDIT = INSERT_EDIT.replace("{0}", prefix);
|
||||
PURGE = PURGE.replace("{0}", prefix);
|
||||
GET_EDITS_USER = GET_EDITS_USER.replace("{0}", prefix);
|
||||
GET_EDITS_USER_ASC = GET_EDITS_USER_ASC.replace("{0}", prefix);
|
||||
GET_EDITS = GET_EDITS.replace("{0}", prefix);
|
||||
GET_EDITS_ASC = GET_EDITS_ASC.replace("{0}", prefix);
|
||||
GET_EDIT_USER = GET_EDIT_USER.replace("{0}", prefix);
|
||||
DELETE_EDITS_USER = DELETE_EDITS_USER.replace("{0}", prefix);
|
||||
DELETE_EDIT_USER = DELETE_EDIT_USER.replace("{0}", prefix);
|
||||
|
||||
@Override
|
||||
public boolean hasQueued() {
|
||||
return connection != null && (!historyChanges.isEmpty() || !tasks.isEmpty());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void operate() {
|
||||
synchronized (this) {
|
||||
if (connection == null) {
|
||||
return;
|
||||
}
|
||||
while (sendBatch()) {
|
||||
// Still processing
|
||||
}
|
||||
try {
|
||||
init().get();
|
||||
purge((int) TimeUnit.DAYS.toMillis(Settings.IMP.HISTORY.DELETE_AFTER_DAYS));
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void init() {
|
||||
try (PreparedStatement stmt = connection.prepareStatement(CREATE_TABLE)) {
|
||||
stmt.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
private byte[] toBytes(UUID uuid) {
|
||||
return ByteBuffer.allocate(16).putLong(uuid.getMostSignificantBits()).putLong(uuid.getLeastSignificantBits()).array();
|
||||
}
|
||||
|
||||
public void delete(UUID uuid, 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);
|
||||
addTask(() -> {
|
||||
try (PreparedStatement stmt = connection.prepareStatement(PURGE)) {
|
||||
stmt.setInt(1, then);
|
||||
public Future<Boolean> init() {
|
||||
return call(() -> {
|
||||
try (PreparedStatement stmt = connection.prepareStatement(CREATE_TABLE)) {
|
||||
stmt.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
try (PreparedStatement stmt = connection.prepareStatement(UPDATE_TABLE)) {
|
||||
stmt.executeUpdate();
|
||||
} catch (SQLException ignore) {} // Already updated
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public Future<Integer> delete(UUID uuid, int id) {
|
||||
return call(() -> {
|
||||
try (PreparedStatement stmt = connection.prepareStatement(DELETE_EDIT_USER)) {
|
||||
stmt.setBytes(1, toBytes(uuid));
|
||||
stmt.setInt(2, id);
|
||||
return stmt.executeUpdate();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void getPotentialEdits(UUID uuid, long minTime, BlockVector3 pos1, BlockVector3 pos2, RunnableVal<DiskStorageHistory> onEach, Runnable whenDone, boolean delete, boolean ascending) {
|
||||
final World world = FaweAPI.getWorld(this.worldName);
|
||||
addTask(() -> {
|
||||
String stmtStr = ascending ? uuid == null ? GET_EDITS_ASC : GET_EDITS_USER_ASC :
|
||||
uuid == null ? GET_EDITS : GET_EDITS_USER;
|
||||
try (PreparedStatement stmt = connection.prepareStatement(stmtStr)) {
|
||||
stmt.setInt(1, pos1.getBlockX());
|
||||
stmt.setInt(2, pos2.getBlockX());
|
||||
stmt.setByte(3, (byte) (pos1.getBlockY() - 128));
|
||||
stmt.setByte(4, (byte) (pos2.getBlockY() - 128));
|
||||
stmt.setInt(5, pos1.getBlockZ());
|
||||
stmt.setInt(6, pos2.getBlockZ());
|
||||
stmt.setInt(7, (int) (minTime / 1000));
|
||||
if (uuid != null) {
|
||||
byte[] uuidBytes = ByteBuffer.allocate(16).putLong(uuid.getMostSignificantBits()).putLong(uuid.getLeastSignificantBits()).array();
|
||||
stmt.setBytes(8, uuidBytes);
|
||||
}
|
||||
public Future<RollbackOptimizedHistory> getEdit(@NotNull UUID uuid, int id) {
|
||||
return call(() -> {
|
||||
try (PreparedStatement stmt = connection.prepareStatement(GET_EDIT_USER)) {
|
||||
stmt.setBytes(1, toBytes(uuid));
|
||||
stmt.setInt(2, id);
|
||||
ResultSet result = stmt.executeQuery();
|
||||
if (!result.next()) {
|
||||
TaskManager.IMP.taskNow(whenDone, false);
|
||||
return;
|
||||
}
|
||||
do {
|
||||
byte[] uuidBytes = result.getBytes(1);
|
||||
int index = result.getInt(2);
|
||||
ByteBuffer bb = ByteBuffer.wrap(uuidBytes);
|
||||
long high = bb.getLong();
|
||||
long low = bb.getLong();
|
||||
DiskStorageHistory history = new DiskStorageHistory(world, new UUID(high, low), index);
|
||||
if (history.getBDFile().exists()) {
|
||||
onEach.run(history);
|
||||
}
|
||||
} while (result.next());
|
||||
TaskManager.IMP.taskNow(whenDone, false);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (delete && uuid != null) {
|
||||
try (PreparedStatement stmt = connection.prepareStatement(DELETE_EDITS_USER)) {
|
||||
stmt.setInt(1, pos1.getBlockX());
|
||||
stmt.setInt(2, pos2.getBlockX());
|
||||
stmt.setByte(3, (byte) (pos1.getBlockY() - 128));
|
||||
stmt.setByte(4, (byte) (pos2.getBlockY() - 128));
|
||||
stmt.setInt(5, pos1.getBlockZ());
|
||||
stmt.setInt(6, pos2.getBlockZ());
|
||||
stmt.setInt(7, (int) (minTime / 1000));
|
||||
byte[] uuidBytes = ByteBuffer.allocate(16).putLong(uuid.getMostSignificantBits()).putLong(uuid.getLeastSignificantBits()).array();
|
||||
stmt.setBytes(8, uuidBytes);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
return create(result).get();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void logEdit(RollbackOptimizedHistory history) {
|
||||
queue(() -> historyChanges.add(history));
|
||||
private Supplier<RollbackOptimizedHistory> create(ResultSet result) throws SQLException {
|
||||
byte[] uuidBytes = result.getBytes("player");
|
||||
int index = result.getInt("id");
|
||||
int x1 = result.getInt("x1");
|
||||
int x2 = result.getInt("x2");
|
||||
int y1 = result.getInt("y1");
|
||||
int y2 = result.getInt("y2");
|
||||
int z1 = result.getInt("z1");
|
||||
int z2 = result.getInt("z2");
|
||||
CuboidRegion region = new CuboidRegion(BlockVector3.at(x1, y1, z1), BlockVector3.at(x2, y2, z2));
|
||||
|
||||
long time = result.getInt("time") * 1000L;
|
||||
long size = result.getInt("size");
|
||||
|
||||
String command = result.getString("command");
|
||||
|
||||
ByteBuffer bb = ByteBuffer.wrap(uuidBytes);
|
||||
long high = bb.getLong();
|
||||
long low = bb.getLong();
|
||||
UUID uuid = new UUID(high, low);
|
||||
|
||||
return () -> new RollbackOptimizedHistory(world, uuid, index, time, size, region, command);
|
||||
}
|
||||
|
||||
public void addTask(Runnable run) {
|
||||
queue(() -> tasks.add(run));
|
||||
public Future<Integer> purge(int diff) {
|
||||
long now = System.currentTimeMillis() / 1000;
|
||||
final int then = (int) (now - diff);
|
||||
return call(() -> {
|
||||
try (PreparedStatement stmt = connection.prepareStatement(PURGE)) {
|
||||
stmt.setInt(1, then);
|
||||
return stmt.executeUpdate();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void runTasks() {
|
||||
Runnable task;
|
||||
while ((task = tasks.poll()) != null) {
|
||||
public Iterable<Supplier<RollbackOptimizedHistory>> getEdits(BlockVector3 pos, boolean ascending) {
|
||||
return getEdits(null, 0, pos, pos, false, ascending);
|
||||
}
|
||||
|
||||
public Iterable<Supplier<RollbackOptimizedHistory>> getEdits(UUID uuid, long minTime, BlockVector3 pos1, BlockVector3 pos2, boolean delete, boolean ascending) {
|
||||
YieldIterable<Supplier<RollbackOptimizedHistory>> yieldIterable = new YieldIterable<>();
|
||||
|
||||
Future<Integer> future = call(() -> {
|
||||
try {
|
||||
task.run();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean sendBatch() {
|
||||
try {
|
||||
runTasks();
|
||||
commit();
|
||||
if (connection.getAutoCommit()) {
|
||||
connection.setAutoCommit(false);
|
||||
}
|
||||
int size = Math.min(1048572, historyChanges.size());
|
||||
|
||||
if (size == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RollbackOptimizedHistory[] copy = IntStream.range(0, size)
|
||||
.mapToObj(i -> historyChanges.poll()).toArray(RollbackOptimizedHistory[]::new);
|
||||
|
||||
try (PreparedStatement stmt = connection.prepareStatement(INSERT_EDIT)) {
|
||||
for (RollbackOptimizedHistory change : copy) {
|
||||
// `player`,`id`,`x1`,`y1`,`z1`,`x2`,`y2`,`z2`,`time`
|
||||
UUID uuid = change.getUUID();
|
||||
byte[] uuidBytes = ByteBuffer.allocate(16).putLong(uuid.getMostSignificantBits()).putLong(uuid.getLeastSignificantBits()).array();
|
||||
stmt.setBytes(1, uuidBytes);
|
||||
stmt.setInt(2, change.getIndex());
|
||||
stmt.setInt(3, change.getMinX());
|
||||
stmt.setByte(4, (byte) (change.getMinY() - 128));
|
||||
stmt.setInt(5, change.getMinZ());
|
||||
stmt.setInt(6, change.getMaxX());
|
||||
stmt.setByte(7, (byte) (change.getMaxY() - 128));
|
||||
stmt.setInt(8, change.getMaxZ());
|
||||
stmt.setInt(9, (int) (change.getTime() / 1000));
|
||||
stmt.executeUpdate();
|
||||
stmt.clearParameters();
|
||||
int count = 0;
|
||||
String stmtStr = ascending ? uuid == null ? GET_EDITS_ASC : GET_EDITS_USER_ASC :
|
||||
uuid == null ? GET_EDITS : GET_EDITS_USER;
|
||||
// `time`>? AND `x2`>=? AND `x1`<=? AND `z2`>=? AND `z1`<=? AND `y2`>=? AND `y1`<=? AND `player`=? ORDER BY `time` DESC, `id` DESC"
|
||||
try (PreparedStatement stmt = connection.prepareStatement(stmtStr)) {
|
||||
stmt.setInt(1, (int) (minTime / 1000));
|
||||
stmt.setInt(2, pos1.getBlockX());
|
||||
stmt.setInt(3, pos2.getBlockX());
|
||||
stmt.setInt(4, pos1.getBlockZ());
|
||||
stmt.setInt(5, pos2.getBlockZ());
|
||||
stmt.setByte(6, (byte) (pos1.getBlockY() - 128));
|
||||
stmt.setByte(7, (byte) (pos2.getBlockY() - 128));
|
||||
if (uuid != null) {
|
||||
byte[] uuidBytes = toBytes(uuid);
|
||||
stmt.setBytes(8, uuidBytes);
|
||||
}
|
||||
ResultSet result = stmt.executeQuery();
|
||||
if (!result.next()) {
|
||||
return 0;
|
||||
}
|
||||
do {
|
||||
count++;
|
||||
Supplier<RollbackOptimizedHistory> history = create(result);
|
||||
// if (history.getBDFile().exists())
|
||||
{
|
||||
yieldIterable.accept(history);
|
||||
}
|
||||
} while (result.next());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
if (delete && uuid != null) {
|
||||
try (PreparedStatement stmt = connection.prepareStatement(DELETE_EDITS_USER)) {
|
||||
stmt.setInt(1, (int) (minTime / 1000));
|
||||
stmt.setInt(2, pos1.getBlockX());
|
||||
stmt.setInt(3, pos2.getBlockX());
|
||||
stmt.setInt(4, pos1.getBlockZ());
|
||||
stmt.setInt(5, pos2.getBlockZ());
|
||||
stmt.setByte(6, (byte) (pos1.getBlockY() - 128));
|
||||
stmt.setByte(7, (byte) (pos2.getBlockY() - 128));
|
||||
byte[] uuidBytes = ByteBuffer.allocate(16).putLong(uuid.getMostSignificantBits()).putLong(uuid.getLeastSignificantBits()).array();
|
||||
stmt.setBytes(8, uuidBytes);
|
||||
}
|
||||
}
|
||||
return count;
|
||||
} finally {
|
||||
yieldIterable.close();
|
||||
}
|
||||
commit();
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
});
|
||||
yieldIterable.setFuture(future);
|
||||
|
||||
return yieldIterable;
|
||||
}
|
||||
|
||||
public void commit() {
|
||||
public Future<?> logEdit(RollbackOptimizedHistory history) {
|
||||
historyChanges.add(history);
|
||||
return call(this::sendBatch);
|
||||
}
|
||||
|
||||
private boolean sendBatch() throws SQLException {
|
||||
int size = Math.min(1048572, historyChanges.size());
|
||||
|
||||
if (size == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
commit();
|
||||
if (connection.getAutoCommit()) {
|
||||
connection.setAutoCommit(false);
|
||||
}
|
||||
|
||||
RollbackOptimizedHistory[] copy = IntStream.range(0, size)
|
||||
.mapToObj(i -> historyChanges.poll()).toArray(RollbackOptimizedHistory[]::new);
|
||||
|
||||
try (PreparedStatement stmt = connection.prepareStatement(INSERT_EDIT)) {
|
||||
// `player`,`id`,`time`,`x1`,`x2`,`z1`,`z2`,`y1`,`y2`,`command`,`size`) VALUES(?,?,?,?,?,?,?,?,?,?,?)"
|
||||
for (RollbackOptimizedHistory change : copy) {
|
||||
UUID uuid = change.getUUID();
|
||||
byte[] uuidBytes = toBytes(uuid);
|
||||
stmt.setBytes(1, uuidBytes);
|
||||
stmt.setInt(2, change.getIndex());
|
||||
stmt.setInt(3, (int) (change.getTime() / 1000));
|
||||
|
||||
BlockVector3 pos1 = change.getMinimumPoint();
|
||||
BlockVector3 pos2 = change.getMaximumPoint();
|
||||
|
||||
stmt.setInt(4, pos1.getX());
|
||||
stmt.setInt(5, pos2.getX());
|
||||
stmt.setInt(6, pos1.getZ());
|
||||
stmt.setInt(7, pos2.getZ());
|
||||
stmt.setByte(8, (byte) (pos1.getY() - 128));
|
||||
stmt.setByte(9, (byte) (pos2.getY() - 128));
|
||||
stmt.setString(10, change.getCommand());
|
||||
stmt.setInt(11, change.size());
|
||||
stmt.executeUpdate();
|
||||
stmt.clearParameters();
|
||||
}
|
||||
} finally {
|
||||
commit();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void commit() {
|
||||
try {
|
||||
if (connection == null) {
|
||||
return;
|
||||
@ -260,7 +297,7 @@ public class RollbackDatabase extends AsyncNotifyQueue {
|
||||
}
|
||||
}
|
||||
|
||||
public Connection openConnection() throws SQLException, ClassNotFoundException {
|
||||
private Connection openConnection() throws SQLException, ClassNotFoundException {
|
||||
if (checkConnection()) {
|
||||
return connection;
|
||||
}
|
||||
@ -281,7 +318,7 @@ public class RollbackDatabase extends AsyncNotifyQueue {
|
||||
return connection;
|
||||
}
|
||||
|
||||
public Connection forceConnection() throws SQLException, ClassNotFoundException {
|
||||
private Connection forceConnection() throws SQLException, ClassNotFoundException {
|
||||
Class.forName("org.sqlite.JDBC");
|
||||
connection = DriverManager.getConnection("jdbc:sqlite:" + dbLocation);
|
||||
return connection;
|
||||
@ -335,4 +372,14 @@ public class RollbackDatabase extends AsyncNotifyQueue {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
try {
|
||||
closeConnection();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
super.close();
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,9 @@ import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.database.DBHandler;
|
||||
import com.boydti.fawe.database.RollbackDatabase;
|
||||
import com.boydti.fawe.object.changeset.DiskStorageHistory;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
@ -19,6 +21,7 @@ public class RollbackOptimizedHistory extends DiskStorageHistory {
|
||||
private int maxY;
|
||||
private int minZ;
|
||||
private int maxZ;
|
||||
private String command;
|
||||
|
||||
public RollbackOptimizedHistory(World world, UUID uuid, int index) {
|
||||
super(world, uuid, index);
|
||||
@ -40,32 +43,40 @@ public class RollbackOptimizedHistory extends DiskStorageHistory {
|
||||
this.time = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public RollbackOptimizedHistory(World world, UUID uuid, int index, long time, long size, CuboidRegion region, String command) {
|
||||
super(world, uuid, index);
|
||||
this.time = time;
|
||||
this.minX = region.getMinimumX();
|
||||
this.minY = region.getMinimumY();
|
||||
this.minZ = region.getMinimumZ();
|
||||
this.maxX = region.getMaximumX();
|
||||
this.maxY = region.getMaximumY();
|
||||
this.maxZ = region.getMaximumZ();
|
||||
this.blockSize = (int) size;
|
||||
this.command = command;
|
||||
this.closed = true;
|
||||
}
|
||||
|
||||
public long getTime() {
|
||||
return time;
|
||||
}
|
||||
|
||||
public int getMinX() {
|
||||
return minX;
|
||||
@Override
|
||||
protected DiskStorageSummary summarizeShallow() {
|
||||
DiskStorageSummary summary = super.summarizeShallow();
|
||||
summary.minX = this.minX;
|
||||
summary.minZ = this.minZ;
|
||||
summary.maxX = this.maxX;
|
||||
summary.maxZ = this.maxZ;
|
||||
return summary;
|
||||
}
|
||||
|
||||
public int getMaxX() {
|
||||
return maxX;
|
||||
public void setCommand(String command) {
|
||||
this.command = command;
|
||||
}
|
||||
|
||||
public int getMinY() {
|
||||
return minY;
|
||||
}
|
||||
|
||||
public int getMaxY() {
|
||||
return maxY;
|
||||
}
|
||||
|
||||
public int getMinZ() {
|
||||
return minZ;
|
||||
}
|
||||
|
||||
public int getMaxZ() {
|
||||
return maxZ;
|
||||
public String getCommand() {
|
||||
return command;
|
||||
}
|
||||
|
||||
public void setDimensions(BlockVector3 pos1, BlockVector3 pos2) {
|
||||
@ -121,4 +132,12 @@ public class RollbackOptimizedHistory extends DiskStorageHistory {
|
||||
maxZ = z;
|
||||
super.writeHeader(os, x, y, z);
|
||||
}
|
||||
|
||||
public BlockVector3 getMinimumPoint() {
|
||||
return BlockVector3.at(minX, minY, minZ);
|
||||
}
|
||||
|
||||
public BlockVector3 getMaximumPoint() {
|
||||
return BlockVector3.at(maxX, maxY, maxZ);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.boydti.fawe.object.brush;
|
||||
|
||||
import static com.boydti.fawe.object.brush.BrushSettings.SettingType.BRUSH;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
@ -273,4 +274,13 @@ public class BrushSettings {
|
||||
return perms.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String name = (String) getSettings().get(BRUSH);
|
||||
if (name != null) {
|
||||
return name;
|
||||
}
|
||||
name = brush.getClass().getName();
|
||||
return name.substring(name.lastIndexOf('.') + 1);
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,12 @@
|
||||
package com.boydti.fawe.object.brush;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.logging.rollback.RollbackOptimizedHistory;
|
||||
import com.sk89q.worldedit.util.formatting.text.TextComponent;
|
||||
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.database.DBHandler;
|
||||
import com.boydti.fawe.database.RollbackDatabase;
|
||||
import com.boydti.fawe.object.RunnableVal;
|
||||
import com.boydti.fawe.object.change.MutableFullBlockChange;
|
||||
import com.boydti.fawe.object.changeset.DiskStorageHistory;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
@ -19,12 +20,16 @@ import com.sk89q.worldedit.extension.platform.Platform;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.math.Vector3;
|
||||
import com.sk89q.worldedit.util.Location;
|
||||
import com.sk89q.worldedit.util.formatting.text.event.ClickEvent;
|
||||
import com.sk89q.worldedit.util.formatting.text.event.HoverEvent;
|
||||
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class InspectBrush extends BrushTool implements DoubleActionTraceTool {
|
||||
|
||||
@ -61,47 +66,49 @@ public class InspectBrush extends BrushTool implements DoubleActionTraceTool {
|
||||
return false;
|
||||
}
|
||||
if (!Settings.IMP.HISTORY.USE_DATABASE) {
|
||||
player.print(TranslatableComponent.of("fawe.error.setting.disable", ("history.use-database (Import with /frb #import )")));
|
||||
player.print(TranslatableComponent.of("fawe.error.setting.disable", ("history.use-database (Import with /history import )")));
|
||||
return false;
|
||||
}
|
||||
BlockVector3 target = getTarget(player, rightClick).toBlockPoint();
|
||||
final int x = target.getBlockX();
|
||||
final int y = target.getBlockY();
|
||||
final int z = target.getBlockZ();
|
||||
World world = player.getWorld();
|
||||
RollbackDatabase db = DBHandler.IMP.getDatabase(world);
|
||||
final AtomicInteger count = new AtomicInteger();
|
||||
db.getPotentialEdits(null, 0, target, target, new RunnableVal<DiskStorageHistory>() {
|
||||
@Override
|
||||
public void run(DiskStorageHistory value) {
|
||||
try {
|
||||
Iterator<MutableFullBlockChange> iter = value.getFullBlockIterator(null, 0, false);
|
||||
while (iter.hasNext()) {
|
||||
MutableFullBlockChange change = iter.next();
|
||||
if (change.x != x || change.y != y || change.z != z) {
|
||||
continue;
|
||||
}
|
||||
int from = change.from;
|
||||
int to = change.to;
|
||||
UUID uuid = value.getUUID();
|
||||
String name = Fawe.imp().getName(uuid);
|
||||
int index = value.getIndex();
|
||||
long age = System.currentTimeMillis() - value.getBDFile().lastModified();
|
||||
String ageFormatted = MainUtil.secToTime(age / 1000);
|
||||
player.print(TranslatableComponent.of("fawe.worldedit.tool.tool.inspect.info" , name, BlockState.getFromOrdinal(from).getAsString(), BlockState.getFromOrdinal(to).getAsString(), ageFormatted));
|
||||
count.incrementAndGet();
|
||||
return;
|
||||
try {
|
||||
BlockVector3 target = getTarget(player, rightClick).toBlockPoint();
|
||||
final int x = target.getBlockX();
|
||||
final int y = target.getBlockY();
|
||||
final int z = target.getBlockZ();
|
||||
World world = player.getWorld();
|
||||
RollbackDatabase db = DBHandler.IMP.getDatabase(world);
|
||||
int count = 0;
|
||||
for (Supplier<RollbackOptimizedHistory> supplier : db.getEdits(target, false)) {
|
||||
count++;
|
||||
RollbackOptimizedHistory edit = supplier.get();
|
||||
Iterator<MutableFullBlockChange> iter = edit.getFullBlockIterator(null, 0, false);
|
||||
while (iter.hasNext()) {
|
||||
MutableFullBlockChange change = iter.next();
|
||||
if (change.x != x || change.y != y || change.z != z) {
|
||||
continue;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
int from = change.from;
|
||||
int to = change.to;
|
||||
UUID uuid = edit.getUUID();
|
||||
String name = Fawe.imp().getName(uuid);
|
||||
int index = edit.getIndex();
|
||||
long age = System.currentTimeMillis() - edit.getBDFile().lastModified();
|
||||
String ageFormatted = MainUtil.secToTime(age / 1000);
|
||||
BlockState blockFrom = BlockState.getFromOrdinal(from);
|
||||
BlockState blockTo = BlockState.getFromOrdinal(to);
|
||||
TranslatableComponent msg = TranslatableComponent.of("fawe.worldedit.tool.tool.inspect.info", name, blockFrom, blockTo, ageFormatted);
|
||||
|
||||
String cmd = edit.getCommand();
|
||||
TextComponent hover = TextComponent.of(cmd, TextColor.GOLD);
|
||||
String infoCmd = "//history summary " + uuid + " " + index;
|
||||
msg = msg.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, hover));
|
||||
msg = msg.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, infoCmd));
|
||||
player.print(msg);
|
||||
}
|
||||
}
|
||||
}, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
player.print(TranslatableComponent.of("fawe.worldedit.tool.tool.inspect.info.footer" , count));
|
||||
}
|
||||
}, false, false);
|
||||
player.print(TranslatableComponent.of("fawe.worldedit.tool.tool.inspect.info.footer" , count));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -48,6 +48,7 @@ import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.registry.state.PropertyKey;
|
||||
import com.sk89q.worldedit.session.ClipboardHolder;
|
||||
import com.sk89q.worldedit.util.Identifiable;
|
||||
import com.sk89q.worldedit.util.Location;
|
||||
import com.sk89q.worldedit.util.TreeGenerator;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
@ -847,7 +848,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
|
||||
try {
|
||||
update();
|
||||
Player esPlayer = curES.getPlayer();
|
||||
UUID uuid = esPlayer != null ? esPlayer.getUniqueId() : EditSession.CONSOLE;
|
||||
UUID uuid = esPlayer != null ? esPlayer.getUniqueId() : Identifiable.CONSOLE;
|
||||
try {
|
||||
curES.setRawChangeSet(new CFIChangeSet(this, uuid));
|
||||
} catch (IOException e) {
|
||||
|
@ -10,14 +10,14 @@ public class MutableBlockChange implements Change {
|
||||
public int z;
|
||||
public int y;
|
||||
public int x;
|
||||
public int combinedId;
|
||||
public int ordinal;
|
||||
|
||||
|
||||
public MutableBlockChange(int x, int y, int z, int combinedId) {
|
||||
public MutableBlockChange(int x, int y, int z, int ordinal) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
this.combinedId = combinedId;
|
||||
this.ordinal = ordinal;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -31,6 +31,6 @@ public class MutableBlockChange implements Change {
|
||||
}
|
||||
|
||||
public void create(UndoContext context) {
|
||||
context.getExtent().setBlock(x, y, z, BlockState.getFromOrdinal(combinedId));
|
||||
context.getExtent().setBlock(x, y, z, BlockState.getFromOrdinal(ordinal));
|
||||
}
|
||||
}
|
||||
|
@ -22,10 +22,6 @@ import java.util.concurrent.Future;
|
||||
public class AbstractDelegateChangeSet extends FaweChangeSet {
|
||||
public final FaweChangeSet parent;
|
||||
|
||||
public static FaweChangeSet getDefaultChangeSet(World world, UUID uuid) {
|
||||
return FaweChangeSet.getDefaultChangeSet(world, uuid);
|
||||
}
|
||||
|
||||
public AbstractDelegateChangeSet(FaweChangeSet parent) {
|
||||
super(parent.getWorld());
|
||||
this.parent = parent;
|
||||
|
@ -8,22 +8,28 @@ import com.boydti.fawe.object.FaweInputStream;
|
||||
import com.boydti.fawe.object.FaweOutputStream;
|
||||
import com.boydti.fawe.object.IntegerPair;
|
||||
import com.boydti.fawe.object.RegionWrapper;
|
||||
import com.boydti.fawe.object.change.MutableFullBlockChange;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.sk89q.jnbt.NBTInputStream;
|
||||
import com.sk89q.jnbt.NBTOutputStream;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.util.Countable;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
@ -168,6 +174,26 @@ public class DiskStorageHistory extends FaweStreamChangeSet {
|
||||
return bdFile;
|
||||
}
|
||||
|
||||
public File getNbtfFile() {
|
||||
return nbtfFile;
|
||||
}
|
||||
|
||||
public File getNbttFile() {
|
||||
return nbttFile;
|
||||
}
|
||||
|
||||
public File getEntfFile() {
|
||||
return entfFile;
|
||||
}
|
||||
|
||||
public File getEnttFile() {
|
||||
return enttFile;
|
||||
}
|
||||
|
||||
public File getBioFile() {
|
||||
return bioFile;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
@ -379,46 +405,35 @@ public class DiskStorageHistory extends FaweStreamChangeSet {
|
||||
return new NBTInputStream(MainUtil.getCompressedIS(new FileInputStream(nbtfFile)));
|
||||
}
|
||||
|
||||
public DiskStorageSummary summarize(RegionWrapper requiredRegion, boolean shallow) {
|
||||
protected DiskStorageSummary summarizeShallow() {
|
||||
return new DiskStorageSummary(getOriginX(), getOriginZ());
|
||||
}
|
||||
|
||||
public DiskStorageSummary summarize(Region region, boolean shallow) {
|
||||
if (bdFile.exists()) {
|
||||
int ox = getOriginX();
|
||||
int oz = getOriginZ();
|
||||
if ((ox != 0 || oz != 0) && !requiredRegion.isIn(ox, oz)) {
|
||||
return new DiskStorageSummary(ox, oz);
|
||||
}
|
||||
try (FileInputStream fis = new FileInputStream(bdFile)) {
|
||||
FaweInputStream gis = MainUtil.getCompressedIS(fis);
|
||||
// skip mode
|
||||
gis.skipFully(1);
|
||||
// origin
|
||||
ox = ((gis.read() << 24) + (gis.read() << 16) + (gis.read() << 8) + gis.read());
|
||||
oz = ((gis.read() << 24) + (gis.read() << 16) + (gis.read() << 8) + gis.read());
|
||||
setOrigin(ox, oz);
|
||||
DiskStorageSummary summary = new DiskStorageSummary(ox, oz);
|
||||
if (!requiredRegion.isIn(ox, oz)) {
|
||||
fis.close();
|
||||
gis.close();
|
||||
return summary;
|
||||
}
|
||||
byte[] buffer = new byte[4];
|
||||
int i = 0;
|
||||
int amount = (Settings.IMP.HISTORY.BUFFER_SIZE - HEADER_SIZE) / 9;
|
||||
while (!shallow && ++i < amount) {
|
||||
if (gis.read(buffer) == -1) {
|
||||
fis.close();
|
||||
gis.close();
|
||||
return summary;
|
||||
}
|
||||
int x = (buffer[0] & 0xFF) + (buffer[1] << 8) + ox;
|
||||
int z = (buffer[2] & 0xFF) + (buffer[3] << 8) + oz;
|
||||
int from = gis.readVarInt();
|
||||
int to = gis.readVarInt();
|
||||
summary.add(x, z, to);
|
||||
}
|
||||
DiskStorageSummary summary = summarizeShallow();
|
||||
if (region != null && !region.contains(ox, oz)) {
|
||||
return summary;
|
||||
}
|
||||
try (FaweInputStream fis = getBlockIS()) {
|
||||
if (!shallow) {
|
||||
int amount = (Settings.IMP.HISTORY.BUFFER_SIZE - HEADER_SIZE) / 9;
|
||||
MutableFullBlockChange change = new MutableFullBlockChange(null, 0, false);
|
||||
for (int i = 0; i < amount; i++) {
|
||||
int x = posDel.readX(fis) + ox;
|
||||
int y = posDel.readY(fis);
|
||||
int z = posDel.readZ(fis) + ox;
|
||||
idDel.readCombined(fis, change);
|
||||
summary.add(x, z, change.to);
|
||||
}
|
||||
}
|
||||
} catch (EOFException ignored) {
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return summary;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -463,7 +478,7 @@ public class DiskStorageHistory extends FaweStreamChangeSet {
|
||||
}
|
||||
|
||||
public void add(int x, int z, int id) {
|
||||
blocks[BlockState.getFromInternalId(id).getOrdinal()]++;
|
||||
blocks[id]++;
|
||||
if (x < minX) {
|
||||
minX = x;
|
||||
} else if (x > maxX) {
|
||||
@ -487,6 +502,14 @@ public class DiskStorageHistory extends FaweStreamChangeSet {
|
||||
return map;
|
||||
}
|
||||
|
||||
public List<Countable<BlockState>> getBlockDistributionWithData() {
|
||||
ArrayList<Countable<BlockState>> list = new ArrayList<>();
|
||||
for (Map.Entry<BlockState, Integer> entry : getBlocks().entrySet()) {
|
||||
list.add(new Countable<>(entry.getKey(), entry.getValue()));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public Map<BlockState, Double> getPercents() {
|
||||
Map<BlockState, Integer> map = getBlocks();
|
||||
int count = getSize();
|
||||
|
@ -49,19 +49,7 @@ public abstract class FaweChangeSet implements ChangeSet, IBatchProcessor, Close
|
||||
private final String worldName;
|
||||
protected AtomicInteger waitingCombined = new AtomicInteger(0);
|
||||
protected AtomicInteger waitingAsync = new AtomicInteger(0);
|
||||
private boolean closed;
|
||||
|
||||
public static FaweChangeSet getDefaultChangeSet(World world, UUID uuid) {
|
||||
if (Settings.IMP.HISTORY.USE_DISK) {
|
||||
if (Settings.IMP.HISTORY.USE_DATABASE) {
|
||||
return new RollbackOptimizedHistory(world, uuid);
|
||||
} else {
|
||||
return new DiskStorageHistory(world, uuid);
|
||||
}
|
||||
} else {
|
||||
return new MemoryOptimizedHistory(world);
|
||||
}
|
||||
}
|
||||
protected boolean closed;
|
||||
|
||||
public FaweChangeSet(String world) {
|
||||
this.worldName = world;
|
||||
|
@ -33,8 +33,8 @@ public abstract class FaweStreamChangeSet extends FaweChangeSet {
|
||||
private int mode;
|
||||
private final int compression;
|
||||
|
||||
private FaweStreamIdDelegate idDel;
|
||||
private FaweStreamPositionDelegate posDel;
|
||||
protected FaweStreamIdDelegate idDel;
|
||||
protected FaweStreamPositionDelegate posDel;
|
||||
|
||||
public FaweStreamChangeSet(World world) {
|
||||
this(world, Settings.IMP.HISTORY.COMPRESSION_LEVEL, Settings.IMP.HISTORY.STORE_REDO, Settings.IMP.HISTORY.SMALL_EDITS);
|
||||
@ -85,10 +85,10 @@ public abstract class FaweStreamChangeSet extends FaweChangeSet {
|
||||
|
||||
void readCombined(FaweInputStream in, MutableBlockChange change, boolean dir) throws IOException;
|
||||
|
||||
void readCombined(FaweInputStream in, MutableFullBlockChange change, boolean dir) throws IOException;
|
||||
void readCombined(FaweInputStream in, MutableFullBlockChange change) throws IOException;
|
||||
}
|
||||
|
||||
private void setupStreamDelegates(int mode) {
|
||||
protected void setupStreamDelegates(int mode) {
|
||||
this.mode = mode;
|
||||
if (mode == 3 || mode == 4) {
|
||||
idDel = new FaweStreamIdDelegate() {
|
||||
@ -102,15 +102,15 @@ public abstract class FaweStreamChangeSet extends FaweChangeSet {
|
||||
public void readCombined(FaweInputStream is, MutableBlockChange change, boolean dir) throws IOException {
|
||||
if (dir) {
|
||||
is.readVarInt();
|
||||
change.combinedId = is.readVarInt();
|
||||
change.ordinal = is.readVarInt();
|
||||
} else {
|
||||
change.combinedId = is.readVarInt();
|
||||
change.ordinal = is.readVarInt();
|
||||
is.readVarInt();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readCombined(FaweInputStream is, MutableFullBlockChange change, boolean dir) throws IOException {
|
||||
public void readCombined(FaweInputStream is, MutableFullBlockChange change) throws IOException {
|
||||
change.from = is.readVarInt();
|
||||
change.to = is.readVarInt();
|
||||
}
|
||||
@ -126,11 +126,11 @@ public abstract class FaweStreamChangeSet extends FaweChangeSet {
|
||||
public void readCombined(FaweInputStream in, MutableBlockChange change, boolean dir) throws IOException {
|
||||
int from1 = in.read();
|
||||
int from2 = in.read();
|
||||
change.combinedId = in.readVarInt();
|
||||
change.ordinal = in.readVarInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readCombined(FaweInputStream is, MutableFullBlockChange change, boolean dir) throws IOException {
|
||||
public void readCombined(FaweInputStream is, MutableFullBlockChange change) throws IOException {
|
||||
change.from = is.readVarInt();
|
||||
change.to = BlockTypes.AIR.getInternalId();
|
||||
}
|
||||
@ -290,7 +290,7 @@ public abstract class FaweStreamChangeSet extends FaweChangeSet {
|
||||
|
||||
public abstract NBTInputStream getTileRemoveIS() throws IOException;
|
||||
|
||||
private int blockSize;
|
||||
protected int blockSize;
|
||||
public int entityCreateSize;
|
||||
public int entityRemoveSize;
|
||||
public int tileCreateSize;
|
||||
@ -530,7 +530,7 @@ public abstract class FaweStreamChangeSet extends FaweChangeSet {
|
||||
change.x = posDel.readX(is) + originX;
|
||||
change.y = posDel.readY(is);
|
||||
change.z = posDel.readZ(is) + originZ;
|
||||
idDel.readCombined(is, change, dir);
|
||||
idDel.readCombined(is, change);
|
||||
return change;
|
||||
} catch (EOFException ignored) {
|
||||
} catch (Exception e) {
|
||||
|
@ -67,7 +67,7 @@ public class ResizableClipboardBuilder extends MemoryOptimizedHistory {
|
||||
Change change = iterator.next();
|
||||
if (change instanceof MutableBlockChange) {
|
||||
MutableBlockChange blockChange = (MutableBlockChange) change;
|
||||
BlockState block = BlockState.getFromInternalId(blockChange.combinedId);
|
||||
BlockState block = BlockState.getFromOrdinal(blockChange.ordinal);
|
||||
clipboard.setBlock(blockChange.x, blockChange.y, blockChange.z, block);
|
||||
} else if (change instanceof MutableTileChange) {
|
||||
MutableTileChange tileChange = (MutableTileChange) change;
|
||||
|
@ -4,8 +4,10 @@ import com.boydti.fawe.util.MathMan;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.DataBufferInt;
|
||||
|
||||
/**
|
||||
* Efficient blur / average color over an image
|
||||
*/
|
||||
public class SummedColorTable {
|
||||
private static float inv256 = 1/256f;
|
||||
private final long[] reds, greens, blues, alpha;
|
||||
private final int[] hasAlpha;
|
||||
private final int length;
|
||||
@ -84,11 +86,6 @@ public class SummedColorTable {
|
||||
}
|
||||
}
|
||||
|
||||
private long getSum(int index, long[] summed) {
|
||||
if (index < 0) return 0;
|
||||
return summed[index];
|
||||
}
|
||||
|
||||
public int averageRGB(int x1, int z1, int x2, int z2) {
|
||||
int minX = Math.max(0, x1);
|
||||
int minZ = Math.max(0, z1);
|
||||
|
@ -0,0 +1,71 @@
|
||||
package com.boydti.fawe.object.collection;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class YieldIterable<T> implements Iterable<T>, Consumer<T>, Closeable {
|
||||
private static final Object END_MARKER = new Object();
|
||||
private final LinkedBlockingQueue<T> queue;
|
||||
private Future future;
|
||||
|
||||
public YieldIterable(@Nullable Future task) {
|
||||
this.queue = new LinkedBlockingQueue<>();
|
||||
this.future = task;
|
||||
}
|
||||
|
||||
public YieldIterable() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
public void setFuture(Future future) {
|
||||
this.future = future;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<T> iterator() {
|
||||
return new Iterator<T>() {
|
||||
private boolean interrupted;
|
||||
private T buffer;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
try {
|
||||
while (buffer == null && !interrupted && (future == null || !future.isCancelled())) {
|
||||
buffer = queue.poll(50, TimeUnit.MILLISECONDS);
|
||||
if (buffer == END_MARKER) {
|
||||
interrupted = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
interrupted = true;
|
||||
}
|
||||
return buffer != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T next() {
|
||||
hasNext();
|
||||
T result = buffer;
|
||||
buffer = null;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(T t) {
|
||||
queue.add(t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
queue.add((T) END_MARKER);
|
||||
}
|
||||
}
|
@ -1,37 +1,72 @@
|
||||
package com.boydti.fawe.object.task;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public abstract class AsyncNotifyQueue {
|
||||
protected Object lock = new Object();
|
||||
protected final Runnable task;
|
||||
protected final AtomicBoolean running = new AtomicBoolean();
|
||||
public class AsyncNotifyQueue implements Closeable {
|
||||
private final Lock lock = new ReentrantLock(true);
|
||||
private final Thread.UncaughtExceptionHandler handler;
|
||||
private boolean closed;
|
||||
|
||||
public AsyncNotifyQueue() {
|
||||
this.task = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
operate();
|
||||
synchronized (lock) {
|
||||
if (hasQueued()) TaskManager.IMP.async(this);
|
||||
else running.set(false);
|
||||
public AsyncNotifyQueue(Thread.UncaughtExceptionHandler handler) {
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
public Thread.UncaughtExceptionHandler getHandler() {
|
||||
return handler;
|
||||
}
|
||||
|
||||
public <T> Future<T> run(Runnable task) {
|
||||
return call(() -> {
|
||||
task.run();
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
public <T> Future<T> supply(Supplier<T> task) {
|
||||
return call(task::get);
|
||||
}
|
||||
|
||||
public <T> Future<T> call(Callable<T> task) {
|
||||
Future[] self = new Future[1];
|
||||
Callable<T> wrapped = () -> {
|
||||
if (!closed) {
|
||||
try {
|
||||
lock.lock();
|
||||
if (!closed) {
|
||||
try {
|
||||
return task.call();
|
||||
} catch (Throwable e) {
|
||||
handler.uncaughtException(Thread.currentThread(), e);
|
||||
if (self[0] != null) self[0].cancel(true);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
if (self[0] != null) self[0].cancel(true);
|
||||
return null;
|
||||
};
|
||||
self[0] = Fawe.get().getQueueHandler().async(wrapped);
|
||||
return self[0];
|
||||
}
|
||||
|
||||
public abstract boolean hasQueued();
|
||||
|
||||
public void queue(Runnable queueTask) {
|
||||
synchronized (lock) {
|
||||
if (queueTask != null) queueTask.run();
|
||||
if (!running.get()) {
|
||||
running.set(true);
|
||||
TaskManager.IMP.async(task);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void close() {
|
||||
closed = true;
|
||||
}
|
||||
|
||||
public abstract void operate();
|
||||
public boolean isClosed() {
|
||||
return closed;
|
||||
}
|
||||
}
|
||||
|
@ -1,49 +0,0 @@
|
||||
package com.boydti.fawe.object.task;
|
||||
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
public class SimpleAsyncNotifyQueue extends AsyncNotifyQueue {
|
||||
private ConcurrentLinkedQueue<Runnable> tasks = new ConcurrentLinkedQueue<>();
|
||||
private Thread.UncaughtExceptionHandler handler;
|
||||
|
||||
public SimpleAsyncNotifyQueue(Thread.UncaughtExceptionHandler handler) {
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasQueued() {
|
||||
return !tasks.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void operate() {
|
||||
while (!tasks.isEmpty()) {
|
||||
Runnable task = tasks.poll();
|
||||
try {
|
||||
if (task != null) task.run();
|
||||
} catch (Throwable e) {
|
||||
if (handler != null) handler.uncaughtException(Thread.currentThread(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void queue(Runnable queueTask) {
|
||||
synchronized (lock) {
|
||||
if (queueTask != null) tasks.add(queueTask);
|
||||
if (!running.get()) {
|
||||
running.set(true);
|
||||
TaskManager.IMP.async(task);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return tasks.size();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
tasks.clear();
|
||||
}
|
||||
}
|
@ -9,6 +9,7 @@ import com.boydti.fawe.beta.IBatchProcessor;
|
||||
import com.boydti.fawe.beta.IQueueExtent;
|
||||
import com.boydti.fawe.beta.implementation.processors.LimitProcessor;
|
||||
import com.boydti.fawe.beta.implementation.queue.ParallelQueueExtent;
|
||||
import com.sk89q.worldedit.util.Identifiable;
|
||||
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.logging.LoggingChangeSet;
|
||||
@ -58,6 +59,7 @@ public class EditSessionBuilder {
|
||||
private BlockBag blockBag;
|
||||
private boolean threaded = true;
|
||||
private EditSessionEvent event;
|
||||
private String command;
|
||||
|
||||
/**
|
||||
* An EditSession builder<br>
|
||||
@ -130,6 +132,11 @@ public class EditSessionBuilder {
|
||||
return setDirty();
|
||||
}
|
||||
|
||||
public EditSessionBuilder command(String command) {
|
||||
this.command = command;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param disk If it should be stored on disk
|
||||
* @param uuid The uuid to store it under (if on disk)
|
||||
@ -360,7 +367,7 @@ public class EditSessionBuilder {
|
||||
if (!this.fastmode || changeSet != null) {
|
||||
if (changeSet == null) {
|
||||
if (Settings.IMP.HISTORY.USE_DISK) {
|
||||
UUID uuid = player == null ? EditSession.CONSOLE : player.getUniqueId();
|
||||
UUID uuid = player == null ? Identifiable.CONSOLE : player.getUniqueId();
|
||||
if (Settings.IMP.HISTORY.USE_DATABASE) {
|
||||
changeSet = new RollbackOptimizedHistory(world, uuid);
|
||||
} else {
|
||||
@ -378,6 +385,9 @@ public class EditSessionBuilder {
|
||||
if (this.limit.SPEED_REDUCTION > 0) {
|
||||
this.extent = this.bypassHistory = new SlowExtent(this.bypassHistory, this.limit.SPEED_REDUCTION);
|
||||
}
|
||||
if (command != null && changeSet instanceof RollbackOptimizedHistory) {
|
||||
((RollbackOptimizedHistory) changeSet).setCommand(this.command);
|
||||
}
|
||||
if (changeSet instanceof NullChangeSet && Fawe.imp().getBlocksHubApi() != null && player != null) {
|
||||
changeSet = LoggingChangeSet.wrap(player, changeSet);
|
||||
}
|
||||
|
@ -80,6 +80,8 @@ import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import it.unimi.dsi.fastutil.io.FastBufferedInputStream;
|
||||
import net.jpountz.lz4.LZ4BlockInputStream;
|
||||
import net.jpountz.lz4.LZ4BlockOutputStream;
|
||||
import net.jpountz.lz4.LZ4Compressor;
|
||||
@ -336,7 +338,7 @@ public class MainUtil {
|
||||
|
||||
public static FaweInputStream getCompressedIS(InputStream is, int buffer) throws IOException {
|
||||
int mode = (byte) is.read();
|
||||
is = new BufferedInputStream(is, buffer);
|
||||
is = new FastBufferedInputStream(is, buffer);
|
||||
if (mode == 0) {
|
||||
return new FaweInputStream(is);
|
||||
}
|
||||
@ -353,7 +355,7 @@ public class MainUtil {
|
||||
int amountAbs = Math.abs(mode);
|
||||
if (amountAbs > 6) {
|
||||
if (mode > 0) {
|
||||
is = new BufferedInputStream(new GZIPInputStream(is, buffer));
|
||||
is = new FastBufferedInputStream(new GZIPInputStream(is, buffer));
|
||||
} else {
|
||||
is = new ZstdInputStream(is);
|
||||
}
|
||||
@ -366,7 +368,7 @@ public class MainUtil {
|
||||
is = new LZ4BlockInputStream(is);
|
||||
}
|
||||
}
|
||||
return new FaweInputStream(is);
|
||||
return new FaweInputStream(new FastBufferedInputStream(is));
|
||||
}
|
||||
|
||||
public static URL upload(UUID uuid, String file, String extension, final RunnableVal<OutputStream> writeTask) {
|
||||
@ -833,7 +835,7 @@ public class MainUtil {
|
||||
long age = now - file.lastModified();
|
||||
if (age > timeDiff) {
|
||||
pool.submit(file::delete);
|
||||
Component msg = WorldEditText.format(TranslatableComponent.of("fawe.info.file.deleted"), Locale.ROOT);
|
||||
Component msg = WorldEditText.format(TranslatableComponent.of("worldedit.schematic.delete.deleted"), Locale.ROOT);
|
||||
if (printDebug) Fawe.debug(msg);
|
||||
}
|
||||
});
|
||||
|
@ -210,8 +210,6 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
|
||||
|
||||
private final int maxY;
|
||||
|
||||
public static final UUID CONSOLE = UUID.fromString("1-1-3-3-7");
|
||||
|
||||
@Deprecated
|
||||
public EditSession(@NotNull World world, @Nullable Player player, @Nullable FaweLimit limit, @Nullable FaweChangeSet changeSet, @Nullable RegionWrapper[] allowedRegions, @Nullable Boolean autoQueue, @Nullable Boolean fastmode, @Nullable Boolean checkMemory, @Nullable Boolean combineStages, @Nullable BlockBag blockBag, @Nullable EventBus bus, @Nullable EditSessionEvent event) {
|
||||
this(null, world, player, limit, changeSet, allowedRegions, autoQueue, fastmode, checkMemory, combineStages, blockBag, bus, event);
|
||||
|
@ -1432,6 +1432,10 @@ public class LocalSession implements TextureHolder {
|
||||
* @return an edit session
|
||||
*/
|
||||
public EditSession createEditSession(Actor actor) {
|
||||
return createEditSession(actor, null);
|
||||
}
|
||||
|
||||
public EditSession createEditSession(Actor actor, String command) {
|
||||
checkNotNull(actor);
|
||||
|
||||
World world = null;
|
||||
@ -1449,6 +1453,7 @@ public class LocalSession implements TextureHolder {
|
||||
builder.player((Player) actor);
|
||||
builder.blockBag(blockBag);
|
||||
}
|
||||
builder.command(command);
|
||||
builder.fastmode(fastMode);
|
||||
|
||||
editSession = builder.build();
|
||||
|
@ -19,19 +19,6 @@
|
||||
|
||||
package com.sk89q.worldedit.command;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweAPI;
|
||||
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.database.DBHandler;
|
||||
import com.boydti.fawe.database.RollbackDatabase;
|
||||
import com.boydti.fawe.logging.rollback.RollbackOptimizedHistory;
|
||||
import com.boydti.fawe.object.RegionWrapper;
|
||||
import com.boydti.fawe.object.RunnableVal;
|
||||
import com.boydti.fawe.object.changeset.DiskStorageHistory;
|
||||
import com.boydti.fawe.regions.FaweMaskManager;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.LocalSession;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
@ -42,20 +29,10 @@ import com.sk89q.worldedit.command.util.annotation.Confirm;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import com.sk89q.worldedit.util.formatting.text.TextComponent;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.util.Location;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import java.io.File;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
|
||||
import org.enginehub.piston.annotation.Command;
|
||||
import org.enginehub.piston.annotation.CommandContainer;
|
||||
import org.enginehub.piston.annotation.param.Arg;
|
||||
import org.enginehub.piston.annotation.param.Switch;
|
||||
import org.jetbrains.annotations.Range;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
@ -77,149 +54,6 @@ public class HistoryCommands {
|
||||
this.worldEdit = worldEdit;
|
||||
}
|
||||
|
||||
@Command(
|
||||
name = "fawerollback",
|
||||
aliases = {"frb", "/fawerollback", "/rollback"},
|
||||
desc = "Undo a specific edit. " +
|
||||
" - The time uses s, m, h, d, y.\n" +
|
||||
" - Import from disk: /frb #import"
|
||||
)
|
||||
@CommandPermissions("worldedit.history.rollback")
|
||||
public void faweRollback(Player player, LocalSession session, @Arg(desc = "String user") String user, @Arg(def = "0", desc = "radius") @Range(from = 0, to=Integer.MAX_VALUE) int radius, @Arg(name = "time", desc = "String", def = "0") String time, @Switch(name = 'r', desc = "TODO") boolean restore) throws WorldEditException {
|
||||
if (!Settings.IMP.HISTORY.USE_DATABASE) {
|
||||
player.print(TranslatableComponent.of("fawe.error.setting.disable" , "history.use-database (Import with /frb #import )"));
|
||||
return;
|
||||
}
|
||||
if (user.charAt(0) == '#') {
|
||||
if (user.equals("#import")) {
|
||||
if (!player.hasPermission("fawe.rollback.import")) {
|
||||
player.print(TranslatableComponent.of("fawe.error.no.perm", "fawe.rollback.import"));
|
||||
return;
|
||||
}
|
||||
File folder = MainUtil.getFile(Fawe.imp().getDirectory(), Settings.IMP.PATHS.HISTORY);
|
||||
if (folder.exists()) {
|
||||
for (File worldFolder : Objects.requireNonNull(folder.listFiles())) {
|
||||
if (worldFolder != null && worldFolder.isDirectory()) {
|
||||
String worldName = worldFolder.getName();
|
||||
World world = FaweAPI.getWorld(worldName);
|
||||
if (world != null) {
|
||||
for (File userFolder : worldFolder.listFiles()) {
|
||||
if (!userFolder.isDirectory()) {
|
||||
continue;
|
||||
}
|
||||
String userUUID = userFolder.getName();
|
||||
try {
|
||||
UUID uuid = UUID.fromString(userUUID);
|
||||
for (File historyFile : userFolder.listFiles()) {
|
||||
String name = historyFile.getName();
|
||||
if (!name.endsWith(".bd")) {
|
||||
continue;
|
||||
}
|
||||
RollbackOptimizedHistory rollback = new RollbackOptimizedHistory(
|
||||
world, uuid,
|
||||
Integer.parseInt(
|
||||
name.substring(0, name.length() - 3)));
|
||||
DiskStorageHistory.DiskStorageSummary summary = rollback
|
||||
.summarize(RegionWrapper.GLOBAL(), false);
|
||||
if (summary != null) {
|
||||
rollback.setDimensions(
|
||||
BlockVector3.at(summary.minX, 0, summary.minZ),
|
||||
BlockVector3
|
||||
.at(summary.maxX, 255, summary.maxZ));
|
||||
rollback.setTime(historyFile.lastModified());
|
||||
RollbackDatabase db = DBHandler.IMP
|
||||
.getDatabase(world);
|
||||
db.logEdit(rollback);
|
||||
player.print("Logging: " + historyFile);
|
||||
}
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
player.print("Done import!");
|
||||
}
|
||||
return;
|
||||
}
|
||||
String toParse = user.substring(1);
|
||||
if (!MathMan.isInteger(toParse)) {
|
||||
player.print(TranslatableComponent.of("fawe.error.command.syntax" , "/frb #<index>"));
|
||||
return;
|
||||
}
|
||||
int index = Integer.parseInt(toParse);
|
||||
final World world = player.getWorld();
|
||||
UUID uuid = player.getUniqueId();
|
||||
DiskStorageHistory file = new DiskStorageHistory(world, uuid, index);
|
||||
if (file.getBDFile().exists()) {
|
||||
if (restore) file.redo(player);
|
||||
else file.undo(player);
|
||||
player.print(TranslatableComponent.of("fawe.worldedit.rollback.rollback.element" , world.getName() + "/" + user + "-" + index));
|
||||
} else {
|
||||
player.print(TranslatableComponent.of("fawe.worldedit.tool.tool.inspect.info.footer" , 0));
|
||||
}
|
||||
return;
|
||||
}
|
||||
UUID other = Fawe.imp().getUUID(user);
|
||||
if (other == null) {
|
||||
player.print(TranslatableComponent.of("fawe.error.player.not.found" , user));
|
||||
return;
|
||||
}
|
||||
if (radius == 0) {
|
||||
player.print(TranslatableComponent.of("fawe.error.command.syntax" , "/frb " + user + " <radius> <time>"));
|
||||
return;
|
||||
}
|
||||
long timeDiff = MainUtil.timeToSec(time) * 1000;
|
||||
if (timeDiff == 0) {
|
||||
player.print(TranslatableComponent.of("fawe.error.command.syntax" , "/frb " + user + " " + radius + " <time>"));
|
||||
return;
|
||||
}
|
||||
radius = Math.max(Math.min(500, radius), 0);
|
||||
final World world = player.getWorld();
|
||||
Location origin = player.getLocation();
|
||||
BlockVector3 bot = origin.toBlockPoint().subtract(radius, radius, radius);
|
||||
bot = bot.withY(Math.max(0, bot.getY()));
|
||||
BlockVector3 top = origin.toBlockPoint().add(radius, radius, radius);
|
||||
bot = bot.withY(Math.min(255, top.getY()));
|
||||
RollbackDatabase database = DBHandler.IMP.getDatabase(world);
|
||||
final AtomicInteger count = new AtomicInteger();
|
||||
|
||||
Region[] allowedRegions = player.getCurrentRegions(FaweMaskManager.MaskType.OWNER);
|
||||
if (allowedRegions == null) {
|
||||
player.printError(TranslatableComponent.of("fawe.error.no.region"));
|
||||
return;
|
||||
}
|
||||
// TODO mask the regions bot / top to the bottom and top coord in the allowedRegions
|
||||
// TODO: then mask the edit to the bot / top
|
||||
// if (allowedRegions.length != 1 || !allowedRegions[0].isGlobal()) {
|
||||
// finalQueue = new MaskedIQueueExtent(SetQueue.IMP.getNewQueue(fp.getWorld(), true, false), allowedRegions);
|
||||
// } else {
|
||||
// finalQueue = SetQueue.IMP.getNewQueue(fp.getWorld(), true, false);
|
||||
// }
|
||||
database.getPotentialEdits(other, System.currentTimeMillis() - timeDiff, bot, top, new RunnableVal<DiskStorageHistory>() {
|
||||
@Override
|
||||
public void run(DiskStorageHistory edit) {
|
||||
edit.undo(player, allowedRegions);
|
||||
player.print(TranslatableComponent.of("fawe.worldedit.rollback.rollback.element" , edit.getWorld().getName() + "/" + user + "-" + edit.getIndex()));
|
||||
count.incrementAndGet();
|
||||
}
|
||||
}, () -> player.print(TranslatableComponent.of("fawe.worldedit.tool.tool.inspect.info.footer" , count)), true, restore);
|
||||
}
|
||||
|
||||
@Command(
|
||||
name = "fawerestore",
|
||||
aliases = {"/fawerestore", "/frestore"},
|
||||
desc = "Redo a specific edit. " +
|
||||
" - The time uses s, m, h, d, y.\n" +
|
||||
" - Import from disk: /frb #import"
|
||||
)
|
||||
@CommandPermissions("worldedit.history.rollback")
|
||||
public void restore(Player player, LocalSession session, @Arg(desc = "String user") String user, @Arg(def = "0", desc = "radius") int radius, @Arg(name = "time", desc = "String", def = "0") String time) throws WorldEditException {
|
||||
faweRollback(player, session, user, radius, time, true);
|
||||
}
|
||||
|
||||
@Command(
|
||||
name = "/undo",
|
||||
aliases = { "/un", "/ud", "undo" },
|
||||
@ -301,14 +135,13 @@ public class HistoryCommands {
|
||||
}
|
||||
|
||||
@Command(
|
||||
name = "clearhistory",
|
||||
aliases = { "/clearhistory" },
|
||||
desc = "Clear your history"
|
||||
name = "clearhistory",
|
||||
aliases = { "/clearhistory" },
|
||||
desc = "Clear your history"
|
||||
)
|
||||
@CommandPermissions("worldedit.history.clear")
|
||||
public void clearHistory(Actor actor, LocalSession session) {
|
||||
session.clearHistory();
|
||||
actor.printInfo(TranslatableComponent.of("worldedit.clearhistory.cleared"));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,376 @@
|
||||
package com.sk89q.worldedit.command;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweAPI;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.database.DBHandler;
|
||||
import com.boydti.fawe.database.RollbackDatabase;
|
||||
import com.boydti.fawe.logging.rollback.RollbackOptimizedHistory;
|
||||
import com.boydti.fawe.object.RegionWrapper;
|
||||
import com.boydti.fawe.object.changeset.DiskStorageHistory;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.sk89q.worldedit.LocalSession;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.command.argument.Arguments;
|
||||
import com.sk89q.worldedit.command.util.CommandPermissions;
|
||||
import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
|
||||
import com.sk89q.worldedit.command.util.annotation.Confirm;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import com.sk89q.worldedit.internal.annotation.AllowedRegion;
|
||||
import com.sk89q.worldedit.internal.annotation.Time;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.util.Countable;
|
||||
import com.sk89q.worldedit.util.Direction;
|
||||
import com.sk89q.worldedit.util.Identifiable;
|
||||
import com.sk89q.worldedit.util.Location;
|
||||
import com.sk89q.worldedit.util.formatting.component.PaginationBox;
|
||||
import com.sk89q.worldedit.util.formatting.text.Component;
|
||||
import com.sk89q.worldedit.util.formatting.text.TextComponent;
|
||||
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
|
||||
import com.sk89q.worldedit.util.formatting.text.event.ClickEvent;
|
||||
import com.sk89q.worldedit.util.formatting.text.event.HoverEvent;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import org.enginehub.piston.annotation.Command;
|
||||
import org.enginehub.piston.annotation.CommandContainer;
|
||||
import org.enginehub.piston.annotation.param.Arg;
|
||||
import org.enginehub.piston.annotation.param.ArgFlag;
|
||||
import org.enginehub.piston.annotation.param.Switch;
|
||||
import org.jetbrains.annotations.Range;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.File;
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.atomic.LongAdder;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static com.sk89q.worldedit.internal.command.CommandUtil.checkCommandArgument;
|
||||
|
||||
@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
|
||||
public class HistorySubCommands {
|
||||
|
||||
private final HistoryCommands parent;
|
||||
|
||||
public HistorySubCommands(HistoryCommands parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Command(
|
||||
name = "restore",
|
||||
aliases = {"rerun"},
|
||||
desc = "Rerun edits" +
|
||||
" - The time uses s, m, h, d, y.\n" +
|
||||
" - Import from disk: /history import"
|
||||
)
|
||||
@CommandPermissions("worldedit.history.redo")
|
||||
@Confirm
|
||||
public synchronized void rerun(Player player, World world, RollbackDatabase database,
|
||||
@AllowedRegion Region[] allowedRegions,
|
||||
@ArgFlag(name = 'u', desc = "String user", def="me") UUID other,
|
||||
@ArgFlag(name = 'r', def = "0", desc = "radius")
|
||||
@Range(from = 0, to=Integer.MAX_VALUE) int radius,
|
||||
@ArgFlag(name = 't', desc = "Time e.g. 20s", def = "0")
|
||||
@Time long timeDiff) throws WorldEditException {
|
||||
rollback(player, world, database, allowedRegions, other, radius, timeDiff, true);
|
||||
}
|
||||
|
||||
@Command(
|
||||
name = "rollback",
|
||||
desc = "Undo a specific edit. " +
|
||||
" - The time uses s, m, h, d, y.\n" +
|
||||
" - Import from disk: /history import"
|
||||
)
|
||||
@CommandPermissions("worldedit.history.undo")
|
||||
@Confirm
|
||||
public synchronized void rollback(Player player, World world, RollbackDatabase database,
|
||||
@AllowedRegion Region[] allowedRegions,
|
||||
@ArgFlag(name = 'u', desc = "String user", def = "") UUID other,
|
||||
@ArgFlag(name = 'r', def = "0", desc = "radius")
|
||||
@Range(from = 0, to=Integer.MAX_VALUE) int radius,
|
||||
@ArgFlag(name = 't', desc = "Time e.g. 20s", def = "0") @Time long timeDiff,
|
||||
@Switch(name = 'f', desc = "Restore instead of rollback") boolean restore) throws WorldEditException {
|
||||
if (!Settings.IMP.HISTORY.USE_DATABASE) {
|
||||
player.print(TranslatableComponent.of("fawe.error.setting.disable" , "history.use-database (Import with /history import )"));
|
||||
return;
|
||||
}
|
||||
checkCommandArgument(radius > 0, "Radius must be >= 0");
|
||||
checkCommandArgument(timeDiff > 0, "Time must be >= 0");
|
||||
|
||||
if (other == null) other = player.getUniqueId();
|
||||
if (!other.equals(player.getUniqueId())) {
|
||||
player.checkPermission("worldedit.history.undo.other");
|
||||
}
|
||||
if (other == Identifiable.EVERYONE) other = null;
|
||||
Location origin = player.getLocation();
|
||||
BlockVector3 bot = origin.toBlockPoint().subtract(radius, radius, radius);
|
||||
BlockVector3 top = origin.toBlockPoint().add(radius, radius, radius);
|
||||
bot = bot.clampY(0, world.getMaxY());
|
||||
top = top.clampY(0, world.getMaxY());
|
||||
// TODO mask the regions bot / top to the bottom and top coord in the allowedRegions
|
||||
// TODO: then mask the edit to the bot / top
|
||||
// if (allowedRegions.length != 1 || !allowedRegions[0].isGlobal()) {
|
||||
// finalQueue = new MaskedIQueueExtent(SetQueue.IMP.getNewQueue(fp.getWorld(), true, false), allowedRegions);
|
||||
// } else {
|
||||
// finalQueue = SetQueue.IMP.getNewQueue(fp.getWorld(), true, false);
|
||||
// }
|
||||
int count = 0;
|
||||
UUID finalOther = other;
|
||||
long minTime = System.currentTimeMillis() - timeDiff;
|
||||
for (Supplier<RollbackOptimizedHistory> supplier : database.getEdits(other, minTime, bot, top, !restore, restore)) {
|
||||
count++;
|
||||
RollbackOptimizedHistory edit = supplier.get();
|
||||
edit.undo(player, allowedRegions);
|
||||
String path = edit.getWorld().getName() + "/" + finalOther + "-" + edit.getIndex();
|
||||
player.print(TranslatableComponent.of("fawe.worldedit.rollback.rollback.element", path));
|
||||
}
|
||||
player.print(TranslatableComponent.of("fawe.worldedit.tool.tool.inspect.info.footer" , count));
|
||||
}
|
||||
|
||||
@Command(
|
||||
name = "import",
|
||||
desc = "Import history into the database" +
|
||||
" - The time uses s, m, h, d, y.\n" +
|
||||
" - Import from disk: /history import"
|
||||
)
|
||||
@CommandPermissions("fawe.rollback.import")
|
||||
@Confirm
|
||||
public synchronized void importdb(Actor actor) throws WorldEditException {
|
||||
File folder = MainUtil.getFile(Fawe.imp().getDirectory(), Settings.IMP.PATHS.HISTORY);
|
||||
if (folder.exists()) {
|
||||
for (File worldFolder : Objects.requireNonNull(folder.listFiles())) {
|
||||
if (worldFolder != null && worldFolder.isDirectory()) {
|
||||
String worldName = worldFolder.getName();
|
||||
World world = FaweAPI.getWorld(worldName);
|
||||
if (world != null) {
|
||||
for (File userFolder : worldFolder.listFiles()) {
|
||||
if (!userFolder.isDirectory()) {
|
||||
continue;
|
||||
}
|
||||
String userUUID = userFolder.getName();
|
||||
try {
|
||||
UUID uuid = UUID.fromString(userUUID);
|
||||
for (File historyFile : userFolder.listFiles()) {
|
||||
String name = historyFile.getName();
|
||||
if (!name.endsWith(".bd")) {
|
||||
continue;
|
||||
}
|
||||
RollbackOptimizedHistory rollback = new RollbackOptimizedHistory(
|
||||
world, uuid,
|
||||
Integer.parseInt(
|
||||
name.substring(0, name.length() - 3)));
|
||||
DiskStorageHistory.DiskStorageSummary summary = rollback
|
||||
.summarize(RegionWrapper.GLOBAL(), false);
|
||||
if (summary != null) {
|
||||
rollback.setDimensions(
|
||||
BlockVector3.at(summary.minX, 0, summary.minZ),
|
||||
BlockVector3
|
||||
.at(summary.maxX, 255, summary.maxZ));
|
||||
rollback.setTime(historyFile.lastModified());
|
||||
RollbackDatabase db = DBHandler.IMP
|
||||
.getDatabase(world);
|
||||
db.logEdit(rollback);
|
||||
actor.print("Logging: " + historyFile);
|
||||
}
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
actor.print("Done import!");
|
||||
}
|
||||
}
|
||||
|
||||
@Command(
|
||||
name = "summary",
|
||||
aliases = {"info", "summarize"},
|
||||
desc = "Summarize an edit"
|
||||
)
|
||||
@CommandPermissions("worldedit.history.find")
|
||||
public synchronized void summary(Player player, RollbackDatabase database, Arguments arguments,
|
||||
@Arg(desc = "Player uuid/name") UUID other,
|
||||
@Arg(desc = "edit index") Integer index,
|
||||
@ArgFlag(name = 'p', desc = "Page to view.", def = "-1") int page) throws WorldEditException, ExecutionException, InterruptedException {
|
||||
RollbackOptimizedHistory edit = database.getEdit(other, index).get();
|
||||
if (edit == null) {
|
||||
player.print(TranslatableComponent.of("fawe.worldedit.schematic.schematic.none"));
|
||||
return;
|
||||
}
|
||||
Location origin = player.getLocation();
|
||||
|
||||
String name = Fawe.imp().getName(edit.getUUID());
|
||||
String cmd = edit.getCommand();
|
||||
BlockVector3 pos1 = edit.getMinimumPoint();
|
||||
BlockVector3 pos2 = edit.getMaximumPoint();
|
||||
|
||||
double distanceX = Math.min( Math.abs(pos1.getX() - origin.getX()), Math.abs(pos2.getX() - origin.getX()));
|
||||
double distanceZ = Math.min( Math.abs(pos1.getZ() - origin.getZ()), Math.abs(pos2.getZ() - origin.getZ()));
|
||||
int distance = (int) Math.sqrt(distanceX * distanceX + distanceZ * distanceZ);
|
||||
|
||||
BlockVector2 dirVec = BlockVector2.at(edit.getOriginX() - origin.getX(), edit.getOriginZ() - origin.getZ());
|
||||
Direction direction = Direction.findClosest(dirVec.toVector3(), Direction.Flag.ALL);
|
||||
|
||||
long seconds = (System.currentTimeMillis() - edit.getBDFile().lastModified()) / 1000;
|
||||
String timeStr = MainUtil.secToTime(seconds);
|
||||
|
||||
int size = edit.size();
|
||||
|
||||
String pageCommand = arguments.get().replaceAll("-p [0-9]+", "").trim();
|
||||
List<Countable<BlockState>> list = null;
|
||||
Reference<List<Countable<BlockState>>> cached = player.getMeta(pageCommand);
|
||||
if (cached != null) {
|
||||
list = cached.get();
|
||||
}
|
||||
if (list == null) {
|
||||
DiskStorageHistory.DiskStorageSummary summary = edit.summarize(null, false);
|
||||
if (summary != null) {
|
||||
list = summary.getBlockDistributionWithData();
|
||||
player.setMeta(pageCommand, new SoftReference<>(list));
|
||||
}
|
||||
}
|
||||
boolean biomes = edit.getBioFile().exists();
|
||||
boolean createdEnts = edit.getEnttFile().exists();
|
||||
boolean removedEnts = edit.getEntfFile().exists();
|
||||
boolean createdTiles = edit.getNbttFile().exists();
|
||||
boolean removedTiles = edit.getNbtfFile().exists();
|
||||
System.out.println("TODO FIXME move to translations");
|
||||
if (page == -1) {
|
||||
player.print("name: " + name
|
||||
+ ", cmd: " + edit.getCommand()
|
||||
+ ", dist: " + distance + "m " + direction.name()
|
||||
+ ", time: " + timeStr + " ago"
|
||||
+ ", size: " + size + " blocks"
|
||||
+ ", biomes: " + biomes
|
||||
+ ", +entity: " + createdEnts
|
||||
+ ", -entity: " + removedEnts
|
||||
+ ", +tile: " + createdTiles
|
||||
+ ", -tile: " + removedTiles
|
||||
+ ", disk: " + (edit.getSizeOnDisk() / 1000) + "mb"
|
||||
+ ", min " + edit.getMinimumPoint()
|
||||
+ ", max " + edit.getMaximumPoint()
|
||||
);
|
||||
}
|
||||
page = 1;
|
||||
if (list != null) {
|
||||
SelectionCommands.BlockDistributionResult pages = new SelectionCommands.BlockDistributionResult((List) list, true, pageCommand);
|
||||
player.print(pages.create(page));
|
||||
}
|
||||
}
|
||||
|
||||
@Command(
|
||||
name = "find",
|
||||
aliases = {"inspect", "search", "near"},
|
||||
desc = "Find nearby edits"
|
||||
)
|
||||
@CommandPermissions("worldedit.history.find")
|
||||
public synchronized void find(Player player, World world, RollbackDatabase database, Arguments arguments,
|
||||
@ArgFlag(name = 'u', desc = "String user") UUID other,
|
||||
@ArgFlag(name = 'r', def = "0", desc = "radius")
|
||||
@Range(from = 0, to=Integer.MAX_VALUE) int radius,
|
||||
@ArgFlag(name = 't', desc = "Time e.g. 20s", def = "0")
|
||||
@Time long timeDiff,
|
||||
@ArgFlag(name = 'p', desc = "Page to view.", def = "1") int page) throws WorldEditException {
|
||||
if (!Settings.IMP.HISTORY.USE_DATABASE) {
|
||||
player.print(TranslatableComponent.of("fawe.error.setting.disable" , "history.use-database (Import with //history import )"));
|
||||
return;
|
||||
}
|
||||
checkCommandArgument(radius > 0, "Radius must be >= 0");
|
||||
checkCommandArgument(timeDiff > 0, "Time must be >= 0");
|
||||
|
||||
Location origin = player.getLocation();
|
||||
String pageCommand = arguments.get().replaceAll("-p [0-9]+", "").trim();
|
||||
|
||||
List<Supplier<RollbackOptimizedHistory>> list = null;
|
||||
Reference<List<Supplier<RollbackOptimizedHistory>>> cached = player.getMeta(pageCommand);
|
||||
if (cached != null) {
|
||||
list = cached.get();
|
||||
}
|
||||
if (list == null) {
|
||||
if (other == null) other = player.getUniqueId();
|
||||
if (!other.equals(player.getUniqueId())) {
|
||||
player.checkPermission("worldedit.history.undo.other");
|
||||
}
|
||||
if (other == Identifiable.EVERYONE) other = null;
|
||||
|
||||
BlockVector3 bot = origin.toBlockPoint().subtract(radius, radius, radius);
|
||||
BlockVector3 top = origin.toBlockPoint().add(radius, radius, radius);
|
||||
bot = bot.clampY(0, world.getMaxY());
|
||||
top = top.clampY(0, world.getMaxY());
|
||||
|
||||
LongAdder total = new LongAdder();
|
||||
|
||||
long minTime = System.currentTimeMillis() - timeDiff;
|
||||
Iterable<Supplier<RollbackOptimizedHistory>> edits = database.getEdits(other, minTime, bot, top, false, false);
|
||||
list = Lists.newArrayList(edits);
|
||||
player.setMeta(pageCommand, new SoftReference<>(list));
|
||||
}
|
||||
|
||||
PaginationBox pages = PaginationBox.fromStrings("Edits:", pageCommand, list, new Function<Supplier<RollbackOptimizedHistory>, Component>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public Component apply(@Nullable Supplier<RollbackOptimizedHistory> input) {
|
||||
RollbackOptimizedHistory edit = input.get();
|
||||
UUID uuid = edit.getUUID();
|
||||
int index = edit.getIndex();
|
||||
if (!edit.getBDFile().exists()) {
|
||||
database.delete(uuid, index);
|
||||
return TextComponent.empty();
|
||||
}
|
||||
String name = Fawe.imp().getName(edit.getUUID());
|
||||
|
||||
String cmd = edit.getCommand();
|
||||
BlockVector3 pos1 = edit.getMinimumPoint();
|
||||
BlockVector3 pos2 = edit.getMaximumPoint();
|
||||
|
||||
double distanceX = Math.min(Math.abs(pos1.getX() - origin.getX()), Math.abs(pos2.getX() - origin.getX()));
|
||||
double distanceZ = Math.min(Math.abs(pos1.getZ() - origin.getZ()), Math.abs(pos2.getZ() - origin.getZ()));
|
||||
int distance = (int) Math.sqrt(distanceX * distanceX + distanceZ * distanceZ);
|
||||
|
||||
BlockVector2 dirVec = BlockVector2.at(edit.getOriginX() - origin.getX(), edit.getOriginZ() - origin.getZ());
|
||||
Direction direction = Direction.findClosest(dirVec.toVector3(), Direction.Flag.ALL);
|
||||
|
||||
long seconds = (System.currentTimeMillis() - edit.getBDFile().lastModified()) / 1000;
|
||||
String timeStr = MainUtil.secToTime(seconds);
|
||||
|
||||
int size = edit.size();
|
||||
|
||||
TranslatableComponent elem = TranslatableComponent.of("fawe.worldedit.history.find.element", name, timeStr, distance, direction.name(), cmd);
|
||||
|
||||
String infoCmd = "//history summary " + uuid + " " + index;
|
||||
TranslatableComponent hover = TranslatableComponent.of("fawe.worldedit.history.find.hover", size);
|
||||
elem = elem.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, hover));
|
||||
elem = elem.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, infoCmd));
|
||||
|
||||
return elem;
|
||||
}
|
||||
});
|
||||
player.print(pages.create(page));
|
||||
}
|
||||
|
||||
@Command(
|
||||
name = "clear",
|
||||
desc = "Clear your history"
|
||||
)
|
||||
@CommandPermissions("worldedit.history.clear")
|
||||
public void clearHistory(Actor actor, LocalSession session) {
|
||||
parent.clearHistory(actor, session);
|
||||
}
|
||||
}
|
@ -552,11 +552,6 @@ public class SchematicCommands {
|
||||
throw new StopExecutionException(TextComponent.of("Cannot sort by oldest and newest."));
|
||||
}
|
||||
String pageCommand = arguments.get();
|
||||
if (pageCommand.contains("-p ")) {
|
||||
pageCommand = pageCommand.replaceAll("-p [0-9]+", "-p %page%");
|
||||
} else{
|
||||
pageCommand = pageCommand + " -p %page%";
|
||||
}
|
||||
LocalConfiguration config = worldEdit.getConfiguration();
|
||||
File dir = worldEdit.getWorkingDirectoryFile(config.saveDir);
|
||||
|
||||
@ -840,7 +835,7 @@ public class SchematicCommands {
|
||||
actor.printError(TranslatableComponent.of("worldedit.schematic.delete.failed", TextComponent.of(filename)));
|
||||
continue;
|
||||
}
|
||||
actor.print(TranslatableComponent.of("fawe.info.file.deleted" , filename));
|
||||
actor.print(TranslatableComponent.of("worldedit.schematic.delete.deleted" , filename));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -558,14 +558,18 @@ public class SelectionCommands {
|
||||
actor.print(res.create(page));
|
||||
}
|
||||
|
||||
private static class BlockDistributionResult extends PaginationBox {
|
||||
public static class BlockDistributionResult extends PaginationBox {
|
||||
|
||||
private final List<Countable> distribution;
|
||||
private final int totalBlocks;
|
||||
private final boolean separateStates;
|
||||
|
||||
BlockDistributionResult(List<Countable> distribution, boolean separateStates) {
|
||||
super("Block Distribution", "//distr -p %page%" + (separateStates ? " -d" : ""));
|
||||
public BlockDistributionResult(List<Countable> distribution, boolean separateStates) {
|
||||
this(distribution, separateStates, "//distr -p %page%" + (separateStates ? " -d" : ""));
|
||||
}
|
||||
|
||||
public BlockDistributionResult(List<Countable> distribution, boolean separateStates, String pageCommand) {
|
||||
super("Block Distribution", pageCommand);
|
||||
this.distribution = distribution;
|
||||
// note: doing things like region.getArea is inaccurate for non-cuboids.
|
||||
this.totalBlocks = distribution.stream().mapToInt(Countable::getAmount).sum();
|
||||
|
@ -69,7 +69,6 @@ public class SuperPickaxeCommands {
|
||||
player.printError(TranslatableComponent.of("worldedit.superpickaxe.max-range", TextComponent.of(config.maxSuperPickaxeSize)));
|
||||
return;
|
||||
}
|
||||
|
||||
session.setSuperPickaxe(new AreaPickaxe(range));
|
||||
session.enableSuperPickAxe();
|
||||
player.printInfo(TranslatableComponent.of("worldedit.tool.superpickaxe.mode.area"));
|
||||
|
@ -62,7 +62,7 @@ public class AreaPickaxe implements BlockTool {
|
||||
return false;
|
||||
}
|
||||
|
||||
try (EditSession editSession = session.createEditSession(player)) {
|
||||
try (EditSession editSession = session.createEditSession(player, "AreaPickaxe")) {
|
||||
editSession.getSurvivalExtent().setToolUse(config.superPickaxeManyDrop);
|
||||
|
||||
try {
|
||||
|
@ -85,7 +85,7 @@ public class BlockDataCyler implements DoubleActionBlockTool {
|
||||
Property<Object> objProp = (Property<Object>) currentProperty;
|
||||
BlockState newBlock = block.with(objProp, currentProperty.getValues().get(index));
|
||||
|
||||
try (EditSession editSession = session.createEditSession(player)) {
|
||||
try (EditSession editSession = session.createEditSession(player, "BlockDataCyler")) {
|
||||
editSession.disableBuffering();
|
||||
|
||||
try {
|
||||
|
@ -54,7 +54,7 @@ public class BlockReplacer implements DoubleActionBlockTool {
|
||||
public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked) {
|
||||
BlockBag bag = session.getBlockBag(player);
|
||||
|
||||
try (EditSession editSession = session.createEditSession(player)) {
|
||||
try (EditSession editSession = session.createEditSession(player, "BlockReplacer")) {
|
||||
try {
|
||||
BlockVector3 position = clicked.toVector().toBlockPoint();
|
||||
editSession.setBlock(position, pattern);
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
package com.sk89q.worldedit.command.tool;
|
||||
|
||||
import static com.boydti.fawe.object.brush.BrushSettings.SettingType.BRUSH;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static org.slf4j.LoggerFactory.getLogger;
|
||||
|
||||
@ -110,7 +111,6 @@ public class BrushTool implements DoubleActionTraceTool, ScrollTool, MovableTool
|
||||
private transient BrushSettings context = primary;
|
||||
|
||||
private transient PersistentChunkSendProcessor visualExtent;
|
||||
private transient Lock lock = new ReentrantLock();
|
||||
|
||||
private transient BaseItem holder;
|
||||
|
||||
@ -210,7 +210,6 @@ public class BrushTool implements DoubleActionTraceTool, ScrollTool, MovableTool
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
|
||||
lock = new ReentrantLock();
|
||||
boolean multi = stream.readBoolean();
|
||||
primary = (BrushSettings) stream.readObject();
|
||||
if (multi) {
|
||||
@ -497,7 +496,7 @@ public class BrushTool implements DoubleActionTraceTool, ScrollTool, MovableTool
|
||||
player.print(TranslatableComponent.of("fawe.error.no.perm" , StringMan.join(current.getPermissions(), ",")));
|
||||
return false;
|
||||
}
|
||||
try (EditSession editSession = session.createEditSession(player)) {
|
||||
try (EditSession editSession = session.createEditSession(player, current.toString())) {
|
||||
Location target = player.getBlockTrace(getRange(), true, traceMask);
|
||||
|
||||
if (target == null) {
|
||||
@ -639,7 +638,9 @@ public class BrushTool implements DoubleActionTraceTool, ScrollTool, MovableTool
|
||||
BrushSettings current = getContext();
|
||||
Brush brush = current.getBrush();
|
||||
if (brush == null) return;
|
||||
|
||||
EditSessionBuilder builder = new EditSessionBuilder(player.getWorld())
|
||||
.command(current.toString())
|
||||
.player(player)
|
||||
.allowedRegionsEverywhere()
|
||||
.autoQueue(false)
|
||||
|
@ -78,7 +78,7 @@ public class FloatingTreeRemover implements BlockTool {
|
||||
return true;
|
||||
}
|
||||
|
||||
try (EditSession editSession = session.createEditSession(player)) {
|
||||
try (EditSession editSession = session.createEditSession(player, "FloatingTreeRemover")) {
|
||||
try {
|
||||
final Set<BlockVector3> blockSet = bfs(world, clicked.toVector().toBlockPoint());
|
||||
if (blockSet == null) {
|
||||
|
@ -73,7 +73,7 @@ public class FloodFillTool implements BlockTool {
|
||||
return true;
|
||||
}
|
||||
|
||||
try (EditSession editSession = session.createEditSession(player)) {
|
||||
try (EditSession editSession = session.createEditSession(player, "FloodFillTool")) {
|
||||
try {
|
||||
Mask mask = initialType.toMask(editSession);
|
||||
BlockReplace function = new BlockReplace(editSession, pattern);
|
||||
|
@ -59,7 +59,7 @@ public class LongRangeBuildTool extends BrushTool implements DoubleActionTraceTo
|
||||
if (pos == null) return false;
|
||||
BlockBag bag = session.getBlockBag(player);
|
||||
|
||||
try (EditSession editSession = session.createEditSession(player)) {
|
||||
try (EditSession editSession = session.createEditSession(player, "LongRangeBuildTool")) {
|
||||
try {
|
||||
editSession.disableBuffering();
|
||||
BlockVector3 blockPoint = pos.toVector().toBlockPoint();
|
||||
@ -87,7 +87,7 @@ public class LongRangeBuildTool extends BrushTool implements DoubleActionTraceTo
|
||||
if (pos == null) return false;
|
||||
BlockBag bag = session.getBlockBag(player);
|
||||
|
||||
try (EditSession editSession = session.createEditSession(player)) {
|
||||
try (EditSession editSession = session.createEditSession(player, "LongRangeBuildTool")) {
|
||||
try {
|
||||
editSession.disableBuffering();
|
||||
BlockVector3 blockPoint = pos.toVector().toBlockPoint();
|
||||
|
@ -72,7 +72,7 @@ public class RecursivePickaxe implements BlockTool {
|
||||
return false;
|
||||
}
|
||||
|
||||
try (EditSession editSession = session.createEditSession(player)) {
|
||||
try (EditSession editSession = session.createEditSession(player, "RecursivePickaxe")) {
|
||||
editSession.getSurvivalExtent().setToolUse(config.superPickaxeManyDrop);
|
||||
|
||||
final int radius = (int) range;
|
||||
|
@ -19,8 +19,10 @@
|
||||
|
||||
package com.sk89q.worldedit.extension.factory.parser;
|
||||
|
||||
import com.boydti.fawe.config.Caption;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import com.sk89q.worldedit.util.formatting.WorldEditText;
|
||||
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
|
||||
import com.boydti.fawe.jnbt.JSON2NBT;
|
||||
import com.boydti.fawe.jnbt.NBTException;
|
||||
@ -421,12 +423,12 @@ public class DefaultBlockParser extends InputParser<BaseBlock> {
|
||||
if (context.isRestricted()) {
|
||||
Actor actor = context.requireActor();
|
||||
if (!actor.hasPermission("worldedit.anyblock") && worldEdit.getConfiguration().checkDisallowedBlocks(holder)) {
|
||||
throw new DisallowedUsageException(TranslatableComponent.of("fawe.error.block.not.allowed") + " '" + holder + "'");
|
||||
throw new DisallowedUsageException(Caption.toString(TranslatableComponent.of("fawe.error.block.not.allowed", holder)));
|
||||
}
|
||||
CompoundTag nbt = holder.getNbtData();
|
||||
if (nbt != null) {
|
||||
if (!actor.hasPermission("worldedit.anyblock")) {
|
||||
throw new DisallowedUsageException("You are not allowed to nbt'");
|
||||
throw new DisallowedUsageException("You are not allowed to use nbt'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,7 @@
|
||||
package com.sk89q.worldedit.extension.platform;
|
||||
|
||||
import com.boydti.fawe.object.exception.FaweException;
|
||||
import com.boydti.fawe.object.task.SimpleAsyncNotifyQueue;
|
||||
import com.boydti.fawe.object.task.AsyncNotifyQueue;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.internal.cui.CUIEvent;
|
||||
@ -65,7 +65,7 @@ public abstract class AbstractNonPlayerActor implements Actor {
|
||||
|
||||
// Queue for async tasks
|
||||
private AtomicInteger runningCount = new AtomicInteger();
|
||||
private SimpleAsyncNotifyQueue asyncNotifyQueue = new SimpleAsyncNotifyQueue(
|
||||
private AsyncNotifyQueue asyncNotifyQueue = new AsyncNotifyQueue(
|
||||
(thread, throwable) -> {
|
||||
while (throwable.getCause() != null) {
|
||||
throwable = throwable.getCause();
|
||||
@ -106,7 +106,7 @@ public abstract class AbstractNonPlayerActor implements Actor {
|
||||
}
|
||||
};
|
||||
if (async) {
|
||||
asyncNotifyQueue.queue(wrapped);
|
||||
asyncNotifyQueue.run(wrapped);
|
||||
} else {
|
||||
TaskManager.IMP.taskNow(wrapped, false);
|
||||
}
|
||||
|
@ -19,11 +19,12 @@
|
||||
|
||||
package com.sk89q.worldedit.extension.platform;
|
||||
|
||||
import com.boydti.fawe.config.Caption;
|
||||
import com.boydti.fawe.object.task.AsyncNotifyQueue;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
|
||||
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
|
||||
import com.boydti.fawe.object.exception.FaweException;
|
||||
import com.boydti.fawe.object.task.SimpleAsyncNotifyQueue;
|
||||
import com.boydti.fawe.regions.FaweMaskManager;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.boydti.fawe.util.WEManager;
|
||||
@ -94,7 +95,7 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
|
||||
|
||||
// Queue for async tasks
|
||||
private AtomicInteger runningCount = new AtomicInteger();
|
||||
private SimpleAsyncNotifyQueue asyncNotifyQueue = new SimpleAsyncNotifyQueue(
|
||||
private AsyncNotifyQueue asyncNotifyQueue = new AsyncNotifyQueue(
|
||||
(thread, throwable) -> {
|
||||
while (throwable.getCause() != null) {
|
||||
throwable = throwable.getCause();
|
||||
@ -618,7 +619,7 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
|
||||
@Override
|
||||
public void checkPermission(String permission) throws AuthorizationException {
|
||||
if (!hasPermission(permission)) {
|
||||
throw new AuthorizationException();
|
||||
throw new AuthorizationException(Caption.toString(TranslatableComponent.of("fawe.error.no.perm", permission)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -675,7 +676,7 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
|
||||
}
|
||||
};
|
||||
if (async) {
|
||||
asyncNotifyQueue.queue(wrapped);
|
||||
asyncNotifyQueue.run(wrapped);
|
||||
} else {
|
||||
TaskManager.IMP.taskNow(wrapped, false);
|
||||
}
|
||||
|
@ -110,7 +110,7 @@ public interface Actor extends Identifiable, SessionOwner, Subject, MapMetadatab
|
||||
* @param component The component to print
|
||||
*/
|
||||
default void printError(Component component) {
|
||||
print(TranslatableComponent.of("error", component));
|
||||
print(TranslatableComponent.of("fawe.error", component));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -119,7 +119,7 @@ public interface Actor extends Identifiable, SessionOwner, Subject, MapMetadatab
|
||||
* @param component The component to print
|
||||
*/
|
||||
default void printInfo(Component component) {
|
||||
print(TranslatableComponent.of("info", component));
|
||||
print(TranslatableComponent.of("fawe.info", component));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -142,7 +142,7 @@ public interface Actor extends Identifiable, SessionOwner, Subject, MapMetadatab
|
||||
* @param component The component to print
|
||||
*/
|
||||
default void printDebug(Component component) {
|
||||
print(TranslatableComponent.of("debug", component));
|
||||
print(TranslatableComponent.of("fawe.debug", component));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -25,6 +25,8 @@ import com.boydti.fawe.command.AnvilCommandsRegistration;
|
||||
import com.boydti.fawe.command.CFICommands;
|
||||
import com.boydti.fawe.command.CFICommandsRegistration;
|
||||
import com.boydti.fawe.util.StringMan;
|
||||
import com.sk89q.worldedit.command.HistorySubCommands;
|
||||
import com.sk89q.worldedit.command.HistorySubCommandsRegistration;
|
||||
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.brush.visualization.cfi.HeightMapMCAGenerator;
|
||||
@ -294,6 +296,7 @@ public final class PlatformCommandManager {
|
||||
}
|
||||
});
|
||||
});
|
||||
/*
|
||||
globalInjectedValues.injectValue(Key.of(EditSession.class),
|
||||
context -> {
|
||||
LocalSession localSession = context.injectedValue(Key.of(LocalSession.class))
|
||||
@ -306,6 +309,7 @@ public final class PlatformCommandManager {
|
||||
return editSession;
|
||||
});
|
||||
});
|
||||
*/
|
||||
globalInjectedValues.injectValue(Key.of(CFICommands.CFISettings.class),
|
||||
context -> context.injectedValue(Key.of(Actor.class))
|
||||
.orElseThrow(() -> new IllegalStateException("No CFI Settings")).getMeta("CFISettings"));
|
||||
@ -518,10 +522,18 @@ public final class PlatformCommandManager {
|
||||
GenerationCommandsRegistration.builder(),
|
||||
new GenerationCommands(worldEdit)
|
||||
);
|
||||
HistoryCommands history = new HistoryCommands(worldEdit);
|
||||
this.registration.register(
|
||||
commandManager,
|
||||
HistoryCommandsRegistration.builder(),
|
||||
new HistoryCommands(worldEdit)
|
||||
commandManager,
|
||||
HistoryCommandsRegistration.builder(),
|
||||
history
|
||||
);
|
||||
registerSubCommands(
|
||||
"/history",
|
||||
ImmutableList.of(),
|
||||
"Manage your history",
|
||||
HistorySubCommandsRegistration.builder(),
|
||||
new HistorySubCommands(history)
|
||||
);
|
||||
this.registration.register(
|
||||
commandManager,
|
||||
@ -739,7 +751,7 @@ public final class PlatformCommandManager {
|
||||
} catch (UsageException e) {
|
||||
ImmutableList<Command> cmd = e.getCommands();
|
||||
if (!cmd.isEmpty()) {
|
||||
actor.printError(TranslatableComponent.of("fawe.error.command.syntax", HelpGenerator.create(e.getCommandParseResult()).getUsage()));
|
||||
actor.printError(TranslatableComponent.of("fawe.error.command.syntax", HelpGenerator.create(e.getCommandParseResult()).getFullHelp()));
|
||||
}
|
||||
actor.printError(e.getRichMessage());
|
||||
} catch (CommandExecutionException e) {
|
||||
|
@ -1,5 +1,8 @@
|
||||
package com.sk89q.worldedit.extension.platform.binding;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.config.Caption;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.boydti.fawe.util.image.ImageUtil;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
@ -14,12 +17,15 @@ import com.sk89q.worldedit.extension.platform.Capability;
|
||||
import com.sk89q.worldedit.extension.platform.PlatformCommandManager;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.internal.annotation.Selection;
|
||||
import com.sk89q.worldedit.internal.annotation.Time;
|
||||
import com.sk89q.worldedit.internal.expression.Expression;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.util.Identifiable;
|
||||
import com.sk89q.worldedit.util.TreeGenerator;
|
||||
import com.sk89q.worldedit.util.formatting.text.TextComponent;
|
||||
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.biome.BiomeTypes;
|
||||
@ -36,6 +42,7 @@ import org.enginehub.piston.inject.InjectedValueAccess;
|
||||
import org.enginehub.piston.inject.Key;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.UUID;
|
||||
|
||||
public class ConsumeBindings extends Bindings {
|
||||
private final PlatformCommandManager manager;
|
||||
@ -45,6 +52,12 @@ public class ConsumeBindings extends Bindings {
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
@Time
|
||||
@Binding
|
||||
public Long time(Actor actor, String argument) {
|
||||
return MainUtil.timeToSec(argument) * 1000;
|
||||
}
|
||||
|
||||
@Binding
|
||||
@Confirm
|
||||
@Selection
|
||||
@ -99,6 +112,30 @@ public class ConsumeBindings extends Bindings {
|
||||
return radius;
|
||||
}
|
||||
|
||||
@Binding
|
||||
public UUID playerUUID(Actor actor, String argument) {
|
||||
if (argument.equals("me")) {
|
||||
return actor.getUniqueId();
|
||||
}
|
||||
if (argument.equals("*")) {
|
||||
return Identifiable.EVERYONE;
|
||||
}
|
||||
if (argument.equalsIgnoreCase("console") || argument.equalsIgnoreCase("server")) {
|
||||
return Identifiable.CONSOLE;
|
||||
}
|
||||
UUID uuid;
|
||||
if (argument.length() > 16) {
|
||||
uuid = UUID.fromString(argument);
|
||||
} else {
|
||||
uuid = Fawe.imp().getUUID(argument);
|
||||
}
|
||||
if (uuid == null) {
|
||||
throw new InputParseException(Caption.toString(TranslatableComponent.of("fawe.error.player.not.found" , argument)));
|
||||
}
|
||||
return uuid;
|
||||
}
|
||||
|
||||
|
||||
@Binding
|
||||
public ProvideBindings.ImageUri getImage(String argument) {
|
||||
return new ProvideBindings.ImageUri(ImageUtil.getImageURI(argument));
|
||||
|
@ -1,19 +1,28 @@
|
||||
package com.sk89q.worldedit.extension.platform.binding;
|
||||
|
||||
import com.boydti.fawe.command.CFICommands;
|
||||
import com.boydti.fawe.config.Caption;
|
||||
import com.boydti.fawe.database.DBHandler;
|
||||
import com.boydti.fawe.database.RollbackDatabase;
|
||||
import com.boydti.fawe.logging.LoggingChangeSet;
|
||||
import com.boydti.fawe.regions.FaweMaskManager;
|
||||
import com.boydti.fawe.util.TextureUtil;
|
||||
import com.boydti.fawe.util.image.ImageUtil;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.LocalSession;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.command.argument.Arguments;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.extension.input.InputParseException;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.history.changeset.ChangeSet;
|
||||
import com.sk89q.worldedit.internal.annotation.AllowedRegion;
|
||||
import com.sk89q.worldedit.internal.annotation.Selection;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.session.request.Request;
|
||||
import com.sk89q.worldedit.util.TreeGenerator;
|
||||
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.biome.BiomeTypes;
|
||||
@ -57,8 +66,10 @@ public class ProvideBindings extends Bindings {
|
||||
}
|
||||
|
||||
@Binding
|
||||
public EditSession editSession(LocalSession localSession, Player player) {
|
||||
EditSession editSession = localSession.createEditSession(player);
|
||||
public EditSession editSession(LocalSession localSession, Player player, InjectedValueAccess context) {
|
||||
Arguments arguments = context.injectedValue(Key.of(Arguments.class)).orElse(null);
|
||||
String command = arguments == null ? null : arguments.get();
|
||||
EditSession editSession = localSession.createEditSession(player, command);
|
||||
editSession.enableStandardMode();
|
||||
Request.request().setEditSession(editSession);
|
||||
return editSession;
|
||||
@ -70,6 +81,31 @@ public class ProvideBindings extends Bindings {
|
||||
return localSession.getSelection(player.getWorld());
|
||||
}
|
||||
|
||||
@Binding
|
||||
public RollbackDatabase database(World world) {
|
||||
return DBHandler.IMP.getDatabase(world);
|
||||
}
|
||||
|
||||
@AllowedRegion(FaweMaskManager.MaskType.OWNER)
|
||||
@Binding
|
||||
public Region[] regionsOwner(Player player) {
|
||||
return regions(player, FaweMaskManager.MaskType.OWNER);
|
||||
}
|
||||
|
||||
@AllowedRegion(FaweMaskManager.MaskType.MEMBER)
|
||||
@Binding
|
||||
public Region[] regionsMember(Player player) {
|
||||
return regions(player, FaweMaskManager.MaskType.MEMBER);
|
||||
}
|
||||
|
||||
public Region[] regions(Player player, FaweMaskManager.MaskType type) {
|
||||
Region[] regions = player.getCurrentRegions(type);
|
||||
if (regions == null) {
|
||||
throw new IllegalArgumentException(Caption.toString(TranslatableComponent.of("fawe.error.no.region")));
|
||||
}
|
||||
return regions;
|
||||
}
|
||||
|
||||
@Binding
|
||||
public TextureUtil getTexture(LocalSession session) {
|
||||
return session.getTextureUtil();
|
||||
@ -102,7 +138,7 @@ public class ProvideBindings extends Bindings {
|
||||
return extent;
|
||||
}
|
||||
Player plr = getPlayer(actor);
|
||||
EditSession editSession = editSession(getLocalSession(plr), plr);
|
||||
EditSession editSession = editSession(getLocalSession(plr), plr, access);
|
||||
if (access instanceof InjectedValueStore) {
|
||||
InjectedValueStore store = (InjectedValueStore) access;
|
||||
store.injectValue(Key.of(EditSession.class), ValueProvider.constant(editSession));
|
||||
|
@ -0,0 +1,16 @@
|
||||
package com.sk89q.worldedit.internal.annotation;
|
||||
|
||||
import com.boydti.fawe.regions.FaweMaskManager;
|
||||
import org.enginehub.piston.inject.InjectAnnotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.PARAMETER, ElementType.METHOD})
|
||||
@InjectAnnotation
|
||||
public @interface AllowedRegion {
|
||||
FaweMaskManager.MaskType value() default FaweMaskManager.MaskType.OWNER;
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package com.sk89q.worldedit.internal.annotation;
|
||||
|
||||
import org.enginehub.piston.inject.InjectAnnotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.PARAMETER, ElementType.METHOD})
|
||||
@InjectAnnotation
|
||||
public @interface Time {
|
||||
}
|
@ -33,4 +33,6 @@ public interface Identifiable {
|
||||
*/
|
||||
UUID getUniqueId();
|
||||
|
||||
UUID CONSOLE = UUID.fromString("a233eb4b-4cab-42cd-9fd9-7e7b9a3f74be");
|
||||
UUID EVERYONE = UUID.fromString("1-1-3-3-7");
|
||||
}
|
||||
|
@ -19,6 +19,10 @@
|
||||
|
||||
package com.sk89q.worldedit.util.formatting.component;
|
||||
|
||||
import com.boydti.fawe.object.collection.AdaptedSetCollection;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Collections2;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.sk89q.worldedit.util.formatting.text.Component;
|
||||
import com.sk89q.worldedit.util.formatting.text.TextComponent;
|
||||
import com.sk89q.worldedit.util.formatting.text.event.ClickEvent;
|
||||
@ -27,9 +31,11 @@ import com.sk89q.worldedit.util.formatting.text.format.TextColor;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public abstract class PaginationBox extends MessageBox {
|
||||
|
||||
@ -75,7 +81,11 @@ public abstract class PaginationBox extends MessageBox {
|
||||
super(title, new TextComponentProducer());
|
||||
|
||||
if (pageCommand != null && !pageCommand.contains("%page%")) {
|
||||
throw new IllegalArgumentException("pageCommand must contain %page% if provided.");
|
||||
if (pageCommand.contains("-p ")) {
|
||||
pageCommand = pageCommand.replaceAll("-p [0-9]+", "-p %page%");
|
||||
} else{
|
||||
pageCommand = pageCommand + " -p %page%";
|
||||
}
|
||||
}
|
||||
this.pageCommand = pageCommand;
|
||||
}
|
||||
@ -131,12 +141,16 @@ public abstract class PaginationBox extends MessageBox {
|
||||
throw new IllegalStateException("Pagination components must be created with a page");
|
||||
}
|
||||
|
||||
public static <T> PaginationBox fromStrings(String header, @Nullable String pageCommand, Collection<T> lines, Function<T, Component> adapt) {
|
||||
return fromStrings(header, pageCommand, Collections2.transform(lines, adapt));
|
||||
}
|
||||
|
||||
public static PaginationBox fromStrings(String header, @Nullable String pageCommand, Collection lines) {
|
||||
return new ListPaginationBox(header, pageCommand, lines);
|
||||
}
|
||||
|
||||
public static PaginationBox fromStrings(String header, @Nullable String pageCommand, List<String> lines) {
|
||||
return new ListPaginationBox(header, pageCommand, lines);
|
||||
return fromStrings(header, pageCommand, (Collection) lines);
|
||||
}
|
||||
|
||||
public static class ListPaginationBox extends PaginationBox {
|
||||
@ -168,6 +182,9 @@ public abstract class PaginationBox extends MessageBox {
|
||||
iterIndex++;
|
||||
} while (iterIndex < number);
|
||||
}
|
||||
if (obj instanceof Supplier) {
|
||||
obj = ((Supplier) obj).get();
|
||||
}
|
||||
if (obj instanceof Component) {
|
||||
return (Component) obj;
|
||||
}
|
||||
@ -179,4 +196,4 @@ public abstract class PaginationBox extends MessageBox {
|
||||
return lines.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -156,4 +156,8 @@ public class TranslationManager {
|
||||
public Component convertText(Component component, Locale locale) {
|
||||
return friendlyComponentRenderer.render(component, locale);
|
||||
}
|
||||
|
||||
public Locale getDefaultLocale() {
|
||||
return defaultLocale;
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +1,23 @@
|
||||
{
|
||||
"fawe.prefix": "&8(&4&lFAWE&8)&7 ",
|
||||
"error": "&c{0}",
|
||||
"info": "&7{0}",
|
||||
"debug": "&3{0}",
|
||||
"fawe.prefix": "&8(&4&lHELLO&8)&7 ",
|
||||
"fawe.error": "&c{0}",
|
||||
"fawe.info": "&7{0}",
|
||||
"fawe.debug": "&3{0}",
|
||||
|
||||
"piston.style.help.text": "Help: {0}",
|
||||
"piston.style.text.modifier": "TODO modifier: {0}, {1}, {2}",
|
||||
"piston.style.main.text": "{0}",
|
||||
"piston.style.part.wrapping": "&8{0}&e{1}&8{2}",
|
||||
"piston.text.command.prefix": "/",
|
||||
"piston.text.command.prefix": "TODO prefix",
|
||||
|
||||
"fawe.worldedit.history.find.element": "&8 - &2{0}: {1} &7ago &3{2}m &6{3} &c/{4}",
|
||||
"fawe.worldedit.history.find.hover": "{0} blocks changed, click for more info",
|
||||
|
||||
|
||||
"fawe.info.file.deleted": "{0} has been deleted.",
|
||||
"fawe.info.schematic.pasting": "&7The schematic is pasting. This cannot be undone.",
|
||||
"fawe.info.lighting.propagate.selection": "Lighting has been propogated in {0} chunks. (Note: To remove light use //removelight)",
|
||||
"fawe.info.updated.lighting.selection": "Lighting has been updated in {0} chunks. (It may take a second for the packets to send)",
|
||||
"fawe.info.set.region": "Selection set to your current allowed region",
|
||||
|
||||
"fawe.info.worldedit.command.limit": "Please wait until your current action completes",
|
||||
"fawe.info.worldedit.delayed": "Please wait while we process your FAWE action...",
|
||||
"fawe.info.worldedit.run": "Apologies for the delay. Now executing: {0}",
|
||||
@ -505,6 +509,7 @@
|
||||
|
||||
"worldedit.paste.pasted": "The clipboard has been pasted at {0}",
|
||||
"worldedit.paste.selected": "Selected clipboard paste region.",
|
||||
|
||||
"worldedit.rotate.no-interpolation": "Note: Interpolation is not yet supported, so angles that are multiples of 90 is recommended.",
|
||||
"worldedit.rotate.rotated": "The clipboard copy has been rotated.",
|
||||
"worldedit.flip.flipped": "The clipboard copy has been flipped.",
|
||||
@ -568,7 +573,7 @@
|
||||
"worldedit.command.permissions": "You are not permitted to do that. Are you in the right mode?",
|
||||
"worldedit.command.player-only": "This command must be used with a player.",
|
||||
"worldedit.command.error.report": "Please report this error: [See console]",
|
||||
"worldedit.pastebin.uploading": "(Please wait... sending output to pastebin...)",
|
||||
"worldedit.pastebin.uploading": "(Please wait... uploading paste...)",
|
||||
"worldedit.session.cant-find-session": "Unable to find session for {0}",
|
||||
"worldedit.platform.no-file-dialog": "File dialogs are not supported in your environment.",
|
||||
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren