mirror of
https://github.com/plexusorg/Plex-FAWE.git
synced 2024-12-23 09:47:38 +00:00
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
This commit is contained in:
parent
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 com.google.common.base.Preconditions.checkNotNull;
|
||||||
import static org.slf4j.LoggerFactory.getLogger;
|
import static org.slf4j.LoggerFactory.getLogger;
|
||||||
|
|
||||||
|
import com.bekvon.bukkit.residence.commands.set;
|
||||||
import com.boydti.fawe.Fawe;
|
import com.boydti.fawe.Fawe;
|
||||||
import com.boydti.fawe.FaweCache;
|
import com.boydti.fawe.FaweCache;
|
||||||
import com.boydti.fawe.beta.IChunkSet;
|
import com.boydti.fawe.beta.IChunkSet;
|
||||||
@ -67,26 +68,18 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
public class BukkitGetBlocks_1_14 extends CharGetBlocks {
|
public class BukkitGetBlocks_1_14 extends CharGetBlocks {
|
||||||
public ChunkSection[] sections;
|
public ChunkSection[] sections;
|
||||||
public Chunk nmsChunk;
|
public Chunk nmsChunk;
|
||||||
public CraftWorld world;
|
public WorldServer world;
|
||||||
public int X, Z;
|
public int X, Z;
|
||||||
// private boolean forceLoad;
|
|
||||||
|
|
||||||
public BukkitGetBlocks_1_14(World world, int X, int Z, boolean forceLoad) {
|
public BukkitGetBlocks_1_14(World world, int X, int Z) {
|
||||||
this.world = (CraftWorld) world;
|
this(((CraftWorld) world).getHandle(), X, Z);
|
||||||
this.X = X;
|
|
||||||
this.Z = Z;
|
|
||||||
// if (forceLoad) {
|
|
||||||
// this.world.getHandle().setForceLoaded(X, Z, this.forceLoad = true);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Override
|
public BukkitGetBlocks_1_14(WorldServer world, int X, int Z) {
|
||||||
// protected void finalize() {
|
this.world = world;
|
||||||
// if (forceLoad) {
|
this.X = X;
|
||||||
// this.world.getHandle().setForceLoaded(X, Z, forceLoad = false);
|
this.Z = Z;
|
||||||
// }
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
public int getX() {
|
public int getX() {
|
||||||
return X;
|
return X;
|
||||||
@ -133,14 +126,16 @@ public class BukkitGetBlocks_1_14 extends CharGetBlocks {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundTag getEntity(UUID uuid) {
|
public CompoundTag getEntity(UUID uuid) {
|
||||||
org.bukkit.entity.Entity bukkitEnt = world.getEntity(uuid);
|
Entity entity = world.getEntity(uuid);
|
||||||
if (bukkitEnt != null) {
|
if (entity != null) {
|
||||||
|
org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity();
|
||||||
return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData();
|
return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData();
|
||||||
}
|
}
|
||||||
for (List<Entity> entry : getChunk().getEntitySlices()) {
|
for (List<Entity> entry : getChunk().getEntitySlices()) {
|
||||||
if (entry != null) {
|
if (entry != null) {
|
||||||
for (Entity entity : entry) {
|
for (Entity ent : entry) {
|
||||||
if (uuid.equals(entity.getUniqueID())) {
|
if (uuid.equals(ent.getUniqueID())) {
|
||||||
|
org.bukkit.entity.Entity bukkitEnt = ent.getBukkitEntity();
|
||||||
return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData();
|
return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -235,7 +230,7 @@ public class BukkitGetBlocks_1_14 extends CharGetBlocks {
|
|||||||
@Override
|
@Override
|
||||||
public <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
|
public <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
|
||||||
try {
|
try {
|
||||||
WorldServer nmsWorld = world.getHandle();
|
WorldServer nmsWorld = world;
|
||||||
Chunk nmsChunk = BukkitAdapter_1_14.ensureLoaded(nmsWorld, X, Z);
|
Chunk nmsChunk = BukkitAdapter_1_14.ensureLoaded(nmsWorld, X, Z);
|
||||||
|
|
||||||
// Remove existing tiles
|
// Remove existing tiles
|
||||||
@ -633,7 +628,7 @@ public class BukkitGetBlocks_1_14 extends CharGetBlocks {
|
|||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
tmp = nmsChunk;
|
tmp = nmsChunk;
|
||||||
if (tmp == null) {
|
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.ArrayDeque;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
@ -19,10 +20,10 @@ public class GriefPreventionFilter extends CuboidRegionFilter {
|
|||||||
|
|
||||||
public GriefPreventionFilter(World world) {
|
public GriefPreventionFilter(World world) {
|
||||||
checkNotNull(world);
|
checkNotNull(world);
|
||||||
this.claims = TaskManager.IMP.sync(new RunnableVal<Collection<Claim>>() {
|
this.claims = TaskManager.IMP.sync(new Supplier<Collection<Claim>>() {
|
||||||
@Override
|
@Override
|
||||||
public void run(Collection<Claim> claims) {
|
public Collection<Claim> get() {
|
||||||
this.value = new ArrayDeque<>(GriefPrevention.instance.dataStore.getClaims());
|
return new ArrayDeque<>(GriefPrevention.instance.dataStore.getClaims());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.world = world;
|
this.world = world;
|
||||||
|
@ -3,6 +3,7 @@ package com.boydti.fawe.bukkit.filter;
|
|||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
import static org.slf4j.LoggerFactory.getLogger;
|
import static org.slf4j.LoggerFactory.getLogger;
|
||||||
|
|
||||||
|
import com.boydti.fawe.Fawe;
|
||||||
import com.boydti.fawe.FaweAPI;
|
import com.boydti.fawe.FaweAPI;
|
||||||
import com.boydti.fawe.object.RunnableVal;
|
import com.boydti.fawe.object.RunnableVal;
|
||||||
import com.boydti.fawe.regions.general.CuboidRegionFilter;
|
import com.boydti.fawe.regions.general.CuboidRegionFilter;
|
||||||
@ -26,9 +27,7 @@ public class WorldGuardFilter extends CuboidRegionFilter {
|
|||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void calculateRegions() {
|
public void calculateRegions() {
|
||||||
TaskManager.IMP.sync(new RunnableVal<Object>() {
|
Fawe.get().getQueueHandler().sync(() -> {
|
||||||
@Override
|
|
||||||
public void run(Object value) {
|
|
||||||
WorldGuardFilter.this.manager = WorldGuard.getInstance().getPlatform().getRegionContainer().get(FaweAPI.getWorld(world.getName()));
|
WorldGuardFilter.this.manager = WorldGuard.getInstance().getPlatform().getRegionContainer().get(FaweAPI.getWorld(world.getName()));
|
||||||
for (ProtectedRegion region : manager.getRegions().values()) {
|
for (ProtectedRegion region : manager.getRegions().values()) {
|
||||||
BlockVector3 min = region.getMinimumPoint();
|
BlockVector3 min = region.getMinimumPoint();
|
||||||
@ -40,7 +39,6 @@ public class WorldGuardFilter extends CuboidRegionFilter {
|
|||||||
}
|
}
|
||||||
add(min.toBlockVector2(), max.toBlockVector2());
|
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
|
@Override
|
||||||
public void print(Component component) {
|
public void print(Component component) {
|
||||||
TextAdapter.sendComponent(sender, WorldEditText.format(component, getLocale()));
|
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
|
@Override
|
||||||
public void print(Component component) {
|
public void print(Component component) {
|
||||||
TextAdapter.sendComponent(sender, WorldEditText.format(component, getLocale()));
|
TextAdapter.sendComponent(sender, WorldEditText.format(component, getLocale()));
|
||||||
|
@ -190,6 +190,10 @@ public class BukkitWorld extends AbstractWorld {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean regenerate(Region region, EditSession editSession) {
|
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)];
|
BaseBlock[] history = new BaseBlock[16 * 16 * (getMaxY() + 1)];
|
||||||
|
|
||||||
@ -560,7 +564,7 @@ public class BukkitWorld extends AbstractWorld {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IChunkGet get(int chunkX, int chunkZ) {
|
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
|
@Override
|
||||||
|
@ -24,11 +24,13 @@ import com.boydti.fawe.beta.implementation.packet.ChunkPacket;
|
|||||||
import com.boydti.fawe.bukkit.FaweBukkit;
|
import com.boydti.fawe.bukkit.FaweBukkit;
|
||||||
import com.sk89q.jnbt.CompoundTag;
|
import com.sk89q.jnbt.CompoundTag;
|
||||||
import com.sk89q.jnbt.Tag;
|
import com.sk89q.jnbt.Tag;
|
||||||
|
import com.sk89q.worldedit.EditSession;
|
||||||
import com.sk89q.worldedit.blocks.BaseItem;
|
import com.sk89q.worldedit.blocks.BaseItem;
|
||||||
import com.sk89q.worldedit.blocks.BaseItemStack;
|
import com.sk89q.worldedit.blocks.BaseItemStack;
|
||||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||||
import com.sk89q.worldedit.entity.BaseEntity;
|
import com.sk89q.worldedit.entity.BaseEntity;
|
||||||
import com.sk89q.worldedit.math.BlockVector3;
|
import com.sk89q.worldedit.math.BlockVector3;
|
||||||
|
import com.sk89q.worldedit.regions.Region;
|
||||||
import com.sk89q.worldedit.registry.state.Property;
|
import com.sk89q.worldedit.registry.state.Property;
|
||||||
import com.sk89q.worldedit.util.Direction;
|
import com.sk89q.worldedit.util.Direction;
|
||||||
import com.sk89q.worldedit.world.DataFixer;
|
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) {
|
default void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket packet) {
|
||||||
throw new UnsupportedOperationException("Cannot send fake chunks");
|
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;
|
package com.sk89q.worldedit.bukkit.adapter.impl;
|
||||||
|
|
||||||
import com.bekvon.bukkit.residence.commands.material;
|
import com.bekvon.bukkit.residence.commands.material;
|
||||||
|
import com.bekvon.bukkit.residence.commands.server;
|
||||||
import com.boydti.fawe.FaweCache;
|
import com.boydti.fawe.FaweCache;
|
||||||
import com.boydti.fawe.beta.implementation.packet.ChunkPacket;
|
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.BlockMaterial_1_14;
|
||||||
import com.boydti.fawe.bukkit.adapter.mc1_14.BukkitAdapter_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.MapChunkUtil_1_14;
|
||||||
import com.boydti.fawe.bukkit.adapter.mc1_14.nbt.LazyCompoundTag_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.CompoundTag;
|
||||||
import com.sk89q.jnbt.Tag;
|
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.BaseItemStack;
|
||||||
import com.sk89q.worldedit.blocks.TileEntityBlock;
|
import com.sk89q.worldedit.blocks.TileEntityBlock;
|
||||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
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.BukkitImplAdapter;
|
||||||
import com.sk89q.worldedit.bukkit.adapter.CachedBukkitAdapter;
|
import com.sk89q.worldedit.bukkit.adapter.CachedBukkitAdapter;
|
||||||
import com.sk89q.worldedit.bukkit.adapter.IDelegateBukkitImplAdapter;
|
import com.sk89q.worldedit.bukkit.adapter.IDelegateBukkitImplAdapter;
|
||||||
import com.sk89q.worldedit.bukkit.adapter.impl.Spigot_v1_14_R4;
|
import com.sk89q.worldedit.bukkit.adapter.impl.Spigot_v1_14_R4;
|
||||||
import com.sk89q.worldedit.entity.BaseEntity;
|
import com.sk89q.worldedit.entity.BaseEntity;
|
||||||
import com.sk89q.worldedit.entity.LazyBaseEntity;
|
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.registry.state.Property;
|
||||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||||
import com.sk89q.worldedit.world.block.BlockState;
|
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.BlockPosition;
|
||||||
import net.minecraft.server.v1_14_R1.Chunk;
|
import net.minecraft.server.v1_14_R1.Chunk;
|
||||||
import net.minecraft.server.v1_14_R1.ChunkCoordIntPair;
|
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.ChunkSection;
|
||||||
import net.minecraft.server.v1_14_R1.Entity;
|
import net.minecraft.server.v1_14_R1.Entity;
|
||||||
import net.minecraft.server.v1_14_R1.EntityPlayer;
|
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.IRegistry;
|
||||||
import net.minecraft.server.v1_14_R1.ItemStack;
|
import net.minecraft.server.v1_14_R1.ItemStack;
|
||||||
import net.minecraft.server.v1_14_R1.MinecraftKey;
|
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.NBTBase;
|
||||||
import net.minecraft.server.v1_14_R1.NBTTagCompound;
|
import net.minecraft.server.v1_14_R1.NBTTagCompound;
|
||||||
import net.minecraft.server.v1_14_R1.NBTTagInt;
|
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.PlayerChunk;
|
||||||
import net.minecraft.server.v1_14_R1.TileEntity;
|
import net.minecraft.server.v1_14_R1.TileEntity;
|
||||||
import net.minecraft.server.v1_14_R1.World;
|
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 net.minecraft.server.v1_14_R1.WorldServer;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.block.data.BlockData;
|
import org.bukkit.block.data.BlockData;
|
||||||
import org.bukkit.craftbukkit.v1_14_R1.CraftChunk;
|
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.CraftWorld;
|
||||||
import org.bukkit.craftbukkit.v1_14_R1.block.data.CraftBlockData;
|
import org.bukkit.craftbukkit.v1_14_R1.block.data.CraftBlockData;
|
||||||
import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
|
import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
|
||||||
@ -80,6 +96,8 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.OptionalInt;
|
import java.util.OptionalInt;
|
||||||
@ -358,4 +376,53 @@ public final class FAWE_Spigot_v1_14_R4 extends CachedBukkitAdapter implements I
|
|||||||
}
|
}
|
||||||
return parent.fromNative(foreign);
|
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;
|
package com.boydti.fawe.config;
|
||||||
|
|
||||||
|
import com.sk89q.worldedit.WorldEdit;
|
||||||
import com.sk89q.worldedit.util.formatting.WorldEditText;
|
import com.sk89q.worldedit.util.formatting.WorldEditText;
|
||||||
import com.sk89q.worldedit.util.formatting.text.Component;
|
import com.sk89q.worldedit.util.formatting.text.Component;
|
||||||
import com.sk89q.worldedit.util.formatting.text.TextComponent;
|
import com.sk89q.worldedit.util.formatting.text.TextComponent;
|
||||||
@ -11,6 +12,14 @@ import java.util.List;
|
|||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
public class Caption {
|
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
|
* Colorize a component with legacy color codes
|
||||||
* @param parent
|
* @param parent
|
||||||
|
@ -6,10 +6,13 @@ import com.boydti.fawe.config.Settings;
|
|||||||
import com.boydti.fawe.logging.rollback.RollbackOptimizedHistory;
|
import com.boydti.fawe.logging.rollback.RollbackOptimizedHistory;
|
||||||
import com.boydti.fawe.object.RunnableVal;
|
import com.boydti.fawe.object.RunnableVal;
|
||||||
import com.boydti.fawe.object.changeset.DiskStorageHistory;
|
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.object.task.AsyncNotifyQueue;
|
||||||
import com.boydti.fawe.util.MainUtil;
|
import com.boydti.fawe.util.MainUtil;
|
||||||
import com.boydti.fawe.util.TaskManager;
|
import com.boydti.fawe.util.TaskManager;
|
||||||
|
import com.sk89q.worldedit.math.BlockVector2;
|
||||||
import com.sk89q.worldedit.math.BlockVector3;
|
import com.sk89q.worldedit.math.BlockVector3;
|
||||||
|
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||||
import com.sk89q.worldedit.world.World;
|
import com.sk89q.worldedit.world.World;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -19,10 +22,21 @@ import java.sql.DriverManager;
|
|||||||
import java.sql.PreparedStatement;
|
import java.sql.PreparedStatement;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
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.concurrent.TimeUnit;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Supplier;
|
||||||
import java.util.stream.IntStream;
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
|
import org.intellij.lang.annotations.Language;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@ -36,217 +50,240 @@ public class RollbackDatabase extends AsyncNotifyQueue {
|
|||||||
private final World world;
|
private final World world;
|
||||||
private Connection connection;
|
private Connection connection;
|
||||||
|
|
||||||
private String INSERT_EDIT;
|
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 String CREATE_TABLE;
|
private @Language("sql") String UPDATE_TABLE = "ALTER TABLE `{0}edits` ADD `command` VARCHAR, ADD `size` INT NOT NULL";
|
||||||
// private String GET_EDITS_POINT;
|
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 String GET_EDITS;
|
private @Language("sql") String PURGE = "DELETE FROM `{0}edits` WHERE `time`<?";
|
||||||
private String GET_EDITS_USER;
|
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 String GET_EDITS_ASC;
|
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 String GET_EDITS_USER_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 String DELETE_EDITS_USER;
|
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 String DELETE_EDIT_USER;
|
private @Language("sql") String GET_EDIT_USER = "SELECT * FROM `{0}edits` WHERE `player`=? AND `id`=?";
|
||||||
private String PURGE;
|
|
||||||
|
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 ConcurrentLinkedQueue<RollbackOptimizedHistory> historyChanges = new ConcurrentLinkedQueue<>();
|
||||||
private final ConcurrentLinkedQueue<Runnable> tasks = new ConcurrentLinkedQueue<>();
|
|
||||||
|
|
||||||
public RollbackDatabase(String world) throws SQLException, ClassNotFoundException {
|
public RollbackDatabase(String world) throws SQLException, ClassNotFoundException {
|
||||||
this(FaweAPI.getWorld(world));
|
this(FaweAPI.getWorld(world));
|
||||||
}
|
}
|
||||||
|
|
||||||
public RollbackDatabase(World world) throws SQLException, ClassNotFoundException {
|
public RollbackDatabase(World world) throws SQLException, ClassNotFoundException {
|
||||||
|
super((t, e) -> e.printStackTrace());
|
||||||
this.prefix = "";
|
this.prefix = "";
|
||||||
this.worldName = world.getName();
|
this.worldName = world.getName();
|
||||||
this.world = world;
|
this.world = world;
|
||||||
this.dbLocation = MainUtil.getFile(Fawe.imp().getDirectory(), Settings.IMP.PATHS.HISTORY + File.separator + world.getName() + File.separator + "summary.db");
|
this.dbLocation = MainUtil.getFile(Fawe.imp().getDirectory(), Settings.IMP.PATHS.HISTORY + File.separator + world.getName() + File.separator + "summary.db");
|
||||||
connection = openConnection();
|
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(?,?,?,?,?,?,?,?,?)";
|
// update vars
|
||||||
PURGE = "DELETE FROM `" + prefix + "edits` WHERE `time`<?";
|
CREATE_TABLE = CREATE_TABLE.replace("{0}", prefix);
|
||||||
// GET_EDITS_POINT = "SELECT `player`,`id` FROM `" + prefix + "edits` WHERE `x2`>=? AND `x1`<=? AND `y2`>=? AND `y1`<=? AND `z2`>=? AND `z1`<=?";
|
UPDATE_TABLE = UPDATE_TABLE.replace("{0}", prefix);
|
||||||
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";
|
INSERT_EDIT = INSERT_EDIT.replace("{0}", prefix);
|
||||||
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";
|
PURGE = PURGE.replace("{0}", prefix);
|
||||||
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 = GET_EDITS_USER.replace("{0}", prefix);
|
||||||
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";
|
GET_EDITS_USER_ASC = GET_EDITS_USER_ASC.replace("{0}", prefix);
|
||||||
DELETE_EDITS_USER = "DELETE FROM `" + prefix + "edits` WHERE `x2`>=? AND `x1`<=? AND `y2`>=? AND `y1`<=? AND `z2`>=? AND `z1`<=? AND `time`>? AND `player`=?";
|
GET_EDITS = GET_EDITS.replace("{0}", prefix);
|
||||||
DELETE_EDIT_USER = "DELETE FROM `" + prefix + "edits` WHERE `player`=? AND `id`=?";
|
GET_EDITS_ASC = GET_EDITS_ASC.replace("{0}", prefix);
|
||||||
init();
|
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);
|
||||||
|
|
||||||
|
try {
|
||||||
|
init().get();
|
||||||
purge((int) TimeUnit.DAYS.toMillis(Settings.IMP.HISTORY.DELETE_AFTER_DAYS));
|
purge((int) TimeUnit.DAYS.toMillis(Settings.IMP.HISTORY.DELETE_AFTER_DAYS));
|
||||||
}
|
} catch (InterruptedException | ExecutionException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
|
||||||
@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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void init() {
|
private byte[] toBytes(UUID uuid) {
|
||||||
|
return ByteBuffer.allocate(16).putLong(uuid.getMostSignificantBits()).putLong(uuid.getLeastSignificantBits()).array();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Future<Boolean> init() {
|
||||||
|
return call(() -> {
|
||||||
try (PreparedStatement stmt = connection.prepareStatement(CREATE_TABLE)) {
|
try (PreparedStatement stmt = connection.prepareStatement(CREATE_TABLE)) {
|
||||||
stmt.executeUpdate();
|
stmt.executeUpdate();
|
||||||
} catch (SQLException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
|
try (PreparedStatement stmt = connection.prepareStatement(UPDATE_TABLE)) {
|
||||||
|
stmt.executeUpdate();
|
||||||
|
} catch (SQLException ignore) {} // Already updated
|
||||||
|
return true;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void delete(UUID uuid, int id) {
|
public Future<Integer> delete(UUID uuid, int id) {
|
||||||
addTask(new Runnable() {
|
return call(() -> {
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try (PreparedStatement stmt = connection.prepareStatement(DELETE_EDIT_USER)) {
|
try (PreparedStatement stmt = connection.prepareStatement(DELETE_EDIT_USER)) {
|
||||||
byte[] uuidBytes = ByteBuffer.allocate(16).putLong(uuid.getMostSignificantBits()).putLong(uuid.getLeastSignificantBits()).array();
|
stmt.setBytes(1, toBytes(uuid));
|
||||||
stmt.setBytes(1, uuidBytes);
|
|
||||||
stmt.setInt(2, id);
|
stmt.setInt(2, id);
|
||||||
} catch (SQLException e) {
|
return stmt.executeUpdate();
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void purge(int diff) {
|
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()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return create(result).get();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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 Future<Integer> purge(int diff) {
|
||||||
long now = System.currentTimeMillis() / 1000;
|
long now = System.currentTimeMillis() / 1000;
|
||||||
final int then = (int) (now - diff);
|
final int then = (int) (now - diff);
|
||||||
addTask(() -> {
|
return call(() -> {
|
||||||
try (PreparedStatement stmt = connection.prepareStatement(PURGE)) {
|
try (PreparedStatement stmt = connection.prepareStatement(PURGE)) {
|
||||||
stmt.setInt(1, then);
|
stmt.setInt(1, then);
|
||||||
stmt.executeUpdate();
|
return stmt.executeUpdate();
|
||||||
} catch (SQLException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void getPotentialEdits(UUID uuid, long minTime, BlockVector3 pos1, BlockVector3 pos2, RunnableVal<DiskStorageHistory> onEach, Runnable whenDone, boolean delete, boolean ascending) {
|
public Iterable<Supplier<RollbackOptimizedHistory>> getEdits(BlockVector3 pos, boolean ascending) {
|
||||||
final World world = FaweAPI.getWorld(this.worldName);
|
return getEdits(null, 0, pos, pos, false, ascending);
|
||||||
addTask(() -> {
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
int count = 0;
|
||||||
String stmtStr = ascending ? uuid == null ? GET_EDITS_ASC : GET_EDITS_USER_ASC :
|
String stmtStr = ascending ? uuid == null ? GET_EDITS_ASC : GET_EDITS_USER_ASC :
|
||||||
uuid == null ? GET_EDITS : GET_EDITS_USER;
|
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)) {
|
try (PreparedStatement stmt = connection.prepareStatement(stmtStr)) {
|
||||||
stmt.setInt(1, pos1.getBlockX());
|
stmt.setInt(1, (int) (minTime / 1000));
|
||||||
stmt.setInt(2, pos2.getBlockX());
|
stmt.setInt(2, pos1.getBlockX());
|
||||||
stmt.setByte(3, (byte) (pos1.getBlockY() - 128));
|
stmt.setInt(3, pos2.getBlockX());
|
||||||
stmt.setByte(4, (byte) (pos2.getBlockY() - 128));
|
stmt.setInt(4, pos1.getBlockZ());
|
||||||
stmt.setInt(5, pos1.getBlockZ());
|
stmt.setInt(5, pos2.getBlockZ());
|
||||||
stmt.setInt(6, pos2.getBlockZ());
|
stmt.setByte(6, (byte) (pos1.getBlockY() - 128));
|
||||||
stmt.setInt(7, (int) (minTime / 1000));
|
stmt.setByte(7, (byte) (pos2.getBlockY() - 128));
|
||||||
if (uuid != null) {
|
if (uuid != null) {
|
||||||
byte[] uuidBytes = ByteBuffer.allocate(16).putLong(uuid.getMostSignificantBits()).putLong(uuid.getLeastSignificantBits()).array();
|
byte[] uuidBytes = toBytes(uuid);
|
||||||
stmt.setBytes(8, uuidBytes);
|
stmt.setBytes(8, uuidBytes);
|
||||||
}
|
}
|
||||||
ResultSet result = stmt.executeQuery();
|
ResultSet result = stmt.executeQuery();
|
||||||
if (!result.next()) {
|
if (!result.next()) {
|
||||||
TaskManager.IMP.taskNow(whenDone, false);
|
return 0;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
do {
|
do {
|
||||||
byte[] uuidBytes = result.getBytes(1);
|
count++;
|
||||||
int index = result.getInt(2);
|
Supplier<RollbackOptimizedHistory> history = create(result);
|
||||||
ByteBuffer bb = ByteBuffer.wrap(uuidBytes);
|
// if (history.getBDFile().exists())
|
||||||
long high = bb.getLong();
|
{
|
||||||
long low = bb.getLong();
|
yieldIterable.accept(history);
|
||||||
DiskStorageHistory history = new DiskStorageHistory(world, new UUID(high, low), index);
|
|
||||||
if (history.getBDFile().exists()) {
|
|
||||||
onEach.run(history);
|
|
||||||
}
|
}
|
||||||
} while (result.next());
|
} while (result.next());
|
||||||
TaskManager.IMP.taskNow(whenDone, false);
|
|
||||||
} catch (SQLException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
if (delete && uuid != null) {
|
if (delete && uuid != null) {
|
||||||
try (PreparedStatement stmt = connection.prepareStatement(DELETE_EDITS_USER)) {
|
try (PreparedStatement stmt = connection.prepareStatement(DELETE_EDITS_USER)) {
|
||||||
stmt.setInt(1, pos1.getBlockX());
|
stmt.setInt(1, (int) (minTime / 1000));
|
||||||
stmt.setInt(2, pos2.getBlockX());
|
stmt.setInt(2, pos1.getBlockX());
|
||||||
stmt.setByte(3, (byte) (pos1.getBlockY() - 128));
|
stmt.setInt(3, pos2.getBlockX());
|
||||||
stmt.setByte(4, (byte) (pos2.getBlockY() - 128));
|
stmt.setInt(4, pos1.getBlockZ());
|
||||||
stmt.setInt(5, pos1.getBlockZ());
|
stmt.setInt(5, pos2.getBlockZ());
|
||||||
stmt.setInt(6, pos2.getBlockZ());
|
stmt.setByte(6, (byte) (pos1.getBlockY() - 128));
|
||||||
stmt.setInt(7, (int) (minTime / 1000));
|
stmt.setByte(7, (byte) (pos2.getBlockY() - 128));
|
||||||
byte[] uuidBytes = ByteBuffer.allocate(16).putLong(uuid.getMostSignificantBits()).putLong(uuid.getLeastSignificantBits()).array();
|
byte[] uuidBytes = ByteBuffer.allocate(16).putLong(uuid.getMostSignificantBits()).putLong(uuid.getLeastSignificantBits()).array();
|
||||||
stmt.setBytes(8, uuidBytes);
|
stmt.setBytes(8, uuidBytes);
|
||||||
} catch (SQLException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return count;
|
||||||
|
} finally {
|
||||||
|
yieldIterable.close();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
yieldIterable.setFuture(future);
|
||||||
|
|
||||||
|
return yieldIterable;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void logEdit(RollbackOptimizedHistory history) {
|
public Future<?> logEdit(RollbackOptimizedHistory history) {
|
||||||
queue(() -> historyChanges.add(history));
|
historyChanges.add(history);
|
||||||
|
return call(this::sendBatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addTask(Runnable run) {
|
private boolean sendBatch() throws SQLException {
|
||||||
queue(() -> tasks.add(run));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void runTasks() {
|
|
||||||
Runnable task;
|
|
||||||
while ((task = tasks.poll()) != null) {
|
|
||||||
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());
|
int size = Math.min(1048572, historyChanges.size());
|
||||||
|
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
commit();
|
||||||
|
if (connection.getAutoCommit()) {
|
||||||
|
connection.setAutoCommit(false);
|
||||||
|
}
|
||||||
|
|
||||||
RollbackOptimizedHistory[] copy = IntStream.range(0, size)
|
RollbackOptimizedHistory[] copy = IntStream.range(0, size)
|
||||||
.mapToObj(i -> historyChanges.poll()).toArray(RollbackOptimizedHistory[]::new);
|
.mapToObj(i -> historyChanges.poll()).toArray(RollbackOptimizedHistory[]::new);
|
||||||
|
|
||||||
try (PreparedStatement stmt = connection.prepareStatement(INSERT_EDIT)) {
|
try (PreparedStatement stmt = connection.prepareStatement(INSERT_EDIT)) {
|
||||||
|
// `player`,`id`,`time`,`x1`,`x2`,`z1`,`z2`,`y1`,`y2`,`command`,`size`) VALUES(?,?,?,?,?,?,?,?,?,?,?)"
|
||||||
for (RollbackOptimizedHistory change : copy) {
|
for (RollbackOptimizedHistory change : copy) {
|
||||||
// `player`,`id`,`x1`,`y1`,`z1`,`x2`,`y2`,`z2`,`time`
|
|
||||||
UUID uuid = change.getUUID();
|
UUID uuid = change.getUUID();
|
||||||
byte[] uuidBytes = ByteBuffer.allocate(16).putLong(uuid.getMostSignificantBits()).putLong(uuid.getLeastSignificantBits()).array();
|
byte[] uuidBytes = toBytes(uuid);
|
||||||
stmt.setBytes(1, uuidBytes);
|
stmt.setBytes(1, uuidBytes);
|
||||||
stmt.setInt(2, change.getIndex());
|
stmt.setInt(2, change.getIndex());
|
||||||
stmt.setInt(3, change.getMinX());
|
stmt.setInt(3, (int) (change.getTime() / 1000));
|
||||||
stmt.setByte(4, (byte) (change.getMinY() - 128));
|
|
||||||
stmt.setInt(5, change.getMinZ());
|
BlockVector3 pos1 = change.getMinimumPoint();
|
||||||
stmt.setInt(6, change.getMaxX());
|
BlockVector3 pos2 = change.getMaximumPoint();
|
||||||
stmt.setByte(7, (byte) (change.getMaxY() - 128));
|
|
||||||
stmt.setInt(8, change.getMaxZ());
|
stmt.setInt(4, pos1.getX());
|
||||||
stmt.setInt(9, (int) (change.getTime() / 1000));
|
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.executeUpdate();
|
||||||
stmt.clearParameters();
|
stmt.clearParameters();
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} finally {
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
commit();
|
commit();
|
||||||
return true;
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void commit() {
|
private void commit() {
|
||||||
try {
|
try {
|
||||||
if (connection == null) {
|
if (connection == null) {
|
||||||
return;
|
return;
|
||||||
@ -260,7 +297,7 @@ public class RollbackDatabase extends AsyncNotifyQueue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Connection openConnection() throws SQLException, ClassNotFoundException {
|
private Connection openConnection() throws SQLException, ClassNotFoundException {
|
||||||
if (checkConnection()) {
|
if (checkConnection()) {
|
||||||
return connection;
|
return connection;
|
||||||
}
|
}
|
||||||
@ -281,7 +318,7 @@ public class RollbackDatabase extends AsyncNotifyQueue {
|
|||||||
return connection;
|
return connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Connection forceConnection() throws SQLException, ClassNotFoundException {
|
private Connection forceConnection() throws SQLException, ClassNotFoundException {
|
||||||
Class.forName("org.sqlite.JDBC");
|
Class.forName("org.sqlite.JDBC");
|
||||||
connection = DriverManager.getConnection("jdbc:sqlite:" + dbLocation);
|
connection = DriverManager.getConnection("jdbc:sqlite:" + dbLocation);
|
||||||
return connection;
|
return connection;
|
||||||
@ -335,4 +372,14 @@ public class RollbackDatabase extends AsyncNotifyQueue {
|
|||||||
return false;
|
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.DBHandler;
|
||||||
import com.boydti.fawe.database.RollbackDatabase;
|
import com.boydti.fawe.database.RollbackDatabase;
|
||||||
import com.boydti.fawe.object.changeset.DiskStorageHistory;
|
import com.boydti.fawe.object.changeset.DiskStorageHistory;
|
||||||
|
import com.sk89q.worldedit.math.BlockVector2;
|
||||||
import com.sk89q.worldedit.math.BlockVector3;
|
import com.sk89q.worldedit.math.BlockVector3;
|
||||||
|
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||||
import com.sk89q.worldedit.world.World;
|
import com.sk89q.worldedit.world.World;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
@ -19,6 +21,7 @@ public class RollbackOptimizedHistory extends DiskStorageHistory {
|
|||||||
private int maxY;
|
private int maxY;
|
||||||
private int minZ;
|
private int minZ;
|
||||||
private int maxZ;
|
private int maxZ;
|
||||||
|
private String command;
|
||||||
|
|
||||||
public RollbackOptimizedHistory(World world, UUID uuid, int index) {
|
public RollbackOptimizedHistory(World world, UUID uuid, int index) {
|
||||||
super(world, uuid, index);
|
super(world, uuid, index);
|
||||||
@ -40,32 +43,40 @@ public class RollbackOptimizedHistory extends DiskStorageHistory {
|
|||||||
this.time = System.currentTimeMillis();
|
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() {
|
public long getTime() {
|
||||||
return time;
|
return time;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getMinX() {
|
@Override
|
||||||
return minX;
|
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() {
|
public void setCommand(String command) {
|
||||||
return maxX;
|
this.command = command;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getMinY() {
|
public String getCommand() {
|
||||||
return minY;
|
return command;
|
||||||
}
|
|
||||||
|
|
||||||
public int getMaxY() {
|
|
||||||
return maxY;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getMinZ() {
|
|
||||||
return minZ;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getMaxZ() {
|
|
||||||
return maxZ;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDimensions(BlockVector3 pos1, BlockVector3 pos2) {
|
public void setDimensions(BlockVector3 pos1, BlockVector3 pos2) {
|
||||||
@ -121,4 +132,12 @@ public class RollbackOptimizedHistory extends DiskStorageHistory {
|
|||||||
maxZ = z;
|
maxZ = z;
|
||||||
super.writeHeader(os, x, y, 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;
|
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 static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
import com.boydti.fawe.Fawe;
|
import com.boydti.fawe.Fawe;
|
||||||
@ -273,4 +274,13 @@ public class BrushSettings {
|
|||||||
return perms.isEmpty();
|
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;
|
package com.boydti.fawe.object.brush;
|
||||||
|
|
||||||
import com.boydti.fawe.Fawe;
|
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.sk89q.worldedit.util.formatting.text.TranslatableComponent;
|
||||||
import com.boydti.fawe.config.Settings;
|
import com.boydti.fawe.config.Settings;
|
||||||
import com.boydti.fawe.database.DBHandler;
|
import com.boydti.fawe.database.DBHandler;
|
||||||
import com.boydti.fawe.database.RollbackDatabase;
|
import com.boydti.fawe.database.RollbackDatabase;
|
||||||
import com.boydti.fawe.object.RunnableVal;
|
|
||||||
import com.boydti.fawe.object.change.MutableFullBlockChange;
|
import com.boydti.fawe.object.change.MutableFullBlockChange;
|
||||||
import com.boydti.fawe.object.changeset.DiskStorageHistory;
|
import com.boydti.fawe.object.changeset.DiskStorageHistory;
|
||||||
import com.boydti.fawe.util.MainUtil;
|
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.BlockVector3;
|
||||||
import com.sk89q.worldedit.math.Vector3;
|
import com.sk89q.worldedit.math.Vector3;
|
||||||
import com.sk89q.worldedit.util.Location;
|
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.World;
|
||||||
import com.sk89q.worldedit.world.block.BlockState;
|
import com.sk89q.worldedit.world.block.BlockState;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public class InspectBrush extends BrushTool implements DoubleActionTraceTool {
|
public class InspectBrush extends BrushTool implements DoubleActionTraceTool {
|
||||||
|
|
||||||
@ -61,21 +66,21 @@ public class InspectBrush extends BrushTool implements DoubleActionTraceTool {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!Settings.IMP.HISTORY.USE_DATABASE) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
BlockVector3 target = getTarget(player, rightClick).toBlockPoint();
|
BlockVector3 target = getTarget(player, rightClick).toBlockPoint();
|
||||||
final int x = target.getBlockX();
|
final int x = target.getBlockX();
|
||||||
final int y = target.getBlockY();
|
final int y = target.getBlockY();
|
||||||
final int z = target.getBlockZ();
|
final int z = target.getBlockZ();
|
||||||
World world = player.getWorld();
|
World world = player.getWorld();
|
||||||
RollbackDatabase db = DBHandler.IMP.getDatabase(world);
|
RollbackDatabase db = DBHandler.IMP.getDatabase(world);
|
||||||
final AtomicInteger count = new AtomicInteger();
|
int count = 0;
|
||||||
db.getPotentialEdits(null, 0, target, target, new RunnableVal<DiskStorageHistory>() {
|
for (Supplier<RollbackOptimizedHistory> supplier : db.getEdits(target, false)) {
|
||||||
@Override
|
count++;
|
||||||
public void run(DiskStorageHistory value) {
|
RollbackOptimizedHistory edit = supplier.get();
|
||||||
try {
|
Iterator<MutableFullBlockChange> iter = edit.getFullBlockIterator(null, 0, false);
|
||||||
Iterator<MutableFullBlockChange> iter = value.getFullBlockIterator(null, 0, false);
|
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
MutableFullBlockChange change = iter.next();
|
MutableFullBlockChange change = iter.next();
|
||||||
if (change.x != x || change.y != y || change.z != z) {
|
if (change.x != x || change.y != y || change.z != z) {
|
||||||
@ -83,25 +88,27 @@ public class InspectBrush extends BrushTool implements DoubleActionTraceTool {
|
|||||||
}
|
}
|
||||||
int from = change.from;
|
int from = change.from;
|
||||||
int to = change.to;
|
int to = change.to;
|
||||||
UUID uuid = value.getUUID();
|
UUID uuid = edit.getUUID();
|
||||||
String name = Fawe.imp().getName(uuid);
|
String name = Fawe.imp().getName(uuid);
|
||||||
int index = value.getIndex();
|
int index = edit.getIndex();
|
||||||
long age = System.currentTimeMillis() - value.getBDFile().lastModified();
|
long age = System.currentTimeMillis() - edit.getBDFile().lastModified();
|
||||||
String ageFormatted = MainUtil.secToTime(age / 1000);
|
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));
|
BlockState blockFrom = BlockState.getFromOrdinal(from);
|
||||||
count.incrementAndGet();
|
BlockState blockTo = BlockState.getFromOrdinal(to);
|
||||||
return;
|
TranslatableComponent msg = TranslatableComponent.of("fawe.worldedit.tool.tool.inspect.info", name, blockFrom, blockTo, ageFormatted);
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
String cmd = edit.getCommand();
|
||||||
e.printStackTrace();
|
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));
|
player.print(TranslatableComponent.of("fawe.worldedit.tool.tool.inspect.info.footer" , count));
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}, false, false);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,6 +48,7 @@ import com.sk89q.worldedit.regions.CuboidRegion;
|
|||||||
import com.sk89q.worldedit.regions.Region;
|
import com.sk89q.worldedit.regions.Region;
|
||||||
import com.sk89q.worldedit.registry.state.PropertyKey;
|
import com.sk89q.worldedit.registry.state.PropertyKey;
|
||||||
import com.sk89q.worldedit.session.ClipboardHolder;
|
import com.sk89q.worldedit.session.ClipboardHolder;
|
||||||
|
import com.sk89q.worldedit.util.Identifiable;
|
||||||
import com.sk89q.worldedit.util.Location;
|
import com.sk89q.worldedit.util.Location;
|
||||||
import com.sk89q.worldedit.util.TreeGenerator;
|
import com.sk89q.worldedit.util.TreeGenerator;
|
||||||
import com.sk89q.worldedit.world.World;
|
import com.sk89q.worldedit.world.World;
|
||||||
@ -847,7 +848,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
|
|||||||
try {
|
try {
|
||||||
update();
|
update();
|
||||||
Player esPlayer = curES.getPlayer();
|
Player esPlayer = curES.getPlayer();
|
||||||
UUID uuid = esPlayer != null ? esPlayer.getUniqueId() : EditSession.CONSOLE;
|
UUID uuid = esPlayer != null ? esPlayer.getUniqueId() : Identifiable.CONSOLE;
|
||||||
try {
|
try {
|
||||||
curES.setRawChangeSet(new CFIChangeSet(this, uuid));
|
curES.setRawChangeSet(new CFIChangeSet(this, uuid));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
@ -10,14 +10,14 @@ public class MutableBlockChange implements Change {
|
|||||||
public int z;
|
public int z;
|
||||||
public int y;
|
public int y;
|
||||||
public int x;
|
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.x = x;
|
||||||
this.y = y;
|
this.y = y;
|
||||||
this.z = z;
|
this.z = z;
|
||||||
this.combinedId = combinedId;
|
this.ordinal = ordinal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -31,6 +31,6 @@ public class MutableBlockChange implements Change {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void create(UndoContext context) {
|
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 class AbstractDelegateChangeSet extends FaweChangeSet {
|
||||||
public final FaweChangeSet parent;
|
public final FaweChangeSet parent;
|
||||||
|
|
||||||
public static FaweChangeSet getDefaultChangeSet(World world, UUID uuid) {
|
|
||||||
return FaweChangeSet.getDefaultChangeSet(world, uuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
public AbstractDelegateChangeSet(FaweChangeSet parent) {
|
public AbstractDelegateChangeSet(FaweChangeSet parent) {
|
||||||
super(parent.getWorld());
|
super(parent.getWorld());
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
|
@ -8,22 +8,28 @@ import com.boydti.fawe.object.FaweInputStream;
|
|||||||
import com.boydti.fawe.object.FaweOutputStream;
|
import com.boydti.fawe.object.FaweOutputStream;
|
||||||
import com.boydti.fawe.object.IntegerPair;
|
import com.boydti.fawe.object.IntegerPair;
|
||||||
import com.boydti.fawe.object.RegionWrapper;
|
import com.boydti.fawe.object.RegionWrapper;
|
||||||
|
import com.boydti.fawe.object.change.MutableFullBlockChange;
|
||||||
import com.boydti.fawe.util.MainUtil;
|
import com.boydti.fawe.util.MainUtil;
|
||||||
import com.sk89q.jnbt.NBTInputStream;
|
import com.sk89q.jnbt.NBTInputStream;
|
||||||
import com.sk89q.jnbt.NBTOutputStream;
|
import com.sk89q.jnbt.NBTOutputStream;
|
||||||
import com.sk89q.worldedit.EditSession;
|
import com.sk89q.worldedit.EditSession;
|
||||||
import com.sk89q.worldedit.entity.Player;
|
import com.sk89q.worldedit.entity.Player;
|
||||||
|
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||||
import com.sk89q.worldedit.regions.Region;
|
import com.sk89q.worldedit.regions.Region;
|
||||||
|
import com.sk89q.worldedit.util.Countable;
|
||||||
import com.sk89q.worldedit.world.World;
|
import com.sk89q.worldedit.world.World;
|
||||||
import com.sk89q.worldedit.world.block.BlockState;
|
import com.sk89q.worldedit.world.block.BlockState;
|
||||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||||
|
|
||||||
|
import java.io.EOFException;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@ -168,6 +174,26 @@ public class DiskStorageHistory extends FaweStreamChangeSet {
|
|||||||
return bdFile;
|
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() {
|
public int getIndex() {
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
@ -379,46 +405,35 @@ public class DiskStorageHistory extends FaweStreamChangeSet {
|
|||||||
return new NBTInputStream(MainUtil.getCompressedIS(new FileInputStream(nbtfFile)));
|
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()) {
|
if (bdFile.exists()) {
|
||||||
int ox = getOriginX();
|
int ox = getOriginX();
|
||||||
int oz = getOriginZ();
|
int oz = getOriginZ();
|
||||||
if ((ox != 0 || oz != 0) && !requiredRegion.isIn(ox, oz)) {
|
DiskStorageSummary summary = summarizeShallow();
|
||||||
return new DiskStorageSummary(ox, oz);
|
if (region != null && !region.contains(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;
|
return summary;
|
||||||
}
|
}
|
||||||
byte[] buffer = new byte[4];
|
try (FaweInputStream fis = getBlockIS()) {
|
||||||
int i = 0;
|
if (!shallow) {
|
||||||
int amount = (Settings.IMP.HISTORY.BUFFER_SIZE - HEADER_SIZE) / 9;
|
int amount = (Settings.IMP.HISTORY.BUFFER_SIZE - HEADER_SIZE) / 9;
|
||||||
while (!shallow && ++i < amount) {
|
MutableFullBlockChange change = new MutableFullBlockChange(null, 0, false);
|
||||||
if (gis.read(buffer) == -1) {
|
for (int i = 0; i < amount; i++) {
|
||||||
fis.close();
|
int x = posDel.readX(fis) + ox;
|
||||||
gis.close();
|
int y = posDel.readY(fis);
|
||||||
return summary;
|
int z = posDel.readZ(fis) + ox;
|
||||||
|
idDel.readCombined(fis, change);
|
||||||
|
summary.add(x, z, change.to);
|
||||||
}
|
}
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
return summary;
|
} catch (EOFException ignored) {
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
return summary;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -463,7 +478,7 @@ public class DiskStorageHistory extends FaweStreamChangeSet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void add(int x, int z, int id) {
|
public void add(int x, int z, int id) {
|
||||||
blocks[BlockState.getFromInternalId(id).getOrdinal()]++;
|
blocks[id]++;
|
||||||
if (x < minX) {
|
if (x < minX) {
|
||||||
minX = x;
|
minX = x;
|
||||||
} else if (x > maxX) {
|
} else if (x > maxX) {
|
||||||
@ -487,6 +502,14 @@ public class DiskStorageHistory extends FaweStreamChangeSet {
|
|||||||
return map;
|
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() {
|
public Map<BlockState, Double> getPercents() {
|
||||||
Map<BlockState, Integer> map = getBlocks();
|
Map<BlockState, Integer> map = getBlocks();
|
||||||
int count = getSize();
|
int count = getSize();
|
||||||
|
@ -49,19 +49,7 @@ public abstract class FaweChangeSet implements ChangeSet, IBatchProcessor, Close
|
|||||||
private final String worldName;
|
private final String worldName;
|
||||||
protected AtomicInteger waitingCombined = new AtomicInteger(0);
|
protected AtomicInteger waitingCombined = new AtomicInteger(0);
|
||||||
protected AtomicInteger waitingAsync = new AtomicInteger(0);
|
protected AtomicInteger waitingAsync = new AtomicInteger(0);
|
||||||
private boolean closed;
|
protected 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public FaweChangeSet(String world) {
|
public FaweChangeSet(String world) {
|
||||||
this.worldName = world;
|
this.worldName = world;
|
||||||
|
@ -33,8 +33,8 @@ public abstract class FaweStreamChangeSet extends FaweChangeSet {
|
|||||||
private int mode;
|
private int mode;
|
||||||
private final int compression;
|
private final int compression;
|
||||||
|
|
||||||
private FaweStreamIdDelegate idDel;
|
protected FaweStreamIdDelegate idDel;
|
||||||
private FaweStreamPositionDelegate posDel;
|
protected FaweStreamPositionDelegate posDel;
|
||||||
|
|
||||||
public FaweStreamChangeSet(World world) {
|
public FaweStreamChangeSet(World world) {
|
||||||
this(world, Settings.IMP.HISTORY.COMPRESSION_LEVEL, Settings.IMP.HISTORY.STORE_REDO, Settings.IMP.HISTORY.SMALL_EDITS);
|
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, 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;
|
this.mode = mode;
|
||||||
if (mode == 3 || mode == 4) {
|
if (mode == 3 || mode == 4) {
|
||||||
idDel = new FaweStreamIdDelegate() {
|
idDel = new FaweStreamIdDelegate() {
|
||||||
@ -102,15 +102,15 @@ public abstract class FaweStreamChangeSet extends FaweChangeSet {
|
|||||||
public void readCombined(FaweInputStream is, MutableBlockChange change, boolean dir) throws IOException {
|
public void readCombined(FaweInputStream is, MutableBlockChange change, boolean dir) throws IOException {
|
||||||
if (dir) {
|
if (dir) {
|
||||||
is.readVarInt();
|
is.readVarInt();
|
||||||
change.combinedId = is.readVarInt();
|
change.ordinal = is.readVarInt();
|
||||||
} else {
|
} else {
|
||||||
change.combinedId = is.readVarInt();
|
change.ordinal = is.readVarInt();
|
||||||
is.readVarInt();
|
is.readVarInt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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.from = is.readVarInt();
|
||||||
change.to = 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 {
|
public void readCombined(FaweInputStream in, MutableBlockChange change, boolean dir) throws IOException {
|
||||||
int from1 = in.read();
|
int from1 = in.read();
|
||||||
int from2 = in.read();
|
int from2 = in.read();
|
||||||
change.combinedId = in.readVarInt();
|
change.ordinal = in.readVarInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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.from = is.readVarInt();
|
||||||
change.to = BlockTypes.AIR.getInternalId();
|
change.to = BlockTypes.AIR.getInternalId();
|
||||||
}
|
}
|
||||||
@ -290,7 +290,7 @@ public abstract class FaweStreamChangeSet extends FaweChangeSet {
|
|||||||
|
|
||||||
public abstract NBTInputStream getTileRemoveIS() throws IOException;
|
public abstract NBTInputStream getTileRemoveIS() throws IOException;
|
||||||
|
|
||||||
private int blockSize;
|
protected int blockSize;
|
||||||
public int entityCreateSize;
|
public int entityCreateSize;
|
||||||
public int entityRemoveSize;
|
public int entityRemoveSize;
|
||||||
public int tileCreateSize;
|
public int tileCreateSize;
|
||||||
@ -530,7 +530,7 @@ public abstract class FaweStreamChangeSet extends FaweChangeSet {
|
|||||||
change.x = posDel.readX(is) + originX;
|
change.x = posDel.readX(is) + originX;
|
||||||
change.y = posDel.readY(is);
|
change.y = posDel.readY(is);
|
||||||
change.z = posDel.readZ(is) + originZ;
|
change.z = posDel.readZ(is) + originZ;
|
||||||
idDel.readCombined(is, change, dir);
|
idDel.readCombined(is, change);
|
||||||
return change;
|
return change;
|
||||||
} catch (EOFException ignored) {
|
} catch (EOFException ignored) {
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -67,7 +67,7 @@ public class ResizableClipboardBuilder extends MemoryOptimizedHistory {
|
|||||||
Change change = iterator.next();
|
Change change = iterator.next();
|
||||||
if (change instanceof MutableBlockChange) {
|
if (change instanceof MutableBlockChange) {
|
||||||
MutableBlockChange blockChange = (MutableBlockChange) change;
|
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);
|
clipboard.setBlock(blockChange.x, blockChange.y, blockChange.z, block);
|
||||||
} else if (change instanceof MutableTileChange) {
|
} else if (change instanceof MutableTileChange) {
|
||||||
MutableTileChange tileChange = (MutableTileChange) change;
|
MutableTileChange tileChange = (MutableTileChange) change;
|
||||||
|
@ -4,8 +4,10 @@ import com.boydti.fawe.util.MathMan;
|
|||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.awt.image.DataBufferInt;
|
import java.awt.image.DataBufferInt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Efficient blur / average color over an image
|
||||||
|
*/
|
||||||
public class SummedColorTable {
|
public class SummedColorTable {
|
||||||
private static float inv256 = 1/256f;
|
|
||||||
private final long[] reds, greens, blues, alpha;
|
private final long[] reds, greens, blues, alpha;
|
||||||
private final int[] hasAlpha;
|
private final int[] hasAlpha;
|
||||||
private final int length;
|
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) {
|
public int averageRGB(int x1, int z1, int x2, int z2) {
|
||||||
int minX = Math.max(0, x1);
|
int minX = Math.max(0, x1);
|
||||||
int minZ = Math.max(0, z1);
|
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;
|
package com.boydti.fawe.object.task;
|
||||||
|
|
||||||
|
import com.boydti.fawe.Fawe;
|
||||||
import com.boydti.fawe.util.TaskManager;
|
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.atomic.AtomicBoolean;
|
||||||
|
import java.util.concurrent.locks.Lock;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public abstract class AsyncNotifyQueue {
|
public class AsyncNotifyQueue implements Closeable {
|
||||||
protected Object lock = new Object();
|
private final Lock lock = new ReentrantLock(true);
|
||||||
protected final Runnable task;
|
private final Thread.UncaughtExceptionHandler handler;
|
||||||
protected final AtomicBoolean running = new AtomicBoolean();
|
private boolean closed;
|
||||||
|
|
||||||
public AsyncNotifyQueue() {
|
public AsyncNotifyQueue(Thread.UncaughtExceptionHandler handler) {
|
||||||
this.task = new Runnable() {
|
this.handler = handler;
|
||||||
@Override
|
}
|
||||||
public void run() {
|
|
||||||
operate();
|
public Thread.UncaughtExceptionHandler getHandler() {
|
||||||
synchronized (lock) {
|
return handler;
|
||||||
if (hasQueued()) TaskManager.IMP.async(this);
|
}
|
||||||
else running.set(false);
|
|
||||||
|
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();
|
@Override
|
||||||
|
public void close() {
|
||||||
public void queue(Runnable queueTask) {
|
closed = true;
|
||||||
synchronized (lock) {
|
|
||||||
if (queueTask != null) queueTask.run();
|
|
||||||
if (!running.get()) {
|
|
||||||
running.set(true);
|
|
||||||
TaskManager.IMP.async(task);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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.IQueueExtent;
|
||||||
import com.boydti.fawe.beta.implementation.processors.LimitProcessor;
|
import com.boydti.fawe.beta.implementation.processors.LimitProcessor;
|
||||||
import com.boydti.fawe.beta.implementation.queue.ParallelQueueExtent;
|
import com.boydti.fawe.beta.implementation.queue.ParallelQueueExtent;
|
||||||
|
import com.sk89q.worldedit.util.Identifiable;
|
||||||
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
|
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
|
||||||
import com.boydti.fawe.config.Settings;
|
import com.boydti.fawe.config.Settings;
|
||||||
import com.boydti.fawe.logging.LoggingChangeSet;
|
import com.boydti.fawe.logging.LoggingChangeSet;
|
||||||
@ -58,6 +59,7 @@ public class EditSessionBuilder {
|
|||||||
private BlockBag blockBag;
|
private BlockBag blockBag;
|
||||||
private boolean threaded = true;
|
private boolean threaded = true;
|
||||||
private EditSessionEvent event;
|
private EditSessionEvent event;
|
||||||
|
private String command;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An EditSession builder<br>
|
* An EditSession builder<br>
|
||||||
@ -130,6 +132,11 @@ public class EditSessionBuilder {
|
|||||||
return setDirty();
|
return setDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public EditSessionBuilder command(String command) {
|
||||||
|
this.command = command;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param disk If it should be stored on disk
|
* @param disk If it should be stored on disk
|
||||||
* @param uuid The uuid to store it under (if 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 (!this.fastmode || changeSet != null) {
|
||||||
if (changeSet == null) {
|
if (changeSet == null) {
|
||||||
if (Settings.IMP.HISTORY.USE_DISK) {
|
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) {
|
if (Settings.IMP.HISTORY.USE_DATABASE) {
|
||||||
changeSet = new RollbackOptimizedHistory(world, uuid);
|
changeSet = new RollbackOptimizedHistory(world, uuid);
|
||||||
} else {
|
} else {
|
||||||
@ -378,6 +385,9 @@ public class EditSessionBuilder {
|
|||||||
if (this.limit.SPEED_REDUCTION > 0) {
|
if (this.limit.SPEED_REDUCTION > 0) {
|
||||||
this.extent = this.bypassHistory = new SlowExtent(this.bypassHistory, this.limit.SPEED_REDUCTION);
|
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) {
|
if (changeSet instanceof NullChangeSet && Fawe.imp().getBlocksHubApi() != null && player != null) {
|
||||||
changeSet = LoggingChangeSet.wrap(player, changeSet);
|
changeSet = LoggingChangeSet.wrap(player, changeSet);
|
||||||
}
|
}
|
||||||
|
@ -80,6 +80,8 @@ import java.util.zip.ZipEntry;
|
|||||||
import java.util.zip.ZipInputStream;
|
import java.util.zip.ZipInputStream;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.io.FastBufferedInputStream;
|
||||||
import net.jpountz.lz4.LZ4BlockInputStream;
|
import net.jpountz.lz4.LZ4BlockInputStream;
|
||||||
import net.jpountz.lz4.LZ4BlockOutputStream;
|
import net.jpountz.lz4.LZ4BlockOutputStream;
|
||||||
import net.jpountz.lz4.LZ4Compressor;
|
import net.jpountz.lz4.LZ4Compressor;
|
||||||
@ -336,7 +338,7 @@ public class MainUtil {
|
|||||||
|
|
||||||
public static FaweInputStream getCompressedIS(InputStream is, int buffer) throws IOException {
|
public static FaweInputStream getCompressedIS(InputStream is, int buffer) throws IOException {
|
||||||
int mode = (byte) is.read();
|
int mode = (byte) is.read();
|
||||||
is = new BufferedInputStream(is, buffer);
|
is = new FastBufferedInputStream(is, buffer);
|
||||||
if (mode == 0) {
|
if (mode == 0) {
|
||||||
return new FaweInputStream(is);
|
return new FaweInputStream(is);
|
||||||
}
|
}
|
||||||
@ -353,7 +355,7 @@ public class MainUtil {
|
|||||||
int amountAbs = Math.abs(mode);
|
int amountAbs = Math.abs(mode);
|
||||||
if (amountAbs > 6) {
|
if (amountAbs > 6) {
|
||||||
if (mode > 0) {
|
if (mode > 0) {
|
||||||
is = new BufferedInputStream(new GZIPInputStream(is, buffer));
|
is = new FastBufferedInputStream(new GZIPInputStream(is, buffer));
|
||||||
} else {
|
} else {
|
||||||
is = new ZstdInputStream(is);
|
is = new ZstdInputStream(is);
|
||||||
}
|
}
|
||||||
@ -366,7 +368,7 @@ public class MainUtil {
|
|||||||
is = new LZ4BlockInputStream(is);
|
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) {
|
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();
|
long age = now - file.lastModified();
|
||||||
if (age > timeDiff) {
|
if (age > timeDiff) {
|
||||||
pool.submit(file::delete);
|
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);
|
if (printDebug) Fawe.debug(msg);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -210,8 +210,6 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
|
|||||||
|
|
||||||
private final int maxY;
|
private final int maxY;
|
||||||
|
|
||||||
public static final UUID CONSOLE = UUID.fromString("1-1-3-3-7");
|
|
||||||
|
|
||||||
@Deprecated
|
@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) {
|
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);
|
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
|
* @return an edit session
|
||||||
*/
|
*/
|
||||||
public EditSession createEditSession(Actor actor) {
|
public EditSession createEditSession(Actor actor) {
|
||||||
|
return createEditSession(actor, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public EditSession createEditSession(Actor actor, String command) {
|
||||||
checkNotNull(actor);
|
checkNotNull(actor);
|
||||||
|
|
||||||
World world = null;
|
World world = null;
|
||||||
@ -1449,6 +1453,7 @@ public class LocalSession implements TextureHolder {
|
|||||||
builder.player((Player) actor);
|
builder.player((Player) actor);
|
||||||
builder.blockBag(blockBag);
|
builder.blockBag(blockBag);
|
||||||
}
|
}
|
||||||
|
builder.command(command);
|
||||||
builder.fastmode(fastMode);
|
builder.fastmode(fastMode);
|
||||||
|
|
||||||
editSession = builder.build();
|
editSession = builder.build();
|
||||||
|
@ -19,19 +19,6 @@
|
|||||||
|
|
||||||
package com.sk89q.worldedit.command;
|
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.EditSession;
|
||||||
import com.sk89q.worldedit.LocalSession;
|
import com.sk89q.worldedit.LocalSession;
|
||||||
import com.sk89q.worldedit.WorldEdit;
|
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.entity.Player;
|
||||||
import com.sk89q.worldedit.extension.platform.Actor;
|
import com.sk89q.worldedit.extension.platform.Actor;
|
||||||
import com.sk89q.worldedit.util.formatting.text.TextComponent;
|
import com.sk89q.worldedit.util.formatting.text.TextComponent;
|
||||||
import com.sk89q.worldedit.math.BlockVector3;
|
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
|
||||||
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 org.enginehub.piston.annotation.Command;
|
import org.enginehub.piston.annotation.Command;
|
||||||
import org.enginehub.piston.annotation.CommandContainer;
|
import org.enginehub.piston.annotation.CommandContainer;
|
||||||
import org.enginehub.piston.annotation.param.Arg;
|
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;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
@ -77,149 +54,6 @@ public class HistoryCommands {
|
|||||||
this.worldEdit = worldEdit;
|
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(
|
@Command(
|
||||||
name = "/undo",
|
name = "/undo",
|
||||||
aliases = { "/un", "/ud", "undo" },
|
aliases = { "/un", "/ud", "undo" },
|
||||||
@ -310,5 +144,4 @@ public class HistoryCommands {
|
|||||||
session.clearHistory();
|
session.clearHistory();
|
||||||
actor.printInfo(TranslatableComponent.of("worldedit.clearhistory.cleared"));
|
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."));
|
throw new StopExecutionException(TextComponent.of("Cannot sort by oldest and newest."));
|
||||||
}
|
}
|
||||||
String pageCommand = arguments.get();
|
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();
|
LocalConfiguration config = worldEdit.getConfiguration();
|
||||||
File dir = worldEdit.getWorkingDirectoryFile(config.saveDir);
|
File dir = worldEdit.getWorkingDirectoryFile(config.saveDir);
|
||||||
|
|
||||||
@ -840,7 +835,7 @@ public class SchematicCommands {
|
|||||||
actor.printError(TranslatableComponent.of("worldedit.schematic.delete.failed", TextComponent.of(filename)));
|
actor.printError(TranslatableComponent.of("worldedit.schematic.delete.failed", TextComponent.of(filename)));
|
||||||
continue;
|
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));
|
actor.print(res.create(page));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class BlockDistributionResult extends PaginationBox {
|
public static class BlockDistributionResult extends PaginationBox {
|
||||||
|
|
||||||
private final List<Countable> distribution;
|
private final List<Countable> distribution;
|
||||||
private final int totalBlocks;
|
private final int totalBlocks;
|
||||||
private final boolean separateStates;
|
private final boolean separateStates;
|
||||||
|
|
||||||
BlockDistributionResult(List<Countable> distribution, boolean separateStates) {
|
public BlockDistributionResult(List<Countable> distribution, boolean separateStates) {
|
||||||
super("Block Distribution", "//distr -p %page%" + (separateStates ? " -d" : ""));
|
this(distribution, separateStates, "//distr -p %page%" + (separateStates ? " -d" : ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockDistributionResult(List<Countable> distribution, boolean separateStates, String pageCommand) {
|
||||||
|
super("Block Distribution", pageCommand);
|
||||||
this.distribution = distribution;
|
this.distribution = distribution;
|
||||||
// note: doing things like region.getArea is inaccurate for non-cuboids.
|
// note: doing things like region.getArea is inaccurate for non-cuboids.
|
||||||
this.totalBlocks = distribution.stream().mapToInt(Countable::getAmount).sum();
|
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)));
|
player.printError(TranslatableComponent.of("worldedit.superpickaxe.max-range", TextComponent.of(config.maxSuperPickaxeSize)));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
session.setSuperPickaxe(new AreaPickaxe(range));
|
session.setSuperPickaxe(new AreaPickaxe(range));
|
||||||
session.enableSuperPickAxe();
|
session.enableSuperPickAxe();
|
||||||
player.printInfo(TranslatableComponent.of("worldedit.tool.superpickaxe.mode.area"));
|
player.printInfo(TranslatableComponent.of("worldedit.tool.superpickaxe.mode.area"));
|
||||||
|
@ -62,7 +62,7 @@ public class AreaPickaxe implements BlockTool {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
try (EditSession editSession = session.createEditSession(player)) {
|
try (EditSession editSession = session.createEditSession(player, "AreaPickaxe")) {
|
||||||
editSession.getSurvivalExtent().setToolUse(config.superPickaxeManyDrop);
|
editSession.getSurvivalExtent().setToolUse(config.superPickaxeManyDrop);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -85,7 +85,7 @@ public class BlockDataCyler implements DoubleActionBlockTool {
|
|||||||
Property<Object> objProp = (Property<Object>) currentProperty;
|
Property<Object> objProp = (Property<Object>) currentProperty;
|
||||||
BlockState newBlock = block.with(objProp, currentProperty.getValues().get(index));
|
BlockState newBlock = block.with(objProp, currentProperty.getValues().get(index));
|
||||||
|
|
||||||
try (EditSession editSession = session.createEditSession(player)) {
|
try (EditSession editSession = session.createEditSession(player, "BlockDataCyler")) {
|
||||||
editSession.disableBuffering();
|
editSession.disableBuffering();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -54,7 +54,7 @@ public class BlockReplacer implements DoubleActionBlockTool {
|
|||||||
public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked) {
|
public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked) {
|
||||||
BlockBag bag = session.getBlockBag(player);
|
BlockBag bag = session.getBlockBag(player);
|
||||||
|
|
||||||
try (EditSession editSession = session.createEditSession(player)) {
|
try (EditSession editSession = session.createEditSession(player, "BlockReplacer")) {
|
||||||
try {
|
try {
|
||||||
BlockVector3 position = clicked.toVector().toBlockPoint();
|
BlockVector3 position = clicked.toVector().toBlockPoint();
|
||||||
editSession.setBlock(position, pattern);
|
editSession.setBlock(position, pattern);
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
package com.sk89q.worldedit.command.tool;
|
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 com.google.common.base.Preconditions.checkNotNull;
|
||||||
import static org.slf4j.LoggerFactory.getLogger;
|
import static org.slf4j.LoggerFactory.getLogger;
|
||||||
|
|
||||||
@ -110,7 +111,6 @@ public class BrushTool implements DoubleActionTraceTool, ScrollTool, MovableTool
|
|||||||
private transient BrushSettings context = primary;
|
private transient BrushSettings context = primary;
|
||||||
|
|
||||||
private transient PersistentChunkSendProcessor visualExtent;
|
private transient PersistentChunkSendProcessor visualExtent;
|
||||||
private transient Lock lock = new ReentrantLock();
|
|
||||||
|
|
||||||
private transient BaseItem holder;
|
private transient BaseItem holder;
|
||||||
|
|
||||||
@ -210,7 +210,6 @@ public class BrushTool implements DoubleActionTraceTool, ScrollTool, MovableTool
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
|
private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
|
||||||
lock = new ReentrantLock();
|
|
||||||
boolean multi = stream.readBoolean();
|
boolean multi = stream.readBoolean();
|
||||||
primary = (BrushSettings) stream.readObject();
|
primary = (BrushSettings) stream.readObject();
|
||||||
if (multi) {
|
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(), ",")));
|
player.print(TranslatableComponent.of("fawe.error.no.perm" , StringMan.join(current.getPermissions(), ",")));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
try (EditSession editSession = session.createEditSession(player)) {
|
try (EditSession editSession = session.createEditSession(player, current.toString())) {
|
||||||
Location target = player.getBlockTrace(getRange(), true, traceMask);
|
Location target = player.getBlockTrace(getRange(), true, traceMask);
|
||||||
|
|
||||||
if (target == null) {
|
if (target == null) {
|
||||||
@ -639,7 +638,9 @@ public class BrushTool implements DoubleActionTraceTool, ScrollTool, MovableTool
|
|||||||
BrushSettings current = getContext();
|
BrushSettings current = getContext();
|
||||||
Brush brush = current.getBrush();
|
Brush brush = current.getBrush();
|
||||||
if (brush == null) return;
|
if (brush == null) return;
|
||||||
|
|
||||||
EditSessionBuilder builder = new EditSessionBuilder(player.getWorld())
|
EditSessionBuilder builder = new EditSessionBuilder(player.getWorld())
|
||||||
|
.command(current.toString())
|
||||||
.player(player)
|
.player(player)
|
||||||
.allowedRegionsEverywhere()
|
.allowedRegionsEverywhere()
|
||||||
.autoQueue(false)
|
.autoQueue(false)
|
||||||
|
@ -78,7 +78,7 @@ public class FloatingTreeRemover implements BlockTool {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
try (EditSession editSession = session.createEditSession(player)) {
|
try (EditSession editSession = session.createEditSession(player, "FloatingTreeRemover")) {
|
||||||
try {
|
try {
|
||||||
final Set<BlockVector3> blockSet = bfs(world, clicked.toVector().toBlockPoint());
|
final Set<BlockVector3> blockSet = bfs(world, clicked.toVector().toBlockPoint());
|
||||||
if (blockSet == null) {
|
if (blockSet == null) {
|
||||||
|
@ -73,7 +73,7 @@ public class FloodFillTool implements BlockTool {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
try (EditSession editSession = session.createEditSession(player)) {
|
try (EditSession editSession = session.createEditSession(player, "FloodFillTool")) {
|
||||||
try {
|
try {
|
||||||
Mask mask = initialType.toMask(editSession);
|
Mask mask = initialType.toMask(editSession);
|
||||||
BlockReplace function = new BlockReplace(editSession, pattern);
|
BlockReplace function = new BlockReplace(editSession, pattern);
|
||||||
|
@ -59,7 +59,7 @@ public class LongRangeBuildTool extends BrushTool implements DoubleActionTraceTo
|
|||||||
if (pos == null) return false;
|
if (pos == null) return false;
|
||||||
BlockBag bag = session.getBlockBag(player);
|
BlockBag bag = session.getBlockBag(player);
|
||||||
|
|
||||||
try (EditSession editSession = session.createEditSession(player)) {
|
try (EditSession editSession = session.createEditSession(player, "LongRangeBuildTool")) {
|
||||||
try {
|
try {
|
||||||
editSession.disableBuffering();
|
editSession.disableBuffering();
|
||||||
BlockVector3 blockPoint = pos.toVector().toBlockPoint();
|
BlockVector3 blockPoint = pos.toVector().toBlockPoint();
|
||||||
@ -87,7 +87,7 @@ public class LongRangeBuildTool extends BrushTool implements DoubleActionTraceTo
|
|||||||
if (pos == null) return false;
|
if (pos == null) return false;
|
||||||
BlockBag bag = session.getBlockBag(player);
|
BlockBag bag = session.getBlockBag(player);
|
||||||
|
|
||||||
try (EditSession editSession = session.createEditSession(player)) {
|
try (EditSession editSession = session.createEditSession(player, "LongRangeBuildTool")) {
|
||||||
try {
|
try {
|
||||||
editSession.disableBuffering();
|
editSession.disableBuffering();
|
||||||
BlockVector3 blockPoint = pos.toVector().toBlockPoint();
|
BlockVector3 blockPoint = pos.toVector().toBlockPoint();
|
||||||
|
@ -72,7 +72,7 @@ public class RecursivePickaxe implements BlockTool {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
try (EditSession editSession = session.createEditSession(player)) {
|
try (EditSession editSession = session.createEditSession(player, "RecursivePickaxe")) {
|
||||||
editSession.getSurvivalExtent().setToolUse(config.superPickaxeManyDrop);
|
editSession.getSurvivalExtent().setToolUse(config.superPickaxeManyDrop);
|
||||||
|
|
||||||
final int radius = (int) range;
|
final int radius = (int) range;
|
||||||
|
@ -19,8 +19,10 @@
|
|||||||
|
|
||||||
package com.sk89q.worldedit.extension.factory.parser;
|
package com.sk89q.worldedit.extension.factory.parser;
|
||||||
|
|
||||||
|
import com.boydti.fawe.config.Caption;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
|
|
||||||
|
import com.sk89q.worldedit.util.formatting.WorldEditText;
|
||||||
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
|
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
|
||||||
import com.boydti.fawe.jnbt.JSON2NBT;
|
import com.boydti.fawe.jnbt.JSON2NBT;
|
||||||
import com.boydti.fawe.jnbt.NBTException;
|
import com.boydti.fawe.jnbt.NBTException;
|
||||||
@ -421,12 +423,12 @@ public class DefaultBlockParser extends InputParser<BaseBlock> {
|
|||||||
if (context.isRestricted()) {
|
if (context.isRestricted()) {
|
||||||
Actor actor = context.requireActor();
|
Actor actor = context.requireActor();
|
||||||
if (!actor.hasPermission("worldedit.anyblock") && worldEdit.getConfiguration().checkDisallowedBlocks(holder)) {
|
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();
|
CompoundTag nbt = holder.getNbtData();
|
||||||
if (nbt != null) {
|
if (nbt != null) {
|
||||||
if (!actor.hasPermission("worldedit.anyblock")) {
|
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;
|
package com.sk89q.worldedit.extension.platform;
|
||||||
|
|
||||||
import com.boydti.fawe.object.exception.FaweException;
|
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.boydti.fawe.util.TaskManager;
|
||||||
import com.sk89q.worldedit.WorldEditException;
|
import com.sk89q.worldedit.WorldEditException;
|
||||||
import com.sk89q.worldedit.internal.cui.CUIEvent;
|
import com.sk89q.worldedit.internal.cui.CUIEvent;
|
||||||
@ -65,7 +65,7 @@ public abstract class AbstractNonPlayerActor implements Actor {
|
|||||||
|
|
||||||
// Queue for async tasks
|
// Queue for async tasks
|
||||||
private AtomicInteger runningCount = new AtomicInteger();
|
private AtomicInteger runningCount = new AtomicInteger();
|
||||||
private SimpleAsyncNotifyQueue asyncNotifyQueue = new SimpleAsyncNotifyQueue(
|
private AsyncNotifyQueue asyncNotifyQueue = new AsyncNotifyQueue(
|
||||||
(thread, throwable) -> {
|
(thread, throwable) -> {
|
||||||
while (throwable.getCause() != null) {
|
while (throwable.getCause() != null) {
|
||||||
throwable = throwable.getCause();
|
throwable = throwable.getCause();
|
||||||
@ -106,7 +106,7 @@ public abstract class AbstractNonPlayerActor implements Actor {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (async) {
|
if (async) {
|
||||||
asyncNotifyQueue.queue(wrapped);
|
asyncNotifyQueue.run(wrapped);
|
||||||
} else {
|
} else {
|
||||||
TaskManager.IMP.taskNow(wrapped, false);
|
TaskManager.IMP.taskNow(wrapped, false);
|
||||||
}
|
}
|
||||||
|
@ -19,11 +19,12 @@
|
|||||||
|
|
||||||
package com.sk89q.worldedit.extension.platform;
|
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.EditSession;
|
||||||
|
|
||||||
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
|
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
|
||||||
import com.boydti.fawe.object.exception.FaweException;
|
import com.boydti.fawe.object.exception.FaweException;
|
||||||
import com.boydti.fawe.object.task.SimpleAsyncNotifyQueue;
|
|
||||||
import com.boydti.fawe.regions.FaweMaskManager;
|
import com.boydti.fawe.regions.FaweMaskManager;
|
||||||
import com.boydti.fawe.util.TaskManager;
|
import com.boydti.fawe.util.TaskManager;
|
||||||
import com.boydti.fawe.util.WEManager;
|
import com.boydti.fawe.util.WEManager;
|
||||||
@ -94,7 +95,7 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
|
|||||||
|
|
||||||
// Queue for async tasks
|
// Queue for async tasks
|
||||||
private AtomicInteger runningCount = new AtomicInteger();
|
private AtomicInteger runningCount = new AtomicInteger();
|
||||||
private SimpleAsyncNotifyQueue asyncNotifyQueue = new SimpleAsyncNotifyQueue(
|
private AsyncNotifyQueue asyncNotifyQueue = new AsyncNotifyQueue(
|
||||||
(thread, throwable) -> {
|
(thread, throwable) -> {
|
||||||
while (throwable.getCause() != null) {
|
while (throwable.getCause() != null) {
|
||||||
throwable = throwable.getCause();
|
throwable = throwable.getCause();
|
||||||
@ -618,7 +619,7 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
|
|||||||
@Override
|
@Override
|
||||||
public void checkPermission(String permission) throws AuthorizationException {
|
public void checkPermission(String permission) throws AuthorizationException {
|
||||||
if (!hasPermission(permission)) {
|
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) {
|
if (async) {
|
||||||
asyncNotifyQueue.queue(wrapped);
|
asyncNotifyQueue.run(wrapped);
|
||||||
} else {
|
} else {
|
||||||
TaskManager.IMP.taskNow(wrapped, false);
|
TaskManager.IMP.taskNow(wrapped, false);
|
||||||
}
|
}
|
||||||
|
@ -110,7 +110,7 @@ public interface Actor extends Identifiable, SessionOwner, Subject, MapMetadatab
|
|||||||
* @param component The component to print
|
* @param component The component to print
|
||||||
*/
|
*/
|
||||||
default void printError(Component component) {
|
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
|
* @param component The component to print
|
||||||
*/
|
*/
|
||||||
default void printInfo(Component component) {
|
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
|
* @param component The component to print
|
||||||
*/
|
*/
|
||||||
default void printDebug(Component component) {
|
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.CFICommands;
|
||||||
import com.boydti.fawe.command.CFICommandsRegistration;
|
import com.boydti.fawe.command.CFICommandsRegistration;
|
||||||
import com.boydti.fawe.util.StringMan;
|
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.sk89q.worldedit.util.formatting.text.TranslatableComponent;
|
||||||
import com.boydti.fawe.config.Settings;
|
import com.boydti.fawe.config.Settings;
|
||||||
import com.boydti.fawe.object.brush.visualization.cfi.HeightMapMCAGenerator;
|
import com.boydti.fawe.object.brush.visualization.cfi.HeightMapMCAGenerator;
|
||||||
@ -294,6 +296,7 @@ public final class PlatformCommandManager {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
/*
|
||||||
globalInjectedValues.injectValue(Key.of(EditSession.class),
|
globalInjectedValues.injectValue(Key.of(EditSession.class),
|
||||||
context -> {
|
context -> {
|
||||||
LocalSession localSession = context.injectedValue(Key.of(LocalSession.class))
|
LocalSession localSession = context.injectedValue(Key.of(LocalSession.class))
|
||||||
@ -306,6 +309,7 @@ public final class PlatformCommandManager {
|
|||||||
return editSession;
|
return editSession;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
*/
|
||||||
globalInjectedValues.injectValue(Key.of(CFICommands.CFISettings.class),
|
globalInjectedValues.injectValue(Key.of(CFICommands.CFISettings.class),
|
||||||
context -> context.injectedValue(Key.of(Actor.class))
|
context -> context.injectedValue(Key.of(Actor.class))
|
||||||
.orElseThrow(() -> new IllegalStateException("No CFI Settings")).getMeta("CFISettings"));
|
.orElseThrow(() -> new IllegalStateException("No CFI Settings")).getMeta("CFISettings"));
|
||||||
@ -518,10 +522,18 @@ public final class PlatformCommandManager {
|
|||||||
GenerationCommandsRegistration.builder(),
|
GenerationCommandsRegistration.builder(),
|
||||||
new GenerationCommands(worldEdit)
|
new GenerationCommands(worldEdit)
|
||||||
);
|
);
|
||||||
|
HistoryCommands history = new HistoryCommands(worldEdit);
|
||||||
this.registration.register(
|
this.registration.register(
|
||||||
commandManager,
|
commandManager,
|
||||||
HistoryCommandsRegistration.builder(),
|
HistoryCommandsRegistration.builder(),
|
||||||
new HistoryCommands(worldEdit)
|
history
|
||||||
|
);
|
||||||
|
registerSubCommands(
|
||||||
|
"/history",
|
||||||
|
ImmutableList.of(),
|
||||||
|
"Manage your history",
|
||||||
|
HistorySubCommandsRegistration.builder(),
|
||||||
|
new HistorySubCommands(history)
|
||||||
);
|
);
|
||||||
this.registration.register(
|
this.registration.register(
|
||||||
commandManager,
|
commandManager,
|
||||||
@ -739,7 +751,7 @@ public final class PlatformCommandManager {
|
|||||||
} catch (UsageException e) {
|
} catch (UsageException e) {
|
||||||
ImmutableList<Command> cmd = e.getCommands();
|
ImmutableList<Command> cmd = e.getCommands();
|
||||||
if (!cmd.isEmpty()) {
|
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());
|
actor.printError(e.getRichMessage());
|
||||||
} catch (CommandExecutionException e) {
|
} catch (CommandExecutionException e) {
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
package com.sk89q.worldedit.extension.platform.binding;
|
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.MathMan;
|
||||||
import com.boydti.fawe.util.image.ImageUtil;
|
import com.boydti.fawe.util.image.ImageUtil;
|
||||||
import com.sk89q.worldedit.WorldEdit;
|
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.extension.platform.PlatformCommandManager;
|
||||||
import com.sk89q.worldedit.extent.Extent;
|
import com.sk89q.worldedit.extent.Extent;
|
||||||
import com.sk89q.worldedit.internal.annotation.Selection;
|
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.internal.expression.Expression;
|
||||||
import com.sk89q.worldedit.math.BlockVector2;
|
import com.sk89q.worldedit.math.BlockVector2;
|
||||||
import com.sk89q.worldedit.math.BlockVector3;
|
import com.sk89q.worldedit.math.BlockVector3;
|
||||||
import com.sk89q.worldedit.regions.Region;
|
import com.sk89q.worldedit.regions.Region;
|
||||||
|
import com.sk89q.worldedit.util.Identifiable;
|
||||||
import com.sk89q.worldedit.util.TreeGenerator;
|
import com.sk89q.worldedit.util.TreeGenerator;
|
||||||
import com.sk89q.worldedit.util.formatting.text.TextComponent;
|
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.World;
|
||||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||||
import com.sk89q.worldedit.world.biome.BiomeTypes;
|
import com.sk89q.worldedit.world.biome.BiomeTypes;
|
||||||
@ -36,6 +42,7 @@ import org.enginehub.piston.inject.InjectedValueAccess;
|
|||||||
import org.enginehub.piston.inject.Key;
|
import org.enginehub.piston.inject.Key;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
public class ConsumeBindings extends Bindings {
|
public class ConsumeBindings extends Bindings {
|
||||||
private final PlatformCommandManager manager;
|
private final PlatformCommandManager manager;
|
||||||
@ -45,6 +52,12 @@ public class ConsumeBindings extends Bindings {
|
|||||||
this.manager = manager;
|
this.manager = manager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Time
|
||||||
|
@Binding
|
||||||
|
public Long time(Actor actor, String argument) {
|
||||||
|
return MainUtil.timeToSec(argument) * 1000;
|
||||||
|
}
|
||||||
|
|
||||||
@Binding
|
@Binding
|
||||||
@Confirm
|
@Confirm
|
||||||
@Selection
|
@Selection
|
||||||
@ -99,6 +112,30 @@ public class ConsumeBindings extends Bindings {
|
|||||||
return radius;
|
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
|
@Binding
|
||||||
public ProvideBindings.ImageUri getImage(String argument) {
|
public ProvideBindings.ImageUri getImage(String argument) {
|
||||||
return new ProvideBindings.ImageUri(ImageUtil.getImageURI(argument));
|
return new ProvideBindings.ImageUri(ImageUtil.getImageURI(argument));
|
||||||
|
@ -1,19 +1,28 @@
|
|||||||
package com.sk89q.worldedit.extension.platform.binding;
|
package com.sk89q.worldedit.extension.platform.binding;
|
||||||
|
|
||||||
import com.boydti.fawe.command.CFICommands;
|
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.TextureUtil;
|
||||||
import com.boydti.fawe.util.image.ImageUtil;
|
import com.boydti.fawe.util.image.ImageUtil;
|
||||||
import com.sk89q.worldedit.EditSession;
|
import com.sk89q.worldedit.EditSession;
|
||||||
import com.sk89q.worldedit.LocalSession;
|
import com.sk89q.worldedit.LocalSession;
|
||||||
import com.sk89q.worldedit.WorldEdit;
|
import com.sk89q.worldedit.WorldEdit;
|
||||||
|
import com.sk89q.worldedit.command.argument.Arguments;
|
||||||
import com.sk89q.worldedit.entity.Player;
|
import com.sk89q.worldedit.entity.Player;
|
||||||
import com.sk89q.worldedit.extension.input.InputParseException;
|
import com.sk89q.worldedit.extension.input.InputParseException;
|
||||||
import com.sk89q.worldedit.extension.platform.Actor;
|
import com.sk89q.worldedit.extension.platform.Actor;
|
||||||
import com.sk89q.worldedit.extent.Extent;
|
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.internal.annotation.Selection;
|
||||||
import com.sk89q.worldedit.regions.Region;
|
import com.sk89q.worldedit.regions.Region;
|
||||||
import com.sk89q.worldedit.session.request.Request;
|
import com.sk89q.worldedit.session.request.Request;
|
||||||
import com.sk89q.worldedit.util.TreeGenerator;
|
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.World;
|
||||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||||
import com.sk89q.worldedit.world.biome.BiomeTypes;
|
import com.sk89q.worldedit.world.biome.BiomeTypes;
|
||||||
@ -57,8 +66,10 @@ public class ProvideBindings extends Bindings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Binding
|
@Binding
|
||||||
public EditSession editSession(LocalSession localSession, Player player) {
|
public EditSession editSession(LocalSession localSession, Player player, InjectedValueAccess context) {
|
||||||
EditSession editSession = localSession.createEditSession(player);
|
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();
|
editSession.enableStandardMode();
|
||||||
Request.request().setEditSession(editSession);
|
Request.request().setEditSession(editSession);
|
||||||
return editSession;
|
return editSession;
|
||||||
@ -70,6 +81,31 @@ public class ProvideBindings extends Bindings {
|
|||||||
return localSession.getSelection(player.getWorld());
|
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
|
@Binding
|
||||||
public TextureUtil getTexture(LocalSession session) {
|
public TextureUtil getTexture(LocalSession session) {
|
||||||
return session.getTextureUtil();
|
return session.getTextureUtil();
|
||||||
@ -102,7 +138,7 @@ public class ProvideBindings extends Bindings {
|
|||||||
return extent;
|
return extent;
|
||||||
}
|
}
|
||||||
Player plr = getPlayer(actor);
|
Player plr = getPlayer(actor);
|
||||||
EditSession editSession = editSession(getLocalSession(plr), plr);
|
EditSession editSession = editSession(getLocalSession(plr), plr, access);
|
||||||
if (access instanceof InjectedValueStore) {
|
if (access instanceof InjectedValueStore) {
|
||||||
InjectedValueStore store = (InjectedValueStore) access;
|
InjectedValueStore store = (InjectedValueStore) access;
|
||||||
store.injectValue(Key.of(EditSession.class), ValueProvider.constant(editSession));
|
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 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;
|
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.Component;
|
||||||
import com.sk89q.worldedit.util.formatting.text.TextComponent;
|
import com.sk89q.worldedit.util.formatting.text.TextComponent;
|
||||||
import com.sk89q.worldedit.util.formatting.text.event.ClickEvent;
|
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 javax.annotation.Nullable;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public abstract class PaginationBox extends MessageBox {
|
public abstract class PaginationBox extends MessageBox {
|
||||||
|
|
||||||
@ -75,7 +81,11 @@ public abstract class PaginationBox extends MessageBox {
|
|||||||
super(title, new TextComponentProducer());
|
super(title, new TextComponentProducer());
|
||||||
|
|
||||||
if (pageCommand != null && !pageCommand.contains("%page%")) {
|
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;
|
this.pageCommand = pageCommand;
|
||||||
}
|
}
|
||||||
@ -131,12 +141,16 @@ public abstract class PaginationBox extends MessageBox {
|
|||||||
throw new IllegalStateException("Pagination components must be created with a page");
|
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) {
|
public static PaginationBox fromStrings(String header, @Nullable String pageCommand, Collection lines) {
|
||||||
return new ListPaginationBox(header, pageCommand, lines);
|
return new ListPaginationBox(header, pageCommand, lines);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PaginationBox fromStrings(String header, @Nullable String pageCommand, List<String> 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 {
|
public static class ListPaginationBox extends PaginationBox {
|
||||||
@ -168,6 +182,9 @@ public abstract class PaginationBox extends MessageBox {
|
|||||||
iterIndex++;
|
iterIndex++;
|
||||||
} while (iterIndex < number);
|
} while (iterIndex < number);
|
||||||
}
|
}
|
||||||
|
if (obj instanceof Supplier) {
|
||||||
|
obj = ((Supplier) obj).get();
|
||||||
|
}
|
||||||
if (obj instanceof Component) {
|
if (obj instanceof Component) {
|
||||||
return (Component) obj;
|
return (Component) obj;
|
||||||
}
|
}
|
||||||
|
@ -156,4 +156,8 @@ public class TranslationManager {
|
|||||||
public Component convertText(Component component, Locale locale) {
|
public Component convertText(Component component, Locale locale) {
|
||||||
return friendlyComponentRenderer.render(component, locale);
|
return friendlyComponentRenderer.render(component, locale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Locale getDefaultLocale() {
|
||||||
|
return defaultLocale;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,23 @@
|
|||||||
{
|
{
|
||||||
"fawe.prefix": "&8(&4&lFAWE&8)&7 ",
|
"fawe.prefix": "&8(&4&lHELLO&8)&7 ",
|
||||||
"error": "&c{0}",
|
"fawe.error": "&c{0}",
|
||||||
"info": "&7{0}",
|
"fawe.info": "&7{0}",
|
||||||
"debug": "&3{0}",
|
"fawe.debug": "&3{0}",
|
||||||
|
|
||||||
"piston.style.help.text": "Help: {0}",
|
"piston.style.help.text": "Help: {0}",
|
||||||
"piston.style.text.modifier": "TODO modifier: {0}, {1}, {2}",
|
"piston.style.text.modifier": "TODO modifier: {0}, {1}, {2}",
|
||||||
"piston.style.main.text": "{0}",
|
"piston.style.main.text": "{0}",
|
||||||
"piston.style.part.wrapping": "&8{0}&e{1}&8{2}",
|
"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.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.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.set.region": "Selection set to your current allowed region",
|
||||||
|
|
||||||
"fawe.info.worldedit.command.limit": "Please wait until your current action completes",
|
"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.delayed": "Please wait while we process your FAWE action...",
|
||||||
"fawe.info.worldedit.run": "Apologies for the delay. Now executing: {0}",
|
"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.pasted": "The clipboard has been pasted at {0}",
|
||||||
"worldedit.paste.selected": "Selected clipboard paste region.",
|
"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.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.rotate.rotated": "The clipboard copy has been rotated.",
|
||||||
"worldedit.flip.flipped": "The clipboard copy has been flipped.",
|
"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.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.player-only": "This command must be used with a player.",
|
||||||
"worldedit.command.error.report": "Please report this error: [See console]",
|
"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.session.cant-find-session": "Unable to find session for {0}",
|
||||||
"worldedit.platform.no-file-dialog": "File dialogs are not supported in your environment.",
|
"worldedit.platform.no-file-dialog": "File dialogs are not supported in your environment.",
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user