Interactive CFI

This commit is contained in:
Jesse Boyd 2017-09-12 03:02:44 +10:00
parent b4c3e3989c
commit 8ac2bf6da3
No known key found for this signature in database
GPG Key ID: 59F1DE6293AF6E1F
37 changed files with 2276 additions and 278 deletions

View File

@ -104,5 +104,6 @@ subprojects {
maven {url "http://ci.frostcast.net/plugin/repository/everything"}
maven {url "http://maven.sk89q.com/artifactory/repo"}
maven {url "http://repo.spongepowered.org/maven"}
maven {url "https://repo.inventivetalent.org/content/groups/public/"}
}
}

View File

@ -17,6 +17,8 @@ import com.boydti.fawe.bukkit.regions.Worldguard;
import com.boydti.fawe.bukkit.util.BukkitTaskMan;
import com.boydti.fawe.bukkit.util.ItemUtil;
import com.boydti.fawe.bukkit.util.VaultUtil;
import com.boydti.fawe.bukkit.util.image.BukkitImageListener;
import com.boydti.fawe.bukkit.util.image.BukkitImageViewer;
import com.boydti.fawe.bukkit.v0.BukkitQueue_0;
import com.boydti.fawe.bukkit.v0.BukkitQueue_All;
import com.boydti.fawe.bukkit.v0.ChunkListener;
@ -33,9 +35,11 @@ import com.boydti.fawe.object.FaweCommand;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.FaweQueue;
import com.boydti.fawe.regions.FaweMaskManager;
import com.boydti.fawe.util.Jars;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.ReflectionUtils;
import com.boydti.fawe.util.TaskManager;
import com.boydti.fawe.util.image.ImageViewer;
import com.boydti.fawe.util.metrics.BStats;
import com.sk89q.bukkit.util.FallbackRegistrationListener;
import com.sk89q.worldedit.bukkit.BukkitPlayerBlockBag;
@ -44,6 +48,7 @@ import com.sk89q.worldedit.bukkit.EditSessionBlockChangeDelegate;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.world.World;
import java.io.File;
import java.io.FileOutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
@ -59,6 +64,7 @@ import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.RegisteredServiceProvider;
import org.primesoft.blockshub.BlocksHubBukkit;
@ -68,6 +74,8 @@ public class FaweBukkit implements IFawe, Listener {
private VaultUtil vault;
private WorldEditPlugin worldedit;
private ItemUtil itemUtil;
private boolean listening;
private BukkitImageListener listener;
public VaultUtil getVault() {
return this.vault;
@ -130,6 +138,35 @@ public class FaweBukkit implements IFawe, Listener {
});
}
@Override
public synchronized ImageViewer getImageViewer(FawePlayer fp) {
if (listening && listener == null) return null;
try {
listening = true;
PluginManager manager = Bukkit.getPluginManager();
if (manager.getPlugin("PacketListenerApi") == null) {
File output = new File(plugin.getDataFolder().getParentFile(), "PacketListenerAPI_v3.6.0-SNAPSHOT.jar");
byte[] jarData = Jars.PL_v3_6_0.download();
try (FileOutputStream fos = new FileOutputStream(output)) {
fos.write(jarData);
}
}
if (manager.getPlugin("MapManager") == null) {
File output = new File(plugin.getDataFolder().getParentFile(), "MapManager_v1.4.0-SNAPSHOT.jar");
byte[] jarData = Jars.MM_v1_4_0.download();
try (FileOutputStream fos = new FileOutputStream(output)) {
fos.write(jarData);
}
}
BukkitImageViewer viewer = new BukkitImageViewer((Player) fp.parent);
if (listener == null) {
this.listener = new BukkitImageListener(plugin);
}
return viewer;
} catch (Throwable ignore) {}
return null;
}
@Override
public int getPlayerCount() {
return plugin.getServer().getOnlinePlayers().size();

View File

@ -42,7 +42,7 @@ public class BrushBoundBaseBlock extends BaseBlock implements BrushHolder {
}
public BrushBoundBaseBlock(Player player, LocalSession session, ItemStack item) {
super(item.getTypeId(), item.getType().getMaxDurability() != 0 ? 0 : Math.max(0, item.getDurability()), getNBT(item));
super(item.getTypeId(), item.getType().getMaxDurability() != 0 || item.getDurability() > 15 ? 0 : Math.max(0, item.getDurability()), getNBT(item));
this.item = item;
this.tool = brushCache.get(getKey(item));
this.player = player;

View File

@ -0,0 +1,31 @@
package com.boydti.fawe.bukkit.util.cui;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.util.cui.CUI;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.plugin.Plugin;
public class CUIListener implements Listener {
public CUIListener(Plugin plugin) {
Bukkit.getPluginManager().registerEvents(this, plugin);
}
@EventHandler
public void onPlayerMove(PlayerMoveEvent event) {
Location from = event.getFrom();
Location to = event.getTo();
if ((int) from.getX() != (int) to.getX() || (int) from.getZ() != (int) to.getZ()) {
FawePlayer<Object> player = FawePlayer.wrap(event.getPlayer());
CUI cui = player.getMeta("CUI");
if (cui instanceof StructureCUI) {
StructureCUI sCui = (StructureCUI) cui;
}
}
}
}

View File

@ -0,0 +1,51 @@
package com.boydti.fawe.bukkit.util.cui;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.util.cui.CUI;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.Vector2D;
import com.sk89q.worldedit.internal.cui.CUIEvent;
import com.sk89q.worldedit.internal.cui.SelectionPointEvent;
import com.sk89q.worldedit.internal.cui.SelectionShapeEvent;
import java.util.HashMap;
import java.util.Map;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Player;
public class StructureCUI extends CUI {
private boolean cuboid;
private Map<Vector2D, Material> chunkMap = new HashMap<>();
public StructureCUI(FawePlayer player) {
super(player);
}
@Override
public void dispatchCUIEvent(CUIEvent event) {
if (event instanceof SelectionShapeEvent) {
clear();
this.cuboid = event.getParameters()[0].equalsIgnoreCase("cuboid");
} else if (cuboid && event instanceof SelectionPointEvent) {
}
}
public void draw(Vector pos1, Vector pos2) {
Player player = this.<Player>getPlayer().parent;
Location position = player.getLocation();
int view;
if (Bukkit.getVersion().contains("paper")) {
view = player.getViewDistance();
} else {
view = Bukkit.getViewDistance();
}
}
public void clear() {
}
}

View File

@ -0,0 +1,259 @@
package com.boydti.fawe.bukkit.util.image;
import com.boydti.fawe.command.CFICommands;
import com.boydti.fawe.jnbt.anvil.HeightMapMCAGenerator;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.brush.BrushSettings;
import com.boydti.fawe.object.extent.FastWorldEditExtent;
import com.boydti.fawe.util.EditSessionBuilder;
import com.boydti.fawe.util.ExtentTraverser;
import com.boydti.fawe.util.TaskManager;
import com.boydti.fawe.util.image.ImageViewer;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.command.tool.BrushTool;
import com.sk89q.worldedit.command.tool.InvalidToolBindException;
import com.sk89q.worldedit.command.tool.brush.Brush;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Rotation;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Entity;
import org.bukkit.entity.ItemFrame;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
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.entity.EntityDamageByEntityEvent;
import org.bukkit.event.hanging.HangingBreakByEntityEvent;
import org.bukkit.event.player.PlayerEvent;
import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.plugin.Plugin;
public class BukkitImageListener implements Listener {
private Location mutable = new Location(Bukkit.getWorlds().get(0), 0, 0, 0);
public BukkitImageListener(Plugin plugin) {
Bukkit.getPluginManager().registerEvents(this, plugin);
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onHangingBreakByEntity(HangingBreakByEntityEvent event) {
if(!(event.getRemover() instanceof Player)) return;
handleInteract(event, (Player) event.getRemover(), event.getEntity(), false);
}
@EventHandler(priority = EventPriority.LOWEST)
public void onEntityDamageByEntity(EntityDamageByEntityEvent event) {
if(!(event.getDamager() instanceof Player)) return;
handleInteract(event, (Player) event.getDamager(), event.getEntity(), false);
}
@EventHandler(priority = EventPriority.LOWEST)
public void onPlayerInteract(PlayerInteractEvent event) {
if (event.useItemInHand() == Event.Result.DENY) return;
Player player = event.getPlayer();
FawePlayer<Object> fp = FawePlayer.wrap(player);
if (fp.getMeta("CFISettings") == null) return;
try {
if (event.getHand() == EquipmentSlot.OFF_HAND) return;
} catch (NoSuchFieldError | NoSuchMethodError ignored) {}
List<Block> target = player.getLastTwoTargetBlocks((Set<Material>) null, 100);
if (target.isEmpty()) return;
Block targetBlock = target.get(0);
World world = player.getWorld();
mutable.setWorld(world);
mutable.setX(targetBlock.getX() + 0.5);
mutable.setY(targetBlock.getY() + 0.5);
mutable.setZ(targetBlock.getZ() + 0.5);
Collection<Entity> entities = world.getNearbyEntities(mutable, 0.46875, 0, 0.46875);
if (!entities.isEmpty()) {
Action action = event.getAction();
boolean primary = action == Action.RIGHT_CLICK_AIR || action == Action.RIGHT_CLICK_BLOCK;
double minDist = Integer.MAX_VALUE;
ItemFrame minItemFrame = null;
for (Entity entity : entities) {
if (entity instanceof ItemFrame) {
ItemFrame itemFrame = (ItemFrame) entity;
Location loc = itemFrame.getLocation();
double dx = loc.getX() - mutable.getX();
double dy = loc.getY() - mutable.getY();
double dz = loc.getZ() - mutable.getZ();
double dist = dx * dx + dy * dy + dz * dz;
if (dist < minDist) {
minItemFrame = itemFrame;
minDist = dist;
}
}
}
if (minItemFrame != null) {
handleInteract(event, minItemFrame, primary);
if (event.isCancelled()) return;
}
}
}
@EventHandler(priority = EventPriority.LOWEST)
public void onPlayerInteractEntity(PlayerInteractEntityEvent event) {
handleInteract(event, event.getRightClicked(), true);
}
private BukkitImageViewer get(HeightMapMCAGenerator generator) {
if (generator == null) return null;
ImageViewer viewer = generator.getImageViewer();
if (viewer == null || !(viewer instanceof BukkitImageViewer)) return null;
BukkitImageViewer biv = (BukkitImageViewer) viewer;
return biv;
}
private void handleInteract(PlayerEvent event, Entity entity, boolean primary) {
handleInteract(event, event.getPlayer(), entity, primary);
}
private void handleInteract(Event event, Player player, Entity entity, boolean primary) {
if (!(entity instanceof ItemFrame)) return;
ItemFrame itemFrame = (ItemFrame) entity;
FawePlayer<Object> fp = FawePlayer.wrap(player);
CFICommands.CFISettings settings = fp.getMeta("CFISettings");
HeightMapMCAGenerator generator = settings == null ? null : settings.getGenerator();
BukkitImageViewer viewer = get(generator);
if (viewer == null) return;
if (itemFrame.getRotation() != Rotation.NONE) {
itemFrame.setRotation(Rotation.NONE);
}
LocalSession session = fp.getSession();
BrushTool tool;
try {
tool = session.getBrushTool(fp.getPlayer(), false);
} catch (InvalidToolBindException e) { return; }
if (tool == null) return;
BrushSettings context = primary ? tool.getPrimary() : tool.getSecondary();
Brush brush = context.getBrush();
ItemFrame[][] frames = viewer.getItemFrames();
if (frames == null || brush == null) {
viewer.selectFrame(itemFrame);
TaskManager.IMP.laterAsync(new Runnable() {
@Override
public void run() {
viewer.view(generator.draw());
}
}, 1);
return;
}
if (brush == null) return;
tool.setContext(context);
if (event instanceof Cancellable) {
((Cancellable) event).setCancelled(true);
}
Location target = itemFrame.getLocation();
Location source = player.getLocation();
double yawRad = Math.toRadians(source.getYaw() + 90d);
double pitchRad = Math.toRadians(-source.getPitch());
double a = Math.cos(pitchRad);
double xRat = Math.cos(yawRad) * a;
double zRat = Math.sin(yawRad) * a;
BlockFace facing = itemFrame.getFacing();
double thickness = 1/32d + 1/128d;
double modX = facing.getModX();
double modZ = facing.getModZ();
double dx = source.getX() - target.getX() - modX * thickness;
double dy = source.getY() + player.getEyeHeight() - target.getY();
double dz = source.getZ() - target.getZ() - modZ * thickness;
double offset;
double localX;
if (modX != 0) {
offset = dx / xRat;
localX = (-modX) * (dz - offset * zRat);
} else {
offset = dz / zRat;
localX = (modZ) * (dx - offset * xRat);
}
double localY = dy - offset * Math.sin(pitchRad);
int localPixelX = (int)((localX + 0.5) * 128);
int localPixelY = (int)((localY + 0.5) * 128);
UUID uuid = itemFrame.getUniqueId();
for (int blockX = 0; blockX < frames.length; blockX++) {
for (int blockY = 0; blockY < frames[0].length; blockY++) {
if (uuid.equals(frames[blockX][blockY].getUniqueId())) {
int pixelX = localPixelX + blockX * 128;
int pixelY = (128 * frames[0].length) - (localPixelY + blockY * 128 + 1);
int width = generator.getWidth();
int length = generator.getLength();
int worldX = (int) (pixelX * width / (frames.length * 128d));
int worldZ = (int) (pixelY * length / (frames[0].length * 128d));
if (worldX < 0 || worldX > width || worldZ < 0 || worldZ > length) return;
Vector wPos = new Vector(worldX, 0, worldZ);
fp.runAction(new Runnable() {
@Override
public void run() {
viewer.refresh();
int topY = generator.getNearestSurfaceTerrainBlock(wPos.getBlockX(), wPos.getBlockZ(), 255, 0, 255);
wPos.mutY(topY);
EditSession es = new EditSessionBuilder(fp.getWorld()).player(fp).combineStages(false).autoQueue(false).blockBag(null).limitUnlimited().build();
ExtentTraverser last = new ExtentTraverser(es.getExtent()).last();
if (last.get() instanceof FastWorldEditExtent) last = last.previous();
last.setNext(generator);
try {
brush.build(es, wPos, context.getMaterial(), context.getSize());
} catch (MaxChangedBlocksException e) {
e.printStackTrace();
}
es.flushQueue();
viewer.view(generator.draw());
}
}, true, true);
return;
}
}
}
}
}

View File

@ -0,0 +1,156 @@
package com.boydti.fawe.bukkit.util.image;
import com.boydti.fawe.util.image.ImageUtil;
import com.boydti.fawe.util.image.ImageViewer;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Collection;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Rotation;
import org.bukkit.World;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Entity;
import org.bukkit.entity.ItemFrame;
import org.bukkit.entity.Player;
import org.inventivetalent.mapmanager.MapManagerPlugin;
import org.inventivetalent.mapmanager.controller.MapController;
import org.inventivetalent.mapmanager.controller.MultiMapController;
import org.inventivetalent.mapmanager.manager.MapManager;
import org.inventivetalent.mapmanager.wrapper.MapWrapper;
public class BukkitImageViewer implements ImageViewer {
private final MapManager mapManager;
private final Player player;
private BufferedImage last;
private ItemFrame[][] frames;
private boolean reverse;
public BukkitImageViewer(Player player) {
mapManager = ((MapManagerPlugin) Bukkit.getPluginManager().getPlugin("MapManager")).getMapManager();
this.player = player;
}
public void selectFrame(ItemFrame start) {
Location pos1 = start.getLocation().clone();
Location pos2 = start.getLocation().clone();
BlockFace facing = start.getFacing();
int planeX = facing.getModX() == 0 ? 1 : 0;
int planeY = facing.getModY() == 0 ? 1 : 0;
int planeZ = facing.getModZ() == 0 ? 1 : 0;
ItemFrame[][] res = find(pos1, pos2, facing);
Location tmp;
while (true) {
if (res != null) {
frames = res;
}
tmp = pos1.clone().subtract(planeX, planeY, planeZ);
if ((res = find(tmp, pos2, facing)) != null) {
pos1 = tmp;
continue;
}
tmp = pos2.clone().add(planeX, planeY, planeZ);
if ((res = find(pos1, tmp, facing)) != null) {
pos2 = tmp;
continue;
}
tmp = pos1.clone().subtract(planeX, 0, planeZ);
if ((res = find(tmp, pos2, facing)) != null) {
pos1 = tmp;
continue;
}
tmp = pos2.clone().add(planeX, 0, planeZ);
if ((res = find(pos1, tmp, facing)) != null) {
pos2 = tmp;
continue;
}
tmp = pos1.clone().subtract(0, 1, 0);
if ((res = find(tmp, pos2, facing)) != null) {
pos1 = tmp;
continue;
}
tmp = pos2.clone().add(0, 1, 0);
if ((res = find(pos1, tmp, facing)) != null) {
pos2 = tmp;
continue;
}
break;
}
}
public ItemFrame[][] getItemFrames() {
return frames;
}
private ItemFrame[][] find(Location pos1, Location pos2, BlockFace facing) {
try {
Location distance = pos2.clone().subtract(pos1).add(1, 1, 1);
int width = Math.max(distance.getBlockX(), distance.getBlockZ());
ItemFrame[][] frames = new ItemFrame[width][distance.getBlockY()];
World world = pos1.getWorld();
this.reverse = (facing == BlockFace.NORTH || facing == BlockFace.EAST);
int v = 0;
for (double y = pos1.getY(); y <= pos2.getY(); y++, v++) {
int h = 0;
for (double z = pos1.getZ(); z <= pos2.getZ(); z++) {
for (double x = pos1.getX(); x <= pos2.getX(); x++, h++) {
Location pos = new Location(world, x, y, z);
Collection<Entity> entities = world.getNearbyEntities(pos, 0.1, 0.1, 0.1);
boolean contains = false;
for (Entity ent : entities) {
if (ent instanceof ItemFrame && ((ItemFrame) ent).getFacing() == facing) {
ItemFrame itemFrame = (ItemFrame) ent;
itemFrame.setRotation(Rotation.NONE);
contains = true;
frames[reverse ? width - 1 - h : h][v] = (ItemFrame) ent;
break;
}
}
if (!contains) return null;
}
}
}
return frames;
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}
@Override
public void view(BufferedImage image) {
last = image;
if (this.frames != null) {
int width = frames.length;
int height = frames[0].length;
BufferedImage scaled = ImageUtil.getScaledInstance(image, 128 * width, 128 * height, RenderingHints.VALUE_INTERPOLATION_BILINEAR, false);
MapWrapper mapWrapper = mapManager.wrapMultiImage(scaled, width, height);
MultiMapController controller = (MultiMapController) mapWrapper.getController();
controller.addViewer(player);
controller.sendContent(player);
controller.showInFrames(player, frames, true);
} else {
BufferedImage scaled = ImageUtil.getScaledInstance(image, 128, 128, RenderingHints.VALUE_INTERPOLATION_BILINEAR, false);
MapWrapper mapWrapper = mapManager.wrapImage(scaled);
MapController controller = mapWrapper.getController();
controller.addViewer(player);
controller.sendContent(player);
controller.showInHand(player, true);
}
}
public void refresh() {
if (last != null) view(last);
}
@Override
public void close() throws IOException {
last = null;
}
}

View File

@ -131,6 +131,14 @@ public class AsyncBlockState implements BlockState {
return result;
}
public CompoundTag getNbtData() {
return nbt;
}
public void setNbtData(CompoundTag nbt) {
this.nbt = nbt;
}
@Override
public byte getRawData() {
return data;

View File

@ -0,0 +1,43 @@
package com.boydti.fawe.bukkit.wrapper.state;
import com.boydti.fawe.bukkit.wrapper.AsyncBlock;
import com.boydti.fawe.bukkit.wrapper.AsyncBlockState;
import com.boydti.fawe.util.ReflectionUtils;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.StringTag;
import com.sk89q.jnbt.Tag;
import java.util.Map;
import org.bukkit.block.Sign;
public class AsyncSign extends AsyncBlockState implements Sign {
public AsyncSign(AsyncBlock block) {
super(block);
}
@Override
public String[] getLines() {
CompoundTag nbt = getNbtData();
String[] data = new String[4];
if (nbt != null) {
for (int i = 1; i <= 4; i++) {
data[i - 1] = nbt.getString("Text" + i);
}
}
return data;
}
@Override
public String getLine(int index) throws IndexOutOfBoundsException {
CompoundTag nbt = getNbtData();
return nbt == null ? null : nbt.getString("Text" + (index + 1));
}
@Override
public void setLine(int index, String line) throws IndexOutOfBoundsException {
CompoundTag nbt = getNbtData();
if (nbt != null) {
Map<String, Tag> map = ReflectionUtils.getMap(nbt.getValue());
map.put("Text" + (index + 1), new StringTag(line));
}
}
}

View File

@ -15,6 +15,7 @@ dependencies {
compile(group: 'com.sk89q.worldedit', name: 'worldedit-core', version:'6.1.3-SNAPSHOT') {
exclude(module: 'bukkit-classloader-check')
}
compile 'org.inventivetalent:mapmanager:1.4.0-SNAPSHOT'
}
processResources {

View File

@ -19,6 +19,7 @@ import com.boydti.fawe.util.Updater;
import com.boydti.fawe.util.WEManager;
import com.boydti.fawe.util.chat.ChatManager;
import com.boydti.fawe.util.chat.PlainChatManager;
import com.boydti.fawe.util.cui.CUI;
import com.boydti.fawe.util.metrics.BStats;
import com.sk89q.jnbt.NBTInputStream;
import com.sk89q.jnbt.NBTOutputStream;
@ -68,6 +69,7 @@ import com.sk89q.worldedit.extension.factory.DefaultMaskParser;
import com.sk89q.worldedit.extension.factory.DefaultTransformParser;
import com.sk89q.worldedit.extension.factory.HashTagPatternParser;
import com.sk89q.worldedit.extension.platform.AbstractPlayerActor;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.CommandManager;
import com.sk89q.worldedit.extension.platform.PlatformManager;
import com.sk89q.worldedit.extension.platform.PlayerProxy;
@ -355,6 +357,25 @@ public class Fawe {
return false;
}
public CUI getCUI(Actor actor) {
FawePlayer<Object> fp = FawePlayer.wrap(actor);
CUI cui = fp.getMeta("CUI");
if (cui == null) {
cui = Fawe.imp().getCUI(fp);
if (cui != null) {
synchronized (fp) {
CUI tmp = fp.getMeta("CUI");
if (tmp == null) {
fp.setMeta("CUI", cui);
} else {
cui = tmp;
}
}
}
}
return cui;
}
public ChatManager getChatManager() {
return chatManager;
}

View File

@ -812,6 +812,8 @@ public class FaweCache {
return asTag((int[]) value);
} else if (value instanceof Tag) {
return (Tag) value;
} else if (value instanceof Boolean) {
return asTag((byte) ((boolean) value ? 1 : 0));
} else if (value == null) {
System.out.println("Invalid nbt: " + value);
return null;

View File

@ -5,6 +5,8 @@ import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.FaweQueue;
import com.boydti.fawe.regions.FaweMaskManager;
import com.boydti.fawe.util.TaskManager;
import com.boydti.fawe.util.cui.CUI;
import com.boydti.fawe.util.image.ImageViewer;
import com.sk89q.worldedit.world.World;
import java.io.File;
import java.util.Collection;
@ -33,6 +35,9 @@ public interface IFawe {
public void startMetrics();
default CUI getCUI(FawePlayer player) { return null; }
default ImageViewer getImageViewer(FawePlayer player) { return null; }
default int getPlayerCount() {
return Fawe.get().getCachedPlayers().size();
@ -42,7 +47,6 @@ public interface IFawe {
public boolean isOnlineMode();
public String getPlatform();
public UUID getUUID(String name);

View File

@ -0,0 +1,83 @@
package com.boydti.fawe.command;
import com.boydti.fawe.config.Commands;
import com.boydti.fawe.object.FawePlayer;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.command.MethodCommands;
import com.sk89q.worldedit.util.command.SimpleDispatcher;
import com.sk89q.worldedit.util.command.parametric.ParametricBuilder;
public class CFICommand extends MethodCommands {
private final CFICommands child;
private final SimpleDispatcher dispatcher;
public CFICommand(WorldEdit worldEdit, ParametricBuilder builder) {
super(worldEdit);
this.child = new CFICommands(worldEdit);
this.dispatcher = new SimpleDispatcher();
builder.registerMethodsAsCommands(dispatcher, child);
}
@Command(
aliases = {"cfi", "createfromimage"},
usage = "",
min = 0,
max = -1,
anyFlags = true,
desc = "Start CreateFromImage"
)
@CommandPermissions("worldedit.anvil.cfi")
public void cfi(FawePlayer fp, CommandContext context) throws CommandException {
CFICommands.CFISettings settings = child.getSettings(fp);
if (!settings.hasGenerator()) {
switch (context.argsLength()) {
case 0: {
String hmCmd = child.alias() + " ";
if (settings.image == null) {
hmCmd += "image";
} else {
hmCmd = Commands.getAlias(CFICommands.class, "heightmap") + " " + settings.imageArg;
}
child.msg("What do you want to use as the base?").newline()
.text("&7[&aHeightMap&7]").cmdTip(hmCmd).text(" - A heightmap like ").text("&7[&athis&7]").linkTip("http://i.imgur.com/qCd30MR.jpg")
.newline()
.text("&7[&aEmpty&7]").cmdTip(child.alias() + " empty").text("- An empty map of a specific size")
.send(fp);
break;
}
default: {
String remaining = context.getJoinedStrings(0);
if (!dispatcher.contains(context.getString(0))) {
switch (context.argsLength()) {
case 1: {
String cmd = Commands.getAlias(CFICommands.class, "heightmap") + " " + context.getJoinedStrings(0);
dispatcher.call(cmd, context.getLocals(), new String[0]);
return;
}
case 2: {
String cmd = Commands.getAlias(CFICommands.class, "empty") + " " + context.getJoinedStrings(0);
dispatcher.call(cmd, context.getLocals(), new String[0]);
return;
}
}
}
dispatcher.call(remaining, context.getLocals(), new String[0]);
}
}
} else {
switch (context.argsLength()) {
case 0:
child.mainMenu(fp);
break;
default:
dispatcher.call(context.getJoinedStrings(0), context.getLocals(), new String[0]);
break;
}
}
}
}

View File

@ -0,0 +1,843 @@
package com.boydti.fawe.command;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.config.Commands;
import com.boydti.fawe.jnbt.anvil.HeightMapMCAGenerator;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.RunnableVal;
import com.boydti.fawe.util.CleanTextureUtil;
import com.boydti.fawe.util.FilteredTextureUtil;
import com.boydti.fawe.util.ImgurUtility;
import com.boydti.fawe.util.StringMan;
import com.boydti.fawe.util.TaskManager;
import com.boydti.fawe.util.TextureUtil;
import com.boydti.fawe.util.chat.Message;
import com.boydti.fawe.util.image.ImageUtil;
import com.intellectualcrafters.plot.PS;
import com.intellectualcrafters.plot.commands.Auto;
import com.intellectualcrafters.plot.config.C;
import com.intellectualcrafters.plot.config.Settings;
import com.intellectualcrafters.plot.object.Plot;
import com.intellectualcrafters.plot.object.PlotId;
import com.intellectualcrafters.plot.object.PlotPlayer;
import com.intellectualcrafters.plot.object.worlds.PlotAreaManager;
import com.intellectualcrafters.plot.object.worlds.SinglePlotArea;
import com.intellectualcrafters.plot.object.worlds.SinglePlotAreaManager;
import com.intellectualcrafters.plot.util.MathMan;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.worldedit.EmptyClipboardException;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.command.MethodCommands;
import com.sk89q.worldedit.extension.input.InputParseException;
import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.session.request.Request;
import com.sk89q.worldedit.util.command.binding.Switch;
import com.sk89q.worldedit.util.command.parametric.Optional;
import com.sk89q.worldedit.util.command.parametric.ParameterException;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.biome.BaseBiome;
import com.sk89q.worldedit.world.registry.BundledBlockData;
import com.sk89q.worldedit.world.registry.WorldData;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;
import java.util.HashSet;
import java.util.Set;
import javax.imageio.ImageIO;
@Command(aliases = {"/cfi"}, desc = "Create a world from images: [More Info](https://git.io/v5iDy)")
public class CFICommands extends MethodCommands {
/**
* Create a new instance.
*
* @param worldEdit reference to WorldEdit
*/
public CFICommands(WorldEdit worldEdit) {
super(worldEdit);
}
@Command(
aliases = {"heightmap"},
usage = "<url>",
desc = "Start CFI with a height map as a base"
)
@CommandPermissions("worldedit.anvil.cfi")
public void heightmap(FawePlayer fp, BufferedImage image) {
HeightMapMCAGenerator generator = new HeightMapMCAGenerator(image, null);
setup(generator, fp);
}
@Command(
aliases = {"empty"},
usage = "<width> <length>",
desc = "Start CFI with an empty map as a base"
)
@CommandPermissions("worldedit.anvil.cfi")
public void heightmap(FawePlayer fp, int width, int length) {
HeightMapMCAGenerator generator = new HeightMapMCAGenerator(width, length, null);
setup(generator, fp);
}
private void setup(HeightMapMCAGenerator generator, FawePlayer fp) {
CFISettings settings = getSettings(fp);
settings.remove().setGenerator(generator).bind();
generator.setImageViewer(Fawe.imp().getImageViewer(fp));
mainMenu(fp);
}
@Command(
aliases = {"brush"},
usage = "",
desc = "Info about using brushes with CFI"
)
@CommandPermissions("worldedit.anvil.cfi")
public void brush(FawePlayer fp) throws ParameterException{
CFISettings settings = assertSettings(fp);
Message msg;
if (settings.getGenerator().getImageViewer() != null) {
msg = msg("CFI supports using brushes during creation").newline()
.text(" - Place the map on a wall of item frames").newline()
.text(" - Use any WorldEdit brush on the item frames").newline()
.text(" - Example: ").text("Video").linkTip("https://goo.gl/PK4DMG").newline();
} else {
msg = msg("This is not supported with your platform/version").newline();
}
msg.text("&8> &7[&aNext&7]").cmdTip(alias()).send(fp);
}
@Command(
aliases = {"cancel", "exit"},
usage = "",
desc = "Cancel creation"
)
@CommandPermissions("worldedit.anvil.cfi")
public void cancel(FawePlayer fp) throws ParameterException, IOException {
getSettings(fp).remove();
fp.sendMessage(BBC.getPrefix() + "Cancelled!");
}
@Command(
aliases = {"done", "create"},
usage = "",
desc = "Create the world"
)
@CommandPermissions("worldedit.anvil.cfi")
public void done(FawePlayer fp) throws ParameterException, IOException {
CFISettings settings = assertSettings(fp);
PlotAreaManager manager = PS.get().getPlotAreaManager();
if (manager instanceof SinglePlotAreaManager) {
SinglePlotAreaManager sManager = (SinglePlotAreaManager) manager;
SinglePlotArea area = sManager.getArea();
PlotPlayer player = PlotPlayer.wrap(fp.parent);
fp.sendMessage(BBC.getPrefix() + "Claiming world");
Plot plot = TaskManager.IMP.sync(new RunnableVal<Plot>() {
@Override
public void run(Plot o) {
int currentPlots = Settings.Limit.GLOBAL ? player.getPlotCount() : player.getPlotCount(area.worldname);
int diff = player.getAllowedPlots() - currentPlots;
if (diff < 1) {
C.CANT_CLAIM_MORE_PLOTS_NUM.send(player, -diff);
return;
}
if (area.getMeta("lastPlot") == null) {
area.setMeta("lastPlot", new PlotId(0, 0));
}
PlotId lastId = (PlotId) area.getMeta("lastPlot");
while (true) {
lastId = Auto.getNextPlotId(lastId, 1);
if (area.canClaim(player, lastId, lastId)) {
break;
}
}
area.setMeta("lastPlot", lastId);
this.value = area.getPlot(lastId);
this.value.setOwner(player.getUUID());
}
});
if (plot == null) return;
File folder = new File(PS.imp().getWorldContainer(), plot.getWorldName() + File.separator + "region");
HeightMapMCAGenerator generator = settings.getGenerator();
generator.setFolder(folder);
fp.sendMessage(BBC.getPrefix() + "Generating");
generator.generate();
settings.remove();
fp.sendMessage(BBC.getPrefix() + "Done!");
TaskManager.IMP.sync(new RunnableVal<Object>() {
@Override
public void run(Object value) {
plot.teleportPlayer(player);
}
});
} else {
fp.sendMessage(BBC.getPrefix() + "Must have the `worlds` component enabled in the PlotSquared config.yml");
}
}
@Command(
aliases = {"column", "setcolumn"},
usage = "<pattern> [url|mask]",
desc = "Set the floor and main block"
)
@CommandPermissions("worldedit.anvil.cfi")
public void column(FawePlayer fp, Pattern pattern, @Optional BufferedImage image, @Optional Mask mask, @Switch('w') boolean disableWhiteOnly) throws ParameterException{
HeightMapMCAGenerator gen = assertSettings(fp).getGenerator();
if (image != null) gen.setColumn(image, pattern, !disableWhiteOnly);
else if (mask != null) gen.setColumn(mask, pattern);
else gen.setColumn(pattern);
fp.sendMessage("Set column!");
}
@Command(
aliases = {"floor", "setfloor"},
usage = "<pattern> [url|mask]",
desc = "Set the floor (default: grass)"
)
@CommandPermissions("worldedit.anvil.cfi")
public void floor(FawePlayer fp, Pattern pattern, @Optional BufferedImage image, @Optional Mask mask, @Switch('w') boolean disableWhiteOnly) throws ParameterException{
HeightMapMCAGenerator gen = assertSettings(fp).getGenerator();
if (image != null) gen.setFloor(image, pattern, !disableWhiteOnly);
else if (mask != null) gen.setFloor(mask, pattern);
else gen.setFloor(pattern);
fp.sendMessage("Set floor!");
}
@Command(
aliases = {"main", "setmain"},
usage = "<pattern> [url|mask]",
desc = "Set the main block (default: stone)"
)
@CommandPermissions("worldedit.anvil.cfi")
public void main(FawePlayer fp, Pattern pattern, @Optional BufferedImage image, @Optional Mask mask, @Switch('w') boolean disableWhiteOnly) throws ParameterException{
HeightMapMCAGenerator gen = assertSettings(fp).getGenerator();
if (image != null) gen.setMain(image, pattern, !disableWhiteOnly);
else if (mask != null) gen.setMain(mask, pattern);
else gen.setMain(pattern);
fp.sendMessage("Set main!");
}
@Command(
aliases = {"overlay", "setoverlay"},
usage = "<pattern> [url|mask]",
desc = "Set the overlay block",
help = "Change the block directly above the floor (default: air)\n" +
"e.g. Tallgrass"
)
@CommandPermissions("worldedit.anvil.cfi")
public void overlay(FawePlayer fp, Pattern pattern, @Optional BufferedImage image, @Optional Mask mask, @Switch('w') boolean disableWhiteOnly) throws ParameterException{
HeightMapMCAGenerator gen = assertSettings(fp).getGenerator();
if (image != null) gen.setOverlay(image, pattern, !disableWhiteOnly);
else if (mask != null) gen.setOverlay(mask, pattern);
else gen.setOverlay(pattern);
fp.sendMessage("Set overlay!");
}
@Command(
aliases = {"smooth"},
usage = "<radius> <iterations> [image|mask]",
desc = "Smooth the terrain",
help = "Smooth terrain within an image-mask, or worldedit mask\n" +
" - You can use !0 as the mask to smooth everything\n" +
" - This supports smoothing snow layers (set the floor to 78:7)\n" +
" - A good value for radius and iterations would be 1 8."
)
@CommandPermissions("worldedit.anvil.cfi")
public void smooth(FawePlayer fp, int radius, int iterations, @Optional BufferedImage image, @Optional Mask mask, @Switch('w') boolean disableWhiteOnly) throws ParameterException{
HeightMapMCAGenerator gen = assertSettings(fp).getGenerator();
if (image != null) gen.smooth(image, !disableWhiteOnly, radius, iterations);
else gen.smooth(mask, radius, iterations);
fp.sendMessage("Performed smooth!");
}
@Command(
aliases = {"snow"},
usage = "[image|mask]",
desc = "Create some snow"
)
@CommandPermissions("worldedit.anvil.cfi")
public void snow(FawePlayer fp, @Optional BufferedImage image, @Optional Mask mask, @Switch('w') boolean disableWhiteOnly) throws ParameterException{
HeightMapMCAGenerator gen = assertSettings(fp).getGenerator();
floor(fp, FaweCache.getBlock(78, 7), image, mask, disableWhiteOnly);
smooth(fp, 1, 8, image, mask, disableWhiteOnly);
msg("Added snow!").newline().text("&8> &7[&aNext&7]").cmdTip(alias()).send(fp);
}
@Command(
aliases = {"biomepriority", "palettebiomepriority", "setpalettebiomepriority"},
usage = "[percent=50]",
desc = "Set the biome priority",
help = "Increase or decrease biome priority when using blockBiomeColor.\n" +
"A value of 50 is the default\n" +
"Above 50 will prefer to color with biomes\n" +
"Below 50 will prefer to color with blocks"
)
@CommandPermissions("worldedit.anvil.cfi")
public void biomepriority(FawePlayer fp, int value) throws ParameterException{
assertSettings(fp).getGenerator().setBiomePriority(value);
coloring(fp);
}
@Command(
aliases = {"paletteblocks", "colorpaletterblocks", "setcolorpaletteblocks"},
usage = "<blocks|#clipboard|*>",
desc = "Set the blocks used for coloring",
help = "Allow only specific blocks to be used for coloring\n" +
"`blocks` is a list of blocks e.g. stone,bedrock,wool\n" +
"`#clipboard` will only use the blocks present in your clipboard."
)
@CommandPermissions("worldedit.anvil.cfi")
public void paletteblocks(FawePlayer fp, @Optional String arg) throws ParameterException, EmptyClipboardException, InputParseException, FileNotFoundException {
if (arg == null) {
msg("What blocks do you want to color with?").newline()
.text("&7[&aAll&7]").cmdTip(alias() + " PaletteBlocks *").text(" - All available blocks")
.newline()
.text("&7[&aClipboard&7]").cmdTip(alias() + " PaletteBlocks #clipboard").text(" - The blocks in your clipboard")
.newline()
.text("&7[&aList&7]").suggestTip(alias() + " PaletteBlocks stone,gravel").text(" - A comma separated list of blocks")
.newline()
.text("&7[&aComplexity&7]").cmdTip(alias() + " Complexity").text(" - Block textures within a complexity range")
.newline()
.text("&8< &7[&aBack&7]").cmdTip(alias() + " " + Commands.getAlias(CFICommands.class, "coloring"))
.send(fp);
return;
}
HeightMapMCAGenerator generator = assertSettings(fp).getGenerator();
ParserContext context = new ParserContext();
context.setActor(fp.getPlayer());
context.setWorld(fp.getWorld());
context.setSession(fp.getSession());
context.setExtent(generator);
Request.request().setExtent(generator);
Set<BaseBlock> blocks;
switch (arg.toLowerCase()) {
case "*": {
generator.setTextureUtil(Fawe.get().getTextureUtil());
return;
}
case "#clipboard": {
ClipboardHolder holder = fp.getSession().getClipboard();
Clipboard clipboard = holder.getClipboard();
boolean[] ids = new boolean[Character.MAX_VALUE + 1];
for (Vector pt : clipboard.getRegion()) {
ids[clipboard.getBlock(pt).getCombined()] = true;
}
blocks = new HashSet<>();
for (int combined = 0; combined < ids.length; combined++) {
if (ids[combined]) blocks.add(FaweCache.CACHE_BLOCK[combined]);
}
break;
}
default: {
blocks = worldEdit.getBlockFactory().parseFromListInput(arg, context);
break;
}
}
generator.setTextureUtil(new FilteredTextureUtil(Fawe.get().getTextureUtil(), blocks));
coloring(fp);
}
@Command(
aliases = {"randomization", "paletterandomization"},
usage = "<true|false>",
desc = "Set whether randomization is enabled",
help = "This is enabled by default, randomization will add some random variation in the blocks used to closer match the provided image.\n" +
"If disabled, the closest block to the color will always be used.\n" +
"Randomization will allow mixing biomes when coloring with biomes"
)
@CommandPermissions("worldedit.anvil.cfi")
public void randomization(FawePlayer fp, boolean enabled) throws ParameterException {
assertSettings(fp).getGenerator().setTextureRandomVariation(enabled);
coloring(fp);
}
@Command(
aliases = {"complexity", "palettecomplexity"},
usage = "<minPercent> <maxPercent>",
desc = "Set the complexity for coloring",
help = "Set the complexity for coloring\n" +
"Filter out blocks to use based on their complexity, which is a measurement of how much color variation there is in the texture for that block.\n" +
"Glazed terracotta is complex, and not very pleasant for terrain, whereas stone and wool are simpler textures.\n" +
"Using 0 73 for the min/max would use the simplest 73% of blocks for coloring, and is a reasonable value."
)
@CommandPermissions("worldedit.anvil.cfi")
public void complexity(FawePlayer fp, int min, int max) throws ParameterException, FileNotFoundException {
HeightMapMCAGenerator gen = assertSettings(fp).getGenerator();
if (min == 0 && max == 100) gen.setTextureUtil(Fawe.get().getTextureUtil());
else gen.setTextureUtil(new CleanTextureUtil(Fawe.get().getTextureUtil(), min, max));
coloring(fp);
}
@Command(
aliases = {"schem", "schematic", "schems", "schematics", "addschems"},
usage = "[url] <mask> <file|folder|url> <rarity> <distance> <rotate=true>",
desc = "Populate schematics",
help = "Populate a schematic on the terrain\n" +
" - Change the mask (e.g. angle mask) to only place the schematic in specific locations.\n" +
" - The rarity is a value between 0 and 100.\n" +
" - The distance is the spacing between each schematic"
)
@CommandPermissions("worldedit.anvil.cfi")
public void schem(FawePlayer fp, @Optional BufferedImage imageMask, Mask mask, String schematic, int rarity, int distance, boolean rotate) throws ParameterException, IOException, WorldEditException {
HeightMapMCAGenerator gen = assertSettings(fp).getGenerator();
World world = fp.getWorld();
WorldData wd = world.getWorldData();
ClipboardHolder[] clipboards = ClipboardFormat.SCHEMATIC.loadAllFromInput(fp.getPlayer(), wd, schematic, true);
if (clipboards == null) {
return;
}
if (imageMask == null) {
gen.addSchems(mask, wd, clipboards, rarity, distance, rotate);
} else {
gen.addSchems(imageMask, mask, wd, clipboards, rarity, distance, rotate);
}
msg("Added schematics!").newline().text("&8> &7[&aNext&7]").cmdTip(alias()).send(fp);
}
@Command(
aliases = {"biome", "setbiome"},
usage = "<biome> [image|mask]",
desc = "Set the biome",
help = "Set the biome in specific parts of the map.\n" +
" - If an image is used, the biome will have a chance to be set based on how white the pixel is (white #FFF = 100% chance)" +
" - The whiteOnly parameter determines if only white values on the image are set" +
" - If a mask is used, the biome will be set anywhere the mask applies"
)
@CommandPermissions("worldedit.anvil.cfi")
public void biome(FawePlayer fp, BaseBiome biome, @Optional BufferedImage image, @Optional Mask mask, @Switch('w') boolean disableWhiteOnly) throws ParameterException{
HeightMapMCAGenerator gen = assertSettings(fp).getGenerator();
if (image != null) gen.setBiome(image, (byte) biome.getId(), !disableWhiteOnly);
else if (mask != null) gen.setBiome(mask, (byte) biome.getId());
else gen.setBiome((byte) biome.getId());
msg("Set biome!").newline().text("&8> &7[&aNext&7]").cmdTip(alias()).send(fp);
}
@Command(
aliases = {"caves", "addcaves"},
desc = "Generate vanilla caves"
)
@CommandPermissions("worldedit.anvil.cfi")
public void caves(FawePlayer fp) throws ParameterException, WorldEditException {
assertSettings(fp).getGenerator().addCaves();
msg("Added caves!").newline().text("&8> &7[&aNext&7]").cmdTip(alias()).send(fp);
}
@Command(
aliases = {"ore", "addore"},
usage = "<mask=stone> <pattern> <size> <frequency> <rarity> <minY> <maxY>",
desc = "Add an ore",
help = "Use a specific pattern and settings to generate ore"
)
@CommandPermissions("worldedit.anvil.cfi")
public void ore(FawePlayer fp, Mask mask, Pattern pattern, int size, int frequency, int rariry, int minY, int maxY) throws ParameterException, WorldEditException {
assertSettings(fp).getGenerator().addOre(mask, pattern, size, frequency, rariry, minY, maxY);
msg("Added ore!").newline().text("&8> &7[&aNext&7]").cmdTip(alias()).send(fp);
}
@Command(
aliases = {"ores", "addores"},
usage = "<mask=stone>",
desc = "Generate the vanilla ores"
)
@CommandPermissions("worldedit.anvil.cfi")
public void ores(FawePlayer fp, Mask mask) throws ParameterException, WorldEditException {
assertSettings(fp).getGenerator().addDefaultOres(mask);
msg("Added ores!").newline().text("&8> &7[&aNext&7]").cmdTip(alias()).send(fp);
}
@Command(
aliases = {"height", "setheight"},
usage = "<height|image>",
desc = "Set the height",
help = "Set the terrain height either based on an image heightmap, or a numeric value."
)
@CommandPermissions("worldedit.anvil.cfi")
public void height(FawePlayer fp, String arg) throws ParameterException, WorldEditException {
HeightMapMCAGenerator gen = assertSettings(fp).getGenerator();
if (!MathMan.isInteger(arg)) {
gen.setHeight(ImageUtil.getImage(arg));
} else {
gen.setHeights(Integer.parseInt(arg));
}
msg("Set height!").newline().text("&8> &7[&aNext&7]").cmdTip(alias()).send(fp);
}
@Command(
aliases = {"water", "waterid"},
usage = "<block>",
desc = "Change the block used for water\n" +
"e.g. Lava"
)
@CommandPermissions("worldedit.anvil.cfi")
public void waterId(FawePlayer fp, BaseBlock block) throws ParameterException, WorldEditException {
assertSettings(fp).getGenerator().setWaterId(block.getId());
msg("Set water id!").newline().text("&8> &7[&aNext&7]").cmdTip(alias()).send(fp);
}
@Command(
aliases = {"waterheight", "sealevel", "setwaterheight"},
usage = "<height>",
desc = "Set the level water is generated at\n" +
"Set the level water is generated at\n" +
" - By default water is disabled (with a value of 0)"
)
@CommandPermissions("worldedit.anvil.cfi")
public void height(FawePlayer fp, int height) throws ParameterException, WorldEditException {
assertSettings(fp).getGenerator().setWaterHeight(height);
msg("Set height!").newline().text("&8> &7[&aNext&7]").cmdTip(alias()).send(fp);
}
@Command(
aliases = {"glass", "glasscolor", "setglasscolor"},
usage = "<url>",
desc = "Color terrain using glass"
)
@CommandPermissions("worldedit.anvil.cfi")
public void glass(FawePlayer fp, BufferedImage image, @Optional BufferedImage imageMask, @Optional Mask mask, @Switch('w') boolean disableWhiteOnly) throws ParameterException, WorldEditException {
assertSettings(fp).getGenerator().setColorWithGlass(image);
msg("Set color with glass!").newline().text("&8> &7[&aNext&7]").cmdTip(alias()).send(fp);
}
@Command(
aliases = {"color", "setcolor", "blockcolor", "blocks"},
usage = "<url> [imageMask|mask]",
desc = "Set the color with blocks and biomes",
help = "Color the terrain using only blocks\n" +
"Provide an image, or worldedit mask for the 2nd argument to restrict what areas are colored\n" +
"The -w (disableWhiteOnly) will randomly apply depending on the pixel luminance"
)
@CommandPermissions("worldedit.anvil.cfi")
public void color(FawePlayer fp, BufferedImage image, @Optional BufferedImage imageMask, @Optional Mask mask, @Switch('w') boolean disableWhiteOnly) throws ParameterException, WorldEditException {
HeightMapMCAGenerator gen = assertSettings(fp).getGenerator();
if (imageMask != null) gen.setColor(image, imageMask, !disableWhiteOnly);
else if (mask != null) gen.setColor(image, mask);
else gen.setColor(image);
msg("Set color with blocks!").newline().text("&8> &7[&aNext&7]").cmdTip(alias()).send(fp);
}
@Command(
aliases = {"blockbiomecolor", "setblockandbiomecolor", "blockandbiome"},
usage = "<url> [imageMask|mask]",
desc = "Set the color with blocks and biomes",
help = "Color the terrain using blocks and biomes.\n" +
"Provide an image, or worldedit mask to restrict what areas are colored\n" +
"The -w (disableWhiteOnly) will randomly apply depending on the pixel luminance"
)
@CommandPermissions("worldedit.anvil.cfi")
public void blockbiome(FawePlayer fp, BufferedImage image, @Optional BufferedImage imageMask, @Optional Mask mask, @Switch('w') boolean disableWhiteOnly) throws ParameterException, WorldEditException {
assertSettings(fp).getGenerator().setBlockAndBiomeColor(image, mask, imageMask, !disableWhiteOnly);
msg("Set color with blocks and biomes!").newline().text("&8> &7[&aNext&7]").cmdTip(alias()).send(fp);
}
@Command(
aliases = {"biomecolor", "setbiomecolor", "biomes"},
usage = "<url> [imageMask|mask]",
desc = "Color the terrain using biomes.\n" +
"Note: Biome coloring does not change blocks:\n" +
" - If you changed the block to something other than grass you will not see anything."
)
@CommandPermissions("worldedit.anvil.cfi")
public void biomecolor(FawePlayer fp, BufferedImage image, @Optional BufferedImage imageMask, @Optional Mask mask, @Switch('w') boolean disableWhiteOnly) throws ParameterException, WorldEditException {
assertSettings(fp).getGenerator().setBiomeColor(image);
msg("Set color with biomes!").newline().text("&8> &7[&aNext&7]").cmdTip(alias()).send(fp);
}
@Command(
aliases = {"coloring", "palette"},
usage = "",
desc = "Color the world using an image"
)
@CommandPermissions("worldedit.anvil.cfi")
public void coloring(FawePlayer fp) throws ParameterException{
CFISettings settings = assertSettings(fp);
HeightMapMCAGenerator gen = settings.getGenerator();
boolean rand = gen.getTextureRandomVariation();
String mask;
if (settings.imageMask != null) {
mask = "Mask Image";
} else if (settings.mask != null) {
mask = "WorldEdit Mask";
} else {
mask = "NONE";
}
TextureUtil tu = gen.getRawTextureUtil();
String blocks;
if (tu.getClass() == TextureUtil.class) {
blocks = "All";
} else if (tu.getClass() == CleanTextureUtil.class) {
CleanTextureUtil clean = (CleanTextureUtil) tu;
blocks = "Complexity(" + clean.getMin() + "," + clean.getMax() + ")";
} else if (tu.getClass() == FilteredTextureUtil.class) {
blocks = "Selected";
} else {
blocks = "Undefined";
}
Set<String> materials = new HashSet<>();
char[] blockArray = tu.getValidBlockIds();
for (char combined : blockArray) {
int id = FaweCache.getId(combined);
BundledBlockData.BlockEntry block = BundledBlockData.getInstance().findById(id);
if (block != null) {
if (block.id.contains(":"))
materials.add(block.id.contains(":") ? block.id.substring(block.id.indexOf(":") + 1) : block.id);
} else materials.add(Integer.toString(id));
}
String blockList = materials.size() > 100 ? materials.size() + " blocks" : StringMan.join(materials, ',');
int biomePriority = gen.getBiomePriority();
Message msg = msg("Current settings:").newline()
.text("Randomization ").text("&7[&a" + (Boolean.toString(rand).toUpperCase()) + "&7]").cmdTip(alias() + " randomization " + (!rand))
.newline()
.text("Mask ").text("&7[&a" + mask + "&7]").cmdTip(alias() + " mask")
.newline()
.text("Blocks ").text("&7[&a" + blocks + "&7]").tooltip(blockList).command(alias() + " paletteBlocks")
.newline()
.text("BiomePriority ").text("&7[&a" + biomePriority + "&7]").cmdTip(alias() + " biomepriority")
.newline();
if (settings.image != null) {
StringBuilder colorArgs = new StringBuilder();
colorArgs.append(" " + settings.imageArg);
if (settings.imageMask != null) colorArgs.append(" " + settings.imageMaskArg);
if (settings.mask != null) colorArgs.append(" " + settings.maskArg);
if (!settings.whiteOnly) colorArgs.append(" -w");
msg.text("Image: ")
.text("&7[&a" + settings.imageArg + "&7]").cmdTip(alias() + " " + Commands.getAlias(CFICommands.class, "image"))
.newline().newline()
.text("Let's Color: ")
.cmdOptions(alias() + " ", colorArgs.toString(), "Biomes", "Blocks", "BlockAndBiome", "Glass")
.newline();
} else {
msg.newline().text("You can color a world using an image like ")
.text("&7[&aThis&7]").linkTip("http://i.imgur.com/vJYinIU.jpg").newline()
.text("Please provide an image: ")
.text("&7[&aNone&7]").cmdTip(alias() + " " + Commands.getAlias(Command.class, "image")).newline();
}
msg.text("&8< &7[&aBack&7]").cmdTip(alias()).send(fp);
}
@Command(
aliases = {"mask"},
usage = "<imageMask|mask>",
desc = "Select a mask"
)
@CommandPermissions("worldedit.anvil.cfi")
public void mask(FawePlayer fp, @Optional BufferedImage imageMask, @Optional Mask mask, @Switch('w') boolean disableWhiteOnly, CommandContext context) throws ParameterException{
CFISettings settings = assertSettings(fp);
String[] split = getArguments(context).split(" ");
int index = 2;
settings.imageMask = imageMask;
settings.imageMaskArg = imageMask != null ? split[index++] : null;
settings.mask = mask;
settings.maskArg = mask != null ? split[index++] : null;
settings.whiteOnly = disableWhiteOnly;
StringBuilder cmd = new StringBuilder(alias() + " mask ");
if (!settings.whiteOnly) cmd.append("-w ");
msg("Current settings:").newline()
.text("Image Mask ").text("&7[&a" + settings.imageMaskArg + "&7]").suggestTip(cmd + "http://")
.newline()
.text("WorldEdit Mask ").text("&7[&a" + settings.maskArg + "&7]").suggestTip(cmd + "<mask>")
.send(fp);
}
@Command(
aliases = {"download"},
desc = "Download the current image"
)
@CommandPermissions("worldedit.anvil.cfi")
public void download(FawePlayer fp) throws ParameterException, IOException {
CFISettings settings = assertSettings(fp);
BufferedImage image = settings.getGenerator().draw();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(image, "jpg", baos );
byte[] data = baos.toByteArray();
fp.sendMessage(BBC.getPrefix() + "Please wait...");
URL url = ImgurUtility.uploadImage(data);
BBC.DOWNLOAD_LINK.send(fp, url);
}
@Command(
aliases = {"image"},
usage = "<image>",
desc = "Select an image"
)
@CommandPermissions("worldedit.anvil.cfi")
public void image(FawePlayer fp, @Optional BufferedImage image, CommandContext context) throws ParameterException{
CFISettings settings = getSettings(fp).bind();
String[] split = getArguments(context).split(" ");
int index = 2;
settings.image = image;
settings.imageArg = image != null ? split[index++] : null;
String maskArg = settings.maskArg == null ? "Click Here" : settings.maskArg;
StringBuilder cmd = new StringBuilder(alias() + " image ");
Message msg;
if (image == null) {
msg = msg("Please provide an image:").newline()
.text("From a URL: ").text("&7[&aClick Here&7]").suggestTip(cmd + "http://")
.newline()
.text("From a file: ").text("&7[&aClick Here&7]").suggestTip(cmd + "file://");
} else {
msg = msg("Current image: ")
.text("&7[&a" + settings.imageArg + "&7]").suggestTip(cmd.toString())
.newline();
if (settings.hasGenerator()) {
msg.text("&8< &7[&aBack&7]").cmdTip(alias() + " " + Commands.getAlias(CFICommands.class, "coloring"));
} else {
msg.text("&8> &7[&aNext&7]").cmdTip(alias() + " " + Commands.getAlias(CFICommands.class, "heightmap " + settings.imageArg));
}
}
msg.send(fp);
}
@Command(
aliases = {"populate"},
usage = "",
desc = ""
)
@CommandPermissions("worldedit.anvil.cfi")
public void populate(FawePlayer fp) throws ParameterException{
CFISettings settings = assertSettings(fp);
msg("What would you like to populate?").newline()
.cmdOptions(alias() + " ", "", "Ores", "Ore", "Caves", "Schematics", "Snow")
.newline().text("&8< &7[&aBack&7]").cmdTip(alias())
.send(fp);
}
@Command(
aliases = {"component", "components"},
usage = "",
desc = "Components menu"
)
@CommandPermissions("worldedit.anvil.cfi")
public void component(FawePlayer fp) throws ParameterException{
CFISettings settings = assertSettings(fp);
msg("What component would you like to change?").newline()
.cmdOptions(alias() + " ", "", "WaterId", "WaterHeight", "Floor", "Main", "Column", "Overlay", "Height", "Smooth")
.newline().text("&8< &7[&aBack&7]").cmdTip(alias())
.send(fp);
}
private CFISettings assertSettings(FawePlayer fp) throws ParameterException {
CFISettings settings = getSettings(fp);
if (!settings.hasGenerator()) throw new ParameterException("Please use /" + alias());
return settings;
}
protected CFISettings getSettings(FawePlayer fp) {
CFISettings settings = fp.getMeta("CFISettings");
return settings == null ? new CFISettings(fp) : settings;
}
public static class CFISettings {
private final FawePlayer fp;
private HeightMapMCAGenerator generator;
protected BufferedImage image;
protected String imageArg;
protected Mask mask;
protected BufferedImage imageMask;
protected boolean whiteOnly = true;
protected String maskArg;
protected String imageMaskArg;
public CFISettings(FawePlayer player) {
this.fp = player;
}
public boolean hasGenerator() {
return generator != null;
}
public HeightMapMCAGenerator getGenerator() {
return generator;
}
public void setMask(Mask mask, String arg) {
this.mask = mask;
this.maskArg = arg;
}
public void setImage(BufferedImage image, String arg) {
this.image = image;
}
public void setImageMask(BufferedImage imageMask, String arg) {
this.imageMask = imageMask;
this.imageMaskArg = arg;
}
public CFISettings setGenerator(HeightMapMCAGenerator generator) {
this.generator = generator;
return this;
}
public CFISettings bind() {
fp.setMeta("CFISettings", this);
return this;
}
public CFISettings remove() {
fp.deleteMeta("CFISettings");
generator = null;
image = null;
imageArg = null;
mask = null;
imageMask = null;
whiteOnly = true;
maskArg = null;
imageMaskArg = null;
return this;
}
}
protected String alias() {
return Commands.getAlias(CFICommand.class, "/cfi");
}
protected Message msg(String text) {
return new Message(BBC.getPrefix())
.text(text);
}
protected void mainMenu(FawePlayer fp) {
msg("What do you want to do now?").newline()
.cmdOptions(alias() + " ", "", "Coloring", "Populate", "Component", "Brush")
.newline().text("&3<> &7[&aView&7]").command(alias() + " " + Commands.getAlias(CFICommands.class, "download")).tooltip("View full resolution image")
.newline().text("&4>< &7[&aCancel&7]").cmdTip(alias() + " " + Commands.getAlias(CFICommands.class, "cancel"))
.newline().text("&2>> &7[&aDone&7]").cmdTip(alias() + " " + Commands.getAlias(CFICommands.class, "done"))
.send(fp);
}
}

View File

@ -4,6 +4,7 @@ import com.boydti.fawe.Fawe;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.extent.NullExtent;
import com.boydti.fawe.object.extent.ResettableExtent;
import com.boydti.fawe.util.image.ImageUtil;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.Vector;
@ -29,6 +30,7 @@ import com.sk89q.worldedit.util.command.parametric.BindingHelper;
import com.sk89q.worldedit.util.command.parametric.BindingMatch;
import com.sk89q.worldedit.util.command.parametric.ParameterException;
import com.sk89q.worldedit.world.World;
import java.awt.image.BufferedImage;
import java.lang.annotation.Annotation;
import javax.annotation.Nullable;
@ -66,6 +68,13 @@ public class FawePrimitiveBinding extends BindingHelper {
}
}
}
@BindingMatch(
type = {BufferedImage.class},
behavior = BindingBehavior.CONSUMES
)
public BufferedImage getImage(ArgumentStack context) throws ParameterException {
return ImageUtil.getImage(context.next());
}
@BindingMatch(
type = {Extent.class},

View File

@ -310,6 +310,11 @@ public class Settings extends Config {
"Allows brushes to be persistent",
})
public boolean PERSISTENT_BRUSHES = false;
@Comment({
"Allow CFI visualization",
})
public boolean CFI_VISUALIZATION = false;
}
public static class WEB {

View File

@ -0,0 +1,142 @@
package com.boydti.fawe.jnbt.anvil;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.util.MathMan;
import com.boydti.fawe.util.TextureUtil;
import com.sk89q.worldedit.blocks.BlockID;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.TimeUnit;
public final class HeightMapMCADrawer {
private final HeightMapMCAGenerator gen;
private final TextureUtil tu;
private final ForkJoinPool pool;
public HeightMapMCADrawer(HeightMapMCAGenerator generator, TextureUtil textureUtil) {
this.gen = generator;
this.tu = textureUtil;
this.pool = new ForkJoinPool();
}
public HeightMapMCADrawer(HeightMapMCAGenerator generator) {
this(generator, Fawe.get().getCachedTextureUtil(false, 0, 100));
}
public BufferedImage draw() {
BufferedImage img = new BufferedImage(gen.getWidth(), gen.getLength(), BufferedImage.TYPE_INT_RGB);
final char[] overlay = gen.overlay == null ? gen.floor : gen.overlay;
final char[] floor = gen.floor;
final char[] main = gen.main;
final byte[] heights = gen.heights;
final int waterHeight = gen.waterHeight;
final int width = gen.getWidth();
final int length = gen.getLength();
int[] raw = ((DataBufferInt) img.getRaster().getDataBuffer()).getData();
int parallelism = pool.getParallelism();
int size = (heights.length + parallelism - 1) / parallelism;
for (int i = 0; i < parallelism; i++) {
int start = i * size;
int end = Math.min(heights.length, start + size);
pool.submit((Runnable) () -> {
for (int index = start; index < end; index ++) {
int height = (heights[index] & 0xFF);
char combined;
if ((combined = overlay[index]) == 0) {
height--;
combined = floor[index];
if (combined == 0) {
height--;
combined = main[index];
}
}
// draw combined
int color;
switch (combined >> 4) {
case 2:
color = getAverageBiomeColor(gen.biomes, width, index);
break;
case 78:
color = (0xDD << 16) + (0xDD << 8) + (0xDD << 0);
break;
default:
color = tu.getColor(FaweCache.CACHE_BLOCK[combined]);
break;
}
int slope = getSlope(heights, width, index, height);
if (slope != 0) {
slope = (slope << 3) + (slope << 2);
int r = MathMan.clamp(((color >> 16) & 0xFF) + slope, 0, 255);
int g = MathMan.clamp(((color >> 8) & 0xFF) + slope, 0, 255);
int b = MathMan.clamp(((color >> 0) & 0xFF) + slope, 0, 255);
color = (r << 16) + (g << 8) + (b << 0);
}
if (height + 1 < waterHeight) {
byte waterId = gen.waterId;
int waterColor = 0;
switch (waterId) {
case BlockID.WATER:
case BlockID.STATIONARY_WATER:
color = tu.averageColor((0x11 << 16) + (0x66 << 8) + (0xCC), color);
break;
case BlockID.LAVA:
case BlockID.STATIONARY_LAVA:
color = (0xCC << 16) + (0x33 << 8) + (0);
break;
default:
color = tu.getColor(FaweCache.getBlock(waterId, 0));
break;
}
}
raw[index] = color;
}
});
}
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
pool.shutdownNow();
return img;
}
private final int getAverageBiomeColor(byte[] biomes, int width, int index) {
int c0 = tu.getBiome(biomes[index] & 0xFF).grassCombined;
int c2 = getBiome(biomes, index + 1 + width, index);
int c1 = getBiome(biomes, index - 1 - width, index);
// int c3 = getBiome(biomes, index + width, index);
// int c4 = getBiome(biomes, index - width, index);
int r = ((c0 >> 16) & 0xFF) + ((c1 >> 16) & 0xFF) + ((c2 >> 16) & 0xFF);// + ((c3 >> 16) & 0xFF) + ((c4 >> 16) & 0xFF);
int g = ((c0 >> 8) & 0xFF) + ((c1 >> 8) & 0xFF) + ((c2 >> 8) & 0xFF);// + ((c3 >> 8) & 0xFF) + ((c4 >> 8) & 0xFF);
int b = ((c0) & 0xFF) + ((c1) & 0xFF) + ((c2) & 0xFF);// + ((c3) & 0xFF) + ((c4) & 0xFF);
r = r * 85 >> 8;
g = g * 85 >> 8;
b = b * 85 >> 8;
return (r << 16) + (g << 8) + (b);
}
private final int getBiome(byte[] biomes, int newIndex, int index) {
if (newIndex < 0 || newIndex >= biomes.length) newIndex = index;
int biome = biomes[newIndex] & 0xFF;
return tu.getBiome(biome).grassCombined;
}
private int getSlope(byte[] heights, int width, int index, int height) {
return (
+ getHeight(heights, index + 1, height)
// + getHeight(heights, index + width, height)
+ getHeight(heights, index + width + 1, height)
- getHeight(heights, index - 1, height)
// - getHeight(heights, index - width, height)
- getHeight(heights, index - width - 1, height)
);
}
private int getHeight(byte[] heights, int index, int height) {
if (index < 0 || index >= heights.length) return height;
return heights[index] & 0xFF;
}
}

View File

@ -11,6 +11,7 @@ import com.boydti.fawe.util.CachedTextureUtil;
import com.boydti.fawe.util.MathMan;
import com.boydti.fawe.util.RandomTextureUtil;
import com.boydti.fawe.util.TextureUtil;
import com.boydti.fawe.util.image.ImageViewer;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MutableBlockVector;
import com.sk89q.worldedit.Vector;
@ -46,17 +47,18 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
private final Int2ObjectOpenHashMap<char[][][]> blocks = new Int2ObjectOpenHashMap<>();
public final byte[] heights;
private final byte[] biomes;
private final char[] floor;
private final char[] main;
private char[] overlay;
private int waterHeight = 0;
private TextureUtil textureUtil;
private boolean randomVariation = true;
private int biomePriority = 0;
private byte waterId = BlockID.STATIONARY_WATER;
private boolean modifiedMain = false;
protected final byte[] heights;
protected final byte[] biomes;
protected final char[] floor;
protected final char[] main;
protected char[] overlay;
protected int waterHeight = 0;
protected TextureUtil textureUtil;
protected boolean randomVariation = true;
protected int biomePriority = 0;
protected byte waterId = BlockID.STATIONARY_WATER;
protected boolean modifiedMain = false;
private ImageViewer viewer;
public HeightMapMCAGenerator(BufferedImage img, File regionFolder) {
this(img.getWidth(), img.getHeight(), regionFolder);
@ -76,6 +78,28 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
Arrays.fill(floor, grass);
}
public void setImageViewer(ImageViewer viewer) {
this.viewer = viewer;
update();
}
public ImageViewer getImageViewer() {
return viewer;
}
private void update() {
if (viewer != null) {
viewer.view(draw());
}
}
public TextureUtil getRawTextureUtil() {
if (textureUtil == null) {
textureUtil = Fawe.get().getTextureUtil();
}
return this.textureUtil;
}
public TextureUtil getTextureUtil() {
if (textureUtil == null) {
textureUtil = Fawe.get().getTextureUtil();
@ -96,16 +120,22 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
public void setWaterHeight(int waterHeight) {
this.waterHeight = waterHeight;
update();
}
public void setWaterId(int waterId) {
this.waterId = (byte) waterId;
update();
}
public void setTextureRandomVariation(boolean randomVariation) {
this.randomVariation = randomVariation;
}
public boolean getTextureRandomVariation() {
return this.randomVariation;
}
public void setTextureUtil(TextureUtil textureUtil) {
this.textureUtil = textureUtil;
}
@ -172,8 +202,23 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
}
}
}
} else {
for (int z = 0; z < getLength(); z++) {
for (int x = 0; x < getWidth(); x++, index++) {
int y = heights[index] & 0xFF;
int newHeight = table.average(x, z, index) - 1;
int blockHeight = (newHeight) >> 3;
int layerHeight = (newHeight) & 0x7;
heights[index] = (byte) blockHeight;
int id = floor[index] >> 4;
if (id == 78 || id == 80) {
floor[index] = (char) (snow + layerHeight);
}
}
}
}
}
update();
}
public void setHeight(BufferedImage img) {
@ -183,17 +228,20 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
heights[index] = (byte) (img.getRGB(x, z) >> 8);
}
}
update();
}
public void addCaves() throws WorldEditException {
CuboidRegion region = new CuboidRegion(new Vector(0, 0, 0), new Vector(getWidth(), 255, getLength()));
addCaves(region);
update();
}
@Deprecated
public void addSchems(Mask mask, WorldData worldData, ClipboardHolder[] clipboards, int rarity, boolean rotate) throws WorldEditException {
CuboidRegion region = new CuboidRegion(new Vector(0, 0, 0), new Vector(getWidth(), 255, getLength()));
addSchems(region, mask, worldData, clipboards, rarity, rotate);
update();
}
public void addSchems(BufferedImage img, Mask mask, WorldData worldData, ClipboardHolder[] clipboards, int rarity, int distance, boolean randomRotate) throws WorldEditException {
@ -245,6 +293,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
}
}
}
update();
}
public void addSchems(Mask mask, WorldData worldData, ClipboardHolder[] clipboards, int rarity, int distance, boolean randomRotate) throws WorldEditException {
@ -294,15 +343,18 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
}
}
}
update();
}
public void addOre(Mask mask, Pattern material, int size, int frequency, int rarity, int minY, int maxY) throws WorldEditException {
CuboidRegion region = new CuboidRegion(new Vector(0, 0, 0), new Vector(getWidth(), 255, getLength()));
addOre(region, mask, material, size, frequency, rarity, minY, maxY);
update();
}
public void addDefaultOres(Mask mask) throws WorldEditException {
addOres(new CuboidRegion(new Vector(0, 0, 0), new Vector(getWidth(), 255, getLength())), mask);
update();
}
@Override
@ -323,7 +375,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
@Override
public boolean setBiome(Vector2D position, BaseBiome biome) {
int index = position.getBlockZ() * getWidth() + position.getBlockX();
if (index < 0 || index >= heights.length) return false;
if (index < 0 || index >= heights.length) index = Math.floorMod(index, heights.length);
biomes[index] = (byte) biome.getId();
return true;
}
@ -331,46 +383,48 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
@Override
public boolean setBlock(int x, int y, int z, BaseBlock block) throws WorldEditException {
int index = z * getWidth() + x;
if (index < 0 || index >= heights.length) return false;
if (index < 0 || index >= heights.length) index = Math.floorMod(index, heights.length);
int height = heights[index] & 0xFF;
char combined = (char) FaweCache.getCombined(block);
if (y > height) {
if (y == height + 1) {
if (overlay == null) {
overlay = new char[getArea()];
}
overlay[index] = combined;
char combined = (char) block.getCombined();
switch (y - height) {
case 0:
floor[index] = combined;
return true;
case 1:
char mainId = main[index];
char floorId = floor[index];
floor[index] = combined;
heights[index]++;
if (mainId == floorId) return true;
y--;
combined = floorId;
default:
short chunkX = (short) (x >> 4);
short chunkZ = (short) (z >> 4);
int pair = MathMan.pair(chunkX, chunkZ);
char[][][] map = blocks.get(pair);
if (map == null) {
map = new char[256][][];
blocks.put(pair, map);
}
char[][] yMap = map[y];
if (yMap == null) {
map[y] = yMap = new char[16][];
}
z = z & 15;
char[] zMap = yMap[z];
if (zMap == null) {
yMap[z] = zMap = new char[16];
}
zMap[x & 15] = combined != 0 ? combined : 1;
return true;
}
} else if (y == height) {
floor[index] = combined;
return true;
}
short chunkX = (short) (x >> 4);
short chunkZ = (short) (z >> 4);
int pair = MathMan.pair(chunkX, chunkZ);
char[][][] map = blocks.get(pair);
if (map == null) {
map = new char[256][][];
blocks.put(pair, map);
}
char[][] yMap = map[y];
if (yMap == null) {
map[y] = yMap = new char[16][];
}
z = z & 15;
char[] zMap = yMap[z];
if (zMap == null) {
yMap[z] = zMap = new char[16];
}
zMap[x & 15] = combined != 0 ? combined : 1;
return true;
}
@Override
public BaseBiome getBiome(Vector2D position) {
int index = position.getBlockZ() * getWidth() + position.getBlockX();
if (index < 0 || index >= heights.length) return EditSession.nullBiome;
if (index < 0 || index >= heights.length) index = Math.floorMod(index, heights.length);
return FaweCache.CACHE_BIOME[biomes[index] & 0xFF];
}
@ -387,7 +441,8 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
@Override
public BaseBlock getLazyBlock(int x, int y, int z) {
int index = z * getWidth() + x;
if (index < 0 || index >= heights.length) return EditSession.nullBlock;
if (y < 0) return EditSession.nullBlock;
if (index < 0 || index >= heights.length) index = Math.floorMod(index, heights.length);
int height = heights[index] & 0xFF;
if (y > height) {
if (y == height + 1) {
@ -431,14 +486,14 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
@Override
public int getNearestSurfaceLayer(int x, int z, int y, int minY, int maxY) {
int index = z * getWidth() + x;
if (index < 0 || index >= heights.length) return y;
if (index < 0 || index >= heights.length) index = Math.floorMod(index, heights.length);
return ((heights[index] & 0xFF) << 3) + (floor[index] & 0xFF) + 1;
}
@Override
public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY) {
int index = z * getWidth() + x;
if (index < 0 || index >= heights.length) return y;
if (index < 0 || index >= heights.length) index = Math.floorMod(index, heights.length);
return heights[index] & 0xFF;
}
@ -454,12 +509,21 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
}
}
}
update();
}
public BufferedImage draw() {
return new HeightMapMCADrawer(this).draw();
}
public void setBiomePriority(int value) {
this.biomePriority = ((value * 65536) / 100) - 32768;
}
public int getBiomePriority() {
return ((biomePriority + 32768) * 100) / 65536;
}
public void setBlockAndBiomeColor(BufferedImage img, Mask mask, BufferedImage imgMask, boolean whiteOnly) {
if (mask == null && imgMask == null) {
setBlockAndBiomeColor(img);
@ -495,6 +559,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
biomes[index] = (byte) buffer[1];
}
}
update();
}
public void setBlockAndBiomeColor(BufferedImage img) {
@ -519,12 +584,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
biomes[index] = (byte) buffer[1];
}
}
}
private void setBiomeIfZero(int index, byte value) {
if (biomes[index] == 0) {
biomes[index] = value;
}
update();
}
public void setBiomeColor(BufferedImage img) {
@ -542,6 +602,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
index++;
}
}
update();
}
public void setColor(BufferedImage img, BufferedImage mask, boolean white) {
@ -566,9 +627,10 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
}
}
}
update();
}
public void setColor(BufferedImage img, Mask mask, boolean white) {
public void setColor(BufferedImage img, Mask mask) {
if (img.getWidth() != getWidth() || img.getHeight() != getLength())
throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
modifiedMain = true;
@ -590,6 +652,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
}
}
}
update();
}
public void setColor(BufferedImage img) {
@ -610,6 +673,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
index++;
}
}
update();
}
public void setColorWithGlass(BufferedImage img) {
@ -628,6 +692,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
index++;
}
}
update();
}
public void setBiome(Mask mask, byte biome) {
@ -643,255 +708,270 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
}
}
}
update();
}
public void setOverlay(BufferedImage img, Pattern pattern, boolean white) {
if (pattern instanceof BaseBlock) {
setOverlay(img, (char) ((BaseBlock) pattern).getCombined(), white);
return;
}
if (img.getWidth() != getWidth() || img.getHeight() != getLength())
throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
if (overlay == null) overlay = new char[getArea()];
int index = 0;
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
for (int x = 0; x < getWidth(); x++, index++) {
int height = img.getRGB(x, z) & 0xFF;
if (height == 255 || height > 0 && !white && PseudoRandom.random.nextInt(256) <= height) {
mutable.mutX(x);
mutable.mutY(height);
overlay[index] = (char) pattern.apply(mutable).getCombined();
} else {
if (img.getWidth() != getWidth() || img.getHeight() != getLength())
throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
if (overlay == null) overlay = new char[getArea()];
int index = 0;
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
for (int x = 0; x < getWidth(); x++, index++) {
int height = img.getRGB(x, z) & 0xFF;
if (height == 255 || height > 0 && !white && PseudoRandom.random.nextInt(256) <= height) {
mutable.mutX(x);
mutable.mutY(height);
overlay[index] = (char) pattern.apply(mutable).getCombined();
}
}
}
}
update();
}
public void setMain(BufferedImage img, Pattern pattern, boolean white) {
if (pattern instanceof BaseBlock) {
setMain(img, (char) ((BaseBlock) pattern).getCombined(), white);
return;
}
if (img.getWidth() != getWidth() || img.getHeight() != getLength())
throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
modifiedMain = true;
int index = 0;
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
for (int x = 0; x < getWidth(); x++, index++) {
int height = img.getRGB(x, z) & 0xFF;
if (height == 255 || height > 0 && !white && PseudoRandom.random.nextInt(256) <= height) {
mutable.mutX(x);
mutable.mutY(height);
main[index] = (char) pattern.apply(mutable).getCombined();
} else {
if (img.getWidth() != getWidth() || img.getHeight() != getLength())
throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
modifiedMain = true;
int index = 0;
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
for (int x = 0; x < getWidth(); x++, index++) {
int height = img.getRGB(x, z) & 0xFF;
if (height == 255 || height > 0 && !white && PseudoRandom.random.nextInt(256) <= height) {
mutable.mutX(x);
mutable.mutY(height);
main[index] = (char) pattern.apply(mutable).getCombined();
}
}
}
}
update();
}
public void setFloor(BufferedImage img, Pattern pattern, boolean white) {
if (pattern instanceof BaseBlock) {
setFloor(img, (char) ((BaseBlock) pattern).getCombined(), white);
return;
}
if (img.getWidth() != getWidth() || img.getHeight() != getLength())
throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
int index = 0;
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
for (int x = 0; x < getWidth(); x++, index++) {
int height = img.getRGB(x, z) & 0xFF;
if (height == 255 || height > 0 && !white && PseudoRandom.random.nextInt(256) <= height) {
mutable.mutX(x);
mutable.mutY(height);
floor[index] = (char) pattern.apply(mutable).getCombined();
} else {
if (img.getWidth() != getWidth() || img.getHeight() != getLength())
throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
int index = 0;
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
for (int x = 0; x < getWidth(); x++, index++) {
int height = img.getRGB(x, z) & 0xFF;
if (height == 255 || height > 0 && !white && PseudoRandom.random.nextInt(256) <= height) {
mutable.mutX(x);
mutable.mutY(height);
floor[index] = (char) pattern.apply(mutable).getCombined();
}
}
}
}
update();
}
public void setColumn(BufferedImage img, Pattern pattern, boolean white) {
if (pattern instanceof BaseBlock) {
setColumn(img, (char) ((BaseBlock) pattern).getCombined(), white);
return;
}
if (img.getWidth() != getWidth() || img.getHeight() != getLength())
throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
modifiedMain = true;
int index = 0;
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
for (int x = 0; x < getWidth(); x++, index++) {
int height = img.getRGB(x, z) & 0xFF;
if (height == 255 || height > 0 && !white && PseudoRandom.random.nextInt(256) <= height) {
mutable.mutX(x);
mutable.mutY(height);
char combined = (char) pattern.apply(mutable).getCombined();
main[index] = combined;
floor[index] = combined;
} else {
if (img.getWidth() != getWidth() || img.getHeight() != getLength())
throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
modifiedMain = true;
int index = 0;
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
for (int x = 0; x < getWidth(); x++, index++) {
int height = img.getRGB(x, z) & 0xFF;
if (height == 255 || height > 0 && !white && PseudoRandom.random.nextInt(256) <= height) {
mutable.mutX(x);
mutable.mutY(height);
char combined = (char) pattern.apply(mutable).getCombined();
main[index] = combined;
floor[index] = combined;
}
}
}
}
update();
}
public void setOverlay(Mask mask, Pattern pattern) {
if (pattern instanceof BaseBlock) {
setOverlay(mask, (char) ((BaseBlock) pattern).getCombined());
return;
}
int index = 0;
if (overlay == null) overlay = new char[getArea()];
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
for (int x = 0; x < getWidth(); x++, index++) {
int y = heights[index] & 0xFF;
mutable.mutX(x);
mutable.mutY(y);
if (mask.test(mutable)) {
overlay[index] = (char) pattern.apply(mutable).getCombined();
} else {
int index = 0;
if (overlay == null) overlay = new char[getArea()];
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
for (int x = 0; x < getWidth(); x++, index++) {
int y = heights[index] & 0xFF;
mutable.mutX(x);
mutable.mutY(y);
if (mask.test(mutable)) {
overlay[index] = (char) pattern.apply(mutable).getCombined();
}
}
}
}
update();
}
public void setFloor(Mask mask, Pattern pattern) {
if (pattern instanceof BaseBlock) {
setFloor(mask, (char) ((BaseBlock) pattern).getCombined());
return;
}
int index = 0;
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
for (int x = 0; x < getWidth(); x++, index++) {
int y = heights[index] & 0xFF;
mutable.mutX(x);
mutable.mutY(y);
if (mask.test(mutable)) {
floor[index] = (char) pattern.apply(mutable).getCombined();
} else {
int index = 0;
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
for (int x = 0; x < getWidth(); x++, index++) {
int y = heights[index] & 0xFF;
mutable.mutX(x);
mutable.mutY(y);
if (mask.test(mutable)) {
floor[index] = (char) pattern.apply(mutable).getCombined();
}
}
}
}
update();
}
public void setMain(Mask mask, Pattern pattern) {
if (pattern instanceof BaseBlock) {
setMain(mask, (char) ((BaseBlock) pattern).getCombined());
return;
}
modifiedMain = true;
int index = 0;
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
for (int x = 0; x < getWidth(); x++, index++) {
int y = heights[index] & 0xFF;
mutable.mutX(x);
mutable.mutY(y);
if (mask.test(mutable)) {
main[index] = (char) pattern.apply(mutable).getCombined();
} else {
modifiedMain = true;
int index = 0;
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
for (int x = 0; x < getWidth(); x++, index++) {
int y = heights[index] & 0xFF;
mutable.mutX(x);
mutable.mutY(y);
if (mask.test(mutable)) {
main[index] = (char) pattern.apply(mutable).getCombined();
}
}
}
}
update();
}
public void setColumn(Mask mask, Pattern pattern) {
if (pattern instanceof BaseBlock) {
setColumn(mask, (char) ((BaseBlock) pattern).getCombined());
return;
}
modifiedMain = true;
int index = 0;
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
for (int x = 0; x < getWidth(); x++, index++) {
int y = heights[index] & 0xFF;
mutable.mutX(x);
mutable.mutY(y);
if (mask.test(mutable)) {
char combined = (char) pattern.apply(mutable).getCombined();
floor[index] = combined;
main[index] = combined;
} else {
modifiedMain = true;
int index = 0;
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
for (int x = 0; x < getWidth(); x++, index++) {
int y = heights[index] & 0xFF;
mutable.mutX(x);
mutable.mutY(y);
if (mask.test(mutable)) {
char combined = (char) pattern.apply(mutable).getCombined();
floor[index] = combined;
main[index] = combined;
}
}
}
}
update();
}
public void setBiome(int biome) {
Arrays.fill(biomes, (byte) biome);
update();
}
public void setFloor(Pattern value) {
if (value instanceof BaseBlock) {
setFloor(((BaseBlock) value).getCombined());
return;
}
int index = 0;
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
for (int x = 0; x < getWidth(); x++, index++) {
int y = heights[index] & 0xFF;
mutable.mutX(x);
mutable.mutY(y);
floor[index] = (char) value.apply(mutable).getCombined();
} else {
int index = 0;
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
for (int x = 0; x < getWidth(); x++, index++) {
int y = heights[index] & 0xFF;
mutable.mutX(x);
mutable.mutY(y);
floor[index] = (char) value.apply(mutable).getCombined();
}
}
}
update();
}
public void setColumn(Pattern value) {
if (value instanceof BaseBlock) {
setColumn(((BaseBlock) value).getCombined());
return;
}
int index = 0;
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
for (int x = 0; x < getWidth(); x++, index++) {
int y = heights[index] & 0xFF;
mutable.mutX(x);
mutable.mutY(y);
char combined = (char) value.apply(mutable).getCombined();
main[index] = combined;
floor[index] = combined;
} else {
int index = 0;
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
for (int x = 0; x < getWidth(); x++, index++) {
int y = heights[index] & 0xFF;
mutable.mutX(x);
mutable.mutY(y);
char combined = (char) value.apply(mutable).getCombined();
main[index] = combined;
floor[index] = combined;
}
}
}
update();
}
public void setMain(Pattern value) {
if (value instanceof BaseBlock) {
setMain(((BaseBlock) value).getCombined());
return;
}
int index = 0;
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
for (int x = 0; x < getWidth(); x++, index++) {
int y = heights[index] & 0xFF;
mutable.mutX(x);
mutable.mutY(y);
main[index] = (char) value.apply(mutable).getCombined();
} else {
int index = 0;
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
for (int x = 0; x < getWidth(); x++, index++) {
int y = heights[index] & 0xFF;
mutable.mutX(x);
mutable.mutY(y);
main[index] = (char) value.apply(mutable).getCombined();
}
}
}
update();
}
public void setOverlay(Pattern value) {
if (overlay == null) overlay = new char[getArea()];
if (value instanceof BaseBlock) {
setOverlay(((BaseBlock) value).getCombined());
return;
}
int index = 0;
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
for (int x = 0; x < getWidth(); x++, index++) {
int y = heights[index] & 0xFF;
mutable.mutX(x);
mutable.mutY(y);
overlay[index] = (char) value.apply(mutable).getCombined();
} else {
int index = 0;
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
for (int x = 0; x < getWidth(); x++, index++) {
int y = heights[index] & 0xFF;
mutable.mutX(x);
mutable.mutY(y);
overlay[index] = (char) value.apply(mutable).getCombined();
}
}
}
update();
}
public void setHeights(int value) {
Arrays.fill(heights, (byte) value);
update();
}
@Override

