sk89q/worldedit — pull request #293 by sk89q (2014-04-03 05:13:44+00:00)
Title: WorldEdit 6.x

This changes the version of WorldEdit to **6.0.0-SNAPSHOT**. I would like to merge this into `master` within the next 1-2 days unless something comes up.

Ideally, I would like to test various WorldEdit-using plugins to see if anything breaks that we can rectify on our end.

Goals
-----

* Rewrite most operations (//set, //replace) to be easily split up into several passes that can be executed over several ticks.
* Make better use of `Pattern`s, `Mask`s, `Region`s and other long-available abstractions in WorldEdit.
* Reorganize the packages in WorldEdit so that there are fewer top level packages.
* Massively reduce the amount of code duplication present in `EditSession`.
* Breakup complex logic (block reordering etc.) in `EditSession`.
* Maintain or exceed performance of operations after the changes.
* Better document WorldEdit code and add preconditions whenever possible.
* Make it easier to implement support for entities (in addition to blocks) in all operations.
* Replace `EditSessionFactory` with a better alternative that is forward-compatible and can support multiple plugins at a time.
* Make use of Guava, which is now included on all platforms that WorldEdit is available on (Bukkit, Forge, vanilla Minecraft, Canary, MCEdu, etc.)

Challenges
----------

* High source and binary compatibility must be kept for third-party plugins that make use of WorldEdit.
* Non-backwards compatible binary changes should not break important plugins such as block loggers due to `LinkageError`s such as `NoClassDefFoundError`.

Changes
-------

### What's New

* Introduced new `Operation` interface and related classes that supports executing tasks over several ticks.
* Added new `Extent` interface that abstracts block operations (and in the future, entity operations) as they apply to worlds, clipboards, .schematic files, and so on.
* Added new `Pattern` and `Mask` interfaces to replace the old ones, which are still in WorldEdit but are deprecated. The new classes use the new pattern and mask interfaces.
* Added new 2D versions of patterns and masks.
* Added new `Transform` interface for performing `Vector` transforms, with `AffineTransform` and `Identity` as implementations.
* Added new `ChangeSet` and `Change` history objects that supports storing changes other than for blocks.
* Added new `EventBus` class (borrowed from Guava, but with changes) for sending events internally within WorldEdit.
* Added new `NoiseGenerator` for generating noise in 2D and 3D.
* Added new `internal.*` package for internal classes.

### What's Changed

* Rewrote most calls in `EditSession` to use a functional approach that reduces code duplication.
* Moved complex block setting logic from `EditSession` into a dozen different `Extent` implementations.
* Removed `EditSessionFactory`. Added a new event bus to allow block loggers and other plugins to hook into block setting.
* Reorganized, renamed, and removed lesser-used packages like `snapshots.*` and `data.*`
* Removed `foundation.*` package.
* Added new **bukkit**, **bukkit-test** and **legacy** source roots.

### What's Broke

* Block loggers and "async implementations" that currently hook into WorldEdit via an `EditSessionFactory` no longer can do so via that method, and may break due to a binary-incompatible change to `EditSessionFactory` (a change may be added to reduce this binary-incompatibility change, but the removal of `EditSessionFactory` will proceed).
* Platform implementions of WorldEdit that are not maintained by us may break due to changes to packages. The notable change is that `BlockBag` was moved to a different package.
* Plugins that use of the snapshot or chunk loading classes in WorldEdit (a number that is presumably very small) will break.

### What Shouldn't Have Broken

* Plugins that use WorldEdit's selections.
* Plugins that use WorldEdit to load/save schematic files or copy and paste portions of worlds.

### What's Left

* Finish rewriting functions in `EditSession` to use the new visitor pattern.
* Rewrite the clipboard and schematic loading code to be `Extent`-compatible.
* Make WorldEdit actually split operations over several ticks.
* Move the functions out of `EditSession` into a set of utility classes with static methods that create `Operation`s for the various commands. (i.e. `AnalyisCommands.count(Region, Mask)` would return an `Operation` that can be run). All methods in `EditSession` would then be deprecated.
* Do something about the change to block string IDs and deprecate `BlockID` and `BlockType`.
* Add support for entities across the board.
* Switch to a declarative command registration framework (i.e. the `new-commands` branch or something similar).
* *Maybe* make WorldEdit a singleton, and then having platform implementations register their implementation on the singleton (i.e. `WorldEdit.getInstance().registerImpl(bukkit)`).
* Add localication, support for calling commands from console, and so on...

Sample Code
-----------

### Stacking a Region (//stack)

`ForwardExtentCopy` is a general purpose `Extent` to `Extent` copy operation that can be used for stacking, copying, pasting, and so on.

```java
Vector size = region.getMaximumPoint().subtract(region.getMinimumPoint()).add(1, 1, 1);
Vector to = region.getMinimumPoint();
ForwardExtentCopy copy = new ForwardExtentCopy(this, region, this, to);
copy.setRepetitions(count);
copy.setTransform(new AffineTransform().translate(dir.multiply(size)));
Operations.completeLegacy(copy);
```

### Adding a Block Logger

`AbstractLoggingExtent` is an abstract class that is intended for block loggers, as it will automatically simplify the logging operation to the act of overriding a `onBlockChange` method.

```java
WorldEdit.getInstance().getEventBus().register(new Object() {
@Subscribe
public void wrapForLogging(EditSessionEvent event) {
LocalPlayer player = event.getPlayer();

event.setExtent(new AbstractLoggingExtent(event.getExtent()) {
@Override
protected void onBlockChange(Vector position, BaseBlock newBlock) {
System.out.println(player + " set block @ " + position);
}
});
}
});
```