Improved web integrated clipboard
Fully fledged brush visualization (modes 0-2): //br vis
Brush targeting modes (0-3): //br target
Brush scroll actions: //br scroll
- change clipboard from directory or web
- change mask
- change pattern
- change range
- change size
- change target mode
Build multi-brushes (choose the brush for left click and right click
individually)
- //br primary
- //br secondary
- Changing the pattern/mask will affect the currently selected brush,
not both
Changes to brush behavior
- spline connects by clicking the same spot twice
- line/copy brush tweaks
Schematics now default per user
- To save/load globally use "../" before the filename
Easily save a schematic to a directory
- `//schem save folder/` will choose save a the next lowest free number
Improved block parsing
Add resettable brushes
- e.g. line brush resets points by shift + left click
This commit is contained in:
Jesse Boyd 2017-03-04 00:54:50 +11:00
parent 9c74d0b981
commit 04603b7cee
No known key found for this signature in database
GPG Key ID: 59F1DE6293AF6E1F
55 changed files with 1635 additions and 837 deletions

View File

@ -1,22 +1,18 @@
package com.boydti.fawe.bukkit;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.brush.MovableBrush;
import com.boydti.fawe.object.brush.scroll.ScrollableBrush;
import com.boydti.fawe.object.brush.visualization.VisualBrush;
import com.boydti.fawe.object.brush.MovableTool;
import com.boydti.fawe.object.brush.ResettableTool;
import com.boydti.fawe.object.brush.scroll.ScrollTool;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.command.tool.BrushTool;
import com.sk89q.worldedit.command.tool.InvalidToolBindException;
import com.sk89q.worldedit.command.tool.Tool;
import com.sk89q.worldedit.command.tool.brush.Brush;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerItemHeldEvent;
import org.bukkit.event.player.PlayerMoveEvent;
@ -40,39 +36,25 @@ public class BrushListener implements Listener {
LocalSession session = fp.getSession();
Tool tool = session.getTool(player);
if (tool != null) {
ScrollableBrush scrollable;
if (tool instanceof ScrollableBrush) {
scrollable = (ScrollableBrush) tool;
} else if (tool instanceof BrushTool) {
Brush brush = ((BrushTool) tool).getBrush();
scrollable = brush instanceof ScrollableBrush ? (ScrollableBrush) brush : null;
} else {
return;
if (tool instanceof ScrollTool) {
}
if (scrollable != null) {
final int slot = event.getNewSlot();
final int oldSlot = event.getPreviousSlot();
final int ri;
if ((((slot - oldSlot) <= 4) && ((slot - oldSlot) > 0)) || (((slot - oldSlot) < -4))) {
ri = 1;
} else {
ri = -1;
}
if (scrollable.increment(ri)) {
final PlayerInventory inv = bukkitPlayer.getInventory();
final ItemStack item = inv.getItem(slot);
final ItemStack newItem = inv.getItem(oldSlot);
inv.setItem(slot, newItem);
inv.setItem(oldSlot, item);
bukkitPlayer.updateInventory();
if (scrollable instanceof VisualBrush) {
try {
((VisualBrush) scrollable).queueVisualization(fp);
} catch (Throwable e) {
WorldEdit.getInstance().getPlatformManager().handleThrowable(e, player);
}
}
}
final int slot = event.getNewSlot();
final int oldSlot = event.getPreviousSlot();
final int ri;
if ((((slot - oldSlot) <= 4) && ((slot - oldSlot) > 0)) || (((slot - oldSlot) < -4))) {
ri = 1;
} else {
ri = -1;
}
ScrollTool scrollable = (ScrollTool) tool;
if (scrollable.increment(player, ri)) {
final PlayerInventory inv = bukkitPlayer.getInventory();
final ItemStack item = inv.getItem(slot);
final ItemStack newItem = inv.getItem(oldSlot);
inv.setItem(slot, newItem);
inv.setItem(oldSlot, item);
bukkitPlayer.updateInventory();
}
}
}
@ -88,21 +70,8 @@ public class BrushListener implements Listener {
LocalSession session = fp.getSession();
Tool tool = session.getTool(player);
if (tool != null) {
if (tool instanceof MovableBrush) {
((MovableBrush) tool).move(player);
} else if (tool instanceof BrushTool) {
Brush brush = ((BrushTool) tool).getBrush();
if (brush instanceof MovableBrush) {
if (((MovableBrush) brush).move(player)) {
if (brush instanceof VisualBrush) {
try {
((VisualBrush) brush).queueVisualization(fp);
} catch (Throwable e) {
WorldEdit.getInstance().getPlatformManager().handleThrowable(e, player);
}
}
}
}
if (tool instanceof MovableTool) {
((MovableTool) tool).move(player);
}
}
}
@ -110,26 +79,21 @@ public class BrushListener implements Listener {
@EventHandler(priority = EventPriority.LOWEST)
public void onPlayerInteract(final PlayerInteractEvent event) {
switch (event.getAction()) {
case LEFT_CLICK_AIR:
case LEFT_CLICK_BLOCK:
Player bukkitPlayer = event.getPlayer();
if (!bukkitPlayer.isSneaking()) {
return;
}
FawePlayer<Object> fp = FawePlayer.wrap(bukkitPlayer);
com.sk89q.worldedit.entity.Player player = fp.getPlayer();
LocalSession session = fp.getSession();
int item = player.getItemInHand();
Tool tool = session.getTool(item);
if (tool != null) {
try {
session.setTool(item, null, player);
BBC.TOOL_NONE.send(player);
} catch (InvalidToolBindException e) {
e.printStackTrace();
}
Player bukkitPlayer = event.getPlayer();
if (bukkitPlayer.isSneaking()) {
if (event.getAction() == Action.PHYSICAL) {
return;
}
FawePlayer<Object> fp = FawePlayer.wrap(bukkitPlayer);
com.sk89q.worldedit.entity.Player player = fp.getPlayer();
LocalSession session = fp.getSession();
int item = player.getItemInHand();
Tool tool = session.getTool(item);
if (tool instanceof ResettableTool) {
if (((ResettableTool) tool).reset()) {
event.setCancelled(true);
}
}
}
}
}

View File

@ -79,6 +79,7 @@ import com.sk89q.worldedit.function.mask.SolidBlockMask;
import com.sk89q.worldedit.function.operation.ChangeSetExecutor;
import com.sk89q.worldedit.function.operation.ForwardExtentCopy;
import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.function.pattern.BlockPattern;
import com.sk89q.worldedit.function.pattern.ClipboardPattern;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.function.pattern.Patterns;
@ -450,6 +451,7 @@ public class Fawe {
ClipboardPattern.inject(); // Optimizations
HashTagPatternParser.inject(); // Add new patterns
DefaultBlockParser.inject(); // Fix block lookups
BlockPattern.inject(); // Optimization
// Mask
Mask.inject(); // Extend deprecated mask
BlockMask.inject(); // Optimizations

View File

@ -48,6 +48,7 @@ public enum BBC {
WORLDEDIT_OOM_ADMIN("&cPossible options:\n&8 - &7//fast\n&8 - &7Do smaller edits\n&8 - &7Allocate more memory\n&8 - &7Disable `max-memory-percent`", "Info"),
COMPRESSED("History compressed. Saved ~ %s0b (%s1x smaller)", "Info"),
WEB_UNAUTHORIZED("Only links from the configured web host is allowed: %s0", "Error"),
ACTION_COMPLETE("Action completed in %s0 seconds", "Info"),
GENERATING_LINK("Uploading %s, please wait...", "Web"),
GENERATING_LINK_FAILED("&cFailed to generate download link!", "Web"),
@ -104,6 +105,9 @@ public enum BBC {
SELECTION_CLEARED("Selection cleared", "WorldEdit.Selection"),
BRUSH_NONE("You aren't holding a brush!", "WorldEdit.Brush"),
BRUSH_SCROLL_ACTION_SET("Set scroll action to %s0", "WorldEdit.Brush"),
BRUSH_VISUAL_MODE_SET("Set visual mode to %s0", "WorldEdit.Brush"),
BRUSH_TARGET_MODE_SET("Set target mode to %s0", "WorldEdit.Brush"),
BRUSH_BUTCHER("Butcher brush equiped (%s0)", "WorldEdit.Brush"),
BRUSH_CLIPBOARD("Clipboard brush shape equipped", "WorldEdit.Brush"),
BRUSH_CYLINDER("Cylinder brush shape equipped (%s0 by %s1).", "WorldEdit.Brush"),
@ -117,15 +121,14 @@ public enum BBC {
BRUSH_SMOOTH("Smooth brush equipped (%s0 x %s1 using %s2. Note: Use the blend brush if you want to smooth overhangs or caves.).", "WorldEdit.Brush"),
BRUSH_SPHERE("Sphere brush shape equipped (%s0).", "WorldEdit.Brush"),
BRUSH_LINE("Line brush shape equipped (%s0).", "WorldEdit.Brush"),
BRUSH_SPLINE("Line brush shape equipped (%s0). Right click an end to add a shape", "WorldEdit.Brush"),
BRUSH_SPLINE_PRIMARY("Added position, left click to spline them together!", "WorldEdit.Brush"),
BRUSH_SPLINE("Spline brush shape equipped (%s0). Right click an end to add a shape", "WorldEdit.Brush"),
BRUSH_SPLINE_PRIMARY("Added position, Click the same spot to join!", "WorldEdit.Brush"),
BRUSH_SPLINE_SECONDARY_ERROR("Not enough positions set!", "WorldEdit.Brush"),
BRUSH_SPLINE_SECONDARY("Created spline", "WorldEdit.Brush"),
BRUSH_BLEND_BALL("Blend ball brush equipped (%s0).", "WorldEdit.Brush"),
BRUSH_BLEND_BALL("Blend ball brush equipped (%s0).", "WorldEdit.Brush"),
BRUSH_ERODE("Erode brush equipped (%s0). Right click to erode, left click to pull.", "WorldEdit.Brush"),
BRUSH_CIRCLE("Circle brush equipped (%s0). Right click to create a circle.", "WorldEdit.Brush"),
BRUSH_RECURSIVE("Recursive brush equipped (%s0).", "WorldEdit.Brush"),
BRUSH_PASTE_NONE("Nothing to paste", "WorldEdit.Brush"),
BRUSH_SIZE("Brush size set", "WorldEdit.Brush"),
BRUSH_RANGE("Brush size set", "WorldEdit.Brush"),
BRUSH_MASK_DISABLED("Brush mask disabled", "WorldEdit.Brush"),

View File

@ -31,7 +31,7 @@ public class PseudoRandom {
}
public double nextDouble() {
return Math.max(0, Math.min(1, Math.abs(nextLong() / Long.MAX_VALUE)));
return Math.max(0, Math.min(1, Math.abs((double) nextLong() / Long.MAX_VALUE)));
}
public int random(final int n) {

View File

@ -0,0 +1,19 @@
package com.boydti.fawe.object.brush;
import com.boydti.fawe.object.brush.scroll.ScrollAction;
import com.boydti.fawe.object.extent.ResettableExtent;
import com.sk89q.worldedit.command.tool.brush.Brush;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.pattern.Pattern;
public class BrushSettings {
public Brush brush = null;
public Mask mask = null;
public Mask sourceMask = null;
public ResettableExtent transform = null;
public Pattern material;
public double size = 1;
public String permission;
public ScrollAction scrollAction;
}

View File

@ -1,39 +1,31 @@
package com.boydti.fawe.object.brush;
import com.boydti.fawe.object.brush.visualization.VisualBrush;
import com.boydti.fawe.object.collection.LocalBlockVectorSet;
import com.boydti.fawe.wrappers.LocationMaskedPlayerWrapper;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.command.tool.BrushTool;
import com.sk89q.worldedit.command.tool.brush.Brush;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.math.transform.AffineTransform;
public class CircleBrush extends VisualBrush {
public class CircleBrush implements Brush {
private final Player player;
private final BrushTool tool;
public CircleBrush(BrushTool tool, Player player) {
super(tool);
this.tool = tool;
this.player = LocationMaskedPlayerWrapper.unwrap(player);
}
@Override
public void build(BrushTool.BrushAction action, EditSession editSession, Vector position, Pattern pattern, double size) throws MaxChangedBlocksException {
switch (action) {
case PRIMARY:
LocalBlockVectorSet set = new LocalBlockVectorSet();
int radius = (int) size;
Vector normal = position.subtract(player.getPosition());
editSession.makeCircle(position, pattern, size, size, size, false, normal);
break;
case SECONDARY:
break;
}
public void build(EditSession editSession, Vector position, Pattern pattern, double size) throws MaxChangedBlocksException {
Vector normal = position.subtract(player.getPosition());
editSession.makeCircle(position, pattern, size, size, size, false, normal);
}
private static Vector any90Rotate(Vector normal) {
private Vector any90Rotate(Vector normal) {
normal = normal.normalize();
if (normal.getX() == 1 || normal.getY() == 1 || normal.getZ() == 1) {
return new Vector(normal.getZ(), normal.getX(), normal.getY());

View File

@ -51,7 +51,7 @@ public class CommandBrush implements Brush {
String[] cmds = replaced.split(";");
for (String cmd : cmds) {
CommandEvent event = new CommandEvent(wePlayer, cmd);
CommandManager.getInstance().handleCommand(event);
CommandManager.getInstance().handleCommandOnCurrentThread(event);
}
}
}

View File

@ -2,16 +2,17 @@ package com.boydti.fawe.object.brush;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.brush.visualization.VisualExtent;
import com.boydti.fawe.object.clipboard.ResizableClipboardBuilder;
import com.boydti.fawe.object.function.NullRegionFunction;
import com.boydti.fawe.object.function.mask.AbstractDelegateMask;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.EmptyClipboardException;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.command.tool.BrushTool;
import com.sk89q.worldedit.command.tool.brush.Brush;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.Masks;
@ -22,70 +23,74 @@ import com.sk89q.worldedit.function.visitor.RecursiveVisitor;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.session.ClipboardHolder;
public class CopyPastaBrush implements DoubleActionBrush {
public class CopyPastaBrush implements Brush, ResettableTool {
private final BrushTool tool;
private final LocalSession session;
public CopyPastaBrush(BrushTool tool) {
public CopyPastaBrush(BrushTool tool, LocalSession session) {
this.tool = tool;
session.setClipboard(null);
this.session = session;
}
@Override
public void build(BrushTool.BrushAction action, final EditSession editSession, Vector position, Pattern pattern, double size) throws MaxChangedBlocksException {
public boolean reset() {
session.setClipboard(null);
return true;
}
@Override
public void build(final EditSession editSession, Vector position, Pattern pattern, double size) throws MaxChangedBlocksException {
FawePlayer fp = editSession.getPlayer();
LocalSession session = fp.getSession();
switch (action) {
case SECONDARY: {
Mask mask = tool.getMask();
if (mask == null) {
mask = Masks.alwaysTrue();
}
final ResizableClipboardBuilder builder = new ResizableClipboardBuilder(editSession.getWorld());
final int size2 = (int) (size * size);
final int minY = position.getBlockY();
mask = new AbstractDelegateMask(mask) {
@Override
public boolean test(Vector vector) {
if (super.test(vector) && vector.getBlockY() >= minY) {
BaseBlock block = editSession.getLazyBlock(vector);
if (block != EditSession.nullBlock) {
builder.add(vector, EditSession.nullBlock, block);
return true;
}
}
return false;
}
};
// Add origin
mask.test(position);
RecursiveVisitor visitor = new RecursiveVisitor(mask, new NullRegionFunction(), (int) size, editSession);
visitor.visit(position);
Operations.completeBlindly(visitor);
// Build the clipboard
Clipboard clipboard = builder.build();
clipboard.setOrigin(position);
ClipboardHolder holder = new ClipboardHolder(clipboard, editSession.getWorld().getWorldData());
session.setClipboard(holder);
int blocks = builder.size();
BBC.COMMAND_COPY.send(fp, blocks);
ClipboardHolder clipboard = session.getExistingClipboard();
if (clipboard == null) {
if (editSession.getExtent() instanceof VisualExtent) {
return;
}
case PRIMARY: {
try {
ClipboardHolder holder = session.getClipboard();
Clipboard clipboard = holder.getClipboard();
Region region = clipboard.getRegion();
Vector centerOffset = region.getCenter().subtract(clipboard.getOrigin());
Operation operation = holder
.createPaste(editSession, editSession.getWorld().getWorldData())
.to(position.add(0, 1, 0))
.ignoreAirBlocks(true)
.build();
Operations.completeLegacy(operation);
} catch (EmptyClipboardException e) {
BBC.BRUSH_PASTE_NONE.send(fp);
}
Mask mask = tool.getMask();
if (mask == null) {
mask = Masks.alwaysTrue();
}
final ResizableClipboardBuilder builder = new ResizableClipboardBuilder(editSession.getWorld());
final int size2 = (int) (size * size);
final int minY = position.getBlockY();
mask = new AbstractDelegateMask(mask) {
@Override
public boolean test(Vector vector) {
if (super.test(vector) && vector.getBlockY() >= minY) {
BaseBlock block = editSession.getLazyBlock(vector);
if (block != EditSession.nullBlock) {
builder.add(vector, EditSession.nullBlock, block);
return true;
}
}
return false;
}
};
// Add origin
mask.test(position);
RecursiveVisitor visitor = new RecursiveVisitor(mask, new NullRegionFunction(), (int) size, editSession);
visitor.visit(position);
Operations.completeBlindly(visitor);
// Build the clipboard
Clipboard newClipboard = builder.build();
newClipboard.setOrigin(position);
ClipboardHolder holder = new ClipboardHolder(newClipboard, editSession.getWorld().getWorldData());
session.setClipboard(holder);
int blocks = builder.size();
BBC.COMMAND_COPY.send(fp, blocks);
return;
} else {
Clipboard faweClip = clipboard.getClipboard();
Region region = faweClip.getRegion();
Vector centerOffset = region.getCenter().subtract(faweClip.getOrigin());
Operation operation = clipboard
.createPaste(editSession, editSession.getWorld().getWorldData())
.to(position.add(0, 1, 0))
.ignoreAirBlocks(true)
.build();
Operations.completeLegacy(operation);
}
}
}

View File

@ -1,18 +0,0 @@
package com.boydti.fawe.object.brush;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.command.tool.BrushTool;
import com.sk89q.worldedit.command.tool.brush.Brush;
import com.sk89q.worldedit.function.pattern.Pattern;
public interface DoubleActionBrush extends Brush {
@Override
default void build(EditSession editSession, Vector position, Pattern pattern, double size) throws MaxChangedBlocksException {
build(BrushTool.BrushAction.PRIMARY, editSession, position, pattern, size);
}
public void build(BrushTool.BrushAction action, EditSession editSession, Vector position, Pattern pattern, double size) throws MaxChangedBlocksException;
}

View File

@ -10,39 +10,22 @@ import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.command.tool.BrushTool;
import com.sk89q.worldedit.command.tool.brush.Brush;
import com.sk89q.worldedit.function.pattern.Pattern;
import java.util.Arrays;
public class ErodeBrush implements DoubleActionBrush {
public class ErodeBrush implements Brush {
private PseudoRandom rand = new PseudoRandom();
private static final Vector[] FACES_TO_CHECK = {new Vector(0, 0, 1), new Vector(0, 0, -1), new Vector(0, 1, 0), new Vector(0, -1, 0), new Vector(1, 0, 0), new Vector(-1, 0, 0)};
@Override
public void build(BrushTool.BrushAction action, EditSession editSession, Vector position, Pattern pattern, double size) throws MaxChangedBlocksException {
switch (action) {
case PRIMARY: {
int erodeFaces = 2;
int erodeRec = 1;
int fillFaces = 5;
int fillRec = 1;
this.erosion(editSession, erodeFaces, erodeRec, fillFaces, fillRec, position, size);
break;
}
case SECONDARY: {
int erodeFaces = 6;
int erodeRec = 0;
int fillFaces = 1;
int fillRec = 1;
this.erosion(editSession, erodeFaces, erodeRec, fillFaces, fillRec, position, size);
break;
}
}
public void build(EditSession editSession, Vector position, Pattern pattern, double size) throws MaxChangedBlocksException {
this.erosion(editSession, 2, 1, 5, 1, position, size);
}
protected void erosion(final EditSession es, int erodeFaces, int erodeRec, int fillFaces, int fillRec, Vector target, double size) {
public void erosion(final EditSession es, int erodeFaces, int erodeRec, int fillFaces, int fillRec, Vector target, double size) {
int brushSize = (int) size + 1;
int brushSizeSquared = (int) (size * size);
int dimension = brushSize * 2 + 1;
@ -86,7 +69,7 @@ public class ErodeBrush implements DoubleActionBrush {
}, true);
}
private void fillIteration(int brushSize, int brushSizeSquared, int fillFaces, FaweClipboard current, FaweClipboard target) {
public void fillIteration(int brushSize, int brushSizeSquared, int fillFaces, FaweClipboard current, FaweClipboard target) {
int[] frequency = null;
for (int x = -brushSize; x <= brushSize; x++) {
int x2 = x * x;
@ -130,7 +113,7 @@ public class ErodeBrush implements DoubleActionBrush {
}
}
private void erosionIteration(int brushSize, int brushSizeSquared, int erodeFaces, FaweClipboard current, FaweClipboard target) {
public void erosionIteration(int brushSize, int brushSizeSquared, int erodeFaces, FaweClipboard current, FaweClipboard target) {
int[] frequency = null;
for (int x = -brushSize; x <= brushSize; x++) {
int x2 = x * x;

View File

@ -18,13 +18,13 @@ public class FlattenBrush extends HeightBrush {
}
@Override
public void build(BrushTool.BrushAction action, EditSession editSession, Vector position, Pattern pattern, double sizeDouble) throws MaxChangedBlocksException {
public void build(EditSession editSession, Vector position, Pattern pattern, double sizeDouble) throws MaxChangedBlocksException {
int size = (int) sizeDouble;
Mask mask = tool.getMask();
if (mask == Masks.alwaysTrue() || mask == Masks.alwaysTrue2D()) {
mask = null;
}
heightMap.setSize(size);
heightMap.apply(editSession, mask, position, size, rotation, action == BrushTool.BrushAction.PRIMARY ? yscale : -yscale, true, true);
heightMap.apply(editSession, mask, position, size, rotation, yscale, true, true);
}
}

View File

@ -7,6 +7,7 @@ import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.command.tool.BrushTool;
import com.sk89q.worldedit.command.tool.brush.Brush;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.Masks;
@ -14,7 +15,7 @@ import com.sk89q.worldedit.function.pattern.Pattern;
import java.io.IOException;
import java.io.InputStream;
public class HeightBrush implements DoubleActionBrush {
public class HeightBrush implements Brush {
public final ScalableHeightMap heightMap;
public final int rotation;
@ -43,13 +44,13 @@ public class HeightBrush implements DoubleActionBrush {
}
@Override
public void build(BrushTool.BrushAction action, EditSession editSession, Vector position, Pattern pattern, double sizeDouble) throws MaxChangedBlocksException {
public void build(EditSession editSession, Vector position, Pattern pattern, double sizeDouble) throws MaxChangedBlocksException {
int size = (int) sizeDouble;
Mask mask = tool.getMask();
if (mask == Masks.alwaysTrue() || mask == Masks.alwaysTrue2D()) {
mask = null;
}
heightMap.setSize(size);
heightMap.apply(editSession, mask, position, size, rotation, action == BrushTool.BrushAction.PRIMARY ? yscale : -yscale, true, false);
heightMap.apply(editSession, mask, position, size, rotation, yscale, true, false);
}
}

View File

@ -3,11 +3,11 @@ package com.boydti.fawe.object.brush;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.command.tool.BrushTool;
import com.sk89q.worldedit.command.tool.brush.Brush;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.function.pattern.Patterns;
public class LineBrush implements DoubleActionBrush {
public class LineBrush implements Brush, ResettableTool {
private final boolean shell, select, flat;
private Vector pos1;
@ -19,20 +19,21 @@ public class LineBrush implements DoubleActionBrush {
}
@Override
public void build(BrushTool.BrushAction action, EditSession editSession, Vector position, final Pattern pattern, double size) throws MaxChangedBlocksException {
switch (action) {
case PRIMARY:
if (pos1 == null) {
pos1 = position;
return;
}
editSession.drawLine(Patterns.wrap(pattern), pos1, position, size, !shell, flat);
if (!select) {
return;
}
case SECONDARY:
pos1 = position;
return;
public void build(EditSession editSession, Vector position, final Pattern pattern, double size) throws MaxChangedBlocksException {
if (pos1 == null) {
pos1 = position;
return;
}
editSession.drawLine(Patterns.wrap(pattern), pos1, position, size, !shell, flat);
if (!select) {
pos1 = null;
return;
}
}
@Override
public boolean reset() {
pos1 = null;
return true;
}
}

View File

@ -2,6 +2,6 @@ package com.boydti.fawe.object.brush;
import com.sk89q.worldedit.entity.Player;
public interface MovableBrush {
public interface MovableTool {
public boolean move(Player player);
}

View File

@ -3,19 +3,11 @@ package com.boydti.fawe.object.brush;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.command.tool.BrushTool;
import com.sk89q.worldedit.function.pattern.Pattern;
public class RaiseBrush implements DoubleActionBrush {
public class RaiseBrush extends ErodeBrush {
@Override
public void build(BrushTool.BrushAction action, EditSession editSession, Vector position, Pattern pattern, double size) throws MaxChangedBlocksException {
switch (action) {
case PRIMARY:
break;
case SECONDARY:
break;
}
public void build(EditSession editSession, Vector position, Pattern pattern, double size) throws MaxChangedBlocksException {
this.erosion(editSession, 6, 0, 1, 1, position, size);
}
}

View File

@ -0,0 +1,5 @@
package com.boydti.fawe.object.brush;
public interface ResettableTool {
boolean reset();
}

View File

@ -11,6 +11,7 @@ import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.command.tool.BrushTool;
import com.sk89q.worldedit.command.tool.brush.Brush;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.function.RegionFunction;
import com.sk89q.worldedit.function.mask.Mask;
@ -22,9 +23,11 @@ import com.sk89q.worldedit.math.interpolation.Node;
import com.sk89q.worldedit.math.transform.AffineTransform;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class SplineBrush implements DoubleActionBrush {
public class SplineBrush implements Brush {
public static int MAX_POINTS = 15;
private ArrayList<ArrayList<Vector>> positionSets;
@ -33,6 +36,7 @@ public class SplineBrush implements DoubleActionBrush {
private final BrushTool tool;
private final LocalSession session;
private final Player player;
private Vector position;
public SplineBrush(Player player, LocalSession session, BrushTool tool) {
this.tool = tool;
@ -42,7 +46,7 @@ public class SplineBrush implements DoubleActionBrush {
}
@Override
public void build(BrushTool.BrushAction action, EditSession editSession, final Vector position, Pattern pattern, double size) throws MaxChangedBlocksException {
public void build(EditSession editSession, final Vector position, Pattern pattern, double size) throws MaxChangedBlocksException {
Mask mask = tool.getMask();
if (mask == null) {
mask = new IdMask(editSession);
@ -54,91 +58,100 @@ public class SplineBrush implements DoubleActionBrush {
return;
}
int originalSize = numSplines;
switch (action) {
case PRIMARY: {
boolean newPos = this.position == null || !position.equals(this.position);
this.position = position;
if (newPos) {
if (positionSets.size() >= MAX_POINTS) {
throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_CHECKS);
}
final ArrayList<Vector> points = new ArrayList<>();
DFSRecursiveVisitor visitor = new DFSRecursiveVisitor(mask, new RegionFunction() {
@Override
public boolean apply(Vector p) throws WorldEditException {
points.add(new Vector(p));
return true;
}
}, (int) size, 1);
Collection<Vector> directions = visitor.getDirections();
for (int x = -1; x <= 1; x++) {
for (int y = -1; y <= 1; y++) {
for (int z = -1; z <= 1; z++) {
Vector pos = new Vector(x, y, z);
if (!directions.contains(pos)) {
directions.add(pos);
if (tool.getSize() > 0) {
DFSRecursiveVisitor visitor = new DFSRecursiveVisitor(mask, new RegionFunction() {
@Override
public boolean apply(Vector p) throws WorldEditException {
points.add(new Vector(p));
return true;
}
}, (int) size, 1);
List<Vector> directions = visitor.getDirections();
for (int x = -1; x <= 1; x++) {
for (int y = -1; y <= 1; y++) {
for (int z = -1; z <= 1; z++) {
if (x != 0 || y != 0 && z != 0) {
Vector pos = new Vector(x, y, z);
if (!directions.contains(pos)) {
directions.add(pos);
}
}
}
}
}
}
visitor.visit(position);
Operations.completeBlindly(visitor);
if (points.size() > numSplines) {
numSplines = points.size();
Collections.sort(directions, new Comparator<Vector>() {
@Override
public int compare(Vector o1, Vector o2) {
return (int) Math.signum(o1.lengthSq() - o2.lengthSq());
}
});
visitor.visit(position);
Operations.completeBlindly(visitor);
if (points.size() > numSplines) {
numSplines = points.size();
}
} else {
points.add(position);
}
this.positionSets.add(points);
player.print(BBC.getPrefix() + BBC.BRUSH_SPLINE_PRIMARY.s());
if (!visualization) {
break;
}
}
case SECONDARY: {
if (positionSets.size() < 2) {
player.print(BBC.getPrefix() + BBC.BRUSH_SPLINE_SECONDARY_ERROR.s());
return;
}
List<Vector> centroids = new ArrayList<>();
for (List<Vector> points : positionSets) {
centroids.add(getCentroid(points));
}
double tension = 0;
double bias = 0;
double continuity = 0;
double quality = 10;
final List<Node> nodes = new ArrayList<Node>(centroids.size());
for (final Vector nodevector : centroids) {
final Node n = new Node(nodevector);
n.setTension(tension);
n.setBias(bias);
n.setContinuity(continuity);
nodes.add(n);
}
Vector up = new Vector(0, 1, 0);
AffineTransform transform = new AffineTransform();
// TODO index offset based on transform
int samples = numSplines;
for (int i = 0; i < numSplines; i++) {
List<Vector> currentSpline = new ArrayList<>();
for (ArrayList<Vector> points : positionSets) {
int listSize = points.size();
int index = (int) (i * listSize / (double) (numSplines));
currentSpline.add(points.get(index));
}
editSession.drawSpline(Patterns.wrap(pattern), currentSpline, 0, 0, 0, 10, 0, true);
}
player.print(BBC.getPrefix() + BBC.BRUSH_SPLINE_SECONDARY.s());
if (visualization) {
positionSets.clear();
numSplines = 0;
} else {
numSplines = originalSize;
positionSets.remove(positionSets.size() - 1);
}
break;
}
if (positionSets.size() < 2) {
player.print(BBC.getPrefix() + BBC.BRUSH_SPLINE_SECONDARY_ERROR.s());
return;
}
List<Vector> centroids = new ArrayList<>();
for (List<Vector> points : positionSets) {
centroids.add(getCentroid(points));
}
double tension = 0;
double bias = 0;
double continuity = 0;
double quality = 10;
final List<Node> nodes = new ArrayList<Node>(centroids.size());
for (final Vector nodevector : centroids) {
final Node n = new Node(nodevector);
n.setTension(tension);
n.setBias(bias);
n.setContinuity(continuity);
nodes.add(n);
}
Vector up = new Vector(0, 1, 0);
AffineTransform transform = new AffineTransform();
// TODO index offset based on transform
int samples = numSplines;
for (int i = 0; i < numSplines; i++) {
List<Vector> currentSpline = new ArrayList<>();
for (ArrayList<Vector> points : positionSets) {
int listSize = points.size();
int index = (int) (i * listSize / (double) (numSplines));
currentSpline.add(points.get(index));
}
editSession.drawSpline(Patterns.wrap(pattern), currentSpline, 0, 0, 0, 10, 0, true);
}
player.print(BBC.getPrefix() + BBC.BRUSH_SPLINE_SECONDARY.s());
if (visualization) {
positionSets.clear();
numSplines = 0;
} else {
numSplines = originalSize;
positionSets.remove(positionSets.size() - 1);
}
}

View File

@ -4,5 +4,5 @@ public enum TargetMode {
TARGET_BLOCK_RANGE,
FOWARD_POINT_PITCH,
TARGET_POINT_HEIGHT,
TARGET_POINT_RANGE,
TARGET_FACE_RANGE,
}

View File

@ -2,7 +2,7 @@ package com.boydti.fawe.object.brush.scroll;
import com.sk89q.worldedit.command.tool.BrushTool;
public abstract class ScrollAction implements ScrollableBrush {
public abstract class ScrollAction implements ScrollTool {
public final BrushTool tool;
public ScrollAction(BrushTool tool) {

View File

@ -1,4 +1,27 @@
package com.boydti.fawe.object.brush.scroll;
public class ScrollClipboard {
import com.boydti.fawe.util.MathMan;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.command.tool.BrushTool;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.session.ClipboardHolder;
public class ScrollClipboard extends ScrollAction {
private final ClipboardHolder[] clipboards;
private final LocalSession session;
int index = 0;
public ScrollClipboard(BrushTool tool, LocalSession session, ClipboardHolder[] clipboards) {
super(tool);
this.clipboards = clipboards;
this.session = session;
}
@Override
public boolean increment(Player player, int amount) {
index = MathMan.wrap(index + amount, 0, clipboards.length - 1);
ClipboardHolder clipboard = clipboards[index];
session.setClipboard(clipboard);
return true;
}
}

View File

@ -2,6 +2,7 @@ package com.boydti.fawe.object.brush.scroll;
import com.boydti.fawe.util.MathMan;
import com.sk89q.worldedit.command.tool.BrushTool;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.function.mask.Mask;
public class ScrollMask extends ScrollAction {
@ -15,7 +16,7 @@ public class ScrollMask extends ScrollAction {
@Override
public boolean increment(int amount) {
public boolean increment(Player player, int amount) {
if (masks.length > 1) {
tool.setMask(masks[MathMan.wrap(index += amount, 0, masks.length - 1)]);
return true;

View File

@ -2,6 +2,7 @@ package com.boydti.fawe.object.brush.scroll;
import com.boydti.fawe.util.MathMan;
import com.sk89q.worldedit.command.tool.BrushTool;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.function.pattern.Pattern;
public class ScrollPattern extends ScrollAction {
@ -15,7 +16,7 @@ public class ScrollPattern extends ScrollAction {
@Override
public boolean increment(int amount) {
public boolean increment(Player player, int amount) {
if (patterns.length > 1) {
tool.setFill(patterns[MathMan.wrap(index += amount, 0, patterns.length - 1)]);
return true;

View File

@ -3,6 +3,7 @@ package com.boydti.fawe.object.brush.scroll;
import com.boydti.fawe.util.MathMan;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.command.tool.BrushTool;
import com.sk89q.worldedit.entity.Player;
public class ScrollRange extends ScrollAction {
public ScrollRange(BrushTool tool) {
@ -10,7 +11,7 @@ public class ScrollRange extends ScrollAction {
}
@Override
public boolean increment(int amount) {
public boolean increment(Player player, int amount) {
int max = WorldEdit.getInstance().getConfiguration().maxBrushRadius;
int newSize = MathMan.wrap(tool.getRange() + amount, (int) (tool.getSize() + 1), max);
tool.setRange(newSize);

View File

@ -2,6 +2,7 @@ package com.boydti.fawe.object.brush.scroll;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.command.tool.BrushTool;
import com.sk89q.worldedit.entity.Player;
public class ScrollSize extends ScrollAction {
public ScrollSize(BrushTool tool) {
@ -9,7 +10,7 @@ public class ScrollSize extends ScrollAction {
}
@Override
public boolean increment(int amount) {
public boolean increment(Player player, int amount) {
int max = WorldEdit.getInstance().getConfiguration().maxRadius;
double newSize = Math.max(0, Math.min(max, tool.getSize() + amount));
tool.setSize(newSize);

View File

@ -0,0 +1,22 @@
package com.boydti.fawe.object.brush.scroll;
import com.boydti.fawe.object.brush.TargetMode;
import com.boydti.fawe.util.MathMan;
import com.sk89q.worldedit.command.tool.BrushTool;
import com.sk89q.worldedit.entity.Player;
public class ScrollTarget extends ScrollAction {
public ScrollTarget(BrushTool tool) {
super(tool);
}
@Override
public boolean increment(Player player, int amount) {
TargetMode mode = tool.getTargetMode();
int index = mode.ordinal() + amount;
TargetMode[] modes = TargetMode.values();
TargetMode newMode = modes[MathMan.wrap(index, 0, modes.length - 1)];
tool.setTargetMode(newMode);
return true;
}
}

View File

@ -0,0 +1,7 @@
package com.boydti.fawe.object.brush.scroll;
import com.sk89q.worldedit.entity.Player;
public interface ScrollTool {
public boolean increment(Player player, int amount);
}

View File

@ -1,5 +0,0 @@
package com.boydti.fawe.object.brush.scroll;
public interface ScrollableBrush {
public boolean increment(int amount);
}

View File

@ -1,32 +0,0 @@
package com.boydti.fawe.object.brush.visualization;
import com.boydti.fawe.object.brush.DoubleActionBrush;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.command.tool.BrushTool;
import com.sk89q.worldedit.command.tool.brush.Brush;
import com.sk89q.worldedit.function.pattern.Pattern;
public class DelegateVisualBrush extends VisualBrush {
private final Brush brush;
public DelegateVisualBrush(BrushTool tool, Brush brush) {
super(tool);
this.brush = brush;
}
@Override
public void build(BrushTool.BrushAction action, EditSession editSession, Vector position, Pattern pattern, double size) throws MaxChangedBlocksException {
switch (action) {
case PRIMARY:
brush.build(editSession, position, pattern, size);
break;
case SECONDARY:
if (brush instanceof DoubleActionBrush) {
((DoubleActionBrush) brush).build(BrushTool.BrushAction.SECONDARY, editSession, position, pattern, size);
}
break;
}
}
}

View File

@ -1,142 +0,0 @@
package com.boydti.fawe.object.brush.visualization;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.brush.DoubleActionBrush;
import com.boydti.fawe.object.brush.MovableBrush;
import com.boydti.fawe.object.brush.TargetMode;
import com.boydti.fawe.object.brush.scroll.ScrollableBrush;
import com.boydti.fawe.util.EditSessionBuilder;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.command.tool.BrushTool;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.util.Location;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public abstract class VisualBrush implements DoubleActionBrush, MovableBrush, ScrollableBrush {
private Lock lock = new ReentrantLock();
private final BrushTool tool;
private VisualExtent visualExtent;
private TargetMode mode;
public VisualBrush(BrushTool tool) {
this.tool = tool;
this.mode = TargetMode.TARGET_POINT_RANGE;
}
public BrushTool getTool() {
return tool;
}
public TargetMode getMode() {
return mode;
}
public void setMode(TargetMode mode) {
this.mode = mode;
}
@Override
public abstract void build(BrushTool.BrushAction action, EditSession editSession, Vector position, Pattern pattern, double size) throws MaxChangedBlocksException;
public Vector getPosition(EditSession editSession, Player player) {
switch (mode) {
case TARGET_BLOCK_RANGE:
return player.getBlockTrace(tool.getRange(), false);
case FOWARD_POINT_PITCH: {
int d = 0;
Location loc = player.getLocation();
float pitch = loc.getPitch();
pitch = 23 - (pitch / 4);
d += (int) (Math.sin(Math.toRadians(pitch)) * 50);
final Vector vector = loc.getDirection().setY(0).normalize().multiply(d);
vector.add(loc.getX(), loc.getY(), loc.getZ()).toBlockVector();
return vector;
}
case TARGET_POINT_HEIGHT: {
Location loc = player.getLocation();
final int height = loc.getBlockY();
final int x = loc.getBlockX();
final int z = loc.getBlockZ();
int y;
for (y = height; y > 0; y--) {
BaseBlock block = editSession.getBlock(x, y, z);
if (!FaweCache.isLiquidOrGas(block.getId())) {
break;
}
}
final int distance = (height - y) + 8;
return player.getBlockTrace(distance, true);
}
case TARGET_POINT_RANGE:
return player.getBlockTrace(tool.getRange(), true);
default:
return null;
}
}
public void queueVisualization(FawePlayer player) {
Fawe.get().getVisualQueue().queue(player);
}
/**
* Visualize the brush action
* @deprecated It is preferred to visualize only if a visualization is not in progress
* @param action
* @param player
* @throws MaxChangedBlocksException
*/
@Deprecated
public synchronized void visualize(BrushTool.BrushAction action, Player player) throws MaxChangedBlocksException {
FawePlayer<Object> fp = FawePlayer.wrap(player);
EditSession editSession = new EditSessionBuilder(player.getWorld())
.player(fp)
.allowedRegionsEverywhere()
.autoQueue(false)
.blockBag(null)
.changeSetNull()
.combineStages(false)
.build();
VisualExtent newVisualExtent = new VisualExtent(editSession.getExtent(), editSession.getQueue());
editSession.setExtent(newVisualExtent);
Vector position = getPosition(editSession, player);
if (position != null) {
build(BrushTool.BrushAction.PRIMARY, editSession, position, tool.getMaterial(), tool.getSize());
}
if (visualExtent != null) {
// clear old data
visualExtent.clear(newVisualExtent, fp);
}
visualExtent = newVisualExtent;
newVisualExtent.visualize(fp);
}
public void clear(Player player) {
FawePlayer<Object> fp = FawePlayer.wrap(player);
Fawe.get().getVisualQueue().dequeue(fp);
if (visualExtent != null) {
visualExtent.clear(null, fp);
}
}
@Override
public boolean move(Player player) {
return true;
}
@Override
public boolean increment(int amount) {
int max = WorldEdit.getInstance().getConfiguration().maxBrushRadius;
double newSize = Math.max(0, Math.min(max, tool.getSize() + amount));
tool.setSize(newSize);
return true;
}
}

View File

@ -35,17 +35,13 @@ public class VisualQueue {
Tool tool = session.getTool(player.getItemInHand());
Brush brush;
if (tool instanceof BrushTool) {
brush = ((BrushTool) tool).getBrush();
} else if (tool instanceof VisualBrush) {
brush = (Brush) tool;
} else {
continue;
}
if (brush instanceof VisualBrush) {
try {
((VisualBrush) brush).visualize(BrushTool.BrushAction.PRIMARY, player);
} catch (Throwable e) {
WorldEdit.getInstance().getPlatformManager().handleThrowable(e, player);
BrushTool brushTool = (BrushTool) tool;
if (brushTool.getVisualMode() != VisualMode.NONE) {
try {
brushTool.visualize(BrushTool.BrushAction.PRIMARY, player);
} catch (Throwable e) {
WorldEdit.getInstance().getPlatformManager().handleThrowable(e, player);
}
}
}
}

View File

@ -0,0 +1,100 @@
package com.boydti.fawe.object.clipboard;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.Vector2D;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.function.operation.Operation;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.biome.BaseBiome;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nullable;
public class EmptyClipboard implements Clipboard {
public static final EmptyClipboard INSTANCE = new EmptyClipboard();
private EmptyClipboard() {}
@Override
public Region getRegion() {
return new CuboidRegion(new Vector(), new Vector());
}
@Override
public Vector getDimensions() {
return new Vector();
}
@Override
public Vector getOrigin() {
return new Vector();
}
@Override
public void setOrigin(Vector origin) {}
@Override
public Vector getMinimumPoint() {
return new Vector();
}
@Override
public Vector getMaximumPoint() {
return new Vector();
}
@Override
public List<? extends Entity> getEntities(Region region) {
return new ArrayList<>();
}
@Override
public List<? extends Entity> getEntities() {
return new ArrayList<>();
}
@Nullable
@Override
public Entity createEntity(Location location, BaseEntity entity) {
return null;
}
@Override
public BaseBlock getBlock(Vector position) {
return EditSession.nullBlock;
}
@Override
public BaseBlock getLazyBlock(Vector position) {
return EditSession.nullBlock;
}
@Override
public BaseBiome getBiome(Vector2D position) {
return EditSession.nullBiome;
}
@Override
public boolean setBlock(Vector position, BaseBlock block) throws WorldEditException {
return false;
}
@Override
public boolean setBiome(Vector2D position, BaseBiome biome) {
return false;
}
@Nullable
@Override
public Operation commit() {
return null;
}
}

View File

@ -0,0 +1,54 @@
package com.boydti.fawe.object.clipboard;
import com.boydti.fawe.object.schematic.StructureFormat;
import com.google.common.io.ByteSource;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader;
import com.sk89q.worldedit.extent.clipboard.io.SchematicReader;
import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.world.registry.WorldData;
import java.io.InputStream;
import java.util.UUID;
public class LazyClipboardHolder extends ClipboardHolder {
private final ByteSource source;
private final ClipboardFormat format;
private final UUID uuid;
private Clipboard clipboard;
/**
* Create a new instance with the given clipboard.
*
* @param worldData the mapping of blocks, entities, and so on
*/
public LazyClipboardHolder(ByteSource source, ClipboardFormat format, WorldData worldData, UUID uuid) {
super(EmptyClipboard.INSTANCE, worldData);
this.source = source;
this.format = format;
this.uuid = uuid != null ? uuid : UUID.randomUUID();
}
@Override
public Clipboard getClipboard() {
if (clipboard == null) {
try {
try (InputStream in = source.openBufferedStream()) {
final ClipboardReader reader = format.getReader(in);
final Clipboard clipboard;
if (reader instanceof SchematicReader) {
this.clipboard = ((SchematicReader) reader).read(getWorldData(), uuid);
} else if (reader instanceof StructureFormat) {
this.clipboard = ((StructureFormat) reader).read(getWorldData(), uuid);
} else {
this.clipboard = reader.read(getWorldData());
}
}
} catch (Throwable e) {
e.printStackTrace();
}
}
return clipboard;
}
}

View File

@ -16,13 +16,18 @@ import java.util.Set;
public class LocalBlockVectorSet implements Set<Vector> {
private int offsetX, offsetZ;
private final SparseBitSet set;
private BlockVector mVec = new BlockVector(0, 0, 0);
public LocalBlockVectorSet() {
offsetX = offsetZ = Integer.MAX_VALUE;
this.set = new SparseBitSet();
}
public LocalBlockVectorSet(int x, int z, SparseBitSet set) {
this.offsetX = x;
this.offsetZ = z;
this.set = set;
}
public SparseBitSet getBitSet() {
return set;
}
@ -50,6 +55,38 @@ public class LocalBlockVectorSet implements Set<Vector> {
return false;
}
@Override
public LocalBlockVectorSet clone() {
return new LocalBlockVectorSet(offsetX, offsetZ, set.clone());
}
public boolean containsRadius(int x, int y, int z, int radius) {
int length = radius * 2;
if (size() < length * length * length) {
int index = -1;
while ((index = set.nextSetBit(index + 1)) != -1) {
int b1 = (index & 0xFF);
int b2 = ((byte) (index >> 8)) & 0x7F;
int b3 = ((byte)(index >> 15)) & 0xFF;
int b4 = ((byte) (index >> 23)) & 0xFF;
if (Math.abs((offsetX + (((b3 + ((MathMan.unpair8x(b2)) << 8)) << 21) >> 21)) - x) <= radius && Math.abs((offsetZ + (((b4 + ((MathMan.unpair8y(b2)) << 8)) << 21) >> 21)) - z) <= radius && Math.abs((b1) - y) <= radius) {
return true;
}
}
return false;
}
for (int xx = -radius; xx <= radius; xx++) {
for (int yy = -radius; yy <= radius; yy++) {
for (int zz = -radius; zz <= radius; zz++) {
if (contains(x + xx, y + yy, z + zz)) {
return true;
}
}
}
}
return false;
}
public void addOffset(int x, int z) {
this.offsetX += x;
this.offsetZ += z;
@ -134,9 +171,12 @@ public class LocalBlockVectorSet implements Set<Vector> {
throw new UnsupportedOperationException("LocalVectorSet can only contain vectors from y elem:[0,255]");
}
int index = getIndex(x, y, z);
boolean value = set.get(index);
set.set(index);
return !value;
if (set.get(index)) {
return false;
} else {
set.set(index);
return true;
}
}
@Override
@ -196,9 +236,10 @@ public class LocalBlockVectorSet implements Set<Vector> {
public boolean retainAll(Collection<?> c) {
boolean result = false;
int size = size();
int index = 0;
int index = -1;
Vector mVec = MutableBlockVector.get(0, 0, 0);
for (int i = 0; i < size; i++) {
index = set.nextSetBit(index);
index = set.nextSetBit(index + 1);
int b1 = (index & 0xFF);
int b2 = ((byte) (index >> 8)) & 0x7F;
int b3 = ((byte)(index >> 15)) & 0xFF;
@ -210,7 +251,6 @@ public class LocalBlockVectorSet implements Set<Vector> {
result = true;
set.clear(index);
}
index++;
}
return result;
}
@ -224,6 +264,27 @@ public class LocalBlockVectorSet implements Set<Vector> {
return result;
}
public void forEach(BlockVectorSetVisitor visitor) {
int size = size();
int index = -1;
Vector mVec = MutableBlockVector.get(0, 0, 0);
for (int i = 0; i < size; i++) {
index = set.nextSetBit(index + 1);
int b1 = (index & 0xFF);
int b2 = ((byte) (index >> 8)) & 0x7F;
int b3 = ((byte)(index >> 15)) & 0xFF;
int b4 = ((byte) (index >> 23)) & 0xFF;
int x = offsetX + (((b3 + ((MathMan.unpair8x(b2)) << 8)) << 21) >> 21);
int y = b1;
int z = offsetZ + (((b4 + ((MathMan.unpair8y(b2)) << 8)) << 21) >> 21);
visitor.run(x, y, z, index);
}
}
public static abstract class BlockVectorSetVisitor {
public abstract void run(int x, int y, int z, int index);
}
@Override
public void clear() {
set.clear();

View File

@ -0,0 +1,55 @@
package com.sk89q.worldedit.function.pattern;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.function.pattern.AbstractPattern;
import static com.google.common.base.Preconditions.checkNotNull;
public class BlockPattern extends AbstractPattern {
private BaseBlock block;
public BlockPattern(BaseBlock block) {
this.block = block;
}
@Override
public BaseBlock apply(Vector position) {
return block;
}
@Override
public BaseBlock next(int x, int y, int z) {
return block;
}
@Override
public BaseBlock next(Vector position) {
return block;
}
/**
* Get the block.
*
* @return the block that is always returned
*/
public BaseBlock getBlock() {
return block;
}
/**
* Set the block that is returned.
*
* @param block the block
*/
public void setBlock(BaseBlock block) {
checkNotNull(block);
this.block = block;
}
public static Class<BlockPattern> inject() {
return BlockPattern.class;
}
}

View File

@ -10,7 +10,6 @@ import com.sk89q.worldedit.function.operation.Operation;
import com.sk89q.worldedit.function.operation.RunContext;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
@ -50,7 +49,7 @@ public abstract class DFSVisitor implements Operation {
public abstract boolean isVisitable(Vector from, Vector to);
public Collection<Vector> getDirections() {
public List<Vector> getDirections() {
return this.directions;
}

View File

@ -523,6 +523,10 @@ public class MainUtil {
}
return newFile;
}
File parent = newFile.getParentFile();
if (!parent.exists()) {
parent.mkdirs();
}
newFile.createNewFile();
try (FileOutputStream fos = new FileOutputStream(newFile)) {
int len;

View File

@ -1150,6 +1150,15 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
}
}
public boolean setBlock(int x, int y, int z, Pattern pattern) {
this.changes++;
try {
return this.extent.setBlock(x, y, z, pattern.next(x, y, z));
} catch (WorldEditException e) {
throw new RuntimeException("Unexpected exception", e);
}
}
@Override
public boolean setBlock(final Vector position, final BaseBlock block, final boolean ignorePhysics) throws MaxChangedBlocksException {
return setBlockFast(position, block);

View File

@ -25,7 +25,6 @@ import com.boydti.fawe.object.FaweInputStream;
import com.boydti.fawe.object.FaweOutputStream;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.RunnableVal2;
import com.boydti.fawe.object.brush.visualization.VisualBrush;
import com.boydti.fawe.object.changeset.DiskStorageHistory;
import com.boydti.fawe.object.changeset.FaweChangeSet;
import com.boydti.fawe.object.clipboard.DiskOptimizedClipboard;
@ -42,7 +41,6 @@ import com.sk89q.worldedit.command.tool.BrushTool;
import com.sk89q.worldedit.command.tool.InvalidToolBindException;
import com.sk89q.worldedit.command.tool.SinglePickaxe;
import com.sk89q.worldedit.command.tool.Tool;
import com.sk89q.worldedit.command.tool.brush.Brush;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
@ -777,6 +775,11 @@ public class LocalSession {
return clipboard;
}
@Nullable
public ClipboardHolder getExistingClipboard() {
return clipboard;
}
/**
* Sets the clipboard.
*
@ -979,11 +982,19 @@ public class LocalSession {
}
public BrushTool getBrushTool(int item, Player player) throws InvalidToolBindException {
return getBrushTool(item, player, true);
}
public BrushTool getBrushTool(int item, Player player, boolean create) throws InvalidToolBindException {
Tool tool = getTool(item);
if (tool == null || !(tool instanceof BrushTool)) {
tool = new BrushTool("worldedit.brush.sphere");
setTool(item, tool, player);
if ((tool == null || !(tool instanceof BrushTool))) {
if (create) {
tool = new BrushTool("worldedit.brush.sphere");
setTool(item, tool, player);
} else {
return null;
}
}
return (BrushTool) tool;
@ -1011,12 +1022,8 @@ public class LocalSession {
Tool previous = this.tools.put(item, tool);
if (player != null) {
if (previous instanceof BrushTool) {
Brush brush = ((BrushTool) previous).getBrush();
if (brush instanceof VisualBrush) {
((VisualBrush) brush).clear(player);
}
} else if (previous instanceof VisualBrush) {
((VisualBrush) tool).clear(player);
BrushTool brushTool = (BrushTool) previous;
brushTool.clear(player);
}
}
}

View File

@ -32,10 +32,24 @@ import com.boydti.fawe.object.brush.ErodeBrush;
import com.boydti.fawe.object.brush.FlattenBrush;
import com.boydti.fawe.object.brush.HeightBrush;
import com.boydti.fawe.object.brush.LineBrush;
import com.boydti.fawe.object.brush.RaiseBrush;
import com.boydti.fawe.object.brush.RecurseBrush;
import com.boydti.fawe.object.brush.SplineBrush;
import com.boydti.fawe.object.brush.TargetMode;
import com.boydti.fawe.object.brush.heightmap.ScalableHeightMap;
import com.boydti.fawe.object.brush.scroll.ScrollClipboard;
import com.boydti.fawe.object.brush.scroll.ScrollMask;
import com.boydti.fawe.object.brush.scroll.ScrollPattern;
import com.boydti.fawe.object.brush.scroll.ScrollRange;
import com.boydti.fawe.object.brush.scroll.ScrollSize;
import com.boydti.fawe.object.brush.scroll.ScrollTarget;
import com.boydti.fawe.object.brush.visualization.VisualMode;
import com.boydti.fawe.object.clipboard.LazyClipboardHolder;
import com.boydti.fawe.object.io.FastByteArrayOutputStream;
import com.boydti.fawe.object.mask.IdMask;
import com.boydti.fawe.util.MathMan;
import com.google.common.io.ByteSource;
import com.google.common.io.Files;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandPermissions;
@ -59,14 +73,21 @@ import com.sk89q.worldedit.command.tool.brush.SmoothBrush;
import com.sk89q.worldedit.command.tool.brush.SphereBrush;
import com.sk89q.worldedit.command.util.CreatureButcher;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.event.platform.CommandEvent;
import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.extension.platform.CommandManager;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
import com.sk89q.worldedit.function.mask.BlockMask;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.pattern.BlockPattern;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.util.command.binding.Switch;
import com.sk89q.worldedit.util.command.parametric.Optional;
import com.sk89q.worldedit.world.registry.WorldData;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
@ -74,6 +95,10 @@ import java.io.InputStream;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import static com.google.common.base.Preconditions.checkNotNull;
@ -95,6 +120,227 @@ public class BrushCommands {
this.worldEdit = worldEdit;
}
@Command(
aliases = { "primary" },
usage = "[brush arguments]",
desc = "Set the right click brush",
help = "Set the right click brush",
min = 1
)
public void primary(Player player, LocalSession session, CommandContext args) throws WorldEditException {
int item = player.getItemInHand();
BrushTool tool = session.getBrushTool(item, player, false);
session.setTool(item, null);
String cmd = "brush " + args.getJoinedStrings(0);
CommandEvent event = new CommandEvent(player, cmd);
CommandManager.getInstance().handleCommandOnCurrentThread(event);
BrushTool newTool = session.getBrushTool(item, player, false);
if (newTool != null && tool != null) {
newTool.setSecondary(tool.getSecondary());
}
}
@Command(
aliases = { "secondary" },
usage = "[brush arguments]",
desc = "Set the left click brush",
help = "Set the left click brush",
min = 1
)
public void secondary(Player player, LocalSession session, CommandContext args) throws WorldEditException {
int item = player.getItemInHand();
BrushTool tool = session.getBrushTool(item, player, false);
session.setTool(item, null);
String cmd = "brush " + args.getJoinedStrings(0);
CommandEvent event = new CommandEvent(player, cmd);
CommandManager.getInstance().handleCommandOnCurrentThread(event);
BrushTool newTool = session.getBrushTool(item, player, false);
if (newTool != null && tool != null) {
newTool.setPrimary(tool.getPrimary());
}
}
@Command(
aliases = { "visualize", "visual", "vis" },
usage = "[mode]",
desc = "Toggle between different visualization modes",
min = 0,
max = 1
)
public void visual(Player player, LocalSession session, @Optional("0") int mode) throws WorldEditException {
int item = player.getItemInHand();
BrushTool tool = session.getBrushTool(item, player, false);
if (tool == null) {
BBC.BRUSH_NONE.send(player);
return;
}
VisualMode[] modes = VisualMode.values();
VisualMode newMode = modes[MathMan.wrap(mode, 0, modes.length - 1)];
tool.setVisualMode(newMode);
BBC.BRUSH_VISUAL_MODE_SET.send(player, newMode);
}
@Command(
aliases = { "target", "tar" },
usage = "[mode]",
desc = "Toggle between different target modes",
min = 0,
max = 1
)
public void target(Player player, LocalSession session, @Optional("0") int mode) throws WorldEditException {
int item = player.getItemInHand();
BrushTool tool = session.getBrushTool(item, player, false);
if (tool == null) {
BBC.BRUSH_NONE.send(player);
return;
}
TargetMode[] modes = TargetMode.values();
TargetMode newMode = modes[MathMan.wrap(mode, 0, modes.length - 1)];
tool.setTargetMode(newMode);
BBC.BRUSH_TARGET_MODE_SET.send(player, newMode);
}
@Command(
aliases = { "scroll" },
usage = "[none|clipboard|mask|pattern|range|size|visual|target]",
desc = "Toggle between different target modes",
min = 1,
max = -1
)
public void scroll(Player player, EditSession editSession, LocalSession session, CommandContext args) throws WorldEditException {
int item = player.getItemInHand();
BrushTool tool = session.getBrushTool(item, player, false);
if (tool == null) {
BBC.BRUSH_NONE.send(player);
return;
}
ParserContext parserContext = new ParserContext();
parserContext.setActor(player);
parserContext.setWorld(player.getWorld());
parserContext.setSession(session);
parserContext.setExtent(editSession);
final LocalConfiguration config = this.worldEdit.getConfiguration();
switch (args.getString(0).toLowerCase()) {
case "none":
tool.setScrollAction(null);
break;
case "clipboard":
if (args.argsLength() != 2) {
BBC.COMMAND_SYNTAX.send(player, "clipboard [file]");
return;
}
String filename = args.getString(1);
try {
WorldData worldData = player.getWorld().getWorldData();
if (filename.startsWith("http")) {
URL url = new URL(filename);
URL webInterface = new URL(Settings.IMP.WEB.URL);
if (!url.getHost().equalsIgnoreCase(webInterface.getHost())) {
BBC.WEB_UNAUTHORIZED.send(player, url);
return;
}
List<LazyClipboardHolder> clipboards = new ArrayList<>();
try (ReadableByteChannel rbc = Channels.newChannel(url.openStream())) {
try (InputStream in = Channels.newInputStream(rbc)) {
try (ZipInputStream zip = new ZipInputStream(in)) {
ZipEntry entry;
byte[] buffer = new byte[8192];
while ((entry = zip.getNextEntry()) != null) {
if (entry.getName().endsWith(".schematic")) {
FastByteArrayOutputStream out = new FastByteArrayOutputStream();
int len = 0;
while ((len = zip.read(buffer)) > 0) {
out.write(buffer, 0, len);
}
byte[] array = out.toByteArray();
ByteSource source = ByteSource.wrap(array);
LazyClipboardHolder clipboard = new LazyClipboardHolder(source, ClipboardFormat.SCHEMATIC, worldData, null);
clipboards.add(clipboard);
}
}
}
}
}
tool.setScrollAction(new ScrollClipboard(tool, session, clipboards.toArray(new LazyClipboardHolder[clipboards.size()])));
} else {
if (filename.contains("../") && !player.hasPermission("worldedit.schematic.load.other")) {
BBC.NO_PERM.send(player, "worldedit.schematic.load.other");
return;
}
File dir = new File(this.worldEdit.getWorkingDirectoryFile(config.saveDir), player.getUniqueId() + File.separator + filename);
if (!dir.exists()) {
if (!filename.contains("/") && !filename.contains("\\")) {
dir = new File(this.worldEdit.getWorkingDirectoryFile(config.saveDir), filename);
}
}
if (!dir.exists() || !dir.isDirectory()) {
BBC.SCHEMATIC_NOT_FOUND.send(player, filename);
return;
}
File[] files = dir.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.getName().endsWith(".schematic");
}
});
if (files.length < 1) {
BBC.SCHEMATIC_NOT_FOUND.send(player, filename);
return;
}
LazyClipboardHolder[] clipboards = new LazyClipboardHolder[files.length];
for (int i = 0; i < files.length; i++) {
File file = files[i];
ByteSource source = Files.asByteSource(file);
clipboards[i] = new LazyClipboardHolder(source, ClipboardFormat.SCHEMATIC, worldData, null);
}
tool.setScrollAction(new ScrollClipboard(tool, session, clipboards));
}
break;
} catch (IOException e) {
throw new RuntimeException(e);
}
case "mask":
if (args.argsLength() < 2) {
BBC.COMMAND_SYNTAX.send(player, "mask [mask 1] [mask 2] [mask 3]...");
return;
}
Mask[] masks = new Mask[args.argsLength() - 1];
for (int i = 1; i < args.argsLength(); i++) {
String arg = args.getString(i);
masks[i - 1] = worldEdit.getMaskFactory().parseFromInput(arg, parserContext);
}
tool.setScrollAction(new ScrollMask(tool, masks));
break;
case "pattern":
if (args.argsLength() < 2) {
BBC.COMMAND_SYNTAX.send(player, "pattern [pattern 1] [pattern 2] [pattern 3]...");
return;
}
Pattern[] patterns = new Pattern[args.argsLength() - 1];
for (int i = 1; i < args.argsLength(); i++) {
String arg = args.getString(i);
patterns[i - 1] = worldEdit.getPatternFactory().parseFromInput(arg, parserContext);
}
tool.setScrollAction(new ScrollPattern(tool, patterns));
break;
case "range":
tool.setScrollAction(new ScrollRange(tool));
break;
case "size":
tool.setScrollAction(new ScrollSize(tool));
break;
case "target":
tool.setScrollAction(new ScrollTarget(tool));
break;
default:
BBC.COMMAND_SYNTAX.send(player, "[none|clipboard|mask|pattern|range|size|visual|target]");
return;
}
BBC.BRUSH_SCROLL_ACTION_SET.send(player, args.getJoinedStrings(0));
}
@Command(
aliases = { "blendball", "bb", "blend" },
usage = "[radius]",
@ -129,6 +375,23 @@ public class BrushCommands {
player.print(BBC.getPrefix() + BBC.BRUSH_ERODE.f(radius));
}
@Command(
aliases = { "raise" },
usage = "[radius]",
desc = "Choose the raise brush",
help = "Chooses the raise brush",
min = 0,
max = 1
)
@CommandPermissions("worldedit.brush.raise")
public void raiseBrush(Player player, LocalSession session, @Optional("5") double radius) throws WorldEditException {
worldEdit.checkMaxBrushRadius(radius);
BrushTool tool = session.getBrushTool(player.getItemInHand(), player);
tool.setSize(radius);
tool.setBrush(new RaiseBrush(), "worldedit.brush.erode", player);
player.print(BBC.getPrefix() + BBC.BRUSH_ERODE.f(radius));
}
@Command(
aliases = { "circle" },
usage = "<pattern> [radius]",
@ -191,7 +454,7 @@ public class BrushCommands {
}
@Command(
aliases = { "spline", "spl" },
aliases = { "spline", "spl", "curve" },
usage = "<pattern>",
desc = "Choose the spline brush",
help = "Chooses the spline brush",
@ -246,6 +509,28 @@ public class BrushCommands {
if (!FawePlayer.wrap(player).hasPermission("fawe.tips")) BBC.TIP_BRUSH_COMMAND.or(BBC.TIP_BRUSH_RELATIVE, BBC.TIP_BRUSH_TRANSFORM, BBC.TIP_BRUSH_MASK_SOURCE, BBC.TIP_BRUSH_MASK, BBC.TIP_BRUSH_COPY, BBC.TIP_BRUSH_HEIGHT, BBC.TIP_BRUSH_SPLINE).send(player);
}
// @Command(
// aliases = { "test" },
// usage = "<pattern> [radius] [count] [distance]",
// flags = "h",
// desc = "Choose the sphere brush",
// help =
// "Chooses the sphere brush.\n" +
// "The -h flag creates hollow spheres instead.",
// min = 1,
// max = -1
// )
// @CommandPermissions("worldedit.brush.test")
// public void testBrush(Player player, LocalSession session, Pattern fill, @Optional("10") double radius, @Optional("10") int count, @Optional("10") int distance) throws WorldEditException {
// worldEdit.checkMaxBrushRadius(radius);
//
// BrushTool tool = session.getBrushTool(player.getItemInHand(), player);
// tool.setFill(fill);
// tool.setSize(radius);
// tool.setBrush(new Test(count), "worldedit.brush.test");
// player.print("equiped");
// }
@Command(
aliases = { "cylinder", "cyl", "c" },
usage = "<block> [radius] [height]",
@ -484,7 +769,7 @@ public class BrushCommands {
worldEdit.checkMaxBrushRadius(radius);
BrushTool tool = session.getBrushTool(player.getItemInHand(), player);
tool.setSize(radius);
tool.setBrush(new CopyPastaBrush(tool), "worldedit.brush.copy", player);
tool.setBrush(new CopyPastaBrush(tool, session), "worldedit.brush.copy", player);
player.print(BBC.getPrefix() + BBC.BRUSH_COPY.f(radius));
}

View File

@ -73,7 +73,7 @@ public class HistoryCommands {
}
@Command(
aliases = { "/frb", "frb", "fawerollback", "/fawerollback" },
aliases = { "/frb", "frb", "fawerollback", "/fawerollback", "/rollback" },
usage = "<user> <radius> <time>",
desc = "Undo edits within a radius",
min = 1,

View File

@ -257,7 +257,7 @@ public class RegionCommands {
}
@Command(
aliases = { "/curve" },
aliases = { "/curve", "/spline" },
usage = "<block> [thickness]",
desc = "Draws a spline through selected points",
help =

View File

@ -22,6 +22,7 @@ package com.sk89q.worldedit.command;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.schematic.StructureFormat;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.MathMan;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
@ -114,12 +115,31 @@ public class SchematicCommands {
BBC.NO_PERM.send(player, "worldedit.clipboard.load");
return;
}
final File dir = this.worldEdit.getWorkingDirectoryFile(config.saveDir);
final File f = this.worldEdit.getSafeOpenFile(player, dir, filename, format.getExtension(), format.getExtension());
if (!f.exists()) {
player.printError("Schematic " + filename + " does not exist!");
if (filename.contains("../") && !player.hasPermission("worldedit.schematic.load.other")) {
BBC.NO_PERM.send(player, "worldedit.schematic.load.other");
return;
}
File dir = new File(this.worldEdit.getWorkingDirectoryFile(config.saveDir), player.getUniqueId().toString());
File f = this.worldEdit.getSafeSaveFile(player, dir, filename, format.getExtension(), format.getExtension());
if (f.getName().replaceAll("." + format.getExtension(), "").isEmpty()) {
File directory = f.getParentFile();
if (directory.exists()) {
int max = MainUtil.getMaxFileId(directory) - 1;
f = new File(directory, max + "." + format.getExtension());
} else {
f = new File(directory, "1." + format.getExtension());
}
}
if (!f.exists()) {
if (!filename.contains("/") && !filename.contains("\\")) {
dir = this.worldEdit.getWorkingDirectoryFile(config.saveDir);
f = this.worldEdit.getSafeSaveFile(player, dir, filename, format.getExtension(), format.getExtension());
}
if (!f.exists()) {
player.printError("Schematic " + filename + " does not exist!");
return;
}
}
final String filePath = f.getCanonicalPath();
final String dirPath = dir.getCanonicalPath();
if (!filePath.substring(0, dirPath.length()).equals(dirPath)) {
@ -156,16 +176,28 @@ public class SchematicCommands {
@Command(aliases = { "save" }, usage = "[<format>] <filename>", desc = "Save a schematic into your clipboard")
@Deprecated
@CommandPermissions({ "worldedit.clipboard.save", "worldedit.schematic.save" })
public void save(final Player player, final LocalSession session, @Optional("schematic") final String formatName, final String filename) throws CommandException, WorldEditException {
public void save(final Player player, final LocalSession session, @Optional("schematic") final String formatName, String filename) throws CommandException, WorldEditException {
final LocalConfiguration config = this.worldEdit.getConfiguration();
final ClipboardFormat format = ClipboardFormat.findByAlias(formatName);
if (format == null) {
player.printError("Unknown schematic format: " + formatName);
return;
}
final File dir = this.worldEdit.getWorkingDirectoryFile(config.saveDir);
final File f = this.worldEdit.getSafeSaveFile(player, dir, filename, format.getExtension(), format.getExtension());
if (filename.contains("../") && !player.hasPermission("worldedit.schematic.save.other")) {
BBC.NO_PERM.send(player, "worldedit.schematic.save.other");
return;
}
final File dir = new File(this.worldEdit.getWorkingDirectoryFile(config.saveDir), player.getUniqueId().toString());
File f = this.worldEdit.getSafeSaveFile(player, dir, filename, format.getExtension(), format.getExtension());
if (f.getName().replaceAll("." + format.getExtension(), "").isEmpty()) {
File directory = f.getParentFile();
if (directory.exists()) {
int max = MainUtil.getMaxFileId(directory);
f = new File(directory, max + "." + format.getExtension());
} else {
f = new File(directory, "1." + format.getExtension());
}
}
final File parent = f.getParentFile();
if ((parent != null) && !parent.exists()) {
if (!parent.mkdirs()) {

View File

@ -1,14 +1,26 @@
package com.sk89q.worldedit.command.tool;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.object.brush.DoubleActionBrush;
import com.boydti.fawe.object.brush.visualization.VisualBrush;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.brush.BrushSettings;
import com.boydti.fawe.object.brush.MovableTool;
import com.boydti.fawe.object.brush.TargetMode;
import com.boydti.fawe.object.brush.scroll.ScrollAction;
import com.boydti.fawe.object.brush.scroll.ScrollTool;
import com.boydti.fawe.object.brush.visualization.VisualChunk;
import com.boydti.fawe.object.brush.visualization.VisualExtent;
import com.boydti.fawe.object.brush.visualization.VisualMode;
import com.boydti.fawe.object.extent.ResettableExtent;
import com.boydti.fawe.util.EditSessionBuilder;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.WorldVector;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.command.tool.brush.Brush;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor;
@ -18,12 +30,15 @@ import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.MaskIntersection;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.session.request.Request;
import com.sk89q.worldedit.util.Location;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkNotNull;
public class BrushTool implements DoubleActionTraceTool {
public class BrushTool implements DoubleActionTraceTool, ScrollTool, MovableTool {
public enum BrushAction {
PRIMARY,
@ -32,14 +47,12 @@ public class BrushTool implements DoubleActionTraceTool {
protected static int MAX_RANGE = 500;
protected int range = -1;
private Mask mask = null;
private Mask sourceMask = null;
private ResettableExtent transform = null;
private Brush brush = null;
@Nullable
private Pattern material;
private double size = 1;
private String permission;
private VisualMode visualMode = VisualMode.NONE;
private TargetMode targetMode = TargetMode.TARGET_BLOCK_RANGE;
private BrushSettings context = new BrushSettings();
private BrushSettings primary = context;
private BrushSettings secondary = context;
/**
* Construct the tool.
@ -48,20 +61,41 @@ public class BrushTool implements DoubleActionTraceTool {
*/
public BrushTool(String permission) {
checkNotNull(permission);
this.permission = permission;
this.context.permission = permission;
}
@Override
public boolean canUse(Actor player) {
return player.hasPermission(permission);
if (primary == secondary) {
return player.hasPermission(context.permission);
}
return player.hasPermission(primary.permission) && player.hasPermission(secondary.permission);
}
public ResettableExtent getTransform() {
return transform;
return context.transform;
}
public BrushSettings getPrimary() {
return primary;
}
public BrushSettings getSecondary() {
return secondary;
}
public void setPrimary(BrushSettings primary) {
checkNotNull(primary);
this.primary = primary;
}
public void setSecondary(BrushSettings secondary) {
checkNotNull(secondary);
this.secondary = secondary;
}
public void setTransform(ResettableExtent transform) {
this.transform = transform;
this.context.transform = transform;
}
/**
@ -70,7 +104,7 @@ public class BrushTool implements DoubleActionTraceTool {
* @return the filter
*/
public Mask getMask() {
return mask;
return context.mask;
}
/**
@ -79,7 +113,7 @@ public class BrushTool implements DoubleActionTraceTool {
* @return the filter
*/
public Mask getSourceMask() {
return sourceMask;
return context.sourceMask;
}
/**
@ -88,7 +122,7 @@ public class BrushTool implements DoubleActionTraceTool {
* @param filter the filter to set
*/
public void setMask(Mask filter) {
this.mask = filter;
this.context.mask = filter;
}
/**
@ -97,7 +131,7 @@ public class BrushTool implements DoubleActionTraceTool {
* @param filter the filter to set
*/
public void setSourceMask(Mask filter) {
this.sourceMask = filter;
this.context.sourceMask = filter;
}
/**
@ -111,11 +145,10 @@ public class BrushTool implements DoubleActionTraceTool {
}
public void setBrush(Brush brush, String permission, Player player) {
if (player != null && brush instanceof VisualBrush) {
((VisualBrush) brush).clear(player);
}
this.brush = brush;
this.permission = permission;
if (player != null) clear(player);
BrushSettings current = context;
current.brush = brush;
current.permission = permission;
}
/**
@ -124,7 +157,7 @@ public class BrushTool implements DoubleActionTraceTool {
* @return the current brush
*/
public Brush getBrush() {
return brush;
return context.brush;
}
/**
@ -133,7 +166,7 @@ public class BrushTool implements DoubleActionTraceTool {
* @param material the material
*/
public void setFill(@Nullable Pattern material) {
this.material = material;
this.context.material = material;
}
/**
@ -142,7 +175,7 @@ public class BrushTool implements DoubleActionTraceTool {
* @return the material
*/
@Nullable public Pattern getMaterial() {
return material;
return context.material;
}
/**
@ -151,7 +184,7 @@ public class BrushTool implements DoubleActionTraceTool {
* @return a radius
*/
public double getSize() {
return size;
return context.size;
}
/**
@ -160,7 +193,7 @@ public class BrushTool implements DoubleActionTraceTool {
* @param radius a radius
*/
public void setSize(double radius) {
this.size = radius;
this.context.size = radius;
}
/**
@ -181,57 +214,96 @@ public class BrushTool implements DoubleActionTraceTool {
this.range = range;
}
public boolean act(BrushAction action, Platform server, LocalConfiguration config, Player player, LocalSession session) {
if (action == BrushAction.SECONDARY && !(brush instanceof DoubleActionBrush)) {
return false;
public Vector getPosition(EditSession editSession, Player player) {
switch (targetMode) {
case TARGET_BLOCK_RANGE:
return player.getBlockTrace(getRange(), true);
case FOWARD_POINT_PITCH: {
int d = 0;
Location loc = player.getLocation();
float pitch = loc.getPitch();
pitch = 23 - (pitch / 4);
d += (int) (Math.sin(Math.toRadians(pitch)) * 50);
final Vector vector = loc.getDirection().setY(0).normalize().multiply(d);
vector.add(loc.getX(), loc.getY(), loc.getZ()).toBlockVector();
return vector;
}
case TARGET_POINT_HEIGHT: {
Location loc = player.getLocation();
final int height = loc.getBlockY();
final int x = loc.getBlockX();
final int z = loc.getBlockZ();
int y;
for (y = height; y > 0; y--) {
BaseBlock block = editSession.getBlock(x, y, z);
if (!FaweCache.isLiquidOrGas(block.getId())) {
break;
}
}
final int distance = (height - y) + 8;
return player.getBlockTrace(distance, true);
}
case TARGET_FACE_RANGE:
return player.getBlockTraceFace(getRange(), true);
default:
return null;
}
WorldVector target = null;
target = player.getBlockTrace(getRange(), true);
}
public boolean act(BrushAction action, Platform server, LocalConfiguration config, Player player, LocalSession session) {
switch (action) {
case PRIMARY:
context = primary;
break;
case SECONDARY:
context = secondary;
break;
}
BrushSettings current = context;
EditSession editSession = session.createEditSession(player);
Vector target = getPosition(editSession, player);
if (target == null) {
editSession.cancel();
BBC.NO_BLOCK.send(player);
return true;
}
BlockBag bag = session.getBlockBag(player);
EditSession editSession = session.createEditSession(player);
Request.request().setEditSession(editSession);
if (mask != null) {
if (current.mask != null) {
Mask existingMask = editSession.getMask();
if (existingMask == null) {
editSession.setMask(mask);
editSession.setMask(current.mask);
} else if (existingMask instanceof MaskIntersection) {
((MaskIntersection) existingMask).add(mask);
((MaskIntersection) existingMask).add(current.mask);
} else {
MaskIntersection newMask = new MaskIntersection(existingMask);
newMask.add(mask);
newMask.add(current.mask);
editSession.setMask(newMask);
}
}
if (sourceMask != null) {
if (current.sourceMask != null) {
Mask existingMask = editSession.getSourceMask();
if (existingMask == null) {
editSession.setSourceMask(sourceMask);
editSession.setSourceMask(current.sourceMask);
} else if (existingMask instanceof MaskIntersection) {
((MaskIntersection) existingMask).add(sourceMask);
((MaskIntersection) existingMask).add(current.sourceMask);
} else {
MaskIntersection newMask = new MaskIntersection(existingMask);
newMask.add(sourceMask);
newMask.add(current.sourceMask);
editSession.setSourceMask(newMask);
}
}
if (transform != null) {
editSession.addTransform(transform);
if (current.transform != null) {
editSession.addTransform(current.transform);
}
try {
if (brush instanceof DoubleActionBrush) {
((DoubleActionBrush) brush).build(action, editSession, target, material, size);
} else {
brush.build(editSession, target, material, size);
}
current.brush.build(editSession, target, current.material, current.size);
} catch (MaxChangedBlocksException e) {
player.printError("Max blocks change limit reached."); // Never happens
} finally {
@ -256,4 +328,104 @@ public class BrushTool implements DoubleActionTraceTool {
public static Class<?> inject() {
return BrushTool.class;
}
public void setScrollAction(ScrollAction scrollAction) {
this.context.scrollAction = scrollAction;
}
public void setTargetMode(TargetMode targetMode) {
this.targetMode = targetMode != null ? targetMode : TargetMode.TARGET_BLOCK_RANGE;
}
public void setVisualMode(VisualMode visualMode) {
this.visualMode = visualMode != null ? visualMode : VisualMode.NONE;
}
public TargetMode getTargetMode() {
return targetMode;
}
public VisualMode getVisualMode() {
return visualMode;
}
@Override
public boolean increment(Player player, int amount) {
BrushSettings current = context;
ScrollAction tmp = current.scrollAction;
if (tmp != null && tmp.increment(player, amount)) {
if (visualMode != VisualMode.NONE) {
try {
queueVisualization(FawePlayer.wrap(player));
} catch (Throwable e) {
WorldEdit.getInstance().getPlatformManager().handleThrowable(e, player);
}
return true;
}
}
return false;
}
public void queueVisualization(FawePlayer player) {
Fawe.get().getVisualQueue().queue(player);
}
@Deprecated
public synchronized void visualize(BrushTool.BrushAction action, Player player) throws MaxChangedBlocksException {
VisualMode mode = getVisualMode();
if (mode == VisualMode.NONE) {
return;
}
FawePlayer<Object> fp = FawePlayer.wrap(player);
EditSession editSession = new EditSessionBuilder(player.getWorld())
.player(fp)
.allowedRegionsEverywhere()
.autoQueue(false)
.blockBag(null)
.changeSetNull()
.combineStages(false)
.build();
VisualExtent newVisualExtent = new VisualExtent(editSession.getExtent(), editSession.getQueue());
Vector position = getPosition(editSession, player);
if (position != null) {
editSession.setExtent(newVisualExtent);
switch (mode) {
case POINT: {
editSession.setBlockFast(position, FaweCache.getBlock(VisualChunk.VISUALIZE_BLOCK, 0));
break;
}
case OUTLINE: {
BrushSettings current = context;
current.brush.build(editSession, position, current.material, current.size);
break;
}
}
}
if (visualExtent != null) {
// clear old data
visualExtent.clear(newVisualExtent, fp);
}
visualExtent = newVisualExtent;
newVisualExtent.visualize(fp);
}
public void clear(Player player) {
FawePlayer<Object> fp = FawePlayer.wrap(player);
Fawe.get().getVisualQueue().dequeue(fp);
if (visualExtent != null) {
visualExtent.clear(null, fp);
}
}
@Override
public boolean move(Player player) {
if (visualMode != VisualMode.NONE) {
queueVisualization(FawePlayer.wrap(player));
return true;
}
return false;
}
private VisualExtent visualExtent;
private Lock lock = new ReentrantLock();
}

View File

@ -162,21 +162,28 @@ public class DefaultBlockParser extends InputParser<BaseBlock> {
} else {
BundledBlockData.BlockEntry block = BundledBlockData.getInstance().findById(testId);
if (block == null) {
blockType = BlockType.lookup(testId);
if (blockType == null) {
int t = worldEdit.getServer().resolveItem(testId);
if (t >= 0) {
blockType = BlockType.fromID(t); // Could be null
blockId = t;
} else if (blockLocator.length == 2) { // Block IDs in MC 1.7 and above use mod:name
t = worldEdit.getServer().resolveItem(blockAndExtraData[0]);
BaseBlock baseBlock = BundledBlockData.getInstance().findByState(testId);
if (baseBlock == null) {
blockType = BlockType.lookup(testId);
if (blockType == null) {
int t = worldEdit.getServer().resolveItem(testId);
if (t >= 0) {
blockType = BlockType.fromID(t); // Could be null
blockId = t;
typeAndData = new String[] { blockAndExtraData[0] };
testId = blockAndExtraData[0];
} else if (blockLocator.length == 2) { // Block IDs in MC 1.7 and above use mod:name
t = worldEdit.getServer().resolveItem(blockAndExtraData[0]);
if (t >= 0) {
blockType = BlockType.fromID(t); // Could be null
blockId = t;
typeAndData = new String[]{blockAndExtraData[0]};
testId = blockAndExtraData[0];
}
}
}
} else {
blockId = baseBlock.getId();
blockType = BlockType.fromID(blockId);
data = baseBlock.getData();
}
} else {
blockId = block.legacyId;

View File

@ -185,7 +185,9 @@ public final class CommandManager {
.group("superpickaxe", "pickaxe", "sp").describeAs("Super-pickaxe commands")
.registerMethods(new SuperPickaxeCommands(worldEdit)).parent().group("tool")
.describeAs("Bind functions to held items")
.registerMethods(new ToolCommands(worldEdit)).parent().graph().getDispatcher();
.registerMethods(new ToolCommands(worldEdit))
.registerMethods(new BrushCommands(worldEdit))
.parent().graph().getDispatcher();
}
public static CommandManager getInstance() {
@ -251,7 +253,7 @@ public final class CommandManager {
return split;
}
public void handleCommandOnCurrentThread(final CommandEvent event, boolean checkLimit) {
public void handleCommandOnCurrentThread(final CommandEvent event) {
Actor actor = platformManager.createProxyActor(event.getActor());
final String args = event.getArguments();
final String[] split = commandDetection(args.split(" "));
@ -294,93 +296,95 @@ public final class CommandManager {
}
locals.put(Actor.class, actor);
final Actor finalActor = actor;
if (!fp.runAction(new Runnable() {
@Override
public void run() {
locals.put("arguments", args);
final long start = System.currentTimeMillis();
try {
// This is a bit of a hack, since the call method can only throw CommandExceptions
// everything needs to be wrapped at least once. Which means to handle all WorldEdit
// exceptions without writing a hook into every dispatcher, we need to unwrap these
// exceptions and rethrow their converted form, if their is one.
try {
dispatcher.call(Joiner.on(" ").join(split), locals, new String[0]);
} catch (Throwable t) {
// Use the exception converter to convert the exception if any of its causes
// can be converted, otherwise throw the original exception
Throwable next = t;
do {
exceptionConverter.convert(next);
next = next.getCause();
} while (next != null);
throw t;
}
} catch (CommandPermissionsException e) {
BBC.NO_PERM.send(finalActor, StringMan.join(failedPermissions, " "));
} catch (InvalidUsageException e) {
if (e.isFullHelpSuggested()) {
finalActor.printRaw(ColorCodeBuilder.asColorCodes(new CommandUsageBox(e.getCommand(), e.getCommandUsed("/", ""), locals)));
String message = e.getMessage();
if (message != null) {
finalActor.printError(message);
}
} else {
String message = e.getMessage();
finalActor.print(BBC.getPrefix() + (message != null ? message : "The command was not used properly (no more help available)."));
BBC.COMMAND_SYNTAX.send(finalActor, e.getSimpleUsageString("/"));
}
} catch (WrappedCommandException e) {
FaweException faweException = FaweException.get(e);
if (faweException != null) {
BBC.WORLDEDIT_CANCEL_REASON.send(finalActor, faweException.getMessage());
} else {
Throwable t = e.getCause();
while (t.getCause() != null) {
t = t.getCause();
}
finalActor.printError("There was an error handling a FAWE command: [See console]");
finalActor.printRaw(t.getClass().getName() + ": " + t.getMessage());
log.log(Level.SEVERE, "An unexpected error occurred while handling a FAWE command", t);
}
} catch (CommandException e) {
String message = e.getMessage();
if (message != null) {
finalActor.printError(e.getMessage());
} else {
finalActor.printError("An unknown error has occurred! Please see console.");
log.log(Level.SEVERE, "An unknown error occurred", e);
}
} finally {
final EditSession editSession = locals.get(EditSession.class);
boolean hasSession = false;
if (editSession != null) {
editSession.flushQueue();
worldEdit.flushBlockBag(finalActor, editSession);
session.remember(editSession);
final long time = System.currentTimeMillis() - start;
if (time > 250 && hasSession) {
BBC.ACTION_COMPLETE.send(finalActor, (time / 1000d));
}
}
locals.put("arguments", args);
final long start = System.currentTimeMillis();
try {
// This is a bit of a hack, since the call method can only throw CommandExceptions
// everything needs to be wrapped at least once. Which means to handle all WorldEdit
// exceptions without writing a hook into every dispatcher, we need to unwrap these
// exceptions and rethrow their converted form, if their is one.
try {
dispatcher.call(Joiner.on(" ").join(split), locals, new String[0]);
} catch (Throwable t) {
// Use the exception converter to convert the exception if any of its causes
// can be converted, otherwise throw the original exception
Throwable next = t;
do {
exceptionConverter.convert(next);
next = next.getCause();
} while (next != null);
throw t;
}
} catch (CommandPermissionsException e) {
BBC.NO_PERM.send(finalActor, StringMan.join(failedPermissions, " "));
} catch (InvalidUsageException e) {
if (e.isFullHelpSuggested()) {
finalActor.printRaw(ColorCodeBuilder.asColorCodes(new CommandUsageBox(e.getCommand(), e.getCommandUsed("/", ""), locals)));
String message = e.getMessage();
if (message != null) {
finalActor.printError(message);
}
} else {
String message = e.getMessage();
finalActor.print(BBC.getPrefix() + (message != null ? message : "The command was not used properly (no more help available)."));
BBC.COMMAND_SYNTAX.send(finalActor, e.getSimpleUsageString("/"));
}
} catch (WrappedCommandException e) {
FaweException faweException = FaweException.get(e);
if (faweException != null) {
BBC.WORLDEDIT_CANCEL_REASON.send(finalActor, faweException.getMessage());
} else {
Throwable t = e.getCause();
while (t.getCause() != null) {
t = t.getCause();
}
finalActor.printError("There was an error handling a FAWE command: [See console]");
finalActor.printRaw(t.getClass().getName() + ": " + t.getMessage());
log.log(Level.SEVERE, "An unexpected error occurred while handling a FAWE command", t);
}
} catch (CommandException e) {
String message = e.getMessage();
if (message != null) {
finalActor.printError(e.getMessage());
} else {
finalActor.printError("An unknown error has occurred! Please see console.");
log.log(Level.SEVERE, "An unknown error occurred", e);
}
} finally {
final EditSession editSession = locals.get(EditSession.class);
boolean hasSession = false;
if (editSession != null) {
editSession.flushQueue();
worldEdit.flushBlockBag(finalActor, editSession);
session.remember(editSession);
final long time = System.currentTimeMillis() - start;
if (time > 250 && hasSession) {
BBC.ACTION_COMPLETE.send(finalActor, (time / 1000d));
}
}
}, checkLimit, false)) {
BBC.WORLDEDIT_COMMAND_LIMIT.send(fp);
}
}
@Subscribe
public void handleCommand(final CommandEvent event) {
Request.reset();
final FawePlayer<Object> fp = FawePlayer.wrap(event.getActor());
TaskManager.IMP.taskNow(new Runnable() {
@Override
public void run() {
handleCommandOnCurrentThread(event, true);
if (!fp.runAction(new Runnable() {
@Override
public void run() {
handleCommandOnCurrentThread(event);
}
}, true, false)) {
BBC.WORLDEDIT_COMMAND_LIMIT.send(fp);
}
event.setCancelled(true);
}
}, Fawe.isMainThread());
event.setCancelled(true);
}
@Subscribe
@ -388,7 +392,6 @@ public final class CommandManager {
try {
CommandLocals locals = new CommandLocals();
locals.put(Actor.class, event.getActor());
locals.put("arguments", event.getArguments());
event.setSuggestions(dispatcher.getSuggestions(event.getArguments(), locals));
} catch (CommandException e) {
event.getActor().printError(e.getMessage());

View File

@ -63,6 +63,7 @@ public class BundledBlockData {
private static final BundledBlockData INSTANCE = new BundledBlockData();
private final Map<String, BlockEntry> idMap = new HashMap<String, BlockEntry>();
private final Map<String, BaseBlock> stateMap = new HashMap<String, BaseBlock>();
private final Map<String, BlockEntry> localIdMap = new HashMap<String, BlockEntry>();
private final BlockEntry[] legacyMap = new BlockEntry[4096];
@ -140,13 +141,23 @@ public class BundledBlockData {
if (!overwrite && (idMap.containsKey(entry.id) || legacyMap[entry.legacyId] != null)) {
return false;
}
String id = entry.id.contains(":") ? entry.id.split(":")[1] : entry.id;
idMap.put(entry.id, entry);
localIdMap.put(id.toLowerCase().replace(" ", "_"), entry);
String id = (entry.id.contains(":") ? entry.id.split(":")[1] : entry.id).toLowerCase().replace(" ", "_");
if (!idMap.containsKey(id)) {
idMap.put(id, entry);
}
legacyMap[entry.legacyId] = entry;
if (entry.states == null) {
return true;
}
for (Map.Entry<String, FaweState> stateEntry : entry.states.entrySet()) {
for (Map.Entry<String, FaweStateValue> valueEntry : stateEntry.getValue().valueMap().entrySet()) {
String key = valueEntry.getKey();
if (!stateMap.containsKey(key)) {
stateMap.put(key, new BaseBlock(entry.legacyId, valueEntry.getValue().data));
}
}
}
FaweState half = entry.states.get("half");
if (half != null && half.values != null) {
FaweStateValue top = half.values.get("top");
@ -230,6 +241,10 @@ public class BundledBlockData {
return true;
}
public BaseBlock findByState(String state) {
return stateMap.get(state);
}
/**
* Return the entry for the given block ID.
*
@ -238,11 +253,7 @@ public class BundledBlockData {
*/
@Nullable
public BlockEntry findById(String id) {
BlockEntry result = idMap.get(id);
if (result == null) {
result = localIdMap.get(id);
}
return result;
return idMap.get(id);
}
/**

View File

@ -6,6 +6,9 @@ import com.boydti.fawe.example.NMSMappedFaweQueue;
import com.boydti.fawe.forge.ForgePlayer;
import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.brush.visualization.VisualChunk;
import com.boydti.fawe.object.number.LongAdder;
import com.boydti.fawe.object.visitor.FaweChunkVisitor;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.MathMan;
import com.boydti.fawe.util.ReflectionUtils;
@ -16,6 +19,7 @@ import com.sk89q.worldedit.world.biome.BaseBiome;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayDeque;
@ -146,30 +150,53 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
}
@Override
public void sendBlockUpdate(Map<Long, Map<Short, Character>> blockMap, FawePlayer... players) {
for (Map.Entry<Long, Map<Short, Character>> chunkEntry : blockMap.entrySet()) {
try {
long chunkHash = chunkEntry.getKey();
Map<Short, Character> blocks = chunkEntry.getValue();
SPacketMultiBlockChange packet = new SPacketMultiBlockChange();
int cx = MathMan.unpairIntX(chunkHash);
int cz = MathMan.unpairIntY(chunkHash);
ByteBuf byteBuf = ByteBufAllocator.DEFAULT.buffer();
PacketBuffer buffer = new PacketBuffer(byteBuf);
buffer.writeInt(cx);
buffer.writeInt(cz);
buffer.writeVarIntToBuffer(blocks.size());
for (Map.Entry<Short, Character> blockEntry : blocks.entrySet()) {
buffer.writeShort(blockEntry.getKey());
buffer.writeVarIntToBuffer(blockEntry.getValue());
public void sendBlockUpdate(FaweChunk chunk, FawePlayer... players) {
try {
PlayerChunkMap playerManager = ((WorldServer) getWorld()).getPlayerChunkMap();
boolean watching = false;
for (int i = 0; i < players.length; i++) {
EntityPlayerMP player = (EntityPlayerMP) ((ForgePlayer) players[i]).parent;
if (!playerManager.isPlayerWatchingChunk(player, chunk.getX(), chunk.getZ())) {
players[i] = null;
} else {
watching = true;
}
packet.readPacketData(buffer);
for (FawePlayer player : players) {
((ForgePlayer) player).parent.connection.sendPacket(packet);
}
} catch (Throwable e) {
e.printStackTrace();
}
if (!watching) return;
final LongAdder size = new LongAdder();
if (chunk instanceof VisualChunk) {
size.add(((VisualChunk) chunk).size());
} else if (chunk instanceof CharFaweChunk) {
size.add(((CharFaweChunk) chunk).getTotalCount());
} else {
chunk.forEachQueuedBlock(new FaweChunkVisitor() {
@Override
public void run(int localX, int y, int localZ, int combined) {
size.add(1);
}
});
}
if (size.intValue() == 0) return;
SPacketMultiBlockChange packet = new SPacketMultiBlockChange();
ByteBuf byteBuf = ByteBufAllocator.DEFAULT.buffer();
final PacketBuffer buffer = new PacketBuffer(byteBuf);
buffer.writeInt(chunk.getX());
buffer.writeInt(chunk.getZ());
buffer.writeVarIntToBuffer(size.intValue());
chunk.forEachQueuedBlock(new FaweChunkVisitor() {
@Override
public void run(int localX, int y, int localZ, int combined) {
short index = (short) (localX << 12 | localZ << 8 | y);
buffer.writeShort(index);
buffer.writeVarIntToBuffer(combined);
}
});
packet.readPacketData(buffer);
for (FawePlayer player : players) {
if (player != null) ((EntityPlayerMP) ((ForgePlayer) player).parent).connection.sendPacket(packet);
}
} catch (IOException e) {
e.printStackTrace();
}
}

View File

@ -7,6 +7,9 @@ import com.boydti.fawe.forge.ForgePlayer;
import com.boydti.fawe.forge.MutableGenLayer;
import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.brush.visualization.VisualChunk;
import com.boydti.fawe.object.number.LongAdder;
import com.boydti.fawe.object.visitor.FaweChunkVisitor;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.MathMan;
import com.boydti.fawe.util.ReflectionUtils;
@ -17,6 +20,7 @@ import com.sk89q.worldedit.world.biome.BaseBiome;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayDeque;
@ -160,32 +164,54 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
return ExtendedBlockStorages[cy];
}
@Override
public void sendBlockUpdate(Map<Long, Map<Short, Character>> blockMap, FawePlayer... players) {
for (Map.Entry<Long, Map<Short, Character>> chunkEntry : blockMap.entrySet()) {
try {
long chunkHash = chunkEntry.getKey();
Map<Short, Character> blocks = chunkEntry.getValue();
SPacketMultiBlockChange packet = new SPacketMultiBlockChange();
int cx = MathMan.unpairIntX(chunkHash);
int cz = MathMan.unpairIntY(chunkHash);
ByteBuf byteBuf = ByteBufAllocator.DEFAULT.buffer();
PacketBuffer buffer = new PacketBuffer(byteBuf);
buffer.writeInt(cx);
buffer.writeInt(cz);
buffer.writeVarInt(blocks.size());
for (Map.Entry<Short, Character> blockEntry : blocks.entrySet()) {
buffer.writeShort(blockEntry.getKey());
buffer.writeVarInt(blockEntry.getValue());
public void sendBlockUpdate(FaweChunk chunk, FawePlayer... players) {
try {
PlayerChunkMap playerManager = ((WorldServer) getWorld()).getPlayerChunkMap();
boolean watching = false;
for (int i = 0; i < players.length; i++) {
EntityPlayerMP player = (EntityPlayerMP) ((ForgePlayer) players[i]).parent;
if (!playerManager.isPlayerWatchingChunk(player, chunk.getX(), chunk.getZ())) {
players[i] = null;
} else {
watching = true;
}
packet.readPacketData(buffer);
for (FawePlayer player : players) {
((ForgePlayer) player).parent.connection.sendPacket(packet);
}
} catch (Throwable e) {
e.printStackTrace();
}
if (!watching) return;
final LongAdder size = new LongAdder();
if (chunk instanceof VisualChunk) {
size.add(((VisualChunk) chunk).size());
} else if (chunk instanceof CharFaweChunk) {
size.add(((CharFaweChunk) chunk).getTotalCount());
} else {
chunk.forEachQueuedBlock(new FaweChunkVisitor() {
@Override
public void run(int localX, int y, int localZ, int combined) {
size.add(1);
}
});
}
if (size.intValue() == 0) return;
SPacketMultiBlockChange packet = new SPacketMultiBlockChange();
ByteBuf byteBuf = ByteBufAllocator.DEFAULT.buffer();
final PacketBuffer buffer = new PacketBuffer(byteBuf);
buffer.writeInt(chunk.getX());
buffer.writeInt(chunk.getZ());
buffer.writeVarInt(size.intValue());
chunk.forEachQueuedBlock(new FaweChunkVisitor() {
@Override
public void run(int localX, int y, int localZ, int combined) {
short index = (short) (localX << 12 | localZ << 8 | y);
buffer.writeShort(index);
buffer.writeVarInt(combined);
}
});
packet.readPacketData(buffer);
for (FawePlayer player : players) {
if (player != null) ((EntityPlayerMP) ((ForgePlayer) player).parent).connection.sendPacket(packet);
}
} catch (IOException e) {
e.printStackTrace();
}
}

View File

@ -8,6 +8,9 @@ import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.IntegerPair;
import com.boydti.fawe.object.RunnableVal;
import com.boydti.fawe.object.brush.visualization.VisualChunk;
import com.boydti.fawe.object.number.LongAdder;
import com.boydti.fawe.object.visitor.FaweChunkVisitor;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.MathMan;
import com.boydti.fawe.util.ReflectionUtils;
@ -18,6 +21,7 @@ import com.sk89q.worldedit.world.biome.BaseBiome;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.UnpooledByteBufAllocator;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
@ -322,30 +326,53 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
}
@Override
public void sendBlockUpdate(Map<Long, Map<Short, Character>> blockMap, FawePlayer... players) {
for (Map.Entry<Long, Map<Short, Character>> chunkEntry : blockMap.entrySet()) {
try {
long chunkHash = chunkEntry.getKey();
Map<Short, Character> blocks = chunkEntry.getValue();
S22PacketMultiBlockChange packet = new S22PacketMultiBlockChange();
int cx = MathMan.unpairIntX(chunkHash);
int cz = MathMan.unpairIntY(chunkHash);
ByteBuf byteBuf = new UnpooledByteBufAllocator(true).buffer();
PacketBuffer buffer = new PacketBuffer(byteBuf);
buffer.writeInt(cx);
buffer.writeInt(cz);
buffer.writeVarIntToBuffer(blocks.size());
for (Map.Entry<Short, Character> blockEntry : blocks.entrySet()) {
buffer.writeShort(blockEntry.getKey());
buffer.writeVarIntToBuffer(blockEntry.getValue());
public void sendBlockUpdate(FaweChunk chunk, FawePlayer... players) {
try {
PlayerManager playerManager = ((WorldServer) getWorld()).getPlayerManager();
boolean watching = false;
for (int i = 0; i < players.length; i++) {
EntityPlayerMP player = (EntityPlayerMP) ((ForgePlayer) players[i]).parent;
if (!playerManager.isPlayerWatchingChunk(player, chunk.getX(), chunk.getZ())) {
players[i] = null;
} else {
watching = true;
}
packet.readPacketData(buffer);
for (FawePlayer player : players) {
((ForgePlayer) player).parent.playerNetServerHandler.sendPacket(packet);
}
} catch (Throwable e) {
e.printStackTrace();
}
if (!watching) return;
final LongAdder size = new LongAdder();
if (chunk instanceof VisualChunk) {
size.add(((VisualChunk) chunk).size());
} else if (chunk instanceof CharFaweChunk) {
size.add(((CharFaweChunk) chunk).getTotalCount());
} else {
chunk.forEachQueuedBlock(new FaweChunkVisitor() {
@Override
public void run(int localX, int y, int localZ, int combined) {
size.add(1);
}
});
}
if (size.intValue() == 0) return;
S22PacketMultiBlockChange packet = new S22PacketMultiBlockChange();
ByteBuf byteBuf = new UnpooledByteBufAllocator(true).buffer();
final PacketBuffer buffer = new PacketBuffer(byteBuf);
buffer.writeInt(chunk.getX());
buffer.writeInt(chunk.getZ());
buffer.writeVarIntToBuffer(size.intValue());
chunk.forEachQueuedBlock(new FaweChunkVisitor() {
@Override
public void run(int localX, int y, int localZ, int combined) {
short index = (short) (localX << 12 | localZ << 8 | y);
buffer.writeShort(index);
buffer.writeVarIntToBuffer(combined);
}
});
packet.readPacketData(buffer);
for (FawePlayer player : players) {
if (player != null) ((EntityPlayerMP) ((ForgePlayer) player).parent).playerNetServerHandler.sendPacket(packet);
}
} catch (IOException e) {
e.printStackTrace();
}
}

View File

@ -6,6 +6,9 @@ import com.boydti.fawe.example.NMSMappedFaweQueue;
import com.boydti.fawe.forge.ForgePlayer;
import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.brush.visualization.VisualChunk;
import com.boydti.fawe.object.number.LongAdder;
import com.boydti.fawe.object.visitor.FaweChunkVisitor;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.MathMan;
import com.boydti.fawe.util.ReflectionUtils;
@ -16,6 +19,7 @@ import com.sk89q.worldedit.world.biome.BaseBiome;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
@ -203,30 +207,53 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
}
@Override
public void sendBlockUpdate(Map<Long, Map<Short, Character>> blockMap, FawePlayer... players) {
for (Map.Entry<Long, Map<Short, Character>> chunkEntry : blockMap.entrySet()) {
try {
long chunkHash = chunkEntry.getKey();
Map<Short, Character> blocks = chunkEntry.getValue();
S22PacketMultiBlockChange packet = new S22PacketMultiBlockChange();
int cx = MathMan.unpairIntX(chunkHash);
int cz = MathMan.unpairIntY(chunkHash);
ByteBuf byteBuf = ByteBufAllocator.DEFAULT.buffer();
PacketBuffer buffer = new PacketBuffer(byteBuf);
buffer.writeInt(cx);
buffer.writeInt(cz);
buffer.writeVarIntToBuffer(blocks.size());
for (Map.Entry<Short, Character> blockEntry : blocks.entrySet()) {
buffer.writeShort(blockEntry.getKey());
buffer.writeVarIntToBuffer(blockEntry.getValue());
public void sendBlockUpdate(FaweChunk chunk, FawePlayer... players) {
try {
PlayerManager playerManager = ((WorldServer) getWorld()).getPlayerManager();
boolean watching = false;
for (int i = 0; i < players.length; i++) {
EntityPlayerMP player = (EntityPlayerMP) ((ForgePlayer) players[i]).parent;
if (!playerManager.isPlayerWatchingChunk(player, chunk.getX(), chunk.getZ())) {
players[i] = null;
} else {
watching = true;
}
packet.readPacketData(buffer);
for (FawePlayer player : players) {
((ForgePlayer) player).parent.playerNetServerHandler.sendPacket(packet);
}
} catch (Throwable e) {
e.printStackTrace();
}
if (!watching) return;
final LongAdder size = new LongAdder();
if (chunk instanceof VisualChunk) {
size.add(((VisualChunk) chunk).size());
} else if (chunk instanceof CharFaweChunk) {
size.add(((CharFaweChunk) chunk).getTotalCount());
} else {
chunk.forEachQueuedBlock(new FaweChunkVisitor() {
@Override
public void run(int localX, int y, int localZ, int combined) {
size.add(1);
}
});
}
if (size.intValue() == 0) return;
S22PacketMultiBlockChange packet = new S22PacketMultiBlockChange();
ByteBuf byteBuf = ByteBufAllocator.DEFAULT.buffer();
final PacketBuffer buffer = new PacketBuffer(byteBuf);
buffer.writeInt(chunk.getX());
buffer.writeInt(chunk.getZ());
buffer.writeVarIntToBuffer(size.intValue());
chunk.forEachQueuedBlock(new FaweChunkVisitor() {
@Override
public void run(int localX, int y, int localZ, int combined) {
short index = (short) (localX << 12 | localZ << 8 | y);
buffer.writeShort(index);
buffer.writeVarIntToBuffer(combined);
}
});
packet.readPacketData(buffer);
for (FawePlayer player : players) {
if (player != null) ((EntityPlayerMP) ((ForgePlayer) player).parent).playerNetServerHandler.sendPacket(packet);
}
} catch (IOException e) {
e.printStackTrace();
}
}

View File

@ -6,6 +6,9 @@ import com.boydti.fawe.example.NMSMappedFaweQueue;
import com.boydti.fawe.forge.ForgePlayer;
import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.brush.visualization.VisualChunk;
import com.boydti.fawe.object.number.LongAdder;
import com.boydti.fawe.object.visitor.FaweChunkVisitor;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.MathMan;
import com.boydti.fawe.util.ReflectionUtils;
@ -16,6 +19,7 @@ import com.sk89q.worldedit.world.biome.BaseBiome;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayDeque;
@ -244,30 +248,53 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
}
@Override
public void sendBlockUpdate(Map<Long, Map<Short, Character>> blockMap, FawePlayer... players) {
for (Map.Entry<Long, Map<Short, Character>> chunkEntry : blockMap.entrySet()) {
try {
long chunkHash = chunkEntry.getKey();
Map<Short, Character> blocks = chunkEntry.getValue();
SPacketMultiBlockChange packet = new SPacketMultiBlockChange();
int cx = MathMan.unpairIntX(chunkHash);
int cz = MathMan.unpairIntY(chunkHash);
ByteBuf byteBuf = ByteBufAllocator.DEFAULT.buffer();
PacketBuffer buffer = new PacketBuffer(byteBuf);
buffer.writeInt(cx);
buffer.writeInt(cz);
buffer.writeVarIntToBuffer(blocks.size());
for (Map.Entry<Short, Character> blockEntry : blocks.entrySet()) {
buffer.writeShort(blockEntry.getKey());
buffer.writeVarIntToBuffer(blockEntry.getValue());
public void sendBlockUpdate(FaweChunk chunk, FawePlayer... players) {
try {
PlayerChunkMap playerManager = ((WorldServer) getWorld()).getPlayerChunkMap();
boolean watching = false;
for (int i = 0; i < players.length; i++) {
EntityPlayerMP player = (EntityPlayerMP) ((ForgePlayer) players[i]).parent;
if (!playerManager.isPlayerWatchingChunk(player, chunk.getX(), chunk.getZ())) {
players[i] = null;
} else {
watching = true;
}
packet.readPacketData(buffer);
for (FawePlayer player : players) {
((ForgePlayer) player).parent.connection.sendPacket(packet);
}
} catch (Throwable e) {
e.printStackTrace();
}
if (!watching) return;
final LongAdder size = new LongAdder();
if (chunk instanceof VisualChunk) {
size.add(((VisualChunk) chunk).size());
} else if (chunk instanceof CharFaweChunk) {
size.add(((CharFaweChunk) chunk).getTotalCount());
} else {
chunk.forEachQueuedBlock(new FaweChunkVisitor() {
@Override
public void run(int localX, int y, int localZ, int combined) {
size.add(1);
}
});
}
if (size.intValue() == 0) return;
SPacketMultiBlockChange packet = new SPacketMultiBlockChange();
ByteBuf byteBuf = ByteBufAllocator.DEFAULT.buffer();
final PacketBuffer buffer = new PacketBuffer(byteBuf);
buffer.writeInt(chunk.getX());
buffer.writeInt(chunk.getZ());
buffer.writeVarIntToBuffer(size.intValue());
chunk.forEachQueuedBlock(new FaweChunkVisitor() {
@Override
public void run(int localX, int y, int localZ, int combined) {
short index = (short) (localX << 12 | localZ << 8 | y);
buffer.writeShort(index);
buffer.writeVarIntToBuffer(combined);
}
});
packet.readPacketData(buffer);
for (FawePlayer player : players) {
if (player != null) ((EntityPlayerMP) ((ForgePlayer) player).parent).connection.sendPacket(packet);
}
} catch (IOException e) {
e.printStackTrace();
}
}

View File

@ -33,6 +33,7 @@ public class NukkitRegistryDumper {
}
}
public NukkitRegistryDumper(File file) {
this.file = file;
GsonBuilder builder = new GsonBuilder().setPrettyPrinting();

View File

@ -17,6 +17,7 @@ import com.boydti.fawe.nukkit.optimization.FaweNukkit;
import com.boydti.fawe.nukkit.optimization.FaweNukkitPlayer;
import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.visitor.FaweChunkVisitor;
import com.boydti.fawe.util.MathMan;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.world.World;
@ -128,39 +129,40 @@ public class NukkitQueue extends NMSMappedFaweQueue<Level, BaseFullChunk, BaseFu
}
@Override
public void sendBlockUpdate(Map<Long, Map<Short, Character>> blockMap, FawePlayer... players) {
ArrayList<Block> blocks = new ArrayList<Block>();
for (Map.Entry<Long, Map<Short, Character>> entry : blockMap.entrySet()) {
long chunkHash = entry.getKey();
int cx = MathMan.unpairIntX(chunkHash);
int cz = MathMan.unpairIntY(chunkHash);
Map<Short, Character> ids = entry.getValue();
for (Map.Entry<Short, Character> blockEntry : ids.entrySet()) {
char combined = blockEntry.getValue();
int id = FaweCache.getId(combined);
int data = FaweCache.getData(combined);
Block block = Block.get(id, data);
short blockHash = blockEntry.getKey();
block.x = (blockHash >> 12 & 0xF) + (cx << 4);
block.y = (blockHash & 0xFF);
block.z = (blockHash >> 8 & 0xF) + (cz << 4);
blocks.add(block);
public void sendBlockUpdate(FaweChunk chunk, FawePlayer... players) {
try {
boolean watching = true; // TODO check if player can see chunk
if (!watching) return;
final ArrayList<Block> blocks = new ArrayList<>();
final int bx = chunk.getX() << 4;
final int bz = chunk.getZ() << 4;
chunk.forEachQueuedBlock(new FaweChunkVisitor() {
@Override
public void run(int localX, int y, int localZ, int combined) {
Block block = Block.get(FaweCache.getId(combined), FaweCache.getData(combined));
block.x = bz + localX;
block.y = y;
block.z = bx + localZ;
blocks.add(block);
}
});
Map<Level, List<Player>> playerMap = new HashMap<>();
for (FawePlayer player : players) {
Player nukkitPlayer = ((FaweNukkitPlayer) player).parent;
List<Player> list = playerMap.get(nukkitPlayer.getLevel());
if (list == null) {
list = new ArrayList<>();
playerMap.put(nukkitPlayer.getLevel(), list);
}
list.add(nukkitPlayer);
}
}
Map<Level, List<Player>> playerMap = new HashMap<>();
for (FawePlayer player : players) {
Player nukkitPlayer = ((FaweNukkitPlayer) player).parent;
List<Player> list = playerMap.get(nukkitPlayer.getLevel());
if (list == null) {
list = new ArrayList<>();
playerMap.put(nukkitPlayer.getLevel(), list);
Block[] blocksArray = blocks.toArray(new Block[blocks.size()]);
for (Map.Entry<Level, List<Player>> levelListEntry : playerMap.entrySet()) {
List<Player> playerList = levelListEntry.getValue();
levelListEntry.getKey().sendBlocks(playerList.toArray(new Player[playerList.size()]), blocksArray, UpdateBlockPacket.FLAG_ALL_PRIORITY);
}
list.add(nukkitPlayer);
}
Block[] blocksArray = blocks.toArray(new Block[blocks.size()]);
for (Map.Entry<Level, List<Player>> levelListEntry : playerMap.entrySet()) {
List<Player> playerList = levelListEntry.getValue();
levelListEntry.getKey().sendBlocks(playerList.toArray(new Player[playerList.size()]), blocksArray, UpdateBlockPacket.FLAG_ALL_PRIORITY);
} catch (Throwable e) {
e.printStackTrace();
}
}

View File

@ -16,7 +16,7 @@ import org.spongepowered.api.plugin.Plugin;
import org.spongepowered.api.plugin.PluginContainer;
import org.spongepowered.api.profile.GameProfileManager;
@Plugin(id = "fastasyncworldedit", name = "FastAsyncWorldEdit", description = "fawe", url = "https://github.com/boy0001/FastAsyncWorldedit", version = "development", authors = "Empire92")
@Plugin(id = "fastasyncworldedit", name = " FastAsyncWorldEdit", description = "fawe", url = "https://github.com/boy0001/FastAsyncWorldedit", version = "development", authors = "Empire92")
public class SpongeMain {
@Inject
public PluginContainer plugin;

View File

@ -5,6 +5,9 @@ import com.boydti.fawe.example.CharFaweChunk;
import com.boydti.fawe.example.NMSMappedFaweQueue;
import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.brush.visualization.VisualChunk;
import com.boydti.fawe.object.number.LongAdder;
import com.boydti.fawe.object.visitor.FaweChunkVisitor;
import com.boydti.fawe.sponge.SpongePlayer;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.MathMan;
@ -19,6 +22,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayDeque;
@ -132,30 +136,53 @@ public class SpongeQueue_1_11 extends NMSMappedFaweQueue<World, net.minecraft.wo
}
@Override
public void sendBlockUpdate(Map<Long, Map<Short, Character>> blockMap, FawePlayer... players) {
for (Map.Entry<Long, Map<Short, Character>> chunkEntry : blockMap.entrySet()) {
try {
long chunkHash = chunkEntry.getKey();
Map<Short, Character> blocks = chunkEntry.getValue();
SPacketMultiBlockChange packet = new SPacketMultiBlockChange();
int cx = MathMan.unpairIntX(chunkHash);
int cz = MathMan.unpairIntY(chunkHash);
ByteBuf byteBuf = ByteBufAllocator.DEFAULT.buffer();
PacketBuffer buffer = new PacketBuffer(byteBuf);
buffer.writeInt(cx);
buffer.writeInt(cz);
buffer.writeVarIntToBuffer(blocks.size());
for (Map.Entry<Short, Character> blockEntry : blocks.entrySet()) {
buffer.writeShort(blockEntry.getKey());
buffer.writeVarIntToBuffer(blockEntry.getValue());
public void sendBlockUpdate(FaweChunk chunk, FawePlayer... players) {
try {
PlayerChunkMap playerManager = ((WorldServer) getWorld()).getPlayerChunkMap();
boolean watching = false;
for (int i = 0; i < players.length; i++) {
EntityPlayerMP player = (EntityPlayerMP) ((SpongePlayer) players[i]).parent;
if (!playerManager.isPlayerWatchingChunk(player, chunk.getX(), chunk.getZ())) {
players[i] = null;
} else {
watching = true;
}
packet.readPacketData(buffer);
for (FawePlayer player : players) {
((EntityPlayerMP) ((SpongePlayer) player).parent).connection.sendPacket(packet);
}
} catch (Throwable e) {
e.printStackTrace();
}
if (!watching) return;
final LongAdder size = new LongAdder();
if (chunk instanceof VisualChunk) {
size.add(((VisualChunk) chunk).size());
} else if (chunk instanceof CharFaweChunk) {
size.add(((CharFaweChunk) chunk).getTotalCount());
} else {
chunk.forEachQueuedBlock(new FaweChunkVisitor() {
@Override
public void run(int localX, int y, int localZ, int combined) {
size.add(1);
}
});
}
if (size.intValue() == 0) return;
SPacketMultiBlockChange packet = new SPacketMultiBlockChange();
ByteBuf byteBuf = ByteBufAllocator.DEFAULT.buffer();
final PacketBuffer buffer = new PacketBuffer(byteBuf);
buffer.writeInt(chunk.getX());
buffer.writeInt(chunk.getZ());
buffer.writeVarIntToBuffer(size.intValue());
chunk.forEachQueuedBlock(new FaweChunkVisitor() {
@Override
public void run(int localX, int y, int localZ, int combined) {
short index = (short) (localX << 12 | localZ << 8 | y);
buffer.writeShort(index);
buffer.writeVarIntToBuffer(combined);
}
});
packet.readPacketData(buffer);
for (FawePlayer player : players) {
if (player != null) ((EntityPlayerMP) ((SpongePlayer) player).parent).connection.sendPacket(packet);
}
} catch (IOException e) {
e.printStackTrace();
}
}