View File

@ -10,7 +10,7 @@ import java.util.concurrent.TimeUnit;
import java.util.zip.Deflater;
public abstract class MCAWriter {
private final File folder;
private File folder;
private final int length;
private final int width;
private final int area;
@ -18,9 +18,6 @@ public abstract class MCAWriter {
public MCAWriter(int width, int length, File regionFolder) {
if (!regionFolder.exists()) {
regionFolder.mkdirs();
}
this.folder = regionFolder;
this.width = width;
this.length = length;
@ -31,6 +28,10 @@ public abstract class MCAWriter {
return folder;
}
public void setFolder(File folder) {
this.folder = folder;
}
public final int getWidth() {
return width;
}
@ -69,6 +70,9 @@ public abstract class MCAWriter {
public abstract MCAChunk write(MCAChunk input, int startX, int endX, int startZ, int endZ);
public void generate() throws IOException {
if (!folder.exists()) {
folder.mkdirs();
}
final ForkJoinPool pool = new ForkJoinPool();
int bcx = 0;
int bcz = 0;

View File

@ -29,7 +29,6 @@ import static com.google.common.base.Preconditions.checkNotNull;
*/
public class HistoryExtent extends AbstractDelegateExtent {
private final AbstractDelegateExtent extent;
private FaweChangeSet changeSet;
private final FaweQueue queue;
private final EditSession session;
@ -43,7 +42,6 @@ public class HistoryExtent extends AbstractDelegateExtent {
public HistoryExtent(final EditSession session, final Extent extent, final FaweChangeSet changeSet, FaweQueue queue) {
super(extent);
checkNotNull(changeSet);
this.extent = (AbstractDelegateExtent) extent;
this.queue = queue;
this.changeSet = changeSet;
this.session = session;
@ -92,12 +90,7 @@ public class HistoryExtent extends AbstractDelegateExtent {
} catch (FaweException ignore) {
return false;
}
return extent.setBlock(x, y, z, block);
}
@Override
public BaseBlock getLazyBlock(int x, int y, int z) {
return extent.getLazyBlock(x, y, z);
return getExtent().setBlock(x, y, z, block);
}
@Override
@ -143,7 +136,7 @@ public class HistoryExtent extends AbstractDelegateExtent {
BaseBiome oldBiome = this.getBiome(position);
if (oldBiome.getId() != newBiome.getId()) {
this.changeSet.addBiomeChange(position.getBlockX(), position.getBlockZ(), oldBiome, newBiome);
return extent.setBiome(position, newBiome);
return getExtent().setBiome(position, newBiome);
} else {
return false;
}

View File

@ -79,8 +79,8 @@ public class CreateFromImage extends Command {
@Override
public void run() {
FawePlayer<Object> fp = FawePlayer.wrap(player.getName());
HeightMapMCAGenerator generator = player.getMeta("HMGenerator");
Plot plot = player.getMeta("HMGeneratorPlot");
HeightMapMCAGenerator generator = fp.getMeta("HMGenerator");
Plot plot = fp.getMeta("HMGeneratorPlot");
if (generator == null) {
final Vector2D dimensions;
final BufferedImage image;
@ -164,7 +164,8 @@ public class CreateFromImage extends Command {
} else {
generator = new HeightMapMCAGenerator(dimensions.getBlockX(), dimensions.getBlockZ(), folder);
}
player.setMeta("HMGenerator", generator);
generator.setImageViewer(Fawe.imp().getImageViewer(fp));
fp.setMeta("HMGenerator", generator);
player.setMeta("HMGeneratorPlot", plot);
}
}, true, false);
@ -310,7 +311,7 @@ public class CreateFromImage extends Command {
} else {
Mask mask = we.getMaskFactory().parseFromInput(argList.get(1), context);
boolean whiteOnly = argList.size() < 4 || Boolean.parseBoolean(argList.get(3));
generator.setColor(image, mask, whiteOnly);
generator.setColor(image, mask);
}
} else {
generator.setColor(image);
@ -594,8 +595,8 @@ public class CreateFromImage extends Command {
return;
case "exit":
case "cancel":
player.deleteMeta("HMGenerator");
player.deleteMeta("HMGeneratorPlot");
fp.deleteMeta("HMGenerator");
fp.deleteMeta("HMGeneratorPlot");
player.sendMessage(BBC.getPrefix() + "Cancelled!");
return;
default:

View File

@ -4,8 +4,12 @@ import java.io.FileNotFoundException;
import java.util.Arrays;
public class CleanTextureUtil extends TextureUtil {
private final int min, max;
public CleanTextureUtil(TextureUtil parent, int minPercent, int maxPercent) throws FileNotFoundException {
super(parent.getFolder());
this.min = minPercent;
this.max = maxPercent;
int minIndex = ((parent.distances.length - 1) * minPercent) / 100;
int maxIndex = ((parent.distances.length - 1) * maxPercent) / 100;
long min = parent.distances[minIndex];
@ -30,4 +34,12 @@ public class CleanTextureUtil extends TextureUtil {
}
this.calculateLayerArrays();
}
public int getMin() {
return min;
}
public int getMax() {
return max;
}
}

View File

@ -28,8 +28,7 @@ public class ExtentTraverser<T extends Extent> {
public boolean setNext(T next) {
try {
Field field = AbstractDelegateExtent.class.getDeclaredField("extent");
field.setAccessible(true);
field.set(root, next);
ReflectionUtils.setFailsafeFieldValue(field, root, next);
return true;
} catch (Throwable e) {
e.printStackTrace();
@ -37,6 +36,16 @@ public class ExtentTraverser<T extends Extent> {
}
}
public ExtentTraverser<T> last() {
ExtentTraverser<T> last = this;
ExtentTraverser<T> traverser = this;
while (traverser != null && traverser.get() instanceof AbstractDelegateExtent) {
last = traverser;
traverser = traverser.next();
}
return last;
}
public boolean insert(T extent) {
try {
Field field = AbstractDelegateExtent.class.getDeclaredField("extent");

View File

@ -6,8 +6,11 @@ import java.io.FileNotFoundException;
import java.util.Set;
public class FilteredTextureUtil extends TextureUtil {
private final Set<BaseBlock> blocks;
public FilteredTextureUtil(TextureUtil parent, Set<BaseBlock> blocks) throws FileNotFoundException {
super(parent.getFolder());
this.blocks = blocks;
this.validMixBiomeColors = parent.validMixBiomeColors;
this.validMixBiomeIds = parent.validMixBiomeIds;
this.validBiomes = parent.validBiomes;
@ -33,4 +36,8 @@ public class FilteredTextureUtil extends TextureUtil {
}
this.calculateLayerArrays();
}
public Set<BaseBlock> getBlocks() {
return blocks;
}
}

View File

@ -3,18 +3,24 @@ package com.boydti.fawe.util;
import com.boydti.fawe.Fawe;
import java.io.DataInputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
public enum Jars {
WE_B_6_1_7_2("https://addons.cursecdn.com/files/2431/372/worldedit-bukkit-6.1.7.2.jar",
"711be37301a327aba4e347131875d0564dbfdc2f41053a12db97f0234661778b", 1726340),
VS_B_5_171_0("https://addons-origin.cursecdn.com/files/912/511/VoxelSniper-5.171.0-SNAPSHOT.jar",
"292c3b38238e0d8e5f036381d28bccfeb15df67cae53d28b52d066bc6238208f", 3632776);
"292c3b38238e0d8e5f036381d28bccfeb15df67cae53d28b52d066bc6238208f", 3632776),
MM_v1_4_0("https://github.com/InventivetalentDev/MapManager/releases/download/1.4.0-SNAPSHOT/MapManager_v1.4.0-SNAPSHOT.jar",
"004A39B0A06E80DE3226B4BCC6080D2DB9B6411CCFB48D647F4FF55B5B91B600", 163279),
PL_v3_6_0("https://github.com/InventivetalentDev/PacketListenerAPI/releases/download/3.6.0-SNAPSHOT/PacketListenerAPI_v3.6.0-SNAPSHOT.jar",
"3B26C4EF9BE253E9E7C07AD5AC46CB0C047003EFD36DD433D6B739EB6AAE9410", 166508),
;
public final String url;
public final int filesize;
@ -28,9 +34,9 @@ public enum Jars {
* @param filesize
* Size of this jar in bytes
*/
private Jars(String url, String digest, int filesize) {
Jars(String url, String digest, int filesize) {
this.url = url;
this.digest = digest;
this.digest = digest.toUpperCase();
this.filesize = filesize;
}
@ -43,16 +49,14 @@ public enum Jars {
if (dis.read() != -1) { // assert that we've read everything
throw new IllegalStateException("downloaded jar is longer than expected");
}
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] jarDigestBytes = md.digest(jarBytes);
String jarDigest = javax.xml.bind.DatatypeConverter.printHexBinary(jarDigestBytes).toUpperCase();
MessageDigest md;
md = MessageDigest.getInstance("SHA-256");
byte[] thisDigest = md.digest(jarBytes);
byte[] realDigest = new BigInteger(this.digest.toUpperCase(), 16).toByteArray();
if (Arrays.equals(thisDigest, realDigest)) {
if (this.digest.equals(jarDigest)) {
Fawe.debug("++++ HASH CHECK ++++");
Fawe.debug(this.url);
Fawe.debug(javax.xml.bind.DatatypeConverter.printHexBinary(thisDigest));
Fawe.debug(this.digest);
return jarBytes;
} else {
throw new IllegalStateException("downloaded jar does not match the hash");

View File

@ -685,6 +685,7 @@ public class TextureUtil {
if (biome.grass != 0 && !biome.name.equalsIgnoreCase("Unknown Biome")) {
valid.add(biome);
}
biome.grassCombined = multiplyColor(grass, biome.grass);
}
this.validBiomes = valid.toArray(new BiomeColor[valid.size()]);
@ -779,10 +780,10 @@ public class TextureUtil {
int red2 = (c2 >> 16) & 0xFF;
int green2 = (c2 >> 8) & 0xFF;
int blue2 = (c2 >> 0) & 0xFF;
int red = ((red1 + red2)) / 2;
int green = ((green1 + green2)) / 2;
int blue = ((blue1 + blue2)) / 2;
int alpha = ((alpha1 + alpha2)) / 2;
int red = ((red1 + red2)) >> 1;
int green = ((green1 + green2)) >> 1;
int blue = ((blue1 + blue2)) >> 1;
int alpha = ((alpha1 + alpha2)) >> 1;
return (alpha << 24) + (red << 16) + (green << 8) + (blue << 0);
}
@ -1049,6 +1050,7 @@ public class TextureUtil {
public float temperature;
public float rainfall;
public int grass;
public int grassCombined;
public int foliage;
public BiomeColor(int id, String name, float temperature, float rainfall, int grass, int foliage) {
@ -1057,7 +1059,12 @@ public class TextureUtil {
this.temperature = temperature;
this.rainfall = rainfall;
this.grass = grass;
this.grassCombined = grass;
this.foliage = foliage;
}
}
public char[] getValidBlockIds() {
return validBlockIds.clone();
}
}

View File

@ -87,6 +87,19 @@ public class Message {
return tooltip(commandAndTooltip).command(commandAndTooltip);
}
public Message linkTip(String linkAndTooltip) {
return tooltip(linkAndTooltip).link(linkAndTooltip);
}
public Message cmdOptions(String prefix, String suffix, String... options) {
for (int i = 0; i < options.length; i++) {
if (i != 0) text(" &8|&7 ");
text("&7[&a" + options[i] + "&7]")
.cmdTip(prefix + options[i] + suffix);
}
return this;
}
public Message suggestTip(String commandAndTooltip) {
return tooltip(commandAndTooltip).suggest(commandAndTooltip);
}

View File

@ -0,0 +1,18 @@
package com.boydti.fawe.util.cui;
import com.boydti.fawe.object.FawePlayer;
import com.sk89q.worldedit.internal.cui.CUIEvent;
public abstract class CUI {
private final FawePlayer player;
public CUI(FawePlayer player) {
this.player = player;
}
public <T> FawePlayer<T> getPlayer() {
return player;
}
public abstract void dispatchCUIEvent(CUIEvent event);
}

View File

@ -0,0 +1,94 @@
package com.boydti.fawe.util.image;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.util.MainUtil;
import com.sk89q.worldedit.util.command.parametric.ParameterException;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URL;
public class ImageUtil {
public static BufferedImage getScaledInstance(BufferedImage img,
int targetWidth,
int targetHeight,
Object hint,
boolean higherQuality)
{
if (img.getHeight() == targetHeight && img.getWidth() == targetWidth) {
return img;
}
int type = (img.getTransparency() == Transparency.OPAQUE) ?
BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
BufferedImage ret = (BufferedImage)img;
int w, h;
if (higherQuality) {
// Use multi-step technique: start with original size, then
// scale down in multiple passes with drawImage()
// until the target size is reached
w = img.getWidth();
h = img.getHeight();
} else {
// Use one-step technique: scale directly from original
// size to target size with a single drawImage() call
w = targetWidth;
h = targetHeight;
}
do {
if (higherQuality && w > targetWidth) {
w /= 2;
if (w < targetWidth) {
w = targetWidth;
}
}
if (higherQuality && h > targetHeight) {
h /= 2;
if (h < targetHeight) {
h = targetHeight;
}
}
BufferedImage tmp = new BufferedImage(w, h, type);
Graphics2D g2 = tmp.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED);
g2.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_SPEED);
g2.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED);
g2.drawImage(ret, 0, 0, w, h, null);
g2.dispose();
ret = tmp;
} while (w != targetWidth || h != targetHeight);
return ret;
}
public static BufferedImage getImage(String arg) throws ParameterException {
try {
if (arg.startsWith("http")) {
if (arg.contains("imgur.com") && !arg.contains("i.imgur.com")) {
arg = "https://i.imgur.com/" + arg.split("imgur.com/")[1] + ".png";
}
URL url = new URL(arg);
BufferedImage img = MainUtil.readImage(url);
if (img == null) {
throw new IOException("Failed to read " + url + ", please try again later");
}
return img;
} else if (arg.startsWith("file://")) {
arg = arg.substring(7);
File file = MainUtil.getFile(MainUtil.getFile(Fawe.imp().getDirectory(), com.boydti.fawe.config.Settings.IMP.PATHS.HEIGHTMAP), arg);
return MainUtil.readImage(file);
} else {
throw new ParameterException("Invalid image " + arg);
}
} catch (IOException e) {
throw new ParameterException(e);
}
}
}

View File

@ -0,0 +1,8 @@
package com.boydti.fawe.util.image;
import java.awt.image.BufferedImage;
import java.io.Closeable;
public interface ImageViewer extends Closeable{
public void view(BufferedImage image);
}

View File

@ -34,6 +34,7 @@ import com.boydti.fawe.object.extent.ResettableExtent;
import com.boydti.fawe.util.EditSessionBuilder;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.StringMan;
import com.boydti.fawe.util.cui.CUI;
import com.boydti.fawe.wrappers.WorldWrapper;
import com.sk89q.jchronic.Chronic;
import com.sk89q.jchronic.Options;
@ -1130,6 +1131,9 @@ public class LocalSession {
if (hasCUISupport) {
actor.dispatchCUIEvent(event);
} else {
CUI cui = Fawe.get().getCUI(actor);
if (cui != null) cui.dispatchCUIEvent(event);
}
}
@ -1151,22 +1155,16 @@ public class LocalSession {
*/
public void dispatchCUISelection(Actor actor) {
checkNotNull(actor);
if (!hasCUISupport) {
return;
}
if (selector instanceof CUIRegion) {
CUIRegion tempSel = (CUIRegion) selector;
if (tempSel.getProtocolVersion() > cuiVersion) {
actor.dispatchCUIEvent(new SelectionShapeEvent(tempSel.getLegacyTypeID()));
dispatchCUIEvent(actor, new SelectionShapeEvent(tempSel.getLegacyTypeID()));
tempSel.describeLegacyCUI(this, actor);
} else {
actor.dispatchCUIEvent(new SelectionShapeEvent(tempSel.getTypeID()));
dispatchCUIEvent(actor, new SelectionShapeEvent(tempSel.getTypeID()));
tempSel.describeCUI(this, actor);
}
}
}
@ -1177,11 +1175,6 @@ public class LocalSession {
*/
public void describeCUI(Actor actor) {
checkNotNull(actor);
if (!hasCUISupport) {
return;
}
if (selector instanceof CUIRegion) {
CUIRegion tempSel = (CUIRegion) selector;

View File

@ -21,6 +21,8 @@ package com.sk89q.worldedit.extension.platform;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.command.AnvilCommands;
import com.boydti.fawe.command.CFICommand;
import com.boydti.fawe.command.CFICommands;
import com.boydti.fawe.command.MaskBinding;
import com.boydti.fawe.command.PatternBinding;
import com.boydti.fawe.config.BBC;
@ -125,7 +127,7 @@ public final class CommandManager {
private final DynamicStreamHandler dynamicHandler = new DynamicStreamHandler();
private final ExceptionConverter exceptionConverter;
private ParametricBuilder builder;
private Map<Object, String[]> methodMap;
private static CommandManager INSTANCE;
@ -151,7 +153,27 @@ public final class CommandManager {
commandLog.addHandler(dynamicHandler);
dynamicHandler.setFormatter(new LogFormat());
builder = new ParametricBuilder();
builder.setAuthorizer(new ActorAuthorizer());
builder.setDefaultCompleter(new UserCommandCompleter(platformManager));
builder.addBinding(new WorldEditBinding(worldEdit));
builder.addBinding(new PatternBinding(worldEdit), com.sk89q.worldedit.function.pattern.Pattern.class);
builder.addBinding(new MaskBinding(worldEdit), com.sk89q.worldedit.function.mask.Mask.class);
builder.addInvokeListener(new LegacyCommandsHandler());
builder.addInvokeListener(new CommandLoggingHandler(worldEdit, commandLog));
this.methodMap = new ConcurrentHashMap<>();
try {
Class.forName("com.intellectualcrafters.plot.PS");
CFICommands cfiCmds = new CFICommands(worldEdit);
CFICommand cfi = new CFICommand(worldEdit, builder);
registerCommands(cfi);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
@ -173,14 +195,6 @@ public final class CommandManager {
*/
public void registerCommands(Object clazz, String... aliases) {
if (platform != null) {
ParametricBuilder builder = new ParametricBuilder();
builder.setAuthorizer(new ActorAuthorizer());
builder.setDefaultCompleter(new UserCommandCompleter(platformManager));
builder.addBinding(new WorldEditBinding(worldEdit));
builder.addBinding(new PatternBinding(worldEdit), com.sk89q.worldedit.function.pattern.Pattern.class);
builder.addBinding(new MaskBinding(worldEdit), com.sk89q.worldedit.function.mask.Mask.class);
DispatcherNode graph = new CommandGraph().builder(builder).commands();
if (aliases.length == 0) {
graph = graph.registerMethods(clazz);
@ -198,16 +212,6 @@ public final class CommandManager {
* Initialize the dispatcher
*/
public void setupDispatcher() {
ParametricBuilder builder = new ParametricBuilder();
builder.setAuthorizer(new ActorAuthorizer());
builder.setDefaultCompleter(new UserCommandCompleter(platformManager));
builder.addBinding(new WorldEditBinding(worldEdit));
builder.addBinding(new PatternBinding(worldEdit), com.sk89q.worldedit.function.pattern.Pattern.class);
builder.addBinding(new MaskBinding(worldEdit), com.sk89q.worldedit.function.mask.Mask.class);
builder.addInvokeListener(new LegacyCommandsHandler());
builder.addInvokeListener(new CommandLoggingHandler(worldEdit, commandLog));
DispatcherNode graph = new CommandGraph().builder(builder).commands();
for (Map.Entry<Object, String[]> entry : methodMap.entrySet()) {

View File

@ -244,15 +244,14 @@ public class HeightMap {
// Skip water/lava
if (!FaweCache.isLiquidOrGas(existing.getId())) {
session.setBlock(xr, newHeight, zr, existing);
++blocksChanged;
// Grow -- start from 1 below top replacing airblocks
for (int y = newHeight - 1 - originY; y >= curHeight; --y) {
for (int y = curHeight; y <= newHeight - 1 - originY; y++) {
int copyFrom = (int) (y * scale);
session.setBlock(xr, originY + y, zr, session.getBlock(xr, originY + copyFrom, zr));
++blocksChanged;
}
session.setBlock(xr, newHeight, zr, existing);
++blocksChanged;
}
} else if (curHeight > newHeight) {
// Set the top block of the column to be the same type

View File

@ -51,6 +51,10 @@ public class ClipboardHolder {
this.worldData = worldData;
}
protected ClipboardHolder() {
worldData = null;
}
/**
* Get the mapping used for blocks, entities, and so on.
*

View File

@ -0,0 +1,45 @@
package com.sk89q.worldedit.session;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.math.transform.Transform;
import com.sk89q.worldedit.world.registry.WorldData;
public class DelegateClipboardHolder extends ClipboardHolder {
private final ClipboardHolder parent;
public DelegateClipboardHolder(ClipboardHolder holder) {
super(holder.getClipboard(), holder.getWorldData());
this.parent = holder;
}
@Override
public WorldData getWorldData() {
return parent.getWorldData();
}
@Override
public Clipboard getClipboard() {
return parent.getClipboard();
}
@Override
public void setTransform(Transform transform) {
parent.setTransform(transform);
}
@Override
public Transform getTransform() {
return parent.getTransform();
}
@Override
public PasteBuilder createPaste(Extent targetExtent, WorldData targetWorldData) {
return parent.createPaste(targetExtent, targetWorldData);
}
@Override
public void close() {
parent.close();
}
}

View File

@ -20,13 +20,20 @@
package com.sk89q.worldedit.util.command.parametric;
import com.boydti.fawe.command.FawePrimitiveBinding;
import com.boydti.fawe.command.MaskBinding;
import com.boydti.fawe.command.PatternBinding;
import com.boydti.fawe.config.Commands;
import com.google.common.collect.ImmutableBiMap.Builder;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.command.MethodCommands;
import com.sk89q.worldedit.internal.command.ActorAuthorizer;
import com.sk89q.worldedit.internal.command.CommandLoggingHandler;
import com.sk89q.worldedit.internal.command.UserCommandCompleter;
import com.sk89q.worldedit.internal.command.WorldEditBinding;
import com.sk89q.worldedit.util.auth.Authorizer;
import com.sk89q.worldedit.util.auth.NullAuthorizer;
import com.sk89q.worldedit.util.command.CallableProcessor;