From 88e8a2d51e6e1d3f752ed16d1ae320af0e7850d1 Mon Sep 17 00:00:00 2001 From: Chaoscaot Date: Mon, 29 Mar 2021 00:18:13 +0200 Subject: [PATCH] Add Regional Reset History --- .../steamwar/bausystem/world/Region_12.java | 8 +- .../steamwar/bausystem/world/Region_15.java | 17 +-- .../steamwar/bausystem/world/SizedStack.java | 124 ++++++++++++++++++ .../bausystem/commands/CommandRegion.java | 65 +++++++++ .../de/steamwar/bausystem/world/Region.java | 94 +++++++++---- 5 files changed, 268 insertions(+), 40 deletions(-) create mode 100644 BauSystem_API/src/de/steamwar/bausystem/world/SizedStack.java create mode 100644 BauSystem_Main/src/de/steamwar/bausystem/commands/CommandRegion.java diff --git a/BauSystem_12/src/de/steamwar/bausystem/world/Region_12.java b/BauSystem_12/src/de/steamwar/bausystem/world/Region_12.java index 302e8dc..d95b106 100644 --- a/BauSystem_12/src/de/steamwar/bausystem/world/Region_12.java +++ b/BauSystem_12/src/de/steamwar/bausystem/world/Region_12.java @@ -40,7 +40,7 @@ class Region_12 { private Region_12() { } - static void paste(File file, int x, int y, int z, boolean rotate) { + static EditSession paste(File file, int x, int y, int z, boolean rotate) { World w = new BukkitWorld(Bukkit.getWorlds().get(0)); Clipboard clipboard; try { @@ -49,10 +49,10 @@ class Region_12 { throw new SecurityException("Bausystem schematic not found", e); } - paste(clipboard, x, y, z, rotate); + return paste(clipboard, x, y, z, rotate); } - static void paste(Clipboard clipboard, int x, int y, int z, boolean rotate) { + static EditSession paste(Clipboard clipboard, int x, int y, int z, boolean rotate) { World w = new BukkitWorld(Bukkit.getWorlds().get(0)); Vector dimensions = clipboard.getDimensions(); @@ -70,6 +70,6 @@ class Region_12 { ClipboardHolder ch = new ClipboardHolder(clipboard, w.getWorldData()); ch.setTransform(aT); Operations.completeBlindly(ch.createPaste(e, w.getWorldData()).to(v).build()); - e.flushQueue(); + return e; } } diff --git a/BauSystem_15/src/de/steamwar/bausystem/world/Region_15.java b/BauSystem_15/src/de/steamwar/bausystem/world/Region_15.java index 3aea08c..63f2e35 100644 --- a/BauSystem_15/src/de/steamwar/bausystem/world/Region_15.java +++ b/BauSystem_15/src/de/steamwar/bausystem/world/Region_15.java @@ -47,7 +47,7 @@ class Region_15 { private Region_15() { } - static void paste(File file, int x, int y, int z, boolean rotate) { + static EditSession paste(File file, int x, int y, int z, boolean rotate) { Clipboard clipboard; try { clipboard = Objects.requireNonNull(ClipboardFormats.findByFile(file)).getReader(new FileInputStream(file)).read(); @@ -55,10 +55,10 @@ class Region_15 { throw new SecurityException("Bausystem schematic not found", e); } - paste(clipboard, x, y, z, rotate); + return paste(clipboard, x, y, z, rotate); } - static void paste(Clipboard clipboard, int x, int y, int z, boolean rotate) { + static EditSession paste(Clipboard clipboard, int x, int y, int z, boolean rotate) { BlockVector3 dimensions = clipboard.getDimensions(); BlockVector3 v = BlockVector3.at(x, y, z); BlockVector3 offset = clipboard.getRegion().getMinimumPoint().subtract(clipboard.getOrigin()); @@ -70,11 +70,12 @@ class Region_15 { v = v.subtract(dimensions.getX() / 2 - dimensions.getX() % 2, 0, dimensions.getZ() / 2 - dimensions.getZ() % 2).subtract(offset); } - EditSession e = WorldEdit.getInstance().getEditSessionFactory().getEditSession(new BukkitWorld(Bukkit.getWorlds().get(0)), -1); - ClipboardHolder ch = new ClipboardHolder(clipboard); - ch.setTransform(aT); - Operations.completeBlindly(ch.createPaste(e).to(v).build()); - e.flushSession(); + try (EditSession e = WorldEdit.getInstance().getEditSessionFactory().getEditSession(new BukkitWorld(Bukkit.getWorlds().get(0)), -1)) { + ClipboardHolder ch = new ClipboardHolder(clipboard); + ch.setTransform(aT); + Operations.completeBlindly(ch.createPaste(e).to(v).build()); + return e; + } } static void fastpaste(File file, int x, int y, int z, boolean rotate) { diff --git a/BauSystem_API/src/de/steamwar/bausystem/world/SizedStack.java b/BauSystem_API/src/de/steamwar/bausystem/world/SizedStack.java new file mode 100644 index 0000000..92a4dd3 --- /dev/null +++ b/BauSystem_API/src/de/steamwar/bausystem/world/SizedStack.java @@ -0,0 +1,124 @@ +package de.steamwar.bausystem.world; + +@SuppressWarnings({"unused", "UnusedReturnValue"}) +public class SizedStack { + + private int maxSize; + private T[] data; + private int size; + private int head; + + public SizedStack(int size) { + this.maxSize = size; + //noinspection unchecked + this.data = (T[]) new Object[this.maxSize]; + this.head = 0; + this.size = 0; + } + + public T push(final T element) { + this.data[this.head] = element; + this.increaseHead(); + this.increaseSize(); + return element; + } + + public T pop() { + this.decreaseHead(); + this.decreaseSize(); + final T result = this.data[this.head]; + this.data[this.head] = null; + return result; + } + + public T peek() { + return this.data[this.head]; + } + + public boolean empty() { + return this.size == 0; + } + + protected boolean canEqual(final Object other) { + return other instanceof SizedStack; + } + + private void increaseHead() { + this.head++; + while (this.head > this.maxSize - 1) { + this.head -= this.maxSize; + } + } + + private void decreaseHead() { + this.head--; + while (this.head < 0) { + this.head += this.maxSize; + } + } + + private void increaseSize() { + if (this.size < this.maxSize) { + this.size++; + } + } + + private void decreaseSize() { + if (this.size > 0) { + this.size--; + } + } + + @Override + public int hashCode() { + final int PRIME = 59; + int result = 1; + result = result * PRIME + this.maxSize; + result = result * PRIME + this.toString().hashCode(); + result = result * PRIME + this.size; + return result; + } + + @Override + public boolean equals(final Object o) { + if (o == this) { + return true; + } + if (!(o instanceof SizedStack)) { + return false; + } + final SizedStack other = (SizedStack) o; + if (!other.canEqual(this)) { + return false; + } + if (this.maxSize != other.maxSize) { + return false; + } + if (this.size != other.size) { + return false; + } + if (!this.data.getClass().equals(other.data.getClass())) { + return false; + } + return this.toString().equals(other.toString()); + } + + public int getMaxSize() { + return maxSize; + } + + public int getSize() { + return size; + } + + @Override + public String toString() { + final StringBuilder result = new StringBuilder("["); + for (int i = 0; i < this.size - 1; i++) { + result.append(this.data[(this.head - i - 1 < 0) ? (this.head - i - 1 + this.maxSize) : (this.head - i - 1)]).append(","); + } + result.append(this.data[(this.head - this.size < 0) ? (this.head - this.size + this.maxSize) : (this.head - this.size)]); + result.append("]"); + return result.toString(); + } +} \ No newline at end of file diff --git a/BauSystem_Main/src/de/steamwar/bausystem/commands/CommandRegion.java b/BauSystem_Main/src/de/steamwar/bausystem/commands/CommandRegion.java new file mode 100644 index 0000000..49f3ee7 --- /dev/null +++ b/BauSystem_Main/src/de/steamwar/bausystem/commands/CommandRegion.java @@ -0,0 +1,65 @@ +package de.steamwar.bausystem.commands; + +import de.steamwar.bausystem.BauSystem; +import de.steamwar.bausystem.Permission; +import de.steamwar.bausystem.world.Region; +import de.steamwar.bausystem.world.Welt; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +public class CommandRegion implements CommandExecutor { + + @Override + public boolean onCommand(CommandSender sender, Command command, String s, String[] args) { + if (!(sender instanceof Player)) + return false; + + Player p = (Player) sender; + if (Welt.noPermission(p, Permission.world)) { + p.sendMessage(BauSystem.PREFIX + "§cDu darfst hier nicht die Region zurücksetzen"); + return false; + } + + if(args.length == 0) { + sendHelp(p); + } else { + Region region = Region.getRegion(p.getLocation()); + switch (args[0].toLowerCase()) { + case "undo": + if(checkGlobalRegion(region, p)) return false; + if(region.undo()) { + p.sendMessage(BauSystem.PREFIX + "Letzte Aktion rückgangig gemacht"); + } else { + p.sendMessage(BauSystem.PREFIX + "§cNichts zum rückgängig machen"); + } + break; + case "redo": + if(checkGlobalRegion(region, p)) return false; + if(region.redo()) { + p.sendMessage(BauSystem.PREFIX + "Letzte Aktion wiederhohlt"); + } else { + p.sendMessage(BauSystem.PREFIX + "§cNichts zum wiederhohlen"); + } + break; + default: + sendHelp(p); + } + } + return false; + } + + static void sendHelp(Player player) { + player.sendMessage(BauSystem.PREFIX + "§8/§7region undo §8- §7Mache die letzten 10 /testblock oder /reset rückgängig"); + player.sendMessage(BauSystem.PREFIX + "§8/§7region redo §8- §7Wiederhohle die letzten 10 §8/§7rg undo"); + } + + static boolean checkGlobalRegion(Region region, Player p) { + if(Region.GlobalRegion.isGlobalRegion(region)) { + p.sendMessage(BauSystem.PREFIX + "§cDu bist in keiner Region"); + return true; + } + return false; + } +} diff --git a/BauSystem_Main/src/de/steamwar/bausystem/world/Region.java b/BauSystem_Main/src/de/steamwar/bausystem/world/Region.java index b41339f..d2ad743 100644 --- a/BauSystem_Main/src/de/steamwar/bausystem/world/Region.java +++ b/BauSystem_Main/src/de/steamwar/bausystem/world/Region.java @@ -19,9 +19,10 @@ package de.steamwar.bausystem.world; +import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.extent.clipboard.Clipboard; import de.steamwar.bausystem.commands.CommandTNT.TNTMode; -import de.steamwar.core.VersionedRunnable; +import de.steamwar.core.VersionedCallable; import de.steamwar.sql.NoClipboardException; import de.steamwar.sql.Schematic; import org.bukkit.Bukkit; @@ -85,6 +86,8 @@ public class Region { private final Prototype prototype; private final String optionsLinkedWith; // nullable private Region linkedRegion = null; // nullable + private SizedStack undosessions; + private SizedStack redosessions; private TNTMode tntMode = Region.buildAreaEnabled() ? TNTMode.ONLY_TB : TNTMode.OFF; private boolean freeze = false; @@ -171,12 +174,14 @@ public class Region { return prototype.buildArea.inRegionExtension(this, l); } - public void fastreset() { - prototype.fastreset(this); + public void reset() throws IOException { + initSessions(); + undosessions.push(prototype.reset(this, null)); } public void reset(Schematic schem) throws IOException, NoClipboardException { - prototype.reset(this, schem); + initSessions(); + undosessions.push(prototype.reset(this, schem)); } public boolean hasTestblock() { @@ -184,7 +189,8 @@ public class Region { } public void resetTestblock(Schematic schem) throws IOException, NoClipboardException { - prototype.resetTestblock(this, schem); + initSessions(); + undosessions.push(prototype.resetTestblock(this, schem)); } public boolean hasProtection() { @@ -203,6 +209,47 @@ public class Region { return prototype.testblock.extensionPrototypeArea; } + private void initSessions() { + if(undosessions == null) { + undosessions = new SizedStack<>(20); + redosessions = new SizedStack<>(20); + } + } + + public boolean undo() { + initSessions(); + EditSession session = null; + try { + session = undosessions.pop(); + if(session == null) + return false; + session.undo(session); + redosessions.push(session); + return true; + } finally { + if (session != null) { + session.flushSession(); + } + } + } + + public boolean redo() { + initSessions(); + EditSession session = null; + try { + session = redosessions.pop(); + if(session == null) + return false; + session.redo(session); + undosessions.push(session); + return true; + } finally { + if (session != null) { + session.flushSession(); + } + } + } + public static class GlobalRegion extends Region { private static final GlobalRegion GLOBAL_REGION = new GlobalRegion(); @@ -320,59 +367,50 @@ public class Region { inRange(l.getZ(), region.minZ + offsetZ - extensionNegativeZ + 1, sizeZ + extensionNegativeZ - 1 + extensionPositiveZ); } - public void fastreset(Region region) { - File file = new File(schematic); - int x = region.minX + offsetX + sizeX / 2; - int y = region.minY + offsetY; - int z = region.minZ + offsetZ + sizeZ / 2; - VersionedRunnable.call(new VersionedRunnable(() -> Region_12.paste(file, x, y, z, rotate), 8), - new VersionedRunnable(() -> Region_15.fastpaste(file, x, y, z, rotate), 15)); - } - - public void reset(Region region, Schematic schem) throws IOException, NoClipboardException { + public EditSession reset(Region region, Schematic schem) throws IOException, NoClipboardException { int x = region.minX + offsetX + sizeX / 2; int y = region.minY + offsetY; int z = region.minZ + offsetZ + sizeZ / 2; if (schem == null) - paste(new File(schematic), x, y, z, rotate); + return paste(new File(schematic), x, y, z, rotate); else - paste(schem.load(), x, y, z, rotate); + return paste(schem.load(), x, y, z, rotate); } public boolean hasProtection() { return protectSchematic != null; } - public void protect(Region region, Schematic schem) throws IOException, NoClipboardException { + public EditSession protect(Region region, Schematic schem) throws IOException, NoClipboardException { int x = region.minX + offsetX + sizeX / 2; int y = region.minY + testblock.offsetY - 1; int z = region.minZ + offsetZ + sizeZ / 2; if (schem == null) - paste(new File(protectSchematic), x, y, z, rotate); + return paste(new File(protectSchematic), x, y, z, rotate); else - paste(schem.load(), x, y, z, rotate); + return paste(schem.load(), x, y, z, rotate); } public boolean hasTestblock() { return testblock != null; } - public void resetTestblock(Region region, Schematic schem) throws IOException, NoClipboardException { - testblock.reset(region, schem); + public EditSession resetTestblock(Region region, Schematic schem) throws IOException, NoClipboardException { + return testblock.reset(region, schem); } private static boolean inRange(double l, int min, int size) { return min <= l && l <= min + size; } - private static void paste(File file, int x, int y, int z, boolean rotate) { //Type of protect - VersionedRunnable.call(new VersionedRunnable(() -> Region_12.paste(file, x, y, z, rotate), 8), - new VersionedRunnable(() -> Region_15.paste(file, x, y, z, rotate), 15)); + private static EditSession paste(File file, int x, int y, int z, boolean rotate) { //Type of protect + return (EditSession) VersionedCallable.call(new VersionedCallable(() -> Region_12.paste(file, x, y, z, rotate), 8), + new VersionedCallable(() -> Region_15.paste(file, x, y, z, rotate), 15)); } - private static void paste(Clipboard clipboard, int x, int y, int z, boolean rotate) { - VersionedRunnable.call(new VersionedRunnable(() -> Region_12.paste(clipboard, x, y, z, rotate), 8), - new VersionedRunnable(() -> Region_15.paste(clipboard, x, y, z, rotate), 15)); + private static EditSession paste(Clipboard clipboard, int x, int y, int z, boolean rotate) { + return (EditSession) VersionedCallable.call(new VersionedCallable(() -> Region_12.paste(clipboard, x, y, z, rotate), 8), + new VersionedCallable(() -> Region_15.paste(clipboard, x, y, z, rotate), 15)); } } }