mirror of
https://github.com/plexusorg/Plex-FAWE.git
synced 2024-12-23 17:57:38 +00:00
Added new history framework, visitors for history.
This commit is contained in:
parent
cfdd87efac
commit
10e672a94a
@ -88,8 +88,8 @@ public class DoubleArrayList<A, B> implements Iterable<Map.Entry<A, B>> {
|
|||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Iterator<Map.Entry<A, B>> iterator() {
|
public Iterator<Map.Entry<A, B>> iterator(boolean reversed) {
|
||||||
if (isReversed) {
|
if (reversed) {
|
||||||
return new ReverseEntryIterator<Map.Entry<A, B>>(
|
return new ReverseEntryIterator<Map.Entry<A, B>>(
|
||||||
listA.listIterator(listA.size()),
|
listA.listIterator(listA.size()),
|
||||||
listB.listIterator(listB.size()));
|
listB.listIterator(listB.size()));
|
||||||
@ -100,6 +100,15 @@ public class DoubleArrayList<A, B> implements Iterable<Map.Entry<A, B>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an entry set.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Iterator<Map.Entry<A, B>> iterator() {
|
||||||
|
return iterator(isReversed);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Entry iterator.
|
* Entry iterator.
|
||||||
*
|
*
|
||||||
|
@ -36,6 +36,7 @@ import com.sk89q.worldedit.function.block.BlockReplace;
|
|||||||
import com.sk89q.worldedit.function.block.Naturalizer;
|
import com.sk89q.worldedit.function.block.Naturalizer;
|
||||||
import com.sk89q.worldedit.function.generator.GardenPatchGenerator;
|
import com.sk89q.worldedit.function.generator.GardenPatchGenerator;
|
||||||
import com.sk89q.worldedit.function.mask.*;
|
import com.sk89q.worldedit.function.mask.*;
|
||||||
|
import com.sk89q.worldedit.function.operation.ChangeSetExecutor;
|
||||||
import com.sk89q.worldedit.function.operation.ForwardExtentCopy;
|
import com.sk89q.worldedit.function.operation.ForwardExtentCopy;
|
||||||
import com.sk89q.worldedit.function.operation.OperationHelper;
|
import com.sk89q.worldedit.function.operation.OperationHelper;
|
||||||
import com.sk89q.worldedit.function.operation.OperationQueue;
|
import com.sk89q.worldedit.function.operation.OperationQueue;
|
||||||
@ -43,6 +44,10 @@ import com.sk89q.worldedit.function.pattern.BlockPattern;
|
|||||||
import com.sk89q.worldedit.function.pattern.Patterns;
|
import com.sk89q.worldedit.function.pattern.Patterns;
|
||||||
import com.sk89q.worldedit.function.util.RegionOffset;
|
import com.sk89q.worldedit.function.util.RegionOffset;
|
||||||
import com.sk89q.worldedit.function.visitor.*;
|
import com.sk89q.worldedit.function.visitor.*;
|
||||||
|
import com.sk89q.worldedit.history.changeset.BlockOptimizedHistory;
|
||||||
|
import com.sk89q.worldedit.history.changeset.ChangeSet;
|
||||||
|
import com.sk89q.worldedit.history.UndoContext;
|
||||||
|
import com.sk89q.worldedit.history.change.BlockChange;
|
||||||
import com.sk89q.worldedit.masks.Mask;
|
import com.sk89q.worldedit.masks.Mask;
|
||||||
import com.sk89q.worldedit.math.interpolation.Interpolation;
|
import com.sk89q.worldedit.math.interpolation.Interpolation;
|
||||||
import com.sk89q.worldedit.math.interpolation.KochanekBartelsInterpolation;
|
import com.sk89q.worldedit.math.interpolation.KochanekBartelsInterpolation;
|
||||||
@ -76,27 +81,10 @@ import static com.sk89q.worldedit.regions.Regions.*;
|
|||||||
*/
|
*/
|
||||||
public class EditSession implements Extent {
|
public class EditSession implements Extent {
|
||||||
|
|
||||||
/**
|
private final static Random prng = new Random();
|
||||||
* Random number generator.
|
|
||||||
*/
|
|
||||||
private static Random prng = new Random();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* World.
|
|
||||||
*/
|
|
||||||
protected LocalWorld world;
|
protected LocalWorld world;
|
||||||
|
private final ChangeSet changeSet = new BlockOptimizedHistory();
|
||||||
/**
|
|
||||||
* Stores the original blocks before modification.
|
|
||||||
*/
|
|
||||||
private DoubleArrayList<BlockVector, BaseBlock> original =
|
|
||||||
new DoubleArrayList<BlockVector, BaseBlock>(true);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stores the current blocks.
|
|
||||||
*/
|
|
||||||
private DoubleArrayList<BlockVector, BaseBlock> current =
|
|
||||||
new DoubleArrayList<BlockVector, BaseBlock>(false);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Blocks that should be placed before last.
|
* Blocks that should be placed before last.
|
||||||
@ -277,31 +265,35 @@ public class EditSession implements Extent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (!original.containsKey(blockPt)) {
|
if (maxBlocks != -1 && changeSet.size() > maxBlocks) {
|
||||||
original.put(blockPt, getBlock(pt));
|
|
||||||
|
|
||||||
if (maxBlocks != -1 && original.size() > maxBlocks) {
|
|
||||||
throw new MaxChangedBlocksException(maxBlocks);
|
throw new MaxChangedBlocksException(maxBlocks);
|
||||||
}
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
current.put(blockPt, block);
|
changeSet.add(new BlockChange(blockPt, getBlock(pt), block));
|
||||||
|
|
||||||
return smartSetBlock(pt, block);
|
return smartSetBlock(pt, block);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the underlying {@link ChangeSet}.
|
||||||
|
*
|
||||||
|
* @return the change set
|
||||||
|
*/
|
||||||
|
public ChangeSet getChangeSet() {
|
||||||
|
return changeSet;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert a contrived block change into the history.
|
* Insert a contrived block change into the history.
|
||||||
*
|
*
|
||||||
* @param pt
|
* @param position the position
|
||||||
* @param existing
|
* @param existing the previous block at that position
|
||||||
* @param block
|
* @param block the new block
|
||||||
|
* @deprecated Get the change set with {@link #getChangeSet()} and add the change with that
|
||||||
*/
|
*/
|
||||||
public void rememberChange(Vector pt, BaseBlock existing, BaseBlock block) {
|
@Deprecated
|
||||||
BlockVector blockPt = pt.toBlockVector();
|
public void rememberChange(Vector position, BaseBlock existing, BaseBlock block) {
|
||||||
|
changeSet.add(new BlockChange(position.toBlockVector(), existing, block));
|
||||||
original.put(blockPt, existing);
|
|
||||||
current.put(pt.toBlockVector(), block);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -436,10 +428,9 @@ public class EditSession implements Extent {
|
|||||||
* @param sess
|
* @param sess
|
||||||
*/
|
*/
|
||||||
public void undo(EditSession sess) {
|
public void undo(EditSession sess) {
|
||||||
for (Map.Entry<BlockVector, BaseBlock> entry : original) {
|
UndoContext context = new UndoContext();
|
||||||
BlockVector pt = entry.getKey();
|
context.setExtent(sess);
|
||||||
sess.smartSetBlock(pt, entry.getValue());
|
OperationHelper.completeBlindly(ChangeSetExecutor.createUndo(changeSet, context));
|
||||||
}
|
|
||||||
sess.flushQueue();
|
sess.flushQueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -449,10 +440,9 @@ public class EditSession implements Extent {
|
|||||||
* @param sess
|
* @param sess
|
||||||
*/
|
*/
|
||||||
public void redo(EditSession sess) {
|
public void redo(EditSession sess) {
|
||||||
for (Map.Entry<BlockVector, BaseBlock> entry : current) {
|
UndoContext context = new UndoContext();
|
||||||
BlockVector pt = entry.getKey();
|
context.setExtent(sess);
|
||||||
sess.smartSetBlock(pt, entry.getValue());
|
OperationHelper.completeBlindly(ChangeSetExecutor.createRedo(changeSet, context));
|
||||||
}
|
|
||||||
sess.flushQueue();
|
sess.flushQueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -462,7 +452,7 @@ public class EditSession implements Extent {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public int size() {
|
public int size() {
|
||||||
return original.size();
|
return changeSet.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -648,7 +638,7 @@ public class EditSession implements Extent {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public int getBlockChangeCount() {
|
public int getBlockChangeCount() {
|
||||||
return original.size();
|
return changeSet.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* Copyright (C) WorldEdit team and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldedit.function.operation;
|
||||||
|
|
||||||
|
import com.sk89q.worldedit.WorldEditException;
|
||||||
|
import com.sk89q.worldedit.history.change.Change;
|
||||||
|
import com.sk89q.worldedit.history.changeset.ChangeSet;
|
||||||
|
import com.sk89q.worldedit.history.UndoContext;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
public class ChangeSetExecutor implements Operation {
|
||||||
|
|
||||||
|
public enum Type {UNDO, REDO}
|
||||||
|
|
||||||
|
private final Iterator<Change> iterator;
|
||||||
|
private final Type type;
|
||||||
|
private final UndoContext context;
|
||||||
|
|
||||||
|
private ChangeSetExecutor(ChangeSet changeSet, Type type, UndoContext context) {
|
||||||
|
checkNotNull(changeSet);
|
||||||
|
checkNotNull(type);
|
||||||
|
checkNotNull(context);
|
||||||
|
|
||||||
|
this.type = type;
|
||||||
|
this.context = context;
|
||||||
|
|
||||||
|
if (type == Type.UNDO) {
|
||||||
|
iterator = changeSet.backwardIterator();
|
||||||
|
} else {
|
||||||
|
iterator = changeSet.forwardIterator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Operation resume() throws WorldEditException {
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
Change change = iterator.next();
|
||||||
|
if (type == Type.UNDO) {
|
||||||
|
change.undo(context);
|
||||||
|
} else {
|
||||||
|
change.redo(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cancel() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ChangeSetExecutor createUndo(ChangeSet changeSet, UndoContext context) {
|
||||||
|
return new ChangeSetExecutor(changeSet, Type.UNDO, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ChangeSetExecutor createRedo(ChangeSet changeSet, UndoContext context) {
|
||||||
|
return new ChangeSetExecutor(changeSet, Type.REDO, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
54
src/main/java/com/sk89q/worldedit/history/UndoContext.java
Normal file
54
src/main/java/com/sk89q/worldedit/history/UndoContext.java
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* Copyright (C) WorldEdit team and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldedit.history;
|
||||||
|
|
||||||
|
import com.sk89q.worldedit.extent.Extent;
|
||||||
|
import com.sk89q.worldedit.history.change.BlockChange;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides context for undo and redo operations.
|
||||||
|
* </p>
|
||||||
|
* For example, {@link BlockChange}s take the {@link Extent} from the
|
||||||
|
* context rather than store a reference to one.
|
||||||
|
*/
|
||||||
|
public class UndoContext {
|
||||||
|
|
||||||
|
private Extent extent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the extent set on this context.
|
||||||
|
*
|
||||||
|
* @return an extent or null
|
||||||
|
*/
|
||||||
|
public @Nullable Extent getExtent() {
|
||||||
|
return extent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the extent on this context.
|
||||||
|
*
|
||||||
|
* @param extent an extent or null
|
||||||
|
*/
|
||||||
|
public void setExtent(@Nullable Extent extent) {
|
||||||
|
this.extent = extent;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* Copyright (C) WorldEdit team and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldedit.history.change;
|
||||||
|
|
||||||
|
import com.sk89q.worldedit.BlockVector;
|
||||||
|
import com.sk89q.worldedit.WorldEditException;
|
||||||
|
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||||
|
import com.sk89q.worldedit.extent.Extent;
|
||||||
|
import com.sk89q.worldedit.history.UndoContext;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a block change that may be undone or replayed.
|
||||||
|
* </p>
|
||||||
|
* This block change does not have an {@link Extent} assigned to it because
|
||||||
|
* one will be taken from the passed {@link UndoContext}. If the context
|
||||||
|
* does not have an extent (it is null), cryptic errors may occur.
|
||||||
|
*/
|
||||||
|
public class BlockChange implements Change {
|
||||||
|
|
||||||
|
private final BlockVector position;
|
||||||
|
private final BaseBlock previous;
|
||||||
|
private final BaseBlock current;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new block change.
|
||||||
|
*
|
||||||
|
* @param position the position
|
||||||
|
* @param previous the previous block
|
||||||
|
* @param current the current block
|
||||||
|
*/
|
||||||
|
public BlockChange(BlockVector position, BaseBlock previous, BaseBlock current) {
|
||||||
|
checkNotNull(position);
|
||||||
|
checkNotNull(previous);
|
||||||
|
checkNotNull(current);
|
||||||
|
this.position = position;
|
||||||
|
this.previous = previous;
|
||||||
|
this.current = current;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the position.
|
||||||
|
*
|
||||||
|
* @return the position
|
||||||
|
*/
|
||||||
|
public BlockVector getPosition() {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the previous block.
|
||||||
|
*
|
||||||
|
* @return the previous block
|
||||||
|
*/
|
||||||
|
public BaseBlock getPrevious() {
|
||||||
|
return previous;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current block.
|
||||||
|
*
|
||||||
|
* @return the current block
|
||||||
|
*/
|
||||||
|
public BaseBlock getCurrent() {
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void undo(UndoContext context) throws WorldEditException {
|
||||||
|
checkNotNull(context.getExtent()).setBlock(position, previous, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void redo(UndoContext context) throws WorldEditException {
|
||||||
|
checkNotNull(context.getExtent()).setBlock(position, current, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
49
src/main/java/com/sk89q/worldedit/history/change/Change.java
Normal file
49
src/main/java/com/sk89q/worldedit/history/change/Change.java
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* Copyright (C) WorldEdit team and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldedit.history.change;
|
||||||
|
|
||||||
|
import com.sk89q.worldedit.WorldEditException;
|
||||||
|
import com.sk89q.worldedit.history.changeset.ChangeSet;
|
||||||
|
import com.sk89q.worldedit.history.UndoContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes a change that can be undone or re-applied.
|
||||||
|
*/
|
||||||
|
public interface Change {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform an undo. This method may not be available if the object
|
||||||
|
* was returned from {@link ChangeSet#forwardIterator()}.
|
||||||
|
*
|
||||||
|
* @param context a context for undo
|
||||||
|
* @throws WorldEditException on an error
|
||||||
|
*/
|
||||||
|
void undo(UndoContext context) throws WorldEditException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform an redo. This method may not be available if the object
|
||||||
|
* was returned from {@link ChangeSet#backwardIterator()} ()}.
|
||||||
|
*
|
||||||
|
* @param context a context for redo
|
||||||
|
* @throws WorldEditException on an error
|
||||||
|
*/
|
||||||
|
void redo(UndoContext context) throws WorldEditException;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* Copyright (C) WorldEdit team and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldedit.history.changeset;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import com.sk89q.worldedit.history.change.Change;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores all {@link Change}s in an {@link ArrayList}.
|
||||||
|
*/
|
||||||
|
public class ArrayListHistory implements ChangeSet {
|
||||||
|
|
||||||
|
private final List<Change> changes = new ArrayList<Change>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void add(Change change) {
|
||||||
|
checkNotNull(change);
|
||||||
|
changes.add(change);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<Change> backwardIterator() {
|
||||||
|
return Lists.reverse(changes).iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<Change> forwardIterator() {
|
||||||
|
return changes.iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int size() {
|
||||||
|
return changes.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* Copyright (C) WorldEdit team and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldedit.history.changeset;
|
||||||
|
|
||||||
|
import com.google.common.base.Function;
|
||||||
|
import com.google.common.collect.Iterators;
|
||||||
|
import com.sk89q.worldedit.BlockVector;
|
||||||
|
import com.sk89q.worldedit.DoubleArrayList;
|
||||||
|
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||||
|
import com.sk89q.worldedit.extent.Extent;
|
||||||
|
import com.sk89q.worldedit.history.change.BlockChange;
|
||||||
|
import com.sk89q.worldedit.history.change.Change;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
import static java.util.Map.Entry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An extension of {@link ArrayListHistory} that stores {@link BlockChange}s
|
||||||
|
* separately in two {@link ArrayList}s.
|
||||||
|
* </p>
|
||||||
|
* Whether this is a good idea or not is highly questionable, but this class
|
||||||
|
* exists because this is how history was implemented in WorldEdit for
|
||||||
|
* many years.
|
||||||
|
*/
|
||||||
|
public class BlockOptimizedHistory extends ArrayListHistory {
|
||||||
|
|
||||||
|
private final DoubleArrayList<BlockVector, BaseBlock> previous = new DoubleArrayList<BlockVector, BaseBlock>(true);
|
||||||
|
private final DoubleArrayList<BlockVector, BaseBlock> current = new DoubleArrayList<BlockVector, BaseBlock>(false);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void add(Change change) {
|
||||||
|
checkNotNull(change);
|
||||||
|
|
||||||
|
if (change instanceof BlockChange) {
|
||||||
|
BlockChange blockChange = (BlockChange) change;
|
||||||
|
BlockVector position = blockChange.getPosition();
|
||||||
|
previous.put(position, blockChange.getPrevious());
|
||||||
|
current.put(position, blockChange.getCurrent());
|
||||||
|
} else {
|
||||||
|
super.add(change);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<Change> forwardIterator() {
|
||||||
|
return Iterators.concat(
|
||||||
|
super.forwardIterator(),
|
||||||
|
Iterators.transform(current.iterator(), createTransform()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<Change> backwardIterator() {
|
||||||
|
return Iterators.concat(
|
||||||
|
super.backwardIterator(),
|
||||||
|
Iterators.transform(previous.iterator(true), createTransform()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int size() {
|
||||||
|
return super.size() + previous.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a function that transforms each entry from the double array lists' iterator
|
||||||
|
* into an {@link Change}.
|
||||||
|
*
|
||||||
|
* @return a function
|
||||||
|
*/
|
||||||
|
private Function<Entry<BlockVector, BaseBlock>, Change> createTransform() {
|
||||||
|
return new Function<Entry<BlockVector, BaseBlock>, Change>() {
|
||||||
|
@Override
|
||||||
|
public Change apply(Entry<BlockVector, BaseBlock> entry) {
|
||||||
|
return new BlockChange(entry.getKey(), entry.getValue(), entry.getValue());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* Copyright (C) WorldEdit team and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldedit.history.changeset;
|
||||||
|
|
||||||
|
import com.sk89q.worldedit.history.change.Change;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tracks a set of undoable operations and allows their undo and redo. The
|
||||||
|
* entirety of a change set should be undone and redone at once.
|
||||||
|
*/
|
||||||
|
public interface ChangeSet {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the given change to the history.
|
||||||
|
*
|
||||||
|
* @param change the change
|
||||||
|
*/
|
||||||
|
void add(Change change);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a backward directed iterator that can be used for undo.
|
||||||
|
* </p>
|
||||||
|
* The iterator may return the changes out of order, as long as the final
|
||||||
|
* result after all changes have been applied is correct.
|
||||||
|
*
|
||||||
|
* @return a undo directed iterator
|
||||||
|
*/
|
||||||
|
Iterator<Change> backwardIterator();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a forward directed iterator that can be used for redo.
|
||||||
|
* </p>
|
||||||
|
* The iterator may return the changes out of order, as long as the final
|
||||||
|
* result after all changes have been applied is correct.
|
||||||
|
*
|
||||||
|
* @return a forward directed iterator
|
||||||
|
*/
|
||||||
|
Iterator<Change> forwardIterator();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the number of stored changes.
|
||||||
|
*
|
||||||
|
* @return the change count
|
||||||
|
*/
|
||||||
|
int size();
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user