mirror of
https://github.com/boy0001/FastAsyncWorldedit.git
synced 2024-11-28 13:45:36 +01:00
Code cleanup, fixes, optimizations, tweaks and new features
Code cleanup: - Slight restructure - FaweAPI class with some useful functions - Abstracting some components for future port different versions / platform Fixes: - Fixed lighting issues - Fixed some async exceptions - Fixed undo/redo having unexpected behavior - Fixed support for third party extents Improvements on the relighting algorithm. - It's slightly slower but results in more reliable lighting Queue optimizations: - Decreased overhead, faster block placement and relighting - Now supports async biome changes Block logging: - Now supports block logging (with BlocksHub) Schematic streaming: - Completely bypass the clipboard and "//stream <file>" giant schematics into the world Region selection: - Use "//worldeditregion" to select your current region restriction Manual relighting: - Use "//fixlighting" to fix the lighting in your current selection
This commit is contained in:
parent
046ab56d30
commit
1169b42fab
4
.gitignore
vendored
4
.gitignore
vendored
@ -41,3 +41,7 @@ $RECYCLE.BIN/
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
*.classpath
|
||||
.project
|
||||
*.prefs
|
||||
*.class
|
||||
|
0
config.yml
Normal file
0
config.yml
Normal file
32
plugin.yml
Normal file
32
plugin.yml
Normal file
@ -0,0 +1,32 @@
|
||||
name: FastAsyncWorldEdit
|
||||
main: com.boydti.fawe.bukkit.FaweBukkit
|
||||
version: 1.1.4
|
||||
description: Fast Async WorldEdit plugin
|
||||
authors: [Empire92]
|
||||
loadbefore: [WorldEdit]
|
||||
load: STARTUP
|
||||
database: false
|
||||
#softdepend: [WorldGuard, PlotSquared, MCore, Factions, GriefPrevention, Residence, Towny, PlotMe, PreciousStones]
|
||||
commands:
|
||||
wea:
|
||||
description: (FAWE) Bypass WorldEdit processing and area restrictions
|
||||
aliases: [weanywhere,worldeditanywhere,/wea,/weanywhere,/worldeditanywhere]
|
||||
usage: "Vault is required for the toggle. Optionally, you can set the permission fawe.bypass"
|
||||
fixlighting:
|
||||
description: (FAWE) Fix the lighting in your current chunk
|
||||
aliases: [/fixlighting]
|
||||
stream:
|
||||
description: (FAWE) Stream a schematic into the world
|
||||
aliases: [/stream]
|
||||
wrg:
|
||||
description: (FAWE) Select your current WorldEdit Region.
|
||||
aliases: [/wrg,wer,/wer,worldeditregion,/worldeditregion,/region]
|
||||
permissions:
|
||||
fawe.bypass:
|
||||
default: false
|
||||
fawe.admin:
|
||||
default: false
|
||||
fawe.stream:
|
||||
default: false
|
||||
fawe.fixlighting:
|
||||
default: false
|
226
src/com/boydti/fawe/Fawe.java
Normal file
226
src/com/boydti/fawe/Fawe.java
Normal file
@ -0,0 +1,226 @@
|
||||
package com.boydti.fawe;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.management.MemoryMXBean;
|
||||
import java.lang.management.MemoryPoolMXBean;
|
||||
import java.lang.management.MemoryUsage;
|
||||
import java.util.List;
|
||||
|
||||
import javax.management.InstanceAlreadyExistsException;
|
||||
import javax.management.Notification;
|
||||
import javax.management.NotificationEmitter;
|
||||
import javax.management.NotificationListener;
|
||||
|
||||
import com.boydti.fawe.command.FixLighting;
|
||||
import com.boydti.fawe.command.Stream;
|
||||
import com.boydti.fawe.command.Wea;
|
||||
import com.boydti.fawe.command.WorldEditRegion;
|
||||
import com.boydti.fawe.config.BBC;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.util.Lag;
|
||||
import com.boydti.fawe.util.MemUtil;
|
||||
import com.boydti.fawe.util.SetBlockQueue;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.boydti.fawe.util.WEManager;
|
||||
import com.boydti.fawe.util.WESubscriber;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.command.SchematicCommands;
|
||||
import com.sk89q.worldedit.command.ScriptingCommands;
|
||||
import com.sk89q.worldedit.function.operation.Operations;
|
||||
import com.sk89q.worldedit.function.visitor.BreadthFirstSearch;
|
||||
import com.sk89q.worldedit.function.visitor.DownwardVisitor;
|
||||
import com.sk89q.worldedit.function.visitor.EntityVisitor;
|
||||
import com.sk89q.worldedit.function.visitor.FlatRegionVisitor;
|
||||
import com.sk89q.worldedit.function.visitor.LayerVisitor;
|
||||
import com.sk89q.worldedit.function.visitor.NonRisingVisitor;
|
||||
import com.sk89q.worldedit.function.visitor.RecursiveVisitor;
|
||||
import com.sk89q.worldedit.function.visitor.RegionVisitor;
|
||||
|
||||
public class Fawe {
|
||||
/**
|
||||
* The FAWE instance;
|
||||
*/
|
||||
private static Fawe INSTANCE;
|
||||
|
||||
/**
|
||||
* Get the implementation specific class
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T extends IFawe> T imp() {
|
||||
return INSTANCE != null ? (T) INSTANCE.IMP : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the implementation independent class
|
||||
* @return
|
||||
*/
|
||||
public static Fawe get() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup Fawe
|
||||
* @param implementation
|
||||
* @throws InstanceAlreadyExistsException
|
||||
*/
|
||||
public static void set(final IFawe implementation) throws InstanceAlreadyExistsException, IllegalArgumentException {
|
||||
if (INSTANCE != null) {
|
||||
throw new InstanceAlreadyExistsException("FAWE has already been initialized with: " + INSTANCE.IMP);
|
||||
}
|
||||
if (implementation == null) {
|
||||
throw new IllegalArgumentException("Implementation may not be null.");
|
||||
}
|
||||
INSTANCE = new Fawe(implementation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write something to the console
|
||||
* @param s
|
||||
*/
|
||||
public static void debug(final String s) {
|
||||
if (INSTANCE != null) {
|
||||
INSTANCE.IMP.debug(s);
|
||||
} else {
|
||||
System.out.print(s);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The platform specific implementation
|
||||
*/
|
||||
private final IFawe IMP;
|
||||
private final Thread thread;
|
||||
|
||||
private Fawe(final IFawe implementation) {
|
||||
IMP = implementation;
|
||||
|
||||
this.thread = Thread.currentThread();
|
||||
|
||||
/*
|
||||
* Implementation dependent stuff
|
||||
*/
|
||||
setupConfigs();
|
||||
setupCommands();
|
||||
|
||||
TaskManager.IMP = IMP.getTaskManager();
|
||||
SetBlockQueue.IMP.queue = IMP.getQueue();
|
||||
|
||||
// Delayed setup
|
||||
TaskManager.IMP.later(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// worldedit
|
||||
WEManager.IMP.managers.addAll(IMP.getMaskManagers());
|
||||
worldedit = WorldEdit.getInstance();
|
||||
// Events
|
||||
setupEvents();
|
||||
IMP.setupVault();
|
||||
}
|
||||
}, 0);
|
||||
|
||||
/*
|
||||
* Instance independent stuff
|
||||
*/
|
||||
setupInjector();
|
||||
setupMemoryListener();
|
||||
|
||||
// Lag
|
||||
final Lag lag = new Lag();
|
||||
TaskManager.IMP.repeat(lag, 100);
|
||||
}
|
||||
|
||||
private void setupEvents() {
|
||||
WorldEdit.getInstance().getEventBus().register(new WESubscriber());
|
||||
if (Settings.COMMAND_PROCESSOR) {
|
||||
IMP.setupWEListener();
|
||||
}
|
||||
}
|
||||
|
||||
private void setupCommands() {
|
||||
IMP.setupCommand("wea", new Wea());
|
||||
IMP.setupCommand("fixlighting", new FixLighting());
|
||||
IMP.setupCommand("stream", new Stream());
|
||||
IMP.setupCommand("wrg", new WorldEditRegion());
|
||||
}
|
||||
|
||||
private void setupConfigs() {
|
||||
// Setting up config.yml
|
||||
Settings.setup(new File(IMP.getDirectory(), "config.yml"));
|
||||
// Setting up message.yml
|
||||
BBC.load(new File(IMP.getDirectory(), "message.yml"));
|
||||
}
|
||||
|
||||
private WorldEdit worldedit;
|
||||
|
||||
public WorldEdit getWorldEdit() {
|
||||
return worldedit;
|
||||
}
|
||||
|
||||
private void setupInjector() {
|
||||
EditSession.inject();
|
||||
Operations.inject();
|
||||
SchematicCommands.inject();
|
||||
ScriptingCommands.inject();
|
||||
BreadthFirstSearch.inject();
|
||||
DownwardVisitor.inject();
|
||||
EntityVisitor.inject();
|
||||
FlatRegionVisitor.inject();
|
||||
LayerVisitor.inject();
|
||||
NonRisingVisitor.inject();
|
||||
RecursiveVisitor.inject();
|
||||
RegionVisitor.inject();
|
||||
}
|
||||
|
||||
private void setupMemoryListener() {
|
||||
final MemoryMXBean memBean = ManagementFactory.getMemoryMXBean();
|
||||
final NotificationEmitter ne = (NotificationEmitter) memBean;
|
||||
|
||||
ne.addNotificationListener(new NotificationListener() {
|
||||
@Override
|
||||
public void handleNotification(final Notification notification, final Object handback) {
|
||||
MemUtil.memoryLimitedTask();
|
||||
}
|
||||
}, null, null);
|
||||
|
||||
final List<MemoryPoolMXBean> memPools = ManagementFactory.getMemoryPoolMXBeans();
|
||||
for (final MemoryPoolMXBean mp : memPools) {
|
||||
if (mp.isUsageThresholdSupported()) {
|
||||
final MemoryUsage mu = mp.getUsage();
|
||||
final long max = mu.getMax();
|
||||
if (max < 0) {
|
||||
continue;
|
||||
}
|
||||
final long alert = (max * Settings.MEM_FREE) / 100;
|
||||
mp.setUsageThreshold(alert);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Thread getMainThread() {
|
||||
return thread;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO FIXME
|
||||
* - Speed up chunk changes i.e. more than 1 chunk a tick
|
||||
* - Async packet sending
|
||||
* - Block logging
|
||||
* - Investigate instance.clearSessions() / move to after manual session clearing
|
||||
* - Redo WEManager delay / command queue
|
||||
* - Support older versions of bukkit
|
||||
* - Optimize lighting updates / chunk sending
|
||||
*
|
||||
* TESTING:
|
||||
* - Undo / Redo
|
||||
* - lighting
|
||||
* - streaming
|
||||
* - That history is kept after relog
|
||||
* - Brush delay
|
||||
* - Chunk loading for edits outside an area
|
||||
*
|
||||
*/
|
||||
}
|
331
src/com/boydti/fawe/FaweAPI.java
Normal file
331
src/com/boydti/fawe/FaweAPI.java
Normal file
@ -0,0 +1,331 @@
|
||||
package com.boydti.fawe;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.util.Map;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
|
||||
import com.boydti.fawe.object.ChunkLoc;
|
||||
import com.boydti.fawe.object.FaweChunk;
|
||||
import com.boydti.fawe.object.FaweLocation;
|
||||
import com.boydti.fawe.util.SetBlockQueue;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.sk89q.jnbt.ByteArrayTag;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.IntTag;
|
||||
import com.sk89q.jnbt.NBTInputStream;
|
||||
import com.sk89q.jnbt.NamedTag;
|
||||
import com.sk89q.jnbt.ShortTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
|
||||
/**
|
||||
* The FaweAPI class offers a few useful functions.<br>
|
||||
* - This class is not intended to replace the WorldEdit API<br>
|
||||
* <br>
|
||||
* FaweAPI.[some method]
|
||||
*/
|
||||
public class FaweAPI {
|
||||
|
||||
/**
|
||||
* Set a block at a location asynchronously
|
||||
* @param loc
|
||||
* @param m
|
||||
*/
|
||||
public static void setBlockAsync(final Location loc, final Material m) {
|
||||
SetBlockQueue.IMP.setBlock(loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), (short) m.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a block at a location asynchronously
|
||||
* @param world
|
||||
* @param x
|
||||
* @param y
|
||||
* @param z
|
||||
* @param id
|
||||
* @param data
|
||||
*/
|
||||
public static void setBlockAsync(final String world, final int x, final int y, final int z, final short id, final byte data) {
|
||||
SetBlockQueue.IMP.setBlock(world, x, y, z, id, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a biome at a location asynchronously
|
||||
* @param world
|
||||
* @param x
|
||||
* @param z
|
||||
* @param id
|
||||
* @param data
|
||||
*/
|
||||
public static void setBiomeAsync(final String world, final int x, final int z, BaseBiome biome) {
|
||||
SetBlockQueue.IMP.setBiome(world, x, z, biome);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a biome at a location asynchronously
|
||||
* @param loc
|
||||
* @param biome
|
||||
*/
|
||||
public static void setBiomeAsync(Location loc, BaseBiome biome) {
|
||||
SetBlockQueue.IMP.setBiome(loc.getWorld().getName(), loc.getBlockX(), loc.getBlockZ(), biome);
|
||||
}
|
||||
|
||||
/**
|
||||
* This will return a FaweChunk object that can be modified.<br>
|
||||
* - The FaweChunk object can be reused if you want identical changes across chunks<br>
|
||||
* - This is additive modification.<br>
|
||||
* - First use {@link FaweChunk#fill(int, byte)} (e.g. with air) for absolute modification<br>
|
||||
* When ready, use {@link #setChunk(FaweChunk, ChunkLoc)}
|
||||
* @return
|
||||
*/
|
||||
public static FaweChunk<?> createChunk() {
|
||||
return SetBlockQueue.IMP.queue.getChunk(new ChunkLoc(null, 0, 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #createChunk()
|
||||
* @param data
|
||||
* @param location
|
||||
*/
|
||||
public static void setChunkAsync(FaweChunk<?> data, ChunkLoc location) {
|
||||
data.setChunkLoc(location);
|
||||
data.addToQueue();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #createChunk()
|
||||
* @param data
|
||||
* @param chunk
|
||||
*/
|
||||
public static void setChunkAsync(FaweChunk<?> data, Chunk chunk) {
|
||||
ChunkLoc loc = new ChunkLoc(chunk.getWorld().getName(), chunk.getX(), chunk.getZ());
|
||||
data.setChunkLoc(loc);
|
||||
data.addToQueue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix the lighting at a chunk location.<br>
|
||||
* - The fixAll parameter determines if extensive relighting should occur (slow)
|
||||
* @param loc
|
||||
*/
|
||||
public static void fixLighting(ChunkLoc loc, boolean fixAll) {
|
||||
SetBlockQueue.IMP.queue.fixLighting(SetBlockQueue.IMP.queue.getChunk(loc), fixAll);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix the lighting at a chunk.<br>
|
||||
* - The fixAll parameter determines if extensive relighting should occur (slow)
|
||||
* @param chunk
|
||||
*/
|
||||
public static void fixLighting(Chunk chunk, boolean fixAll) {
|
||||
ChunkLoc loc = new ChunkLoc(chunk.getWorld().getName(), chunk.getX(), chunk.getZ());
|
||||
SetBlockQueue.IMP.queue.fixLighting(SetBlockQueue.IMP.queue.getChunk(loc), fixAll);
|
||||
}
|
||||
|
||||
/**
|
||||
* If a schematic is too large to be pasted normally<br>
|
||||
* - Skips any block history
|
||||
* - Ignores some block data
|
||||
* @param file
|
||||
* @param loc
|
||||
* @return
|
||||
*/
|
||||
public static void streamSchematicAsync(final File file, final Location loc) {
|
||||
FaweLocation fl = new FaweLocation(loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
|
||||
streamSchematicAsync(file, fl);
|
||||
}
|
||||
|
||||
/**
|
||||
* If a schematic is too large to be pasted normally<br>
|
||||
* - Skips any block history
|
||||
* - Ignores some block data
|
||||
* @param file
|
||||
* @param loc
|
||||
* @return
|
||||
*/
|
||||
public static void streamSchematicAsync(final File file, final FaweLocation loc) {
|
||||
TaskManager.IMP.async(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
FileInputStream is = new FileInputStream(file);
|
||||
streamSchematic(is, loc);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* If a schematic is too large to be pasted normally<br>
|
||||
* - Skips any block history
|
||||
* - Ignores some block data
|
||||
* @param url
|
||||
* @param loc
|
||||
*/
|
||||
public static void streamSchematicAsync(final URL url, final FaweLocation loc) {
|
||||
TaskManager.IMP.async(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
ReadableByteChannel rbc = Channels.newChannel(url.openStream());
|
||||
final InputStream is = Channels.newInputStream(rbc);
|
||||
streamSchematic(is, loc);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* If a schematic is too large to be pasted normally<br>
|
||||
* - Skips any block history
|
||||
* - Ignores some block data
|
||||
* @param is
|
||||
* @param loc
|
||||
* @throws IOException
|
||||
*/
|
||||
public static void streamSchematic(InputStream is, FaweLocation loc) throws IOException {
|
||||
NBTInputStream stream = new NBTInputStream(new GZIPInputStream(is));
|
||||
NamedTag name = stream.readNamedTag();
|
||||
stream.close();
|
||||
|
||||
CompoundTag tag = (CompoundTag) name.getTag();
|
||||
Map<String, Tag> tagMap = tag.getValue();
|
||||
|
||||
short width = ShortTag.class.cast(tagMap.get("Width")).getValue();
|
||||
short length = ShortTag.class.cast(tagMap.get("Length")).getValue();
|
||||
short height = ShortTag.class.cast(tagMap.get("Height")).getValue();
|
||||
byte[] ids = ByteArrayTag.class.cast(tagMap.get("Blocks")).getValue();
|
||||
byte[] datas = ByteArrayTag.class.cast(tagMap.get("Data")).getValue();
|
||||
|
||||
String world = loc.world;
|
||||
|
||||
int x_offset = loc.x + IntTag.class.cast(tagMap.get("WEOffsetX")).getValue();
|
||||
int y_offset = loc.y + IntTag.class.cast(tagMap.get("WEOffsetY")).getValue();
|
||||
int z_offset = loc.z + IntTag.class.cast(tagMap.get("WEOffsetZ")).getValue();
|
||||
|
||||
name = null;
|
||||
tagMap = null;
|
||||
tag = null;
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
final int yy = y_offset + y;
|
||||
if (yy > 255) {
|
||||
continue;
|
||||
}
|
||||
final int i1 = y * width * length;
|
||||
for (int z = 0; z < length; z++) {
|
||||
final int i2 = (z * width) + i1;
|
||||
int zz = z_offset + z;
|
||||
for (int x = 0; x < width; x++) {
|
||||
final int i = i2 + x;
|
||||
int xx = x_offset + x;
|
||||
short id = (short) (ids[i] & 0xFF);
|
||||
switch (id) {
|
||||
case 0:
|
||||
case 2:
|
||||
case 4:
|
||||
case 13:
|
||||
case 14:
|
||||
case 15:
|
||||
case 20:
|
||||
case 21:
|
||||
case 22:
|
||||
case 30:
|
||||
case 32:
|
||||
case 37:
|
||||
case 39:
|
||||
case 40:
|
||||
case 41:
|
||||
case 42:
|
||||
case 45:
|
||||
case 46:
|
||||
case 47:
|
||||
case 48:
|
||||
case 49:
|
||||
case 50:
|
||||
case 51:
|
||||
case 55:
|
||||
case 56:
|
||||
case 57:
|
||||
case 58:
|
||||
case 60:
|
||||
case 7:
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
case 73:
|
||||
case 74:
|
||||
case 75:
|
||||
case 76:
|
||||
case 78:
|
||||
case 79:
|
||||
case 80:
|
||||
case 81:
|
||||
case 82:
|
||||
case 83:
|
||||
case 85:
|
||||
case 87:
|
||||
case 88:
|
||||
case 101:
|
||||
case 102:
|
||||
case 103:
|
||||
case 110:
|
||||
case 112:
|
||||
case 113:
|
||||
case 121:
|
||||
case 122:
|
||||
case 129:
|
||||
case 133:
|
||||
case 165:
|
||||
case 166:
|
||||
case 169:
|
||||
case 170:
|
||||
case 172:
|
||||
case 173:
|
||||
case 174:
|
||||
case 181:
|
||||
case 182:
|
||||
case 188:
|
||||
case 189:
|
||||
case 190:
|
||||
case 191:
|
||||
case 192:
|
||||
setBlockAsync(world, xx, yy, zz, id, (byte) 0);
|
||||
break;
|
||||
default: {
|
||||
setBlockAsync(world, xx, yy, zz, id, datas[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ids = null;
|
||||
datas = null;
|
||||
System.gc();
|
||||
System.gc();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a task to run when the async queue is empty
|
||||
* @param whenDone
|
||||
*/
|
||||
public static void addTask(final Runnable whenDone) {
|
||||
SetBlockQueue.IMP.addTask(whenDone);
|
||||
}
|
||||
}
|
39
src/com/boydti/fawe/FaweCache.java
Normal file
39
src/com/boydti/fawe/FaweCache.java
Normal file
@ -0,0 +1,39 @@
|
||||
package com.boydti.fawe;
|
||||
|
||||
import com.boydti.fawe.object.PseudoRandom;
|
||||
|
||||
public class FaweCache {
|
||||
public final static short[][][] CACHE_I = new short[256][16][16];
|
||||
public final static short[][][] CACHE_J = new short[256][16][16];
|
||||
|
||||
public final static byte[][] CACHE_X = new byte[16][4096];
|
||||
public final static short[][] CACHE_Y = new short[16][4096];
|
||||
public final static byte[][] CACHE_Z = new byte[16][4096];
|
||||
|
||||
public final static short[] CACHE_ID = new short[65535];
|
||||
public final static byte[] CACHE_DATA = new byte[65535];
|
||||
|
||||
public final static PseudoRandom RANDOM = new PseudoRandom();
|
||||
|
||||
static {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int y = 0; y < 256; y++) {
|
||||
final short i = (short) (y >> 4);
|
||||
final short j = (short) (((y & 0xF) << 8) | (z << 4) | x);
|
||||
CACHE_I[y][x][z] = i;
|
||||
CACHE_J[y][x][z] = j;
|
||||
CACHE_X[i][j] = (byte) x;
|
||||
CACHE_Y[i][j] = (short) y;
|
||||
CACHE_Z[i][j] = (byte) z;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 65535; i++) {
|
||||
final int j = i >> 4;
|
||||
final int k = i & 0xF;
|
||||
CACHE_ID[i] = (short) j;
|
||||
CACHE_DATA[i] = (byte) k;
|
||||
}
|
||||
}
|
||||
}
|
36
src/com/boydti/fawe/IFawe.java
Normal file
36
src/com/boydti/fawe/IFawe.java
Normal file
@ -0,0 +1,36 @@
|
||||
package com.boydti.fawe;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collection;
|
||||
|
||||
import com.boydti.fawe.object.EditSessionWrapper;
|
||||
import com.boydti.fawe.object.FaweCommand;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.regions.FaweMaskManager;
|
||||
import com.boydti.fawe.util.FaweQueue;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
|
||||
public interface IFawe {
|
||||
public void debug(final String s);
|
||||
|
||||
public File getDirectory();
|
||||
|
||||
public void setupCommand(final String label, final FaweCommand cmd);
|
||||
|
||||
public FawePlayer wrap(final Object obj);
|
||||
|
||||
public void setupWEListener();
|
||||
|
||||
public void setupVault();
|
||||
|
||||
public TaskManager getTaskManager();
|
||||
|
||||
public int[] getVersion();
|
||||
|
||||
public FaweQueue getQueue();
|
||||
|
||||
public EditSessionWrapper getEditSessionWrapper(final EditSession session);
|
||||
|
||||
public Collection<FaweMaskManager> getMaskManagers();
|
||||
}
|
24
src/com/boydti/fawe/bukkit/BukkitCommand.java
Normal file
24
src/com/boydti/fawe/bukkit/BukkitCommand.java
Normal file
@ -0,0 +1,24 @@
|
||||
package com.boydti.fawe.bukkit;
|
||||
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.object.FaweCommand;
|
||||
|
||||
public class BukkitCommand implements CommandExecutor {
|
||||
|
||||
private final FaweCommand cmd;
|
||||
|
||||
public BukkitCommand(final FaweCommand cmd) {
|
||||
this.cmd = cmd;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(final CommandSender sender, final Command cmd, final String label, final String[] args) {
|
||||
this.cmd.execute(Fawe.imp().wrap(sender), args);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
65
src/com/boydti/fawe/bukkit/BukkitPlayer.java
Normal file
65
src/com/boydti/fawe/bukkit/BukkitPlayer.java
Normal file
@ -0,0 +1,65 @@
|
||||
package com.boydti.fawe.bukkit;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.object.FaweLocation;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
|
||||
public class BukkitPlayer extends FawePlayer<Player> {
|
||||
|
||||
public BukkitPlayer(final Player parent) {
|
||||
super(parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return parent.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getUUID() {
|
||||
return parent.getUniqueId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(final String perm) {
|
||||
return parent.hasPermission(perm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPermission(final String perm, final boolean flag) {
|
||||
if (flag) {
|
||||
Fawe.<FaweBukkit> imp().getVault().permission.playerAdd(parent, perm);
|
||||
} else {
|
||||
Fawe.<FaweBukkit> imp().getVault().permission.playerRemove(parent, perm);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(final String message) {
|
||||
parent.sendMessage(ChatColor.translateAlternateColorCodes('&', message));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executeCommand(final String cmd) {
|
||||
Bukkit.getServer().dispatchCommand(parent, cmd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FaweLocation getLocation() {
|
||||
Location loc = parent.getLocation();
|
||||
return new FaweLocation(loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
|
||||
}
|
||||
|
||||
@Override
|
||||
public com.sk89q.worldedit.entity.Player getPlayer() {
|
||||
return Fawe.<FaweBukkit> imp().getWorldEditPlugin().wrapPlayer(parent);
|
||||
}
|
||||
|
||||
}
|
67
src/com/boydti/fawe/bukkit/BukkitTaskMan.java
Normal file
67
src/com/boydti/fawe/bukkit/BukkitTaskMan.java
Normal file
@ -0,0 +1,67 @@
|
||||
package com.boydti.fawe.bukkit;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.apache.commons.lang.mutable.MutableInt;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
|
||||
public class BukkitTaskMan extends TaskManager {
|
||||
|
||||
private final Plugin plugin;
|
||||
|
||||
public BukkitTaskMan(Plugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int repeat(final Runnable r, final int interval) {
|
||||
return plugin.getServer().getScheduler().scheduleSyncRepeatingTask(plugin, r, interval, interval);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int repeatAsync(final Runnable r, final int interval) {
|
||||
return plugin.getServer().getScheduler().scheduleAsyncRepeatingTask(plugin, r, interval, interval);
|
||||
}
|
||||
|
||||
public MutableInt index = new MutableInt(0);
|
||||
public HashMap<Integer, Integer> tasks = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public void async(final Runnable r) {
|
||||
if (r == null) {
|
||||
return;
|
||||
}
|
||||
plugin.getServer().getScheduler().runTaskAsynchronously(plugin, r).getTaskId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void task(final Runnable r) {
|
||||
if (r == null) {
|
||||
return;
|
||||
}
|
||||
plugin.getServer().getScheduler().runTask(plugin, r).getTaskId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void later(final Runnable r, final int delay) {
|
||||
if (r == null) {
|
||||
return;
|
||||
}
|
||||
plugin.getServer().getScheduler().runTaskLater(plugin, r, delay).getTaskId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void laterAsync(final Runnable r, final int delay) {
|
||||
plugin.getServer().getScheduler().runTaskLaterAsynchronously(plugin, r, delay);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel(final int task) {
|
||||
if (task != -1) {
|
||||
Bukkit.getScheduler().cancelTask(task);
|
||||
}
|
||||
}
|
||||
}
|
201
src/com/boydti/fawe/bukkit/FaweBukkit.java
Normal file
201
src/com/boydti/fawe/bukkit/FaweBukkit.java
Normal file
@ -0,0 +1,201 @@
|
||||
package com.boydti.fawe.bukkit;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.IFawe;
|
||||
import com.boydti.fawe.bukkit.regions.FactionsFeature;
|
||||
import com.boydti.fawe.bukkit.regions.FactionsUUIDFeature;
|
||||
import com.boydti.fawe.bukkit.regions.GriefPreventionFeature;
|
||||
import com.boydti.fawe.bukkit.regions.PlotMeFeature;
|
||||
import com.boydti.fawe.bukkit.regions.PlotSquaredFeature;
|
||||
import com.boydti.fawe.bukkit.regions.PreciousStonesFeature;
|
||||
import com.boydti.fawe.bukkit.regions.ResidenceFeature;
|
||||
import com.boydti.fawe.bukkit.regions.TownyFeature;
|
||||
import com.boydti.fawe.bukkit.regions.Worldguard;
|
||||
import com.boydti.fawe.bukkit.v1_8.BukkitEditSessionWrapper_1_8;
|
||||
import com.boydti.fawe.bukkit.v1_8.BukkitQueue_1_8;
|
||||
import com.boydti.fawe.object.EditSessionWrapper;
|
||||
import com.boydti.fawe.object.FaweCommand;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.regions.FaweMaskManager;
|
||||
import com.boydti.fawe.util.FaweQueue;
|
||||
import com.boydti.fawe.util.StringMan;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
|
||||
public class FaweBukkit extends JavaPlugin implements IFawe {
|
||||
|
||||
private VaultUtil vault;
|
||||
private WorldEditPlugin worldedit;
|
||||
|
||||
public VaultUtil getVault() {
|
||||
return vault;
|
||||
}
|
||||
|
||||
public WorldEditPlugin getWorldEditPlugin() {
|
||||
if (worldedit == null) {
|
||||
worldedit = (WorldEditPlugin) Bukkit.getPluginManager().getPlugin("WorldEdit");
|
||||
}
|
||||
return worldedit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
try {
|
||||
Fawe.set(this);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
getServer().shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(final String s) {
|
||||
getLogger().info(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getDirectory() {
|
||||
return getDataFolder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupCommand(final String label, final FaweCommand cmd) {
|
||||
getCommand(label).setExecutor(new BukkitCommand(cmd));
|
||||
}
|
||||
|
||||
@Override
|
||||
public FawePlayer<Player> wrap(final Object obj) {
|
||||
if (obj.getClass() == String.class) {
|
||||
return new BukkitPlayer(Bukkit.getPlayer((String) obj));
|
||||
} else if (obj instanceof Player) {
|
||||
return new BukkitPlayer((Player) obj);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupWEListener() {
|
||||
getServer().getPluginManager().registerEvents(new WEListener(), this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupVault() {
|
||||
try {
|
||||
vault = new VaultUtil();
|
||||
} catch (final Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskManager getTaskManager() {
|
||||
return new BukkitTaskMan(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getVersion() {
|
||||
try {
|
||||
final int[] version = new int[3];
|
||||
final String[] split = Bukkit.getBukkitVersion().split("-")[0].split("\\.");
|
||||
version[0] = Integer.parseInt(split[0]);
|
||||
version[1] = Integer.parseInt(split[1]);
|
||||
if (split.length == 3) {
|
||||
version[2] = Integer.parseInt(split[2]);
|
||||
}
|
||||
return version;
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
debug(StringMan.getString(Bukkit.getBukkitVersion()));
|
||||
debug(StringMan.getString(Bukkit.getBukkitVersion().split("-")[0].split("\\.")));
|
||||
return new int[] { Integer.MAX_VALUE, 0, 0 };
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FaweQueue getQueue() {
|
||||
return new BukkitQueue_1_8();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EditSessionWrapper getEditSessionWrapper(final EditSession session) {
|
||||
return new BukkitEditSessionWrapper_1_8(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<FaweMaskManager> getMaskManagers() {
|
||||
final Plugin worldguardPlugin = Bukkit.getServer().getPluginManager().getPlugin("WorldGuard");
|
||||
final ArrayList<FaweMaskManager> managers = new ArrayList<>();
|
||||
if ((worldguardPlugin != null) && worldguardPlugin.isEnabled()) {
|
||||
managers.add(new Worldguard(worldguardPlugin, this));
|
||||
Fawe.debug("Plugin 'WorldGuard' found. Using it now.");
|
||||
} else {
|
||||
Fawe.debug("Plugin 'WorldGuard' not found. Worldguard features disabled.");
|
||||
}
|
||||
final Plugin plotmePlugin = Bukkit.getServer().getPluginManager().getPlugin("PlotMe");
|
||||
if ((plotmePlugin != null) && plotmePlugin.isEnabled()) {
|
||||
managers.add(new PlotMeFeature(plotmePlugin, this));
|
||||
Fawe.debug("Plugin 'PlotMe' found. Using it now.");
|
||||
} else {
|
||||
Fawe.debug("Plugin 'PlotMe' not found. PlotMe features disabled.");
|
||||
}
|
||||
final Plugin townyPlugin = Bukkit.getServer().getPluginManager().getPlugin("Towny");
|
||||
if ((townyPlugin != null) && townyPlugin.isEnabled()) {
|
||||
managers.add(new TownyFeature(townyPlugin, this));
|
||||
Fawe.debug("Plugin 'Towny' found. Using it now.");
|
||||
} else {
|
||||
Fawe.debug("Plugin 'Towny' not found. Towny features disabled.");
|
||||
}
|
||||
final Plugin factionsPlugin = Bukkit.getServer().getPluginManager().getPlugin("Factions");
|
||||
if ((factionsPlugin != null) && factionsPlugin.isEnabled()) {
|
||||
try {
|
||||
managers.add(new FactionsFeature(factionsPlugin, this));
|
||||
Fawe.debug("Plugin 'Factions' found. Using it now.");
|
||||
} catch (final Throwable e) {
|
||||
managers.add(new FactionsUUIDFeature(factionsPlugin, this));
|
||||
Fawe.debug("Plugin 'FactionsUUID' found. Using it now.");
|
||||
}
|
||||
} else {
|
||||
Fawe.debug("Plugin 'Factions' not found. Factions features disabled.");
|
||||
}
|
||||
final Plugin residencePlugin = Bukkit.getServer().getPluginManager().getPlugin("Residence");
|
||||
if ((residencePlugin != null) && residencePlugin.isEnabled()) {
|
||||
managers.add(new ResidenceFeature(residencePlugin, this));
|
||||
Fawe.debug("Plugin 'Residence' found. Using it now.");
|
||||
} else {
|
||||
Fawe.debug("Plugin 'Residence' not found. Factions features disabled.");
|
||||
}
|
||||
final Plugin griefpreventionPlugin = Bukkit.getServer().getPluginManager().getPlugin("GriefPrevention");
|
||||
if ((griefpreventionPlugin != null) && griefpreventionPlugin.isEnabled()) {
|
||||
managers.add(new GriefPreventionFeature(griefpreventionPlugin, this));
|
||||
Fawe.debug("Plugin 'GriefPrevention' found. Using it now.");
|
||||
} else {
|
||||
Fawe.debug("Plugin 'GriefPrevention' not found. GriefPrevention features disabled.");
|
||||
}
|
||||
final Plugin plotsquaredPlugin = Bukkit.getServer().getPluginManager().getPlugin("PlotSquared");
|
||||
if ((plotsquaredPlugin != null) && plotsquaredPlugin.isEnabled()) {
|
||||
managers.add(new PlotSquaredFeature(plotsquaredPlugin, this));
|
||||
Fawe.debug("Plugin 'PlotSquared' found. Using it now.");
|
||||
} else {
|
||||
Fawe.debug("Plugin 'PlotSquared' not found. PlotSquared features disabled.");
|
||||
}
|
||||
final Plugin preciousstonesPlugin = Bukkit.getServer().getPluginManager().getPlugin("PreciousStones");
|
||||
if ((preciousstonesPlugin != null) && preciousstonesPlugin.isEnabled()) {
|
||||
managers.add(new PreciousStonesFeature(preciousstonesPlugin, this));
|
||||
Fawe.debug("Plugin 'PreciousStones' found. Using it now.");
|
||||
} else {
|
||||
Fawe.debug("Plugin 'PreciousStones' not found. PreciousStones features disabled.");
|
||||
}
|
||||
return managers;
|
||||
}
|
||||
}
|
19
src/com/boydti/fawe/bukkit/VaultUtil.java
Normal file
19
src/com/boydti/fawe/bukkit/VaultUtil.java
Normal file
@ -0,0 +1,19 @@
|
||||
package com.boydti.fawe.bukkit;
|
||||
|
||||
import net.milkbowl.vault.permission.Permission;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.RegisteredServiceProvider;
|
||||
|
||||
public class VaultUtil {
|
||||
public final Permission permission;
|
||||
|
||||
public VaultUtil() {
|
||||
final RegisteredServiceProvider<Permission> permissionProvider = Bukkit.getServer().getServicesManager().getRegistration(net.milkbowl.vault.permission.Permission.class);
|
||||
if (permissionProvider != null) {
|
||||
permission = permissionProvider.getProvider();
|
||||
} else {
|
||||
permission = null;
|
||||
}
|
||||
}
|
||||
}
|
311
src/com/boydti/fawe/bukkit/WEListener.java
Normal file
311
src/com/boydti/fawe/bukkit/WEListener.java
Normal file
@ -0,0 +1,311 @@
|
||||
package com.boydti.fawe.bukkit;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.config.BBC;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.object.RegionWrapper;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.boydti.fawe.util.Perm;
|
||||
import com.boydti.fawe.util.WEManager;
|
||||
import com.sk89q.worldedit.BlockVector;
|
||||
import com.sk89q.worldedit.IncompleteRegionException;
|
||||
import com.sk89q.worldedit.LocalSession;
|
||||
import com.sk89q.worldedit.LocalWorld;
|
||||
import com.sk89q.worldedit.bukkit.BukkitUtil;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
|
||||
@Deprecated
|
||||
public class WEListener implements Listener {
|
||||
|
||||
public final HashSet<String> rad1 = new HashSet<>(Arrays.asList("forestgen", "pumpkins", "drain", "fixwater", "fixlava", "replacenear", "snow", "thaw", "ex", "butcher", "size"));
|
||||
public final HashSet<String> rad2 = new HashSet<>(Arrays.asList("fill", "fillr", "removenear", "remove"));
|
||||
public final HashSet<String> rad2_1 = new HashSet<>(Arrays.asList("hcyl", "cyl"));
|
||||
public final HashSet<String> rad2_2 = new HashSet<>(Arrays.asList("sphere", "pyramid"));
|
||||
public final HashSet<String> rad2_3 = new HashSet<>(Arrays.asList("brush smooth"));
|
||||
public final HashSet<String> rad3_1 = new HashSet<>(Arrays.asList("brush gravity"));
|
||||
public final HashSet<String> rad3_2 = new HashSet<>(Arrays.asList("brush sphere", "brush cylinder"));
|
||||
|
||||
public final HashSet<String> region = new HashSet<>(Arrays.asList("move", "set", "replace", "overlay", "walls", "outline", "deform", "hollow", "smooth", "naturalize", "paste", "count", "distr",
|
||||
"copy", "cut", "green", "setbiome"));
|
||||
public final HashSet<String> regionExtend = new HashSet<>(Arrays.asList("stack"));
|
||||
public final HashSet<String> unregioned = new HashSet<>(Arrays.asList("paste", "redo", "undo", "rotate", "flip", "generate", "schematic", "schem"));
|
||||
public final HashSet<String> unsafe1 = new HashSet<>(Arrays.asList("cs", ".s", "restore", "snapshot", "delchunks", "listchunks"));
|
||||
public final HashSet<String> restricted = new HashSet<>(Arrays.asList("up"));
|
||||
public final HashSet<String> other = new HashSet<>(Arrays.asList("undo", "redo", "schematic", "schem", "count"));
|
||||
|
||||
public boolean checkCommand(final List<String> list, final String cmd) {
|
||||
for (final String identifier : list) {
|
||||
if (("/" + identifier).equals(cmd) || ("//" + identifier).equals(cmd) || ("/worldedit:/" + identifier).equals(cmd) || ("/worldedit:" + identifier).equals(cmd)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public String reduceCmd(final String cmd, final boolean single) {
|
||||
if (cmd.startsWith("/worldedit:/")) {
|
||||
return cmd.substring(12);
|
||||
}
|
||||
if (cmd.startsWith("/worldedit:")) {
|
||||
return cmd.substring(11);
|
||||
}
|
||||
if (cmd.startsWith("//")) {
|
||||
return cmd.substring(2);
|
||||
}
|
||||
if (single && cmd.startsWith("/")) {
|
||||
return cmd.substring(1);
|
||||
}
|
||||
return cmd;
|
||||
}
|
||||
|
||||
public int getInt(final String s) {
|
||||
try {
|
||||
int max = 0;
|
||||
final String[] split = s.split(",");
|
||||
for (final String rad : split) {
|
||||
final int val = Integer.parseInt(rad);
|
||||
if (val > max) {
|
||||
max = val;
|
||||
}
|
||||
}
|
||||
return max;
|
||||
} catch (final NumberFormatException e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean checkVolume(final FawePlayer<Player> player, final long volume, final long max, final Cancellable e) {
|
||||
if (volume > max) {
|
||||
MainUtil.sendMessage(FawePlayer.wrap(player.getName()), BBC.WORLDEDIT_VOLUME.s().replaceAll("%current%", volume + "").replaceAll("%max%", max + ""));
|
||||
e.setCancelled(true);
|
||||
}
|
||||
if (Perm.hasPermission(player, "fawe.admin") && !Perm.hasPermission(player, "fawe.bypass")) {
|
||||
BBC.WORLDEDIT_BYPASS.send(player);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean checkSelection(final FawePlayer<Player> player, final int modifier, final long max, final Cancellable e) {
|
||||
LocalSession session = Fawe.get().getWorldEdit().getSession(player.getName());
|
||||
LocalWorld w = BukkitUtil.getLocalWorld(player.parent.getWorld());
|
||||
Region selection = null;
|
||||
try {
|
||||
selection = session.getSelection(w);
|
||||
} catch (IncompleteRegionException e2) {}
|
||||
if (selection == null) {
|
||||
return true;
|
||||
}
|
||||
final BlockVector pos1 = selection.getMinimumPoint().toBlockVector();
|
||||
final BlockVector pos2 = selection.getMaximumPoint().toBlockVector();
|
||||
final HashSet<RegionWrapper> mask = WEManager.IMP.getMask(player);
|
||||
final RegionWrapper region = new RegionWrapper(pos1.getBlockX(), pos2.getBlockX(), pos1.getBlockZ(), pos2.getBlockZ());
|
||||
if (Settings.REQUIRE_SELECTION) {
|
||||
String arg = null;
|
||||
if (!WEManager.IMP.regionContains(region, mask)) {
|
||||
arg = "pos1 + pos2";
|
||||
} else if (!WEManager.IMP.maskContains(mask, pos1.getBlockX(), pos1.getBlockZ())) {
|
||||
arg = "pos1";
|
||||
} else if (!WEManager.IMP.maskContains(mask, pos2.getBlockX(), pos2.getBlockZ())) {
|
||||
arg = "pos2";
|
||||
}
|
||||
if (arg != null) {
|
||||
BBC.REQUIRE_SELECTION_IN_MASK.send(player, arg);
|
||||
e.setCancelled(true);
|
||||
if (Perm.hasPermission(player, "fawe.admin") && !Perm.hasPermission(player, "fawe.bypass")) {
|
||||
BBC.WORLDEDIT_BYPASS.send(player);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (!WEManager.IMP.regionContains(region, mask)) {
|
||||
BBC.REQUIRE_SELECTION_IN_MASK.send(player, "pos1 + pos2");
|
||||
e.setCancelled(true);
|
||||
if (Perm.hasPermission(player, "fawe.admin") && !Perm.hasPermission(player, "fawe.bypass")) {
|
||||
BBC.WORLDEDIT_BYPASS.send(player);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
final long volume = Math.abs((pos1.getBlockX() - pos2.getBlockX()) * (pos1.getBlockY() - pos2.getBlockY()) * (pos1.getBlockZ() - pos2.getBlockZ())) * modifier;
|
||||
return checkVolume(player, volume, max, e);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
public boolean onPlayerCommand(final PlayerCommandPreprocessEvent e) {
|
||||
final FawePlayer<Player> player = FawePlayer.wrap(e.getPlayer());
|
||||
final String message = e.getMessage();
|
||||
final String cmd = message.toLowerCase();
|
||||
final boolean single = true;
|
||||
final String[] split = cmd.split(" ");
|
||||
|
||||
final long maxVolume = Settings.WE_MAX_VOLUME;
|
||||
final long maxIterations = Settings.WE_MAX_ITERATIONS;
|
||||
// if (player.hasPermission("fawe.bypass")) {
|
||||
// return true;
|
||||
// }
|
||||
if (split.length >= 2) {
|
||||
final String reduced = reduceCmd(split[0], single);
|
||||
final String reduced2 = reduceCmd(split[0] + " " + split[1], single);
|
||||
if (rad1.contains(reduced)) {
|
||||
if (WEManager.IMP.delay(player, message)) {
|
||||
e.setCancelled(true);
|
||||
return true;
|
||||
}
|
||||
final long volume = getInt(split[1]) * 256;
|
||||
return checkVolume(player, volume, maxVolume, e);
|
||||
}
|
||||
if (rad2.contains(reduced)) {
|
||||
if (WEManager.IMP.delay(player, message)) {
|
||||
e.setCancelled(true);
|
||||
return true;
|
||||
}
|
||||
if (split.length >= 3) {
|
||||
final long volume = getInt(split[2]) * 256;
|
||||
return checkVolume(player, volume, maxVolume, e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (rad2_1.contains(reduced)) {
|
||||
if (WEManager.IMP.delay(player, message)) {
|
||||
e.setCancelled(true);
|
||||
return true;
|
||||
}
|
||||
if (split.length >= 4) {
|
||||
final long volume = getInt(split[2]) * getInt(split[3]);
|
||||
return checkVolume(player, volume, maxVolume, e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (rad2_2.contains(reduced)) {
|
||||
if (WEManager.IMP.delay(player, message)) {
|
||||
e.setCancelled(true);
|
||||
return true;
|
||||
}
|
||||
if (split.length >= 3) {
|
||||
final long radius = getInt(split[2]);
|
||||
final long volume = radius * radius;
|
||||
return checkVolume(player, volume, maxVolume, e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (rad2_3.contains(reduced2)) {
|
||||
if (WEManager.IMP.delay(player, message)) {
|
||||
e.setCancelled(true);
|
||||
return true;
|
||||
}
|
||||
if (split.length >= 3) {
|
||||
if (split.length == 4) {
|
||||
final int iterations = getInt(split[3]);
|
||||
if (iterations > maxIterations) {
|
||||
MainUtil.sendMessage(player, BBC.WORLDEDIT_ITERATIONS.s().replaceAll("%current%", iterations + "").replaceAll("%max%", maxIterations + ""));
|
||||
e.setCancelled(true);
|
||||
if (Perm.hasPermission(player, "fawe.admin") && !Perm.hasPermission(player, "fawe.bypass")) {
|
||||
BBC.WORLDEDIT_BYPASS.send(player);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
final long radius = getInt(split[2]);
|
||||
final long volume = radius * radius;
|
||||
return checkVolume(player, volume, maxVolume, e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (rad3_1.contains(reduced2)) {
|
||||
if (WEManager.IMP.delay(player, message)) {
|
||||
e.setCancelled(true);
|
||||
return true;
|
||||
}
|
||||
if (split.length >= 3) {
|
||||
int i = 2;
|
||||
if (split[i].equalsIgnoreCase("-h")) {
|
||||
i = 3;
|
||||
}
|
||||
final long radius = getInt(split[i]);
|
||||
final long volume = radius * radius;
|
||||
return checkVolume(player, volume, maxVolume, e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (rad3_2.contains(reduced2)) {
|
||||
if (WEManager.IMP.delay(player, message)) {
|
||||
e.setCancelled(true);
|
||||
return true;
|
||||
}
|
||||
if (split.length >= 4) {
|
||||
int i = 3;
|
||||
if (split[i].equalsIgnoreCase("-h")) {
|
||||
i = 4;
|
||||
}
|
||||
final long radius = getInt(split[i]);
|
||||
final long volume = radius * radius;
|
||||
return checkVolume(player, volume, maxVolume, e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (regionExtend.contains(reduced)) {
|
||||
if (WEManager.IMP.delay(player, message)) {
|
||||
e.setCancelled(true);
|
||||
return true;
|
||||
}
|
||||
return checkSelection(player, getInt(split[1]), maxVolume, e);
|
||||
}
|
||||
}
|
||||
final String reduced = reduceCmd(split[0], single);
|
||||
if (Settings.WE_BLACKLIST.contains(reduced)) {
|
||||
BBC.WORLDEDIT_UNSAFE.send(player);
|
||||
e.setCancelled(true);
|
||||
if (Perm.hasPermission(player, "fawe.admin") && !Perm.hasPermission(player, "fawe.bypass")) {
|
||||
BBC.WORLDEDIT_BYPASS.send(player);
|
||||
}
|
||||
}
|
||||
if (restricted.contains(reduced)) {
|
||||
final HashSet<RegionWrapper> mask = WEManager.IMP.getMask(player);
|
||||
Location loc = player.parent.getLocation();
|
||||
for (final RegionWrapper region : mask) {
|
||||
if (region.isIn(loc.getBlockX(), loc.getBlockZ())) {
|
||||
if (WEManager.IMP.delay(player, message)) {
|
||||
e.setCancelled(true);
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
e.setCancelled(true);
|
||||
BBC.REQUIRE_SELECTION_IN_MASK.send(player);
|
||||
return true;
|
||||
}
|
||||
if (region.contains(reduced)) {
|
||||
if (WEManager.IMP.delay(player, message)) {
|
||||
e.setCancelled(true);
|
||||
return true;
|
||||
}
|
||||
return checkSelection(player, 1, maxVolume, e);
|
||||
}
|
||||
if (unregioned.contains(reduced)) {
|
||||
if (WEManager.IMP.delay(player, message)) {
|
||||
e.setCancelled(true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (other.contains(reduced)) {
|
||||
if (WEManager.IMP.delay(player, message)) {
|
||||
e.setCancelled(true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
12
src/com/boydti/fawe/bukkit/regions/BukkitMaskManager.java
Normal file
12
src/com/boydti/fawe/bukkit/regions/BukkitMaskManager.java
Normal file
@ -0,0 +1,12 @@
|
||||
package com.boydti.fawe.bukkit.regions;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import com.boydti.fawe.regions.FaweMaskManager;
|
||||
|
||||
public abstract class BukkitMaskManager extends FaweMaskManager<Player> {
|
||||
|
||||
public BukkitMaskManager(final String plugin) {
|
||||
super(plugin);
|
||||
}
|
||||
}
|
48
src/com/boydti/fawe/bukkit/regions/FactionsFeature.java
Normal file
48
src/com/boydti/fawe/bukkit/regions/FactionsFeature.java
Normal file
@ -0,0 +1,48 @@
|
||||
package com.boydti.fawe.bukkit.regions;
|
||||
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import com.boydti.fawe.bukkit.FaweBukkit;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.massivecraft.factions.entity.BoardColl;
|
||||
import com.massivecraft.factions.entity.Faction;
|
||||
import com.massivecraft.massivecore.ps.PS;
|
||||
|
||||
public class FactionsFeature extends BukkitMaskManager implements Listener {
|
||||
FaweBukkit plugin;
|
||||
Plugin factions;
|
||||
|
||||
public FactionsFeature(final Plugin factionsPlugin, final FaweBukkit p3) {
|
||||
super(factionsPlugin.getName());
|
||||
factions = factionsPlugin;
|
||||
plugin = p3;
|
||||
BoardColl.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FaweMask getMask(final FawePlayer<Player> fp) {
|
||||
final Player player = fp.parent;
|
||||
final Location loc = player.getLocation();
|
||||
final Faction fac = BoardColl.get().getFactionAt(PS.valueOf(loc));
|
||||
if (fac != null) {
|
||||
if (fac.getOnlinePlayers().contains(player)) {
|
||||
if (fac.getComparisonName().equals("wilderness") == false) {
|
||||
final Chunk chunk = loc.getChunk();
|
||||
final Location pos1 = new Location(loc.getWorld(), chunk.getX() * 16, 0, chunk.getZ() * 16);
|
||||
final Location pos2 = new Location(loc.getWorld(), (chunk.getX() * 16) + 15, 156, (chunk.getZ() * 16) + 15);
|
||||
return new FaweMask(pos1, pos2) {
|
||||
@Override
|
||||
public String getName() {
|
||||
return "CHUNK:" + loc.getChunk().getX() + "," + loc.getChunk().getZ();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
103
src/com/boydti/fawe/bukkit/regions/FactionsUUIDFeature.java
Normal file
103
src/com/boydti/fawe/bukkit/regions/FactionsUUIDFeature.java
Normal file
@ -0,0 +1,103 @@
|
||||
package com.boydti.fawe.bukkit.regions;
|
||||
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import com.boydti.fawe.bukkit.FaweBukkit;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.object.RegionWrapper;
|
||||
import com.boydti.fawe.util.Perm;
|
||||
import com.massivecraft.factions.Board;
|
||||
import com.massivecraft.factions.FLocation;
|
||||
import com.massivecraft.factions.Faction;
|
||||
|
||||
public class FactionsUUIDFeature extends BukkitMaskManager implements Listener {
|
||||
private final Board instance;
|
||||
|
||||
public FactionsUUIDFeature(final Plugin factionsPlugin, final FaweBukkit p3) {
|
||||
super(factionsPlugin.getName());
|
||||
instance = Board.getInstance();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FaweMask getMask(final FawePlayer<Player> fp) {
|
||||
final Player player = fp.parent;
|
||||
final Chunk chunk = player.getLocation().getChunk();
|
||||
final boolean perm = Perm.hasPermission(FawePlayer.wrap(player), "fawe.factions.wilderness");
|
||||
final RegionWrapper locs = new RegionWrapper(chunk.getX(), chunk.getX(), chunk.getZ(), chunk.getZ());
|
||||
final World world = player.getWorld();
|
||||
|
||||
int count = 32;
|
||||
|
||||
if (isAdded(locs, world, player, perm)) {
|
||||
boolean hasPerm = true;
|
||||
|
||||
RegionWrapper chunkSelection;
|
||||
while (hasPerm && (count > 0)) {
|
||||
count--;
|
||||
|
||||
hasPerm = false;
|
||||
|
||||
chunkSelection = new RegionWrapper(locs.maxX + 1, locs.maxX + 1, locs.minZ, locs.maxZ);
|
||||
|
||||
if (isAdded(chunkSelection, world, player, perm)) {
|
||||
locs.maxX += 1;
|
||||
hasPerm = true;
|
||||
}
|
||||
|
||||
chunkSelection = new RegionWrapper(locs.minX - 1, locs.minX - 1, locs.minZ, locs.maxZ);
|
||||
|
||||
if (isAdded(chunkSelection, world, player, perm)) {
|
||||
locs.minX -= 1;
|
||||
hasPerm = true;
|
||||
}
|
||||
|
||||
chunkSelection = new RegionWrapper(locs.minX, locs.maxX, locs.maxZ + 1, locs.maxZ + 1);
|
||||
|
||||
if (isAdded(chunkSelection, world, player, perm)) {
|
||||
locs.maxZ += 1;
|
||||
hasPerm = true;
|
||||
}
|
||||
|
||||
chunkSelection = new RegionWrapper(locs.minX, locs.maxX, locs.minZ - 1, locs.minZ - 1);
|
||||
|
||||
if (isAdded(chunkSelection, world, player, perm)) {
|
||||
locs.minZ -= 1;
|
||||
hasPerm = true;
|
||||
}
|
||||
}
|
||||
|
||||
final Location pos1 = new Location(world, locs.minX << 4, 1, locs.minZ << 4);
|
||||
final Location pos2 = new Location(world, 15 + (locs.maxX << 4), 256, 15 + (locs.maxZ << 4));
|
||||
return new FaweMask(pos1, pos2) {
|
||||
@Override
|
||||
public String getName() {
|
||||
return "CHUNK:" + pos1.getChunk().getX() + "," + pos1.getChunk().getZ();
|
||||
}
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isAdded(final RegionWrapper locs, final World world, final Player player, final boolean perm) {
|
||||
for (int x = locs.minX; x <= locs.maxX; x++) {
|
||||
for (int z = locs.minZ; z <= locs.maxZ; z++) {
|
||||
final Faction fac = instance.getFactionAt(new FLocation(world.getName(), x, z));
|
||||
if (fac == null) {
|
||||
return false;
|
||||
}
|
||||
if (!fac.getOnlinePlayers().contains(player)) {
|
||||
return false;
|
||||
}
|
||||
if (fac.isWilderness() && !perm) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
97
src/com/boydti/fawe/bukkit/regions/FaweMask.java
Normal file
97
src/com/boydti/fawe/bukkit/regions/FaweMask.java
Normal file
@ -0,0 +1,97 @@
|
||||
package com.boydti.fawe.bukkit.regions;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
|
||||
import org.bukkit.Location;
|
||||
|
||||
import com.boydti.fawe.object.RegionWrapper;
|
||||
|
||||
public class FaweMask {
|
||||
private String description = null;
|
||||
private Location position1;
|
||||
private Location position2;
|
||||
|
||||
public FaweMask(final Location pos1, final Location pos2, final String id) {
|
||||
if ((pos1 == null) || (pos2 == null)) {
|
||||
throw new IllegalArgumentException("Locations cannot be null!");
|
||||
}
|
||||
if (pos1.getWorld().equals(pos2.getWorld()) == false) {
|
||||
throw new IllegalArgumentException("Locations must be in the same world!");
|
||||
}
|
||||
description = id;
|
||||
position1 = new Location(pos1.getWorld(), Math.min(pos1.getBlockX(), pos2.getBlockX()), 0, Math.min(pos1.getBlockZ(), pos2.getBlockZ()));
|
||||
position2 = new Location(pos1.getWorld(), Math.max(pos1.getBlockX(), pos2.getBlockX()), 256, Math.max(pos1.getBlockZ(), pos2.getBlockZ()));
|
||||
}
|
||||
|
||||
public FaweMask(final Location pos1, final Location pos2) {
|
||||
if ((pos1 == null) || (pos2 == null)) {
|
||||
throw new IllegalArgumentException("Locations cannot be null!");
|
||||
}
|
||||
if (pos1.getWorld().equals(pos2.getWorld()) == false) {
|
||||
throw new IllegalArgumentException("Locations must be in the same world!");
|
||||
}
|
||||
position1 = new Location(pos1.getWorld(), Math.min(pos1.getBlockX(), pos2.getBlockX()), 0, Math.min(pos1.getBlockZ(), pos2.getBlockZ()));
|
||||
position2 = new Location(pos1.getWorld(), Math.max(pos1.getBlockX(), pos2.getBlockX()), 256, Math.max(pos1.getBlockZ(), pos2.getBlockZ()));
|
||||
}
|
||||
|
||||
public HashSet<RegionWrapper> getRegions() {
|
||||
final Location lower = getLowerBound();
|
||||
final Location upper = getUpperBound();
|
||||
return new HashSet<>(Arrays.asList(new RegionWrapper(lower.getBlockX(), upper.getBlockX(), lower.getBlockZ(), upper.getBlockZ())));
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public Location getLowerBound() {
|
||||
return position1;
|
||||
}
|
||||
|
||||
public Location getUpperBound() {
|
||||
return position2;
|
||||
}
|
||||
|
||||
public void setBounds(final Location pos1, final Location pos2) {
|
||||
if ((pos1 == null) || (pos2 == null)) {
|
||||
throw new IllegalArgumentException("Locations cannot be null!");
|
||||
}
|
||||
if (pos1.getWorld().equals(pos2.getWorld()) == false) {
|
||||
throw new IllegalArgumentException("Locations must be in the same world!");
|
||||
}
|
||||
position1 = new Location(pos1.getWorld(), Math.min(pos1.getBlockX(), pos2.getBlockX()), 0, Math.min(pos1.getBlockZ(), pos2.getBlockZ()));
|
||||
position2 = new Location(pos1.getWorld(), Math.max(pos1.getBlockX(), pos2.getBlockX()), 256, Math.max(pos1.getBlockZ(), pos2.getBlockZ()));
|
||||
}
|
||||
|
||||
public Location[] getBounds() {
|
||||
final Location[] locations = { position1, position2 };
|
||||
return locations;
|
||||
}
|
||||
|
||||
public boolean contains(final Location loc) {
|
||||
if (position1.getWorld().equals(loc.getWorld())) {
|
||||
if (loc.getBlockX() < position1.getBlockX()) {
|
||||
return false;
|
||||
}
|
||||
if (loc.getBlockX() > position2.getBlockX()) {
|
||||
return false;
|
||||
}
|
||||
if (loc.getBlockZ() < position1.getBlockZ()) {
|
||||
return false;
|
||||
}
|
||||
if (loc.getBlockZ() > position2.getBlockZ()) {
|
||||
return false;
|
||||
}
|
||||
if (loc.getBlockY() < position1.getBlockY()) {
|
||||
return false;
|
||||
}
|
||||
if (loc.getBlockY() > position2.getBlockY()) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package com.boydti.fawe.bukkit.regions;
|
||||
|
||||
import me.ryanhamshire.GriefPrevention.Claim;
|
||||
import me.ryanhamshire.GriefPrevention.GriefPrevention;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import com.boydti.fawe.bukkit.FaweBukkit;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
|
||||
public class GriefPreventionFeature extends BukkitMaskManager implements Listener {
|
||||
FaweBukkit plugin;
|
||||
Plugin griefprevention;
|
||||
|
||||
public GriefPreventionFeature(final Plugin griefpreventionPlugin, final FaweBukkit p3) {
|
||||
super(griefpreventionPlugin.getName());
|
||||
griefprevention = griefpreventionPlugin;
|
||||
plugin = p3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FaweMask getMask(final FawePlayer<Player> fp) {
|
||||
final Player player = fp.parent;
|
||||
final Location location = player.getLocation();
|
||||
final Claim claim = GriefPrevention.instance.dataStore.getClaimAt(location, true, null);
|
||||
if (claim != null) {
|
||||
final String uuid = player.getUniqueId().toString();
|
||||
if (claim.getOwnerName().equalsIgnoreCase(player.getName()) || claim.getOwnerName().equals(uuid)) {
|
||||
claim.getGreaterBoundaryCorner().getBlockX();
|
||||
final Location pos1 = new Location(location.getWorld(), claim.getLesserBoundaryCorner().getBlockX(), 0, claim.getLesserBoundaryCorner().getBlockZ());
|
||||
final Location pos2 = new Location(location.getWorld(), claim.getGreaterBoundaryCorner().getBlockX(), 256, claim.getGreaterBoundaryCorner().getBlockZ());
|
||||
return new FaweMask(pos1, pos2) {
|
||||
@Override
|
||||
public String getName() {
|
||||
return "CLAIM:" + claim.toString();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
50
src/com/boydti/fawe/bukkit/regions/PlotMeFeature.java
Normal file
50
src/com/boydti/fawe/bukkit/regions/PlotMeFeature.java
Normal file
@ -0,0 +1,50 @@
|
||||
package com.boydti.fawe.bukkit.regions;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import com.boydti.fawe.bukkit.FaweBukkit;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.worldcretornica.plotme_core.Plot;
|
||||
import com.worldcretornica.plotme_core.PlotMe_Core;
|
||||
import com.worldcretornica.plotme_core.bukkit.PlotMe_CorePlugin;
|
||||
import com.worldcretornica.plotme_core.bukkit.api.BukkitPlayer;
|
||||
import com.worldcretornica.plotme_core.bukkit.api.BukkitWorld;
|
||||
|
||||
public class PlotMeFeature extends BukkitMaskManager implements Listener {
|
||||
FaweBukkit plugin;
|
||||
PlotMe_Core plotme;
|
||||
|
||||
public PlotMeFeature(final Plugin plotmePlugin, final FaweBukkit p3) {
|
||||
super(plotmePlugin.getName());
|
||||
plotme = ((PlotMe_CorePlugin) plotmePlugin).getAPI();
|
||||
plugin = p3;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public FaweMask getMask(final FawePlayer<Player> fp) {
|
||||
final Player player = fp.parent;
|
||||
final Location location = player.getLocation();
|
||||
final Plot plot = plotme.getPlotMeCoreManager().getPlotById(new BukkitPlayer(player));
|
||||
if (plot == null) {
|
||||
return null;
|
||||
}
|
||||
final boolean isallowed = plot.isAllowed(player.getUniqueId());
|
||||
if (isallowed) {
|
||||
final Location pos1 = new Location(location.getWorld(), plotme.getGenManager(player.getWorld().getName()).bottomX(plot.getId(), new BukkitWorld(player.getWorld())), 0, plotme
|
||||
.getGenManager(player.getWorld().getName()).bottomZ(plot.getId(), new BukkitWorld(player.getWorld())));
|
||||
final Location pos2 = new Location(location.getWorld(), plotme.getGenManager(player.getWorld().getName()).topX(plot.getId(), new BukkitWorld(player.getWorld())), 256, plotme
|
||||
.getGenManager(player.getWorld().getName()).topZ(plot.getId(), new BukkitWorld(player.getWorld())));
|
||||
return new FaweMask(pos1, pos2) {
|
||||
@Override
|
||||
public String getName() {
|
||||
return plot.getId();
|
||||
}
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
86
src/com/boydti/fawe/bukkit/regions/PlotSquaredFeature.java
Normal file
86
src/com/boydti/fawe/bukkit/regions/PlotSquaredFeature.java
Normal file
@ -0,0 +1,86 @@
|
||||
package com.boydti.fawe.bukkit.regions;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import com.boydti.fawe.bukkit.FaweBukkit;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.object.RegionWrapper;
|
||||
import com.intellectualcrafters.plot.PS;
|
||||
import com.intellectualcrafters.plot.object.Plot;
|
||||
import com.intellectualcrafters.plot.object.PlotId;
|
||||
import com.intellectualcrafters.plot.object.PlotPlayer;
|
||||
import com.intellectualcrafters.plot.util.MainUtil;
|
||||
import com.plotsquared.bukkit.BukkitMain;
|
||||
|
||||
public class PlotSquaredFeature extends BukkitMaskManager implements Listener {
|
||||
FaweBukkit plugin;
|
||||
|
||||
public PlotSquaredFeature(final Plugin plotPlugin, final FaweBukkit p3) {
|
||||
super(plotPlugin.getName());
|
||||
plugin = p3;
|
||||
BukkitMain.worldEdit = null;
|
||||
PS.get().worldedit = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FaweMask getMask(final FawePlayer<Player> fp) {
|
||||
final PlotPlayer pp = PlotPlayer.wrap(fp.parent);
|
||||
Plot plot = pp.getCurrentPlot();
|
||||
if (plot == null) {
|
||||
final com.intellectualcrafters.plot.object.Location loc = pp.getLocation();
|
||||
final String world = loc.getWorld();
|
||||
int min = Integer.MAX_VALUE;
|
||||
for (final Plot p : pp.getPlots()) {
|
||||
if (p.world.equals(world)) {
|
||||
final double d = p.getHome().getEuclideanDistanceSquared(loc);
|
||||
if (d < min) {
|
||||
min = (int) d;
|
||||
plot = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (plot != null) {
|
||||
final PlotId id = plot.id;
|
||||
boolean hasPerm = false;
|
||||
if (plot.owner != null) {
|
||||
if (plot.owner.equals(pp.getUUID())) {
|
||||
hasPerm = true;
|
||||
} else if (plot.isAdded(pp.getUUID()) && pp.hasPermission("fawe.plotsquared.member")) {
|
||||
hasPerm = true;
|
||||
}
|
||||
if (hasPerm) {
|
||||
final World world = fp.parent.getWorld();
|
||||
final com.intellectualcrafters.plot.object.RegionWrapper region = MainUtil.getLargestRegion(plot);
|
||||
final HashSet<com.intellectualcrafters.plot.object.RegionWrapper> regions = MainUtil.getRegions(plot);
|
||||
|
||||
final Location pos1 = new Location(world, region.minX, 0, region.minZ);
|
||||
final Location pos2 = new Location(world, region.maxX, 256, region.maxZ);
|
||||
|
||||
final HashSet<RegionWrapper> faweRegions = new HashSet<RegionWrapper>();
|
||||
for (final com.intellectualcrafters.plot.object.RegionWrapper current : regions) {
|
||||
faweRegions.add(new RegionWrapper(current.minX, current.maxX, current.minZ, current.maxZ));
|
||||
}
|
||||
return new FaweMask(pos1, pos2) {
|
||||
@Override
|
||||
public String getName() {
|
||||
return "PLOT^2:" + id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashSet<RegionWrapper> getRegions() {
|
||||
return faweRegions;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package com.boydti.fawe.bukkit.regions;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import net.sacredlabyrinth.Phaed.PreciousStones.FieldFlag;
|
||||
import net.sacredlabyrinth.Phaed.PreciousStones.PreciousStones;
|
||||
import net.sacredlabyrinth.Phaed.PreciousStones.vectors.Field;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import com.boydti.fawe.bukkit.FaweBukkit;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
|
||||
public class PreciousStonesFeature extends BukkitMaskManager implements Listener {
|
||||
FaweBukkit plugin;
|
||||
Plugin preciousstones;
|
||||
|
||||
public PreciousStonesFeature(final Plugin preciousstonesPlugin, final FaweBukkit p3) {
|
||||
super(preciousstonesPlugin.getName());
|
||||
preciousstones = preciousstonesPlugin;
|
||||
plugin = p3;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public FaweMask getMask(final FawePlayer<Player> fp) {
|
||||
final Player player = fp.parent;
|
||||
final Location location = player.getLocation();
|
||||
final List<Field> fields = PreciousStones.API().getFieldsProtectingArea(FieldFlag.PLOT, location);
|
||||
for (final Field myfield : fields) {
|
||||
if (myfield.getOwner().equalsIgnoreCase(player.getName()) || (myfield.getAllowed().contains(player.getName()))) {
|
||||
final Location pos1 = new Location(location.getWorld(), myfield.getCorners().get(0).getBlockX(), myfield.getCorners().get(0).getBlockY(), myfield.getCorners().get(0).getBlockZ());
|
||||
final Location pos2 = new Location(location.getWorld(), myfield.getCorners().get(1).getBlockX(), myfield.getCorners().get(1).getBlockY(), myfield.getCorners().get(1).getBlockZ());
|
||||
return new FaweMask(pos1, pos2) {
|
||||
@Override
|
||||
public String getName() {
|
||||
return "FIELD:" + myfield.toString();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
45
src/com/boydti/fawe/bukkit/regions/ResidenceFeature.java
Normal file
45
src/com/boydti/fawe/bukkit/regions/ResidenceFeature.java
Normal file
@ -0,0 +1,45 @@
|
||||
package com.boydti.fawe.bukkit.regions;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import com.bekvon.bukkit.residence.Residence;
|
||||
import com.bekvon.bukkit.residence.protection.ClaimedResidence;
|
||||
import com.bekvon.bukkit.residence.protection.CuboidArea;
|
||||
import com.boydti.fawe.bukkit.FaweBukkit;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
|
||||
public class ResidenceFeature extends BukkitMaskManager implements Listener {
|
||||
FaweBukkit plugin;
|
||||
Plugin residence;
|
||||
|
||||
public ResidenceFeature(final Plugin residencePlugin, final FaweBukkit p3) {
|
||||
super(residencePlugin.getName());
|
||||
residence = residencePlugin;
|
||||
plugin = p3;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public FaweMask getMask(final FawePlayer<Player> fp) {
|
||||
final Player player = fp.parent;
|
||||
final Location location = player.getLocation();
|
||||
final ClaimedResidence residence = Residence.getResidenceManager().getByLoc(location);
|
||||
if (residence != null) {
|
||||
if (residence.getPlayersInResidence().contains(player)) {
|
||||
final CuboidArea area = residence.getAreaArray()[0];
|
||||
final Location pos1 = area.getHighLoc();
|
||||
final Location pos2 = area.getLowLoc();
|
||||
return new FaweMask(pos1, pos2) {
|
||||
@Override
|
||||
public String getName() {
|
||||
return "RESIDENCE: " + residence.getName();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
72
src/com/boydti/fawe/bukkit/regions/TownyFeature.java
Normal file
72
src/com/boydti/fawe/bukkit/regions/TownyFeature.java
Normal file
@ -0,0 +1,72 @@
|
||||
package com.boydti.fawe.bukkit.regions;
|
||||
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import com.boydti.fawe.bukkit.FaweBukkit;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.palmergames.bukkit.towny.Towny;
|
||||
import com.palmergames.bukkit.towny.object.PlayerCache;
|
||||
import com.palmergames.bukkit.towny.object.TownBlock;
|
||||
import com.palmergames.bukkit.towny.object.TownyUniverse;
|
||||
import com.palmergames.bukkit.towny.object.WorldCoord;
|
||||
|
||||
public class TownyFeature extends BukkitMaskManager implements Listener {
|
||||
FaweBukkit plugin;
|
||||
Plugin towny;
|
||||
|
||||
public TownyFeature(final Plugin townyPlugin, final FaweBukkit p3) {
|
||||
super(townyPlugin.getName());
|
||||
towny = townyPlugin;
|
||||
plugin = p3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FaweMask getMask(final FawePlayer<Player> fp) {
|
||||
final Player player = fp.parent;
|
||||
final Location location = player.getLocation();
|
||||
try {
|
||||
final PlayerCache cache = ((Towny) towny).getCache(player);
|
||||
final WorldCoord mycoord = cache.getLastTownBlock();
|
||||
if (mycoord == null) {
|
||||
return null;
|
||||
} else {
|
||||
final TownBlock myplot = mycoord.getTownBlock();
|
||||
if (myplot == null) {
|
||||
return null;
|
||||
} else {
|
||||
boolean isMember = false;
|
||||
try {
|
||||
if (myplot.getResident().getName().equals(player.getName())) {
|
||||
isMember = true;
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
|
||||
}
|
||||
if (!isMember) {
|
||||
if (player.hasPermission("fawe.towny.*")) {
|
||||
isMember = true;
|
||||
} else if (myplot.getTown().isMayor(TownyUniverse.getDataSource().getResident(player.getName()))) {
|
||||
isMember = true;
|
||||
}
|
||||
}
|
||||
if (isMember) {
|
||||
final Chunk chunk = location.getChunk();
|
||||
final Location pos1 = new Location(location.getWorld(), chunk.getX() * 16, 0, chunk.getZ() * 16);
|
||||
final Location pos2 = new Location(location.getWorld(), (chunk.getX() * 16) + 15, 156, (chunk.getZ() * 16) + 15);
|
||||
return new FaweMask(pos1, pos2) {
|
||||
@Override
|
||||
public String getName() {
|
||||
return "PLOT:" + location.getChunk().getX() + "," + location.getChunk().getZ();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (final Exception e) {}
|
||||
return null;
|
||||
}
|
||||
}
|
93
src/com/boydti/fawe/bukkit/regions/Worldguard.java
Normal file
93
src/com/boydti/fawe/bukkit/regions/Worldguard.java
Normal file
@ -0,0 +1,93 @@
|
||||
package com.boydti.fawe.bukkit.regions;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import com.boydti.fawe.bukkit.FaweBukkit;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.sk89q.worldedit.BlockVector;
|
||||
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
|
||||
import com.sk89q.worldguard.protection.ApplicableRegionSet;
|
||||
import com.sk89q.worldguard.protection.managers.RegionManager;
|
||||
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
|
||||
|
||||
public class Worldguard extends BukkitMaskManager implements Listener {
|
||||
WorldGuardPlugin worldguard;
|
||||
FaweBukkit plugin;
|
||||
|
||||
private WorldGuardPlugin getWorldGuard() {
|
||||
final Plugin plugin = Bukkit.getPluginManager().getPlugin("WorldGuard");
|
||||
|
||||
// WorldGuard may not be loaded
|
||||
if ((plugin == null) || !(plugin instanceof WorldGuardPlugin)) {
|
||||
return null; // Maybe you want throw an exception instead
|
||||
}
|
||||
|
||||
return (WorldGuardPlugin) plugin;
|
||||
}
|
||||
|
||||
public Worldguard(final Plugin p2, final FaweBukkit p3) {
|
||||
super(p2.getName());
|
||||
worldguard = getWorldGuard();
|
||||
plugin = p3;
|
||||
|
||||
}
|
||||
|
||||
public ProtectedRegion isowner(final Player player, final Location location) {
|
||||
final com.sk89q.worldguard.LocalPlayer localplayer = worldguard.wrapPlayer(player);
|
||||
final RegionManager manager = worldguard.getRegionManager(player.getWorld());
|
||||
final ApplicableRegionSet regions = manager.getApplicableRegions(player.getLocation());
|
||||
for (final ProtectedRegion region : regions) {
|
||||
if (region.isOwner(localplayer)) {
|
||||
return region;
|
||||
} else if (region.getId().toLowerCase().equals(player.getName().toLowerCase())) {
|
||||
return region;
|
||||
} else if (region.getId().toLowerCase().contains(player.getName().toLowerCase() + "//")) {
|
||||
return region;
|
||||
} else if (region.isOwner("*")) {
|
||||
return region;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public ProtectedRegion getregion(final Player player, final BlockVector location) {
|
||||
final com.sk89q.worldguard.LocalPlayer localplayer = worldguard.wrapPlayer(player);
|
||||
final ApplicableRegionSet regions = worldguard.getRegionManager(player.getWorld()).getApplicableRegions(location);
|
||||
for (final ProtectedRegion region : regions) {
|
||||
if (region.isOwner(localplayer)) {
|
||||
return region;
|
||||
} else if (region.getId().toLowerCase().equals(player.getName().toLowerCase())) {
|
||||
return region;
|
||||
} else if (region.getId().toLowerCase().contains(player.getName().toLowerCase() + "//")) {
|
||||
return region;
|
||||
} else if (region.isOwner("*")) {
|
||||
return region;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FaweMask getMask(final FawePlayer<Player> fp) {
|
||||
final Player player = fp.parent;
|
||||
final Location location = player.getLocation();
|
||||
final ProtectedRegion myregion = isowner(player, location);
|
||||
if (myregion != null) {
|
||||
final Location pos1 = new Location(location.getWorld(), myregion.getMinimumPoint().getBlockX(), myregion.getMinimumPoint().getBlockY(), myregion.getMinimumPoint().getBlockZ());
|
||||
final Location pos2 = new Location(location.getWorld(), myregion.getMaximumPoint().getBlockX(), myregion.getMaximumPoint().getBlockY(), myregion.getMaximumPoint().getBlockZ());
|
||||
return new FaweMask(pos1, pos2) {
|
||||
@Override
|
||||
public String getName() {
|
||||
return myregion.getId();
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package com.boydti.fawe.bukkit.v0;
|
||||
|
||||
import com.boydti.fawe.logging.BlocksHubHook;
|
||||
import com.boydti.fawe.object.EditSessionWrapper;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.history.changeset.ChangeSet;
|
||||
|
||||
public class BukkitEditSessionWrapper_0 extends EditSessionWrapper {
|
||||
|
||||
private BlocksHubHook hook;
|
||||
|
||||
public BukkitEditSessionWrapper_0(EditSession session) {
|
||||
super(session);
|
||||
try {
|
||||
this.hook = new BlocksHubHook();
|
||||
} catch (Throwable e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Extent getHistoryExtent(Extent parent, ChangeSet set, FawePlayer<?> player) {
|
||||
if (hook != null) {
|
||||
return hook.getLoggingExtent(parent, set, player);
|
||||
}
|
||||
return super.getHistoryExtent(parent, set, player);
|
||||
}
|
||||
|
||||
}
|
183
src/com/boydti/fawe/bukkit/v0/BukkitQueue_0.java
Normal file
183
src/com/boydti/fawe/bukkit/v0/BukkitQueue_0.java
Normal file
@ -0,0 +1,183 @@
|
||||
package com.boydti.fawe.bukkit.v0;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerMoveEvent;
|
||||
import org.bukkit.event.world.ChunkLoadEvent;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.ChunkLoc;
|
||||
import com.boydti.fawe.object.FaweChunk;
|
||||
import com.boydti.fawe.util.FaweQueue;
|
||||
import com.boydti.fawe.util.SetBlockQueue;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
|
||||
public abstract class BukkitQueue_0 extends FaweQueue implements Listener {
|
||||
|
||||
private final HashMap<ChunkLoc, FaweChunk<Chunk>> toLight = new HashMap<>();
|
||||
|
||||
public BukkitQueue_0() {
|
||||
TaskManager.IMP.task(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Bukkit.getPluginManager().registerEvents(BukkitQueue_0.this, (Plugin) Fawe.imp());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onMove(PlayerMoveEvent event) {
|
||||
Location loc = event.getTo();
|
||||
if (!loc.getChunk().equals(event.getFrom().getChunk())) {
|
||||
Chunk chunk = loc.getChunk();
|
||||
ChunkLoc cl = new ChunkLoc(chunk.getWorld().getName(), chunk.getX(), chunk.getZ());
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onChunkLoad(ChunkLoadEvent event) {
|
||||
if (toLight.size() == 0) {
|
||||
return;
|
||||
}
|
||||
Chunk chunk = event.getChunk();
|
||||
ChunkLoc loc = new ChunkLoc(chunk.getWorld().getName(), chunk.getX(), chunk.getZ());
|
||||
for (int x = -1; x <= 1; x++) {
|
||||
for (int z = -1; z <= 1; z++) {
|
||||
ChunkLoc a = new ChunkLoc(loc.world, loc.x + x, loc.z + z);
|
||||
if (toLight.containsKey(a)) {
|
||||
if (fixLighting(toLight.get(a), Settings.FIX_ALL_LIGHTING)) {
|
||||
toLight.remove(a);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final ConcurrentHashMap<ChunkLoc, FaweChunk<Chunk>> blocks = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
public boolean setBlock(final String world, int x, final int y, int z, final short id, final byte data) {
|
||||
if ((y > 255) || (y < 0)) {
|
||||
return false;
|
||||
}
|
||||
final ChunkLoc wrap = new ChunkLoc(world, x >> 4, z >> 4);
|
||||
x = x & 15;
|
||||
z = z & 15;
|
||||
FaweChunk<Chunk> result = blocks.get(wrap);
|
||||
if (result == null) {
|
||||
result = getChunk(wrap);
|
||||
result.setBlock(x, y, z, id, data);
|
||||
final FaweChunk<Chunk> previous = blocks.put(wrap, result);
|
||||
if (previous == null) {
|
||||
return true;
|
||||
}
|
||||
blocks.put(wrap, previous);
|
||||
result = previous;
|
||||
}
|
||||
result.setBlock(x, y, z, id, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBiome(String world, int x, int z, BaseBiome biome) {
|
||||
final ChunkLoc wrap = new ChunkLoc(world, x >> 4, z >> 4);
|
||||
x = x & 15;
|
||||
z = z & 15;
|
||||
FaweChunk<Chunk> result = blocks.get(wrap);
|
||||
if (result == null) {
|
||||
result = getChunk(wrap);
|
||||
final FaweChunk<Chunk> previous = blocks.put(wrap, result);
|
||||
if (previous != null) {
|
||||
blocks.put(wrap, previous);
|
||||
result = previous;
|
||||
}
|
||||
}
|
||||
result.setBiome(x, z, biome);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FaweChunk<Chunk> next() {
|
||||
try {
|
||||
if (blocks.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
final Iterator<Entry<ChunkLoc, FaweChunk<Chunk>>> iter = blocks.entrySet().iterator();
|
||||
final FaweChunk<Chunk> toReturn = iter.next().getValue();
|
||||
if (SetBlockQueue.IMP.isWaiting()) {
|
||||
return null;
|
||||
}
|
||||
iter.remove();
|
||||
execute(toReturn);
|
||||
return toReturn;
|
||||
} catch (final Throwable e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private final ArrayDeque<FaweChunk<Chunk>> toUpdate = new ArrayDeque<>();
|
||||
|
||||
public boolean execute(final FaweChunk<Chunk> fc) {
|
||||
if (fc == null) {
|
||||
return false;
|
||||
}
|
||||
// Load chunk
|
||||
final Chunk chunk = fc.getChunk();
|
||||
chunk.load(true);
|
||||
// Set blocks / entities / biome
|
||||
if (!setComponents(fc)) {
|
||||
return false;
|
||||
}
|
||||
toUpdate.add(fc);
|
||||
// Fix lighting
|
||||
SetBlockQueue.IMP.addTask(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (toUpdate.size() == 0) {
|
||||
return;
|
||||
}
|
||||
for (FaweChunk<Chunk> fc : sendChunk(toUpdate)) {
|
||||
toLight.put(fc.getChunkLoc(), fc);
|
||||
}
|
||||
toUpdate.clear();
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
blocks.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChunk(FaweChunk<?> chunk) {
|
||||
blocks.put(chunk.getChunkLoc(), (FaweChunk<Chunk>) chunk);
|
||||
}
|
||||
|
||||
public abstract Collection<FaweChunk<Chunk>> sendChunk(final Collection<FaweChunk<Chunk>> fcs);
|
||||
|
||||
public abstract boolean setComponents(final FaweChunk<Chunk> fc);
|
||||
|
||||
@Override
|
||||
public abstract FaweChunk<Chunk> getChunk(final ChunkLoc wrap);
|
||||
|
||||
@Override
|
||||
public abstract boolean fixLighting(FaweChunk<?> fc, boolean fixAll);
|
||||
}
|
233
src/com/boydti/fawe/bukkit/v1_8/BukkitChunk_1_8.java
Normal file
233
src/com/boydti/fawe/bukkit/v1_8/BukkitChunk_1_8.java
Normal file
@ -0,0 +1,233 @@
|
||||
package com.boydti.fawe.bukkit.v1_8;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Chunk;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.object.ChunkLoc;
|
||||
import com.boydti.fawe.object.FaweChunk;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
|
||||
public class BukkitChunk_1_8 extends FaweChunk<Chunk> {
|
||||
|
||||
private char[][] ids;
|
||||
|
||||
private final short[] count;
|
||||
private final short[] air;
|
||||
private final short[] relight;
|
||||
private int[][] biomes;
|
||||
|
||||
public Chunk chunk;
|
||||
|
||||
/**
|
||||
* A FaweSections object represents a chunk and the blocks that you wish to change in it.
|
||||
*/
|
||||
protected BukkitChunk_1_8(final ChunkLoc chunk) {
|
||||
super(chunk);
|
||||
ids = new char[16][];
|
||||
count = new short[16];
|
||||
air = new short[16];
|
||||
relight = new short[16];
|
||||
}
|
||||
|
||||
@Override
|
||||
public Chunk getChunk() {
|
||||
if (chunk == null) {
|
||||
final ChunkLoc cl = getChunkLoc();
|
||||
chunk = Bukkit.getWorld(cl.world).getChunkAt(cl.x, cl.z);
|
||||
}
|
||||
return chunk;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChunkLoc(final ChunkLoc loc) {
|
||||
super.setChunkLoc(loc);
|
||||
chunk = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of block changes in a specified section
|
||||
* @param i
|
||||
* @return
|
||||
*/
|
||||
public int getCount(final int i) {
|
||||
return count[i];
|
||||
}
|
||||
|
||||
public int getAir(final int i) {
|
||||
return air[i];
|
||||
}
|
||||
|
||||
public void setCount(int i, short value) {
|
||||
count[i] = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of block changes in a specified section
|
||||
* @param i
|
||||
* @return
|
||||
*/
|
||||
public int getRelight(final int i) {
|
||||
return relight[i];
|
||||
}
|
||||
|
||||
public int getTotalCount() {
|
||||
int total = 0;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
total += count[i];
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
public int getTotalRelight() {
|
||||
if (getTotalCount() == 0 && biomes == null) {
|
||||
Arrays.fill(count, (short) 1);
|
||||
Arrays.fill(relight, Short.MAX_VALUE);
|
||||
return Short.MAX_VALUE;
|
||||
}
|
||||
int total = 0;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
total += relight[i];
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the raw data for a section
|
||||
* @param i
|
||||
* @return
|
||||
*/
|
||||
public char[] getIdArray(final int i) {
|
||||
return ids[i];
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
ids = null;
|
||||
biomes = null;
|
||||
}
|
||||
public int[][] getBiomeArray() {
|
||||
return biomes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlock(final int x, final int y, final int z, final int id, byte data) {
|
||||
final int i = FaweCache.CACHE_I[y][x][z];
|
||||
final int j = FaweCache.CACHE_J[y][x][z];
|
||||
char[] vs = ids[i];
|
||||
if (vs == null) {
|
||||
vs = ids[i] = new char[4096];
|
||||
count[i]++;
|
||||
} else if (vs[j] == 0) {
|
||||
count[i]++;
|
||||
}
|
||||
switch (id) {
|
||||
case 0:
|
||||
air[i]++;
|
||||
vs[j] = (char) 1;
|
||||
return;
|
||||
case 10:
|
||||
case 11:
|
||||
case 39:
|
||||
case 40:
|
||||
case 50:
|
||||
case 51:
|
||||
case 74:
|
||||
case 76:
|
||||
case 89:
|
||||
case 122:
|
||||
case 124:
|
||||
case 138:
|
||||
case 169:
|
||||
relight[i]++;
|
||||
case 2:
|
||||
case 4:
|
||||
case 13:
|
||||
case 14:
|
||||
case 15:
|
||||
case 20:
|
||||
case 21:
|
||||
case 22:
|
||||
case 30:
|
||||
case 32:
|
||||
case 37:
|
||||
case 41:
|
||||
case 42:
|
||||
case 45:
|
||||
case 46:
|
||||
case 47:
|
||||
case 48:
|
||||
case 49:
|
||||
case 55:
|
||||
case 56:
|
||||
case 57:
|
||||
case 58:
|
||||
case 60:
|
||||
case 7:
|
||||
case 8:
|
||||
case 9:
|
||||
case 73:
|
||||
case 75:
|
||||
case 78:
|
||||
case 79:
|
||||
case 80:
|
||||
case 81:
|
||||
case 82:
|
||||
case 83:
|
||||
case 85:
|
||||
case 87:
|
||||
case 88:
|
||||
case 101:
|
||||
case 102:
|
||||
case 103:
|
||||
case 110:
|
||||
case 112:
|
||||
case 113:
|
||||
case 121:
|
||||
case 129:
|
||||
case 133:
|
||||
case 165:
|
||||
case 166:
|
||||
case 170:
|
||||
case 172:
|
||||
case 173:
|
||||
case 174:
|
||||
case 181:
|
||||
case 182:
|
||||
case 188:
|
||||
case 189:
|
||||
case 190:
|
||||
case 191:
|
||||
case 192:
|
||||
vs[j] = (char) (id << 4);
|
||||
return;
|
||||
case 130:
|
||||
case 62:
|
||||
relight[i]++;
|
||||
case 54:
|
||||
case 146:
|
||||
case 61:
|
||||
case 65:
|
||||
case 68:
|
||||
if (data < 2) {
|
||||
data = 2;
|
||||
}
|
||||
default:
|
||||
vs[j] = (char) ((id << 4) + data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBiome(int x, int z, BaseBiome biome) {
|
||||
if (biomes == null) {
|
||||
biomes = new int[16][];
|
||||
}
|
||||
int[] index = biomes[x];
|
||||
if (index == null) {
|
||||
index = biomes[x] = new int[16];
|
||||
}
|
||||
index[z] = biome.getId();
|
||||
}
|
||||
}
|
@ -0,0 +1,167 @@
|
||||
package com.boydti.fawe.bukkit.v1_8;
|
||||
|
||||
import static com.boydti.fawe.util.ReflectionUtils.getRefClass;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import com.boydti.fawe.bukkit.v0.BukkitEditSessionWrapper_0;
|
||||
import com.boydti.fawe.util.ReflectionUtils.RefClass;
|
||||
import com.boydti.fawe.util.ReflectionUtils.RefField;
|
||||
import com.boydti.fawe.util.ReflectionUtils.RefMethod;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.blocks.BlockType;
|
||||
|
||||
public class BukkitEditSessionWrapper_1_8 extends BukkitEditSessionWrapper_0 {
|
||||
|
||||
private final RefClass classCraftWorld = getRefClass("{cb}.CraftWorld");
|
||||
private final RefClass classChunk = getRefClass("{nms}.Chunk");
|
||||
private final RefClass classWorld = getRefClass("{nms}.World");
|
||||
|
||||
private RefMethod worldGetHandle;
|
||||
private RefMethod methodGetChunkAt;
|
||||
private RefField heightMap;
|
||||
private Object nmsWorld;
|
||||
|
||||
private int lastXMin;
|
||||
private int lastZMin;
|
||||
private Object lastChunk;
|
||||
|
||||
public BukkitEditSessionWrapper_1_8(final EditSession session) {
|
||||
super(session);
|
||||
try {
|
||||
worldGetHandle = classCraftWorld.getMethod("getHandle");
|
||||
methodGetChunkAt = classWorld.getMethod("getChunkAt", int.class, int.class);
|
||||
heightMap = classChunk.getField("heightMap");
|
||||
nmsWorld = worldGetHandle.of(Bukkit.getWorld(session.getWorld().getName())).call();
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHighestTerrainBlock(final int x, final int z, final int minY, final int maxY, final boolean naturalOnly) {
|
||||
final int bx = x >> 4;
|
||||
final int bz = z >> 4;
|
||||
int[] heights;
|
||||
if ((lastChunk == null) || (bx != lastXMin) || (bz != lastZMin)) {
|
||||
lastXMin = bx;
|
||||
lastZMin = bz;
|
||||
lastChunk = methodGetChunkAt.of(nmsWorld).call(bx, bz);
|
||||
}
|
||||
if (lastChunk != null) {
|
||||
heights = (int[]) heightMap.of(lastChunk).get();
|
||||
final int lx = x & 15;
|
||||
final int lz = z & 15;
|
||||
final int height = heights[((lz << 4) | lx)];
|
||||
if ((height <= maxY) && (height >= minY)) {
|
||||
final Vector pt = new Vector(x, height, z);
|
||||
final int id = session.getBlockType(pt);
|
||||
if (naturalOnly ? BlockType.isNaturalTerrainBlock(id, 0) : !BlockType.canPassThrough(id, 0)) {
|
||||
return height;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int y = maxY; y >= minY; --y) {
|
||||
final Vector pt = new Vector(x, y, z);
|
||||
final int id = session.getBlockType(pt);
|
||||
int data;
|
||||
switch (id) {
|
||||
case 0: {
|
||||
continue;
|
||||
}
|
||||
case 2:
|
||||
case 4:
|
||||
case 13:
|
||||
case 14:
|
||||
case 15:
|
||||
case 20:
|
||||
case 21:
|
||||
case 22:
|
||||
case 25:
|
||||
case 30:
|
||||
case 32:
|
||||
case 37:
|
||||
case 39:
|
||||
case 40:
|
||||
case 41:
|
||||
case 42:
|
||||
case 45:
|
||||
case 46:
|
||||
case 47:
|
||||
case 48:
|
||||
case 49:
|
||||
case 50:
|
||||
case 51:
|
||||
case 52:
|
||||
case 54:
|
||||
case 55:
|
||||
case 56:
|
||||
case 57:
|
||||
case 58:
|
||||
case 60:
|
||||
case 61:
|
||||
case 62:
|
||||
case 7:
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
case 73:
|
||||
case 74:
|
||||
case 75:
|
||||
case 76:
|
||||
case 78:
|
||||
case 79:
|
||||
case 80:
|
||||
case 81:
|
||||
case 82:
|
||||
case 83:
|
||||
case 84:
|
||||
case 85:
|
||||
case 87:
|
||||
case 88:
|
||||
case 101:
|
||||
case 102:
|
||||
case 103:
|
||||
case 110:
|
||||
case 112:
|
||||
case 113:
|
||||
case 117:
|
||||
case 121:
|
||||
case 122:
|
||||
case 123:
|
||||
case 124:
|
||||
case 129:
|
||||
case 133:
|
||||
case 138:
|
||||
case 137:
|
||||
case 140:
|
||||
case 165:
|
||||
case 166:
|
||||
case 169:
|
||||
case 170:
|
||||
case 172:
|
||||
case 173:
|
||||
case 174:
|
||||
case 176:
|
||||
case 177:
|
||||
case 181:
|
||||
case 182:
|
||||
case 188:
|
||||
case 189:
|
||||
case 190:
|
||||
case 191:
|
||||
case 192:
|
||||
return y;
|
||||
default:
|
||||
data = 0;
|
||||
}
|
||||
if (naturalOnly ? BlockType.isNaturalTerrainBlock(id, data) : !BlockType.canPassThrough(id, data)) {
|
||||
return y;
|
||||
}
|
||||
}
|
||||
return minY;
|
||||
}
|
||||
|
||||
}
|
693
src/com/boydti/fawe/bukkit/v1_8/BukkitQueue_1_8.java
Normal file
693
src/com/boydti/fawe/bukkit/v1_8/BukkitQueue_1_8.java
Normal file
@ -0,0 +1,693 @@
|
||||
package com.boydti.fawe.bukkit.v1_8;
|
||||
|
||||
import static com.boydti.fawe.util.ReflectionUtils.getRefClass;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.World.Environment;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.generator.BlockPopulator;
|
||||
import org.bukkit.generator.ChunkGenerator;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.bukkit.v0.BukkitQueue_0;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.ChunkLoc;
|
||||
import com.boydti.fawe.object.FaweChunk;
|
||||
import com.boydti.fawe.object.IntegerPair;
|
||||
import com.boydti.fawe.util.MemUtil;
|
||||
import com.boydti.fawe.util.ReflectionUtils.RefClass;
|
||||
import com.boydti.fawe.util.ReflectionUtils.RefConstructor;
|
||||
import com.boydti.fawe.util.ReflectionUtils.RefField;
|
||||
import com.boydti.fawe.util.ReflectionUtils.RefMethod;
|
||||
import com.boydti.fawe.util.ReflectionUtils.RefMethod.RefExecutor;
|
||||
import com.sk89q.worldedit.LocalSession;
|
||||
import com.sk89q.worldedit.LocalWorld;
|
||||
import com.sk89q.worldedit.Vector2D;
|
||||
import com.sk89q.worldedit.bukkit.BukkitUtil;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
|
||||
public class BukkitQueue_1_8 extends BukkitQueue_0 {
|
||||
|
||||
private final RefClass classEntityPlayer = getRefClass("{nms}.EntityPlayer");
|
||||
private final RefClass classMapChunk = getRefClass("{nms}.PacketPlayOutMapChunk");
|
||||
private final RefClass classPacket = getRefClass("{nms}.Packet");
|
||||
private final RefClass classConnection = getRefClass("{nms}.PlayerConnection");
|
||||
private final RefClass classChunk = getRefClass("{nms}.Chunk");
|
||||
private final RefClass classCraftPlayer = getRefClass("{cb}.entity.CraftPlayer");
|
||||
private final RefClass classCraftChunk = getRefClass("{cb}.CraftChunk");
|
||||
private final RefClass classWorld = getRefClass("{nms}.World");
|
||||
private final RefClass classCraftWorld = getRefClass("{cb}.CraftWorld");
|
||||
private final RefField mustSave = classChunk.getField("mustSave");
|
||||
private final RefClass classBlockPosition = getRefClass("{nms}.BlockPosition");
|
||||
private final RefClass classChunkSection = getRefClass("{nms}.ChunkSection");
|
||||
|
||||
private RefMethod methodGetHandlePlayer;
|
||||
private RefMethod methodGetHandleChunk;
|
||||
private RefConstructor MapChunk;
|
||||
private RefField connection;
|
||||
private RefMethod send;
|
||||
private RefMethod methodInitLighting;
|
||||
private RefConstructor classBlockPositionConstructor;
|
||||
private RefConstructor classChunkSectionConstructor;
|
||||
private RefMethod methodX;
|
||||
private RefMethod methodAreNeighborsLoaded;
|
||||
private RefMethod methodD;
|
||||
private RefField fieldSections;
|
||||
private RefField fieldWorld;
|
||||
private RefMethod methodGetIdArray;
|
||||
|
||||
private final HashMap<String, FaweGenerator_1_8> worldMap = new HashMap<>();
|
||||
|
||||
public BukkitQueue_1_8() {
|
||||
try {
|
||||
methodGetHandlePlayer = classCraftPlayer.getMethod("getHandle");
|
||||
methodGetHandleChunk = classCraftChunk.getMethod("getHandle");
|
||||
methodInitLighting = classChunk.getMethod("initLighting");
|
||||
MapChunk = classMapChunk.getConstructor(classChunk.getRealClass(), boolean.class, int.class);
|
||||
connection = classEntityPlayer.getField("playerConnection");
|
||||
send = classConnection.getMethod("sendPacket", classPacket.getRealClass());
|
||||
classBlockPositionConstructor = classBlockPosition.getConstructor(int.class, int.class, int.class);
|
||||
methodX = classWorld.getMethod("x", classBlockPosition.getRealClass());
|
||||
methodD = classChunk.getMethod("d", int.class, int.class, int.class);
|
||||
fieldSections = classChunk.getField("sections");
|
||||
fieldWorld = classChunk.getField("world");
|
||||
methodGetIdArray = classChunkSection.getMethod("getIdArray");
|
||||
methodAreNeighborsLoaded = classChunk.getMethod("areNeighborsLoaded", int.class);
|
||||
classChunkSectionConstructor = classChunkSection.getConstructor(int.class, boolean.class, char[].class);
|
||||
} catch (final NoSuchMethodException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public FaweGenerator_1_8 getFaweGenerator(final World world) {
|
||||
final ChunkGenerator gen = world.getGenerator();
|
||||
if ((gen != null) && (gen instanceof FaweGenerator_1_8)) {
|
||||
return (FaweGenerator_1_8) gen;
|
||||
}
|
||||
FaweGenerator_1_8 faweGen = worldMap.get(world.getName());
|
||||
if (faweGen != null) {
|
||||
return faweGen;
|
||||
}
|
||||
faweGen = new FaweGenerator_1_8(this, world);
|
||||
worldMap.put(world.getName(), faweGen);
|
||||
return faweGen;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<FaweChunk<Chunk>> sendChunk(final Collection<FaweChunk<Chunk>> fcs) {
|
||||
final HashMap<FaweChunk<Chunk>, Object> packets = new HashMap<>();
|
||||
final HashMap<String, ArrayList<FaweChunk<Chunk>>> map = new HashMap<>();
|
||||
|
||||
for (final FaweChunk<Chunk> fc : fcs) {
|
||||
String world = fc.getChunkLoc().world;
|
||||
ArrayList<FaweChunk<Chunk>> list = map.get(world);
|
||||
if (list == null) {
|
||||
list = new ArrayList<>();
|
||||
map.put(world, list);
|
||||
}
|
||||
list.add(fc);
|
||||
}
|
||||
final int view = Bukkit.getServer().getViewDistance();
|
||||
for (final Player player : Bukkit.getOnlinePlayers()) {
|
||||
final String world = player.getWorld().getName();
|
||||
final ArrayList<FaweChunk<Chunk>> list = map.get(world);
|
||||
if (list == null) {
|
||||
continue;
|
||||
}
|
||||
final Location loc = player.getLocation();
|
||||
final int cx = loc.getBlockX() >> 4;
|
||||
final int cz = loc.getBlockZ() >> 4;
|
||||
final Object entity = methodGetHandlePlayer.of(player).call();
|
||||
|
||||
for (final FaweChunk<Chunk> fc : list) {
|
||||
final int dx = Math.abs(cx - fc.getChunkLoc().x);
|
||||
final int dz = Math.abs(cz - fc.getChunkLoc().z);
|
||||
if ((dx > view) || (dz > view)) {
|
||||
continue;
|
||||
}
|
||||
RefExecutor con = send.of(connection.of(entity).get());
|
||||
Object packet = packets.get(fc);
|
||||
if (packet == null) {
|
||||
final Object c = methodGetHandleChunk.of(fc.getChunk()).call();
|
||||
packet = MapChunk.create(c, true, 65535);
|
||||
packets.put(fc, packet);
|
||||
con.call(packet);
|
||||
} else {
|
||||
con.call(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
final HashSet<FaweChunk<Chunk>> chunks = new HashSet<FaweChunk<Chunk>>();
|
||||
for (FaweChunk<Chunk> fc : fcs) {
|
||||
Chunk chunk = fc.getChunk();
|
||||
chunk.unload(true, false);
|
||||
chunk.load();
|
||||
ChunkLoc loc = fc.getChunkLoc();
|
||||
chunk.getWorld().refreshChunk(loc.x, loc.z);
|
||||
if (!fixLighting(fc, Settings.FIX_ALL_LIGHTING)) {
|
||||
chunks.add(fc);
|
||||
}
|
||||
}
|
||||
return chunks;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean fixLighting(final FaweChunk<?> fc, boolean fixAll) {
|
||||
try {
|
||||
BukkitChunk_1_8 bc = (BukkitChunk_1_8) fc;
|
||||
final Chunk chunk = bc.getChunk();
|
||||
if (!chunk.isLoaded()) {
|
||||
chunk.load(false);
|
||||
}
|
||||
|
||||
// Initialize lighting
|
||||
final Object c = methodGetHandleChunk.of(chunk).call();
|
||||
|
||||
if (!(boolean) methodAreNeighborsLoaded.of(c).call(1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
methodInitLighting.of(c).call();
|
||||
|
||||
if ((bc.getTotalRelight() == 0 && !fixAll)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final Object[] sections = (Object[]) fieldSections.of(c).get();
|
||||
final Object w = fieldWorld.of(c).get();
|
||||
|
||||
final int X = chunk.getX() << 4;
|
||||
final int Z = chunk.getZ() << 4;
|
||||
|
||||
RefExecutor relight = methodX.of(w);
|
||||
for (int j = 0; j < sections.length; j++) {
|
||||
final Object section = sections[j];
|
||||
if (section == null) {
|
||||
continue;
|
||||
}
|
||||
if ((bc.getRelight(j) == 0 && !fixAll) || bc.getCount(j) == 0 || (bc.getCount(j) >= 4096 && bc.getAir(j) == 0)) {
|
||||
continue;
|
||||
}
|
||||
final char[] array = getIdArray(section);
|
||||
int l = FaweCache.RANDOM.random(2);
|
||||
for (int k = 0; k < array.length; k++) {
|
||||
final int i = array[k];
|
||||
if (i < 16) {
|
||||
continue;
|
||||
}
|
||||
final short id = FaweCache.CACHE_ID[i];
|
||||
switch (id) { // Lighting
|
||||
default:
|
||||
if (!fixAll) {
|
||||
continue;
|
||||
}
|
||||
if ((k & 1) == l) {
|
||||
l = 1 - l;
|
||||
continue;
|
||||
}
|
||||
case 10:
|
||||
case 11:
|
||||
case 39:
|
||||
case 40:
|
||||
case 50:
|
||||
case 51:
|
||||
case 62:
|
||||
case 74:
|
||||
case 76:
|
||||
case 89:
|
||||
case 122:
|
||||
case 124:
|
||||
case 130:
|
||||
case 138:
|
||||
case 169:
|
||||
final int x = FaweCache.CACHE_X[j][k];
|
||||
final int y = FaweCache.CACHE_Y[j][k];
|
||||
final int z = FaweCache.CACHE_Z[j][k];
|
||||
if (isSurrounded(sections, x, y, z)) {
|
||||
continue;
|
||||
}
|
||||
final Object pos = classBlockPositionConstructor.create(X + x, y, Z + z);
|
||||
relight.call(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} catch (final Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isSurrounded(Object[] sections, int x, int y, int z) {
|
||||
return isSolid(getId(sections, x, y + 1, z))
|
||||
&& isSolid(getId(sections, x + 1, y - 1, z))
|
||||
&& isSolid(getId(sections, x - 1, y, z))
|
||||
&& isSolid(getId(sections, x, y, z + 1))
|
||||
&& isSolid(getId(sections, x, y, z - 1));
|
||||
}
|
||||
|
||||
public boolean isSolid(int i) {
|
||||
if (i == 0) {
|
||||
return false;
|
||||
}
|
||||
return Material.getMaterial(i).isOccluding();
|
||||
}
|
||||
|
||||
public int getId(Object[] sections, int x, int y, int z) {
|
||||
if (x < 0 || x > 15 || z < 0 || z > 15) {
|
||||
return 1;
|
||||
}
|
||||
if (y < 0 || y > 255) {
|
||||
return 1;
|
||||
}
|
||||
int i = FaweCache.CACHE_I[y][x][z];
|
||||
Object section = sections[i];
|
||||
if (section == null) {
|
||||
return 0;
|
||||
}
|
||||
char[] array = getIdArray(section);
|
||||
int j = FaweCache.CACHE_J[y][x][z];
|
||||
return array[j] >> 4;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setComponents(final FaweChunk<Chunk> fc) {
|
||||
try {
|
||||
final BukkitChunk_1_8 fs = ((BukkitChunk_1_8) fc);
|
||||
final Chunk chunk = fs.getChunk();
|
||||
final World world = chunk.getWorld();
|
||||
|
||||
final boolean flag = world.getEnvironment() == Environment.NORMAL;
|
||||
|
||||
// Sections
|
||||
final Method getHandele = chunk.getClass().getDeclaredMethod("getHandle");
|
||||
final Object c = getHandele.invoke(chunk);
|
||||
final Class<? extends Object> clazz = c.getClass();
|
||||
final Field sf = clazz.getDeclaredField("sections");
|
||||
sf.setAccessible(true);
|
||||
final Field tf = clazz.getDeclaredField("tileEntities");
|
||||
final Field ef = clazz.getDeclaredField("entitySlices");
|
||||
|
||||
final Object[] sections = (Object[]) sf.get(c);
|
||||
final HashMap<?, ?> tiles = (HashMap<?, ?>) tf.get(c);
|
||||
final List<?>[] entities = (List<?>[]) ef.get(c);
|
||||
|
||||
Method xm = null;
|
||||
Method ym = null;
|
||||
Method zm = null;
|
||||
|
||||
// Trim tiles
|
||||
final Set<Entry<?, ?>> entryset = (Set<Entry<?, ?>>) (Set<?>) tiles.entrySet();
|
||||
final Iterator<Entry<?, ?>> iter = entryset.iterator();
|
||||
while (iter.hasNext()) {
|
||||
final Entry<?, ?> tile = iter.next();
|
||||
final Object pos = tile.getKey();
|
||||
if (xm == null) {
|
||||
final Class<? extends Object> clazz2 = pos.getClass().getSuperclass();
|
||||
xm = clazz2.getDeclaredMethod("getX");
|
||||
ym = clazz2.getDeclaredMethod("getY");
|
||||
zm = clazz2.getDeclaredMethod("getZ");
|
||||
}
|
||||
final int lx = (int) xm.invoke(pos) & 15;
|
||||
final int ly = (int) ym.invoke(pos);
|
||||
final int lz = (int) zm.invoke(pos) & 15;
|
||||
final int j = FaweCache.CACHE_I[ly][lx][lz];
|
||||
final int k = FaweCache.CACHE_J[ly][lx][lz];
|
||||
final char[] array = fs.getIdArray(j);
|
||||
if (array == null) {
|
||||
continue;
|
||||
}
|
||||
if (array[k] != 0) {
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
|
||||
// Trim entities
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if ((entities[i] != null) && (fs.getCount(i) >= 4096)) {
|
||||
entities[i].clear();
|
||||
}
|
||||
}
|
||||
|
||||
// Efficiently merge sections
|
||||
for (int j = 0; j < sections.length; j++) {
|
||||
if (fs.getCount(j) == 0) {
|
||||
continue;
|
||||
}
|
||||
final char[] newArray = fs.getIdArray(j);
|
||||
if (newArray == null) {
|
||||
continue;
|
||||
}
|
||||
Object section = sections[j];
|
||||
if ((section == null) || (fs.getCount(j) >= 4096)) {
|
||||
section = sections[j] = newChunkSection(j << 4, flag, newArray);
|
||||
continue;
|
||||
}
|
||||
final char[] currentArray = getIdArray(section);
|
||||
boolean fill = true;
|
||||
for (int k = 0; k < newArray.length; k++) {
|
||||
final char n = newArray[k];
|
||||
if (n == 0) {
|
||||
fill = false;
|
||||
continue;
|
||||
}
|
||||
switch (n) {
|
||||
case 0:
|
||||
fill = false;
|
||||
continue;
|
||||
case 1:
|
||||
fill = false;
|
||||
currentArray[k] = 0;
|
||||
continue;
|
||||
default:
|
||||
currentArray[k] = n;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (fill) {
|
||||
fs.setCount(j, Short.MAX_VALUE);
|
||||
}
|
||||
}
|
||||
|
||||
// Biomes
|
||||
int[][] biomes = fs.getBiomeArray();
|
||||
if (biomes != null) {
|
||||
LocalWorld lw = BukkitUtil.getLocalWorld(world);
|
||||
int X = fs.getChunkLoc().x << 4;
|
||||
int Z = fs.getChunkLoc().z << 4;
|
||||
BaseBiome bb = new BaseBiome(0);
|
||||
int last = 0;
|
||||
for (int x = 0; x < 16; x++) {
|
||||
int[] array = biomes[x];
|
||||
if (array == null) {
|
||||
continue;
|
||||
}
|
||||
for (int z = 0; z < 16; z++) {
|
||||
int biome = array[z];
|
||||
if (biome == 0) {
|
||||
continue;
|
||||
}
|
||||
if (last != biome) {
|
||||
last = biome;
|
||||
bb.setId(biome);
|
||||
}
|
||||
lw.setBiome(new Vector2D(X + x, Z + z), bb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clear
|
||||
fs.clear();
|
||||
return true;
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
super.clear();
|
||||
ArrayDeque<Chunk> toUnload = new ArrayDeque<>();
|
||||
final int distance = Bukkit.getViewDistance() + 2;
|
||||
HashMap<String, HashMap<IntegerPair, Integer>> players = new HashMap<>();
|
||||
for (final Player player : Bukkit.getOnlinePlayers()) {
|
||||
// Clear history
|
||||
final LocalSession session = Fawe.get().getWorldEdit().getSession(player.getName());
|
||||
session.clearHistory();
|
||||
session.setClipboard(null);
|
||||
final Location loc = player.getLocation();
|
||||
final World worldObj = loc.getWorld();
|
||||
final String world = worldObj.getName();
|
||||
HashMap<IntegerPair, Integer> map = players.get(world);
|
||||
if (map == null) {
|
||||
map = new HashMap<>();
|
||||
players.put(world, map);
|
||||
}
|
||||
final IntegerPair origin = new IntegerPair(loc.getBlockX() >> 4, loc.getBlockZ() >> 4);
|
||||
Integer val = map.get(origin);
|
||||
int check;
|
||||
if (val != null) {
|
||||
if (val == distance) {
|
||||
continue;
|
||||
}
|
||||
check = distance - val;
|
||||
} else {
|
||||
check = distance;
|
||||
map.put(origin, distance);
|
||||
}
|
||||
for (int x = -distance; x <= distance; x++) {
|
||||
if ((x >= check) || (-x >= check)) {
|
||||
continue;
|
||||
}
|
||||
for (int z = -distance; z <= distance; z++) {
|
||||
if ((z >= check) || (-z >= check)) {
|
||||
continue;
|
||||
}
|
||||
final int weight = distance - Math.max(Math.abs(x), Math.abs(z));
|
||||
final IntegerPair chunk = new IntegerPair(x + origin.x, z + origin.z);
|
||||
val = map.get(chunk);
|
||||
if ((val == null) || (val < weight)) {
|
||||
map.put(chunk, weight);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (final World world : Bukkit.getWorlds()) {
|
||||
final String name = world.getName();
|
||||
final HashMap<IntegerPair, Integer> map = players.get(name);
|
||||
if ((map == null) || (map.size() == 0)) {
|
||||
final boolean save = world.isAutoSave();
|
||||
world.setAutoSave(false);
|
||||
for (final Chunk chunk : world.getLoadedChunks()) {
|
||||
unloadChunk(name, chunk);
|
||||
}
|
||||
world.setAutoSave(save);
|
||||
continue;
|
||||
}
|
||||
final Chunk[] chunks = world.getLoadedChunks();
|
||||
for (final Chunk chunk : chunks) {
|
||||
final int x = chunk.getX();
|
||||
final int z = chunk.getZ();
|
||||
if (!map.containsKey(new IntegerPair(x, z))) {
|
||||
toUnload.add(chunk);
|
||||
} else if (chunk.getEntities().length > 4096) {
|
||||
for (final Entity ent : chunk.getEntities()) {
|
||||
ent.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// GC again
|
||||
System.gc();
|
||||
System.gc();
|
||||
// If still critical memory
|
||||
int free = MemUtil.calculateMemory();
|
||||
if (free <= 1) {
|
||||
for (final Chunk chunk : toUnload) {
|
||||
unloadChunk(chunk.getWorld().getName(), chunk);
|
||||
}
|
||||
} else if (free == Integer.MAX_VALUE) {
|
||||
for (final Chunk chunk : toUnload) {
|
||||
chunk.unload(true, false);
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
toUnload = null;
|
||||
players = null;
|
||||
System.gc();
|
||||
System.gc();
|
||||
free = MemUtil.calculateMemory();
|
||||
if (free > 1) {
|
||||
return;
|
||||
}
|
||||
Collection<? extends Player> online = Bukkit.getOnlinePlayers();
|
||||
if (online.size() > 0) {
|
||||
online.iterator().next().kickPlayer("java.lang.OutOfMemoryError");
|
||||
}
|
||||
online = null;
|
||||
System.gc();
|
||||
System.gc();
|
||||
free = MemUtil.calculateMemory();
|
||||
if ((free > 1) || (Bukkit.getOnlinePlayers().size() > 0)) {
|
||||
return;
|
||||
}
|
||||
for (final World world : Bukkit.getWorlds()) {
|
||||
final String name = world.getName();
|
||||
for (final Chunk chunk : world.getLoadedChunks()) {
|
||||
unloadChunk(name, chunk);
|
||||
}
|
||||
}
|
||||
System.gc();
|
||||
System.gc();
|
||||
}
|
||||
|
||||
public Object newChunkSection(final int i, final boolean flag, final char[] ids) {
|
||||
return classChunkSectionConstructor.create(i, flag, ids);
|
||||
}
|
||||
|
||||
public char[] getIdArray(final Object obj) {
|
||||
return (char[]) methodGetIdArray.of(obj).call();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FaweChunk<Chunk> getChunk(final ChunkLoc wrap) {
|
||||
return new BukkitChunk_1_8(wrap);
|
||||
}
|
||||
|
||||
public boolean unloadChunk(final String world, final Chunk chunk) {
|
||||
final Object c = methodGetHandleChunk.of(chunk).call();
|
||||
mustSave.of(c).set(false);
|
||||
if (chunk.isLoaded()) {
|
||||
chunk.unload(false, false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public ChunkGenerator setGenerator(final World world, final ChunkGenerator newGen) {
|
||||
try {
|
||||
final ChunkGenerator gen = world.getGenerator();
|
||||
final Class<? extends World> clazz = world.getClass();
|
||||
final Field generator = clazz.getDeclaredField("generator");
|
||||
generator.setAccessible(true);
|
||||
generator.set(world, newGen);
|
||||
|
||||
final Field wf = clazz.getDeclaredField("world");
|
||||
wf.setAccessible(true);
|
||||
final Object w = wf.get(world);
|
||||
final Class<?> clazz2 = w.getClass().getSuperclass();
|
||||
final Field generator2 = clazz2.getDeclaredField("generator");
|
||||
generator2.set(w, newGen);
|
||||
|
||||
return gen;
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<BlockPopulator> setPopulator(final World world, final List<BlockPopulator> newPop) {
|
||||
try {
|
||||
final List<BlockPopulator> pop = world.getPopulators();
|
||||
final Field populators = world.getClass().getDeclaredField("populators");
|
||||
populators.setAccessible(true);
|
||||
populators.set(world, newPop);
|
||||
return pop;
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setEntitiesAndTiles(final Chunk chunk, final List<?>[] entities, final Map<?, ?> tiles) {
|
||||
try {
|
||||
final Class<? extends Chunk> clazz = chunk.getClass();
|
||||
final Method handle = clazz.getMethod("getHandle");
|
||||
final Object c = handle.invoke(chunk);
|
||||
final Class<? extends Object> clazz2 = c.getClass();
|
||||
|
||||
if (tiles.size() > 0) {
|
||||
final Field tef = clazz2.getDeclaredField("tileEntities");
|
||||
final Map<?, ?> te = (Map<?, ?>) tef.get(c);
|
||||
final Method put = te.getClass().getMethod("putAll", Map.class);
|
||||
put.invoke(te, tiles);
|
||||
}
|
||||
|
||||
final Field esf = clazz2.getDeclaredField("entitySlices");
|
||||
esf.setAccessible(true);
|
||||
esf.set(c, entities);
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public Object getProvider(final World world) {
|
||||
try {
|
||||
// Provider 1
|
||||
final Class<? extends World> clazz = world.getClass();
|
||||
final Field wf = clazz.getDeclaredField("world");
|
||||
wf.setAccessible(true);
|
||||
final Object w = wf.get(world);
|
||||
final Field provider = w.getClass().getSuperclass().getDeclaredField("chunkProvider");
|
||||
provider.setAccessible(true);
|
||||
// ChunkProviderServer
|
||||
final Class<? extends Object> clazz2 = w.getClass();
|
||||
final Field wpsf = clazz2.getDeclaredField("chunkProviderServer");
|
||||
// Store old provider server
|
||||
final Object worldProviderServer = wpsf.get(w);
|
||||
// Store the old provider
|
||||
final Field cp = worldProviderServer.getClass().getDeclaredField("chunkProvider");
|
||||
return cp.get(worldProviderServer);
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Object setProvider(final World world, Object newProvider) {
|
||||
try {
|
||||
// Provider 1
|
||||
final Class<? extends World> clazz = world.getClass();
|
||||
final Field wf = clazz.getDeclaredField("world");
|
||||
wf.setAccessible(true);
|
||||
final Object w = wf.get(world);
|
||||
// ChunkProviderServer
|
||||
final Class<? extends Object> clazz2 = w.getClass();
|
||||
final Field wpsf = clazz2.getDeclaredField("chunkProviderServer");
|
||||
// Store old provider server
|
||||
final Object worldProviderServer = wpsf.get(w);
|
||||
// Store the old provider
|
||||
final Field cp = worldProviderServer.getClass().getDeclaredField("chunkProvider");
|
||||
final Object oldProvider = cp.get(worldProviderServer);
|
||||
// Provider 2
|
||||
final Class<? extends Object> clazz3 = worldProviderServer.getClass();
|
||||
final Field provider2 = clazz3.getDeclaredField("chunkProvider");
|
||||
// If the provider needs to be calculated
|
||||
if (newProvider == null) {
|
||||
Method k;
|
||||
try {
|
||||
k = clazz2.getDeclaredMethod("k");
|
||||
} catch (final Throwable e) {
|
||||
try {
|
||||
k = clazz2.getDeclaredMethod("j");
|
||||
} catch (final Throwable e2) {
|
||||
e2.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
k.setAccessible(true);
|
||||
final Object tempProviderServer = k.invoke(w);
|
||||
newProvider = cp.get(tempProviderServer);
|
||||
// Restore old provider
|
||||
wpsf.set(w, worldProviderServer);
|
||||
}
|
||||
// Set provider for provider server
|
||||
provider2.set(worldProviderServer, newProvider);
|
||||
// Return the previous provider
|
||||
return oldProvider;
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
459
src/com/boydti/fawe/bukkit/v1_8/FaweGenerator_1_8.java
Normal file
459
src/com/boydti/fawe/bukkit/v1_8/FaweGenerator_1_8.java
Normal file
@ -0,0 +1,459 @@
|
||||
package com.boydti.fawe.bukkit.v1_8;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.world.ChunkPopulateEvent;
|
||||
import org.bukkit.generator.BlockPopulator;
|
||||
import org.bukkit.generator.ChunkGenerator;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.bukkit.FaweBukkit;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.ChunkLoc;
|
||||
|
||||
public class FaweGenerator_1_8 extends ChunkGenerator implements Listener {
|
||||
private boolean events;
|
||||
|
||||
private final ChunkGenerator parent;
|
||||
private final List<BlockPopulator> pops;
|
||||
private final Object provider;
|
||||
|
||||
private short[][] ids;
|
||||
private byte[][] data;
|
||||
private Map<?, ?> tiles;
|
||||
private List<?>[] entities;
|
||||
private Biome[][] biomes;
|
||||
|
||||
private final World world;
|
||||
|
||||
private final BukkitQueue_1_8 queue;
|
||||
|
||||
private void registerEvents() {
|
||||
if (events) {
|
||||
return;
|
||||
}
|
||||
Bukkit.getPluginManager().registerEvents(this, Fawe.<FaweBukkit> imp());
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
private void onPopulate(final ChunkPopulateEvent event) {
|
||||
final World world = event.getWorld();
|
||||
final ChunkGenerator gen = world.getGenerator();
|
||||
if (gen instanceof FaweGenerator_1_8) {
|
||||
final FaweGenerator_1_8 fawe = (FaweGenerator_1_8) gen;
|
||||
if (fawe.data == null) {
|
||||
return;
|
||||
}
|
||||
fawe.populate(event.getChunk());
|
||||
decouple((FaweGenerator_1_8) gen, world);
|
||||
}
|
||||
}
|
||||
|
||||
public void setBlock(final short[][] result, final int x, final int y, final int z, final short blkid) {
|
||||
if (result[FaweCache.CACHE_I[y][x][z]] == null) {
|
||||
result[FaweCache.CACHE_I[y][x][z]] = new short[4096];
|
||||
}
|
||||
result[FaweCache.CACHE_I[y][x][z]][FaweCache.CACHE_J[y][x][z]] = blkid;
|
||||
}
|
||||
|
||||
public void setBlock(final short[][] result, final int x, final int y, final int z, final short[] blkid) {
|
||||
if (blkid.length == 1) {
|
||||
setBlock(result, x, y, z, blkid[0]);
|
||||
}
|
||||
final short id = blkid[FaweCache.RANDOM.random(blkid.length)];
|
||||
if (result[FaweCache.CACHE_I[y][x][z]] == null) {
|
||||
result[FaweCache.CACHE_I[y][x][z]] = new short[4096];
|
||||
}
|
||||
result[FaweCache.CACHE_I[y][x][z]][FaweCache.CACHE_J[y][x][z]] = id;
|
||||
}
|
||||
|
||||
public void setBlocks(final short[][] ids, final byte[][] data, final int x, final int z) {
|
||||
this.ids = ids;
|
||||
this.data = data == null ? new byte[16][] : data;
|
||||
if (parent == null) {
|
||||
inject(this, world);
|
||||
}
|
||||
world.regenerateChunk(x, z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Regenerate chunk with the provided id / data / block count<br>
|
||||
* - You can provide null for datas / count but it will be marginally slower
|
||||
* @param ids
|
||||
* @param datas
|
||||
* @param count
|
||||
* @param chunk
|
||||
*/
|
||||
@Deprecated
|
||||
public void regenerateBlocks(final short[][] ids, byte[][] datas, short[] count, final Chunk chunk) {
|
||||
if (datas == null) {
|
||||
datas = new byte[16][];
|
||||
}
|
||||
if (count == null) {
|
||||
count = new short[16];
|
||||
}
|
||||
final int x = chunk.getX();
|
||||
final int z = chunk.getZ();
|
||||
|
||||
boolean skip = true;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (count[i] < 4096) {
|
||||
skip = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!skip) {
|
||||
try {
|
||||
chunk.load(true);
|
||||
biomes = new Biome[16][16];
|
||||
final int X = x << 4;
|
||||
final int Z = z << 4;
|
||||
for (int xx = 0; xx < 16; xx++) {
|
||||
final int xxx = X + x;
|
||||
for (int zz = 0; zz < 16; zz++) {
|
||||
final int zzz = Z + zz;
|
||||
biomes[xx][zz] = world.getBiome(xxx, zzz);
|
||||
}
|
||||
}
|
||||
final Method getHandele = chunk.getClass().getDeclaredMethod("getHandle");
|
||||
final Object c = getHandele.invoke(chunk);
|
||||
final Class<? extends Object> clazz = c.getClass();
|
||||
final Field sf = clazz.getDeclaredField("sections");
|
||||
sf.setAccessible(true);
|
||||
final Field tf = clazz.getDeclaredField("tileEntities");
|
||||
final Field ef = clazz.getDeclaredField("entitySlices");
|
||||
|
||||
final Object[] sections = (Object[]) sf.get(c);
|
||||
final HashMap<?, ?> tiles = (HashMap<?, ?>) tf.get(c);
|
||||
final List<?>[] entities = (List<?>[]) ef.get(c);
|
||||
|
||||
Method xm = null;
|
||||
Method ym = null;
|
||||
Method zm = null;
|
||||
|
||||
// Copy entities / blockstates
|
||||
final Set<Entry<?, ?>> entryset = (Set<Entry<?, ?>>) (Set<?>) tiles.entrySet();
|
||||
final Iterator<Entry<?, ?>> iter = entryset.iterator();
|
||||
while (iter.hasNext()) {
|
||||
final Entry<?, ?> tile = iter.next();
|
||||
final Object loc = tile.getKey();
|
||||
if (xm == null) {
|
||||
final Class<? extends Object> clazz2 = loc.getClass().getSuperclass();
|
||||
xm = clazz2.getDeclaredMethod("getX");
|
||||
ym = clazz2.getDeclaredMethod("getY");
|
||||
zm = clazz2.getDeclaredMethod("getZ");
|
||||
}
|
||||
final int lx = (int) xm.invoke(loc) & 15;
|
||||
final int ly = (int) ym.invoke(loc);
|
||||
final int lz = (int) zm.invoke(loc) & 15;
|
||||
final int j = FaweCache.CACHE_I[ly][lx][lz];
|
||||
final int k = FaweCache.CACHE_J[ly][lx][lz];
|
||||
if (ids[j] == null) {
|
||||
continue;
|
||||
}
|
||||
if (ids[j][k] != 0) {
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
|
||||
this.tiles = tiles;
|
||||
// Trim entities
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if ((entities[i] != null) && (count[i] >= 4096)) {
|
||||
entities[i].clear();
|
||||
}
|
||||
}
|
||||
this.entities = entities;
|
||||
|
||||
// Efficiently merge sections
|
||||
Method getIdArray = null;
|
||||
for (int j = 0; j < sections.length; j++) {
|
||||
if (count[j] >= 4096) {
|
||||
continue;
|
||||
}
|
||||
final Object section = sections[j];
|
||||
if (section == null) {
|
||||
continue;
|
||||
}
|
||||
if (getIdArray == null) {
|
||||
final Class<? extends Object> clazz2 = section.getClass();
|
||||
getIdArray = clazz2.getDeclaredMethod("getIdArray");
|
||||
}
|
||||
final char[] array = (char[]) getIdArray.invoke(section);
|
||||
for (int k = 0; k < array.length; k++) {
|
||||
final int i = array[k];
|
||||
if (i < 16) {
|
||||
continue;
|
||||
}
|
||||
short[] va = ids[j];
|
||||
if (va == null) {
|
||||
va = new short[4096];
|
||||
ids[j] = va;
|
||||
}
|
||||
final short v = va[k];
|
||||
if (v != 0) {
|
||||
continue;
|
||||
}
|
||||
final short id = FaweCache.CACHE_ID[i];
|
||||
va[k] = id;
|
||||
switch (id) {
|
||||
case 0:
|
||||
case 2:
|
||||
case 4:
|
||||
case 13:
|
||||
case 14:
|
||||
case 15:
|
||||
case 20:
|
||||
case 21:
|
||||
case 22:
|
||||
case 30:
|
||||
case 32:
|
||||
case 37:
|
||||
case 39:
|
||||
case 40:
|
||||
case 41:
|
||||
case 42:
|
||||
case 45:
|
||||
case 46:
|
||||
case 47:
|
||||
case 48:
|
||||
case 49:
|
||||
case 50:
|
||||
case 51:
|
||||
case 55:
|
||||
case 56:
|
||||
case 57:
|
||||
case 58:
|
||||
case 60:
|
||||
case 7:
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
case 73:
|
||||
case 74:
|
||||
case 75:
|
||||
case 76:
|
||||
case 78:
|
||||
case 79:
|
||||
case 80:
|
||||
case 81:
|
||||
case 82:
|
||||
case 83:
|
||||
case 85:
|
||||
case 87:
|
||||
case 88:
|
||||
case 101:
|
||||
case 102:
|
||||
case 103:
|
||||
case 110:
|
||||
case 112:
|
||||
case 113:
|
||||
case 121:
|
||||
case 122:
|
||||
case 129:
|
||||
case 133:
|
||||
case 165:
|
||||
case 166:
|
||||
case 169:
|
||||
case 170:
|
||||
case 172:
|
||||
case 173:
|
||||
case 174:
|
||||
case 181:
|
||||
case 182:
|
||||
case 188:
|
||||
case 189:
|
||||
case 190:
|
||||
case 191:
|
||||
case 192:
|
||||
continue;
|
||||
case 53:
|
||||
case 67:
|
||||
case 108:
|
||||
case 109:
|
||||
case 114:
|
||||
case 128:
|
||||
case 134:
|
||||
case 135:
|
||||
case 136:
|
||||
case 156:
|
||||
case 163:
|
||||
case 164:
|
||||
case 180:
|
||||
byte db = FaweCache.CACHE_DATA[i];
|
||||
if (db == 0) {
|
||||
db = -1;
|
||||
}
|
||||
if (datas[j] == null) {
|
||||
datas[j] = new byte[4096];
|
||||
}
|
||||
datas[j][k] = db;
|
||||
continue;
|
||||
}
|
||||
final byte db = FaweCache.CACHE_DATA[i];
|
||||
if (db == 0) {
|
||||
continue;
|
||||
}
|
||||
if (datas[j] == null) {
|
||||
datas[j] = new byte[4096];
|
||||
}
|
||||
datas[j][k] = db;
|
||||
}
|
||||
}
|
||||
|
||||
} catch (final Throwable e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Execute
|
||||
this.ids = ids;
|
||||
data = datas;
|
||||
if (parent == null) {
|
||||
inject(this, world);
|
||||
}
|
||||
world.regenerateChunk(x, z);
|
||||
}
|
||||
|
||||
public void inject(final FaweGenerator_1_8 gen, final World world) {
|
||||
queue.setGenerator(world, gen);
|
||||
queue.setPopulator(world, new ArrayList<BlockPopulator>());
|
||||
queue.setProvider(world, null);
|
||||
}
|
||||
|
||||
public void decouple(final FaweGenerator_1_8 gen, final World world) {
|
||||
gen.data = null;
|
||||
gen.ids = null;
|
||||
gen.tiles = null;
|
||||
gen.entities = null;
|
||||
gen.biomes = null;
|
||||
if (gen.parent == null) {
|
||||
queue.setGenerator(world, gen.parent);
|
||||
queue.setPopulator(world, gen.pops);
|
||||
if (gen.provider != null) {
|
||||
queue.setProvider(world, gen.provider);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public FaweGenerator_1_8(final BukkitQueue_1_8 queue, final World world) {
|
||||
this.queue = queue;
|
||||
this.world = world;
|
||||
parent = world.getGenerator();
|
||||
pops = world.getPopulators();
|
||||
if (parent == null) {
|
||||
provider = queue.getProvider(world);
|
||||
} else {
|
||||
provider = null;
|
||||
}
|
||||
registerEvents();
|
||||
}
|
||||
|
||||
@Override
|
||||
public short[][] generateExtBlockSections(final World world, final Random random, final int x, final int z, final BiomeGrid biomes) {
|
||||
short[][] result;
|
||||
if (ids != null) {
|
||||
result = ids;
|
||||
if ((biomes != null) && (this.biomes != null)) {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
for (int j = 0; j < 16; j++) {
|
||||
biomes.setBiome(i, j, this.biomes[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (parent != null) {
|
||||
result = parent.generateExtBlockSections(world, random, x, z, biomes);
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void populate(final Chunk chunk) {
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
final byte[] section = data[i];
|
||||
if (section == null) {
|
||||
continue;
|
||||
}
|
||||
for (int j = 0; j < section.length; j++) {
|
||||
final byte v = section[j];
|
||||
if (v == 0) {
|
||||
continue;
|
||||
}
|
||||
final int x = FaweCache.CACHE_X[i][j];
|
||||
final int y = FaweCache.CACHE_Y[i][j];
|
||||
final int z = FaweCache.CACHE_Z[i][j];
|
||||
chunk.getBlock(x, y, z).setData(v != -1 ? v : 0, false);
|
||||
}
|
||||
}
|
||||
if ((tiles != null) || (entities != null)) {
|
||||
queue.setEntitiesAndTiles(chunk, entities, tiles);
|
||||
}
|
||||
final BukkitChunk_1_8 fc = new BukkitChunk_1_8(new ChunkLoc(chunk.getWorld().getName(), chunk.getX(), chunk.getZ()));
|
||||
fc.chunk = chunk;
|
||||
queue.fixLighting(fc, Settings.FIX_ALL_LIGHTING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] generate(final World world, final Random random, final int x, final int z) {
|
||||
if (ids == null) {
|
||||
try {
|
||||
parent.generate(world, random, x, z);
|
||||
} catch (final Throwable e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[][] generateBlockSections(final World world, final Random random, final int x, final int z, final BiomeGrid biomes) {
|
||||
if ((ids == null) && (parent != null)) {
|
||||
return parent.generateBlockSections(world, random, x, z, biomes);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canSpawn(final World world, final int x, final int z) {
|
||||
if (parent != null) {
|
||||
return parent.canSpawn(world, x, z);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BlockPopulator> getDefaultPopulators(final World world) {
|
||||
if ((ids == null) && (parent != null)) {
|
||||
return parent.getDefaultPopulators(world);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location getFixedSpawnLocation(final World world, final Random random) {
|
||||
if ((ids == null) && (parent != null)) {
|
||||
return parent.getFixedSpawnLocation(world, random);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
54
src/com/boydti/fawe/command/FixLighting.java
Normal file
54
src/com/boydti/fawe/command/FixLighting.java
Normal file
@ -0,0 +1,54 @@
|
||||
package com.boydti.fawe.command;
|
||||
|
||||
import com.boydti.fawe.FaweAPI;
|
||||
import com.boydti.fawe.config.BBC;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.ChunkLoc;
|
||||
import com.boydti.fawe.object.FaweCommand;
|
||||
import com.boydti.fawe.object.FaweLocation;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
|
||||
public class FixLighting extends FaweCommand {
|
||||
|
||||
public FixLighting() {
|
||||
super("fawe.fixlighting");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(final FawePlayer player, final String... args) {
|
||||
if (player == null) {
|
||||
return false;
|
||||
}
|
||||
FaweLocation loc = player.getLocation();
|
||||
Region selection = player.getSelection();
|
||||
if (selection == null) {
|
||||
FaweAPI.fixLighting(new ChunkLoc(loc.world, loc.x >> 4, loc.z >> 4), Settings.FIX_ALL_LIGHTING);
|
||||
BBC.FIX_LIGHTING_CHUNK.send(player);
|
||||
return true;
|
||||
}
|
||||
int cx = loc.x >> 4;
|
||||
int cz = loc.z >> 4;
|
||||
Vector bot = selection.getMinimumPoint();
|
||||
Vector top = selection.getMaximumPoint();
|
||||
|
||||
int minX = Math.max(cx - 8, bot.getBlockX() >> 4);
|
||||
int minZ = Math.max(cz - 8, bot.getBlockZ() >> 4);
|
||||
|
||||
int maxX = Math.min(cx + 8, top.getBlockX() >> 4);
|
||||
int maxZ = Math.min(cz + 8, top.getBlockZ() >> 4);
|
||||
|
||||
int count = 0;
|
||||
for (int x = minX; x <= maxX; x++) {
|
||||
for (int z = minZ; z <= maxZ; z++) {
|
||||
ChunkLoc cl = new ChunkLoc(loc.world, x, z);
|
||||
FaweAPI.fixLighting(new ChunkLoc(loc.world, x >> 4, z >> 4), Settings.FIX_ALL_LIGHTING);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
BBC.FIX_LIGHTING_SELECTION.send(player, count);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
38
src/com/boydti/fawe/command/Stream.java
Normal file
38
src/com/boydti/fawe/command/Stream.java
Normal file
@ -0,0 +1,38 @@
|
||||
package com.boydti.fawe.command;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweAPI;
|
||||
import com.boydti.fawe.config.BBC;
|
||||
import com.boydti.fawe.object.FaweCommand;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
|
||||
public class Stream extends FaweCommand {
|
||||
|
||||
public Stream() {
|
||||
super("fawe.stream");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(final FawePlayer player, final String... args) {
|
||||
if (player == null) {
|
||||
return false;
|
||||
}
|
||||
if (args.length != 1) {
|
||||
BBC.COMMAND_SYNTAX.send(player, "/stream <file>");
|
||||
return false;
|
||||
}
|
||||
if (!args[0].endsWith(".schematic")) {
|
||||
args[0] += ".schematic";
|
||||
}
|
||||
File file = Fawe.get().getWorldEdit().getWorkingDirectoryFile(Fawe.get().getWorldEdit().getConfiguration().saveDir + File.separator + args[0]);
|
||||
if (!file.exists()) {
|
||||
BBC.SCHEMATIC_NOT_FOUND.send(player, args);
|
||||
return false;
|
||||
}
|
||||
FaweAPI.streamSchematicAsync(file, player.getLocation());
|
||||
BBC.SCHEMATIC_PASTING.send(player);
|
||||
return true;
|
||||
}
|
||||
}
|
35
src/com/boydti/fawe/command/Wea.java
Normal file
35
src/com/boydti/fawe/command/Wea.java
Normal file
@ -0,0 +1,35 @@
|
||||
package com.boydti.fawe.command;
|
||||
|
||||
import com.boydti.fawe.config.BBC;
|
||||
import com.boydti.fawe.object.FaweCommand;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
|
||||
public class Wea extends FaweCommand {
|
||||
|
||||
public Wea() {
|
||||
super("fawe.admin");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(final FawePlayer player, final String... args) {
|
||||
if (player == null) {
|
||||
return false;
|
||||
}
|
||||
if (toggle(player)) {
|
||||
BBC.WORLDEDIT_BYPASSED.send(player);
|
||||
} else {
|
||||
BBC.WORLDEDIT_RESTRICTED.send(player);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean toggle(FawePlayer player) {
|
||||
if (player.hasPermission("fawe.bypass")) {
|
||||
player.setPermission("fawe.bypass", false);
|
||||
return false;
|
||||
} else {
|
||||
player.setPermission("fawe.bypass", true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
38
src/com/boydti/fawe/command/WorldEditRegion.java
Normal file
38
src/com/boydti/fawe/command/WorldEditRegion.java
Normal file
@ -0,0 +1,38 @@
|
||||
package com.boydti.fawe.command;
|
||||
|
||||
import com.boydti.fawe.config.BBC;
|
||||
import com.boydti.fawe.object.FaweCommand;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.object.RegionWrapper;
|
||||
|
||||
public class WorldEditRegion extends FaweCommand {
|
||||
|
||||
public WorldEditRegion() {
|
||||
super("fawe.worldeditregion");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(final FawePlayer player, final String... args) {
|
||||
if (player == null) {
|
||||
return false;
|
||||
}
|
||||
RegionWrapper region = player.getLargestRegion();
|
||||
if (region == null) {
|
||||
BBC.NO_REGION.send(player);
|
||||
return false;
|
||||
}
|
||||
player.setSelection(region);
|
||||
BBC.SET_REGION.send(player);
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean toggle(FawePlayer player) {
|
||||
if (player.hasPermission("fawe.bypass")) {
|
||||
player.setPermission("fawe.bypass", false);
|
||||
return false;
|
||||
} else {
|
||||
player.setPermission("fawe.bypass", true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
210
src/com/boydti/fawe/config/BBC.java
Normal file
210
src/com/boydti/fawe/config/BBC.java
Normal file
@ -0,0 +1,210 @@
|
||||
package com.boydti.fawe.config;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.util.StringMan;
|
||||
|
||||
public enum BBC {
|
||||
|
||||
/*
|
||||
* Things to note about this class:
|
||||
* Can use multiple arguments %s, %s1, %s2, %s3 etc
|
||||
*/
|
||||
COMMAND_SYNTAX("&cUsage: &7%s0", "Error"),
|
||||
SCHEMATIC_NOT_FOUND("&cSchematic not found: &7%s0", "Error"),
|
||||
SCHEMATIC_PASTING("&7The schematic is pasting. This cannot be undone.", "Info"),
|
||||
FIX_LIGHTING_CHUNK("&7Lighting has been fixed in your current chunk. Relog to see the affect.", "Info"),
|
||||
FIX_LIGHTING_SELECTION("&7Lighting has been fixed in %s0 chunks. Relog to see the affect.", "Info"),
|
||||
NO_REGION("&cYou have no current WorldEdit region", "Error"),
|
||||
SET_REGION("&7Selection set to your current WorldEdit region", "Info"),
|
||||
WORLDEDIT_DELAYED("&7Please wait while we process your WorldEdit action...", "Info"),
|
||||
WORLDEDIT_RUN("&7Apologies for the delay. Now executing: %s", "Info"),
|
||||
WORLDEDIT_COMPLETE("&7WorldEdit action completed.", "Info"),
|
||||
REQUIRE_SELECTION_IN_MASK("&7%s of your selection is not within your mask. You can only make edits within allowed regions.", "Info"),
|
||||
WORLDEDIT_VOLUME("&7You cannot select a volume of %current%. The maximum volume you can modify is %max%.", "Info"),
|
||||
WORLDEDIT_ITERATIONS("&7You cannot iterate %current% times. The maximum number of iterations allowed is %max%.", "Info"),
|
||||
WORLDEDIT_UNSAFE("&7Access to that command has been blocked", "Info"),
|
||||
WORLDEDIT_DANGEROUS_WORLDEDIT("&cFAWE processed unsafe WorldEdit at %s0 by %s1", "Info"),
|
||||
WORLDEDIT_BYPASS("&7&oTo bypass your restrictions use &c/wea", "Info"),
|
||||
WORLDEDIT_EXTEND("&cYour WorldEdit may have extended outside your allowed region.", "Error"),
|
||||
WORLDEDIT_BYPASSED("&7Currently bypassing WorldEdit restriction.", "Info"),
|
||||
WORLDEDIT_UNMASKED("&6Your WorldEdit is now unrestricted.", "Info"),
|
||||
WORLDEDIT_RESTRICTED("&6Your WorldEdit is now restricted.", "Info"),
|
||||
WORLDEDIT_OOM("&cYour WorldEdit action was cancelled due to low memory.", "Info"),
|
||||
WORLDEDIT_OOM_ADMIN("&cPossible options:\n&8 - &7//fast\n&8 - &7Do smaller edits\n&8 - &7Allocate more memory\n&8 - &7Disable this safeguard", "Info"),
|
||||
NOT_PLAYER("&cYou must be a player to perform this action!", "Error"),
|
||||
OOM(
|
||||
"&8[&cCritical&8] &cDetected low memory i.e. < 1%. FAWE will take the following actions:\n&8 - &7Terminate WE block placement\n&8 - &7Clear WE history\n&8 - &7Unload non essential chunks\n&8 - &7Kill entities\n&8 - &7Garbage collect\n&cIgnore this if trying to crash server.\n&7Note: Low memory is likely (but not necessarily) caused by WE",
|
||||
"Error");
|
||||
|
||||
private static final HashMap<String, String> replacements = new HashMap<>();
|
||||
/**
|
||||
* Translated
|
||||
*/
|
||||
private String s;
|
||||
/**
|
||||
* Default
|
||||
*/
|
||||
private String d;
|
||||
/**
|
||||
* What locale category should this translation fall under
|
||||
*/
|
||||
private String cat;
|
||||
/**
|
||||
* Should the string be prefixed?
|
||||
*/
|
||||
private boolean prefix;
|
||||
|
||||
/**
|
||||
* Constructor for custom strings.
|
||||
*/
|
||||
BBC() {
|
||||
/*
|
||||
* use setCustomString();
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param d default
|
||||
* @param prefix use prefix
|
||||
*/
|
||||
BBC(final String d, final boolean prefix, final String cat) {
|
||||
this.d = d;
|
||||
if (s == null) {
|
||||
s = d;
|
||||
}
|
||||
this.prefix = prefix;
|
||||
this.cat = cat.toLowerCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param d default
|
||||
*/
|
||||
BBC(final String d, final String cat) {
|
||||
this(d, true, cat.toLowerCase());
|
||||
}
|
||||
|
||||
public String format(final Object... args) {
|
||||
String m = s;
|
||||
for (int i = args.length - 1; i >= 0; i--) {
|
||||
if (args[i] == null) {
|
||||
continue;
|
||||
}
|
||||
m = m.replaceAll("%s" + i, args[i].toString());
|
||||
}
|
||||
if (args.length > 0) {
|
||||
m = m.replaceAll("%s", args[0].toString());
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
public static void load(final File file) {
|
||||
try {
|
||||
if (!file.exists()) {
|
||||
file.getParentFile().mkdirs();
|
||||
file.createNewFile();
|
||||
}
|
||||
final YamlConfiguration yml = YamlConfiguration.loadConfiguration(file);
|
||||
final Set<String> keys = yml.getKeys(true);
|
||||
final EnumSet<BBC> all = EnumSet.allOf(BBC.class);
|
||||
final HashSet<String> allNames = new HashSet<>();
|
||||
final HashSet<String> allCats = new HashSet<>();
|
||||
final HashSet<String> toRemove = new HashSet<>();
|
||||
for (final BBC c : all) {
|
||||
allNames.add(c.name());
|
||||
allCats.add(c.cat.toLowerCase());
|
||||
}
|
||||
final HashSet<BBC> captions = new HashSet<>();
|
||||
boolean changed = false;
|
||||
for (final String key : keys) {
|
||||
if (!yml.isString(key)) {
|
||||
if (!allCats.contains(key)) {
|
||||
toRemove.add(key);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
final String[] split = key.split("\\.");
|
||||
final String node = split[split.length - 1].toUpperCase();
|
||||
final BBC caption = allNames.contains(node) ? valueOf(node) : null;
|
||||
if (caption != null) {
|
||||
final String value = yml.getString(key);
|
||||
if (!split[0].equalsIgnoreCase(caption.cat)) {
|
||||
changed = true;
|
||||
yml.set(key, null);
|
||||
yml.set(caption.cat + "." + caption.name().toLowerCase(), value);
|
||||
}
|
||||
captions.add(caption);
|
||||
caption.s = value;
|
||||
} else {
|
||||
toRemove.add(key);
|
||||
}
|
||||
}
|
||||
for (final String remove : toRemove) {
|
||||
changed = true;
|
||||
yml.set(remove, null);
|
||||
}
|
||||
replacements.clear();
|
||||
for (final char letter : "1234567890abcdefklmnor".toCharArray()) {
|
||||
replacements.put("&" + letter, "\u00a7" + letter);
|
||||
}
|
||||
replacements.put("\\\\n", "\n");
|
||||
replacements.put("\\n", "\n");
|
||||
replacements.put("&-", "\n");
|
||||
for (final BBC caption : all) {
|
||||
if (!captions.contains(caption)) {
|
||||
changed = true;
|
||||
yml.set(caption.cat + "." + caption.name().toLowerCase(), caption.d);
|
||||
}
|
||||
caption.s = StringMan.replaceFromMap(caption.s, replacements);
|
||||
}
|
||||
if (changed) {
|
||||
yml.save(file);
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public String s() {
|
||||
return s;
|
||||
}
|
||||
|
||||
public boolean usePrefix() {
|
||||
return prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return translated and color decoded
|
||||
*
|
||||
* @see org.bukkit.ChatColor#translateAlternateColorCodes(char, String)
|
||||
*/
|
||||
public String translated() {
|
||||
return ChatColor.translateAlternateColorCodes('&', s());
|
||||
}
|
||||
|
||||
public String getCat() {
|
||||
return cat;
|
||||
}
|
||||
|
||||
public void send(final FawePlayer<?> player, final Object... args) {
|
||||
if (player == null) {
|
||||
Fawe.debug(format(args));
|
||||
} else {
|
||||
player.sendMessage(format(args));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
69
src/com/boydti/fawe/config/Settings.java
Normal file
69
src/com/boydti/fawe/config/Settings.java
Normal file
@ -0,0 +1,69 @@
|
||||
package com.boydti.fawe.config;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
public class Settings {
|
||||
|
||||
public static int MAX_BLOCKSTATES = 1337;
|
||||
public static int MAX_ENTITIES = 1337;
|
||||
public static long WE_MAX_ITERATIONS = 1000;
|
||||
public static long WE_MAX_VOLUME = 50000000;
|
||||
public static boolean REQUIRE_SELECTION = false;
|
||||
public static boolean FIX_ALL_LIGHTING = true;
|
||||
public static boolean COMMAND_PROCESSOR = false;
|
||||
public static List<String> WE_BLACKLIST = Arrays.asList("cs", ".s", "restore", "snapshot", "delchunks", "listchunks");
|
||||
public static long MEM_FREE = 95;
|
||||
|
||||
public static void setup(final File file) {
|
||||
if (!file.exists()) {
|
||||
file.getParentFile().mkdirs();
|
||||
try {
|
||||
file.createNewFile();
|
||||
} catch (final IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
final YamlConfiguration config = YamlConfiguration.loadConfiguration(file);
|
||||
|
||||
final Map<String, Object> options = new HashMap<>();
|
||||
options.put("max-blockstates", MAX_BLOCKSTATES);
|
||||
options.put("max-entities", MAX_ENTITIES);
|
||||
options.put("max-iterations", WE_MAX_ITERATIONS);
|
||||
options.put("max-volume", WE_MAX_VOLUME);
|
||||
options.put("require-selection-in-mask", REQUIRE_SELECTION);
|
||||
options.put("command-blacklist", WE_BLACKLIST);
|
||||
options.put("command-processor", COMMAND_PROCESSOR);
|
||||
options.put("max-memory-percent", MEM_FREE);
|
||||
options.put("fix-all-lighting", FIX_ALL_LIGHTING);
|
||||
|
||||
for (final Entry<String, Object> node : options.entrySet()) {
|
||||
if (!config.contains(node.getKey())) {
|
||||
config.set(node.getKey(), node.getValue());
|
||||
}
|
||||
}
|
||||
FIX_ALL_LIGHTING = config.getBoolean("fix-all-lighting");
|
||||
COMMAND_PROCESSOR = config.getBoolean("command-processor");
|
||||
MAX_BLOCKSTATES = config.getInt("max-blockstates");
|
||||
MAX_ENTITIES = config.getInt("max-entities");
|
||||
WE_MAX_ITERATIONS = config.getInt("max-iterations");
|
||||
WE_MAX_VOLUME = config.getInt("max-volume");
|
||||
MEM_FREE = config.getInt("max-memory-percent");
|
||||
REQUIRE_SELECTION = config.getBoolean("require-selection-in-mask");
|
||||
WE_BLACKLIST = config.getStringList("command-blacklist");
|
||||
|
||||
|
||||
try {
|
||||
config.save(file);
|
||||
} catch (final IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
24
src/com/boydti/fawe/logging/BlocksHubHook.java
Normal file
24
src/com/boydti/fawe/logging/BlocksHubHook.java
Normal file
@ -0,0 +1,24 @@
|
||||
package com.boydti.fawe.logging;
|
||||
|
||||
import org.PrimeSoft.blocksHub.BlocksHub;
|
||||
import org.PrimeSoft.blocksHub.IBlocksHubApi;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.history.changeset.ChangeSet;
|
||||
|
||||
public class BlocksHubHook {
|
||||
private final BlocksHub hub;
|
||||
private final IBlocksHubApi api;
|
||||
|
||||
public BlocksHubHook() {
|
||||
this.hub = (BlocksHub) Bukkit.getServer().getPluginManager().getPlugin("BlocksHub");
|
||||
this.api = hub.getApi();
|
||||
}
|
||||
|
||||
public Extent getLoggingExtent(Extent parent, ChangeSet set, FawePlayer<?> player) {
|
||||
return new LoggingExtent(parent, set, (FawePlayer<Player>) player, api);
|
||||
}
|
||||
}
|
247
src/com/boydti/fawe/logging/LoggingExtent.java
Normal file
247
src/com/boydti/fawe/logging/LoggingExtent.java
Normal file
@ -0,0 +1,247 @@
|
||||
package com.boydti.fawe.logging;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.PrimeSoft.blocksHub.IBlocksHubApi;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.entity.Entity;
|
||||
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.history.change.BlockChange;
|
||||
import com.sk89q.worldedit.history.change.EntityCreate;
|
||||
import com.sk89q.worldedit.history.change.EntityRemove;
|
||||
import com.sk89q.worldedit.history.changeset.ChangeSet;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.util.Location;
|
||||
|
||||
/**
|
||||
* Stores changes to a {@link ChangeSet}.
|
||||
* Logs changes to BlocksHub
|
||||
*/
|
||||
public class LoggingExtent extends AbstractDelegateExtent {
|
||||
|
||||
private final ChangeSet changeSet;
|
||||
private final IBlocksHubApi api;
|
||||
private final String playerName;
|
||||
private final World world;
|
||||
private final org.bukkit.Location loc;
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param extent the extent
|
||||
* @param changeSet the change set
|
||||
* @param api
|
||||
* @param player
|
||||
* @param thread
|
||||
*/
|
||||
public LoggingExtent(final Extent extent, final ChangeSet changeSet, FawePlayer<Player> player, IBlocksHubApi api) {
|
||||
super(extent);
|
||||
checkNotNull(changeSet);
|
||||
this.changeSet = changeSet;
|
||||
this.api = api;
|
||||
this.playerName = player.getName();
|
||||
this.world = player.parent.getWorld();
|
||||
this.loc = new org.bukkit.Location(world, 0, 0, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean setBlock(final Vector location, final BaseBlock block) throws WorldEditException {
|
||||
if (super.setBlock(location, block)) {
|
||||
BaseBlock previous;
|
||||
try {
|
||||
previous = getBlock(location);
|
||||
} catch (final Exception e) {
|
||||
previous = getBlock(location);
|
||||
}
|
||||
final int id_p = previous.getId();
|
||||
final int id_b = block.getId();
|
||||
switch (id_p) {
|
||||
case 0:
|
||||
case 2:
|
||||
case 4:
|
||||
case 13:
|
||||
case 14:
|
||||
case 15:
|
||||
case 20:
|
||||
case 21:
|
||||
case 22:
|
||||
case 25:
|
||||
case 30:
|
||||
case 32:
|
||||
case 37:
|
||||
case 39:
|
||||
case 40:
|
||||
case 41:
|
||||
case 42:
|
||||
case 45:
|
||||
case 46:
|
||||
case 47:
|
||||
case 48:
|
||||
case 49:
|
||||
case 50:
|
||||
case 51:
|
||||
case 52:
|
||||
case 54:
|
||||
case 55:
|
||||
case 56:
|
||||
case 57:
|
||||
case 58:
|
||||
case 60:
|
||||
case 61:
|
||||
case 62:
|
||||
case 7:
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
case 73:
|
||||
case 74:
|
||||
case 75:
|
||||
case 76:
|
||||
case 78:
|
||||
case 79:
|
||||
case 80:
|
||||
case 81:
|
||||
case 82:
|
||||
case 83:
|
||||
case 84:
|
||||
case 85:
|
||||
case 87:
|
||||
case 88:
|
||||
case 101:
|
||||
case 102:
|
||||
case 103:
|
||||
case 110:
|
||||
case 112:
|
||||
case 113:
|
||||
case 117:
|
||||
case 121:
|
||||
case 122:
|
||||
case 123:
|
||||
case 124:
|
||||
case 129:
|
||||
case 133:
|
||||
case 138:
|
||||
case 137:
|
||||
case 140:
|
||||
case 165:
|
||||
case 166:
|
||||
case 169:
|
||||
case 170:
|
||||
case 172:
|
||||
case 173:
|
||||
case 174:
|
||||
case 176:
|
||||
case 177:
|
||||
case 181:
|
||||
case 182:
|
||||
case 188:
|
||||
case 189:
|
||||
case 190:
|
||||
case 191:
|
||||
case 192:
|
||||
if (id_p == id_b) {
|
||||
return false;
|
||||
}
|
||||
loc.setX(location.getX());
|
||||
loc.setY(location.getY());
|
||||
loc.setZ(location.getZ());
|
||||
api.logBlock(playerName, world, loc, id_p, (byte) 0, id_b, (byte) 0);
|
||||
default:
|
||||
int data_p = previous.getData();
|
||||
int data_b = block.getData();
|
||||
if (id_p == id_b && data_b == data_p) {
|
||||
return false;
|
||||
}
|
||||
loc.setX(location.getX());
|
||||
loc.setY(location.getY());
|
||||
loc.setZ(location.getZ());
|
||||
api.logBlock(playerName, world, loc, id_p, (byte) data_p, id_b, (byte) data_b);
|
||||
}
|
||||
changeSet.add(new BlockChange(location.toBlockVector(), previous, block));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Entity createEntity(final Location location, final BaseEntity state) {
|
||||
final Entity entity = super.createEntity(location, state);
|
||||
if (state != null) {
|
||||
changeSet.add(new EntityCreate(location, state, entity));
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends Entity> getEntities() {
|
||||
return wrapEntities(super.getEntities());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends Entity> getEntities(final Region region) {
|
||||
return wrapEntities(super.getEntities(region));
|
||||
}
|
||||
|
||||
private List<? extends Entity> wrapEntities(final List<? extends Entity> entities) {
|
||||
final List<Entity> newList = new ArrayList<Entity>(entities.size());
|
||||
for (final Entity entity : entities) {
|
||||
newList.add(new TrackedEntity(entity));
|
||||
}
|
||||
return newList;
|
||||
}
|
||||
|
||||
private class TrackedEntity implements Entity {
|
||||
private final Entity entity;
|
||||
|
||||
private TrackedEntity(final Entity entity) {
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseEntity getState() {
|
||||
return entity.getState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location getLocation() {
|
||||
return entity.getLocation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Extent getExtent() {
|
||||
return entity.getExtent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove() {
|
||||
final Location location = entity.getLocation();
|
||||
final BaseEntity state = entity.getState();
|
||||
final boolean success = entity.remove();
|
||||
if ((state != null) && success) {
|
||||
changeSet.add(new EntityRemove(location, state));
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public <T> T getFacet(final Class<? extends T> cls) {
|
||||
return entity.getFacet(cls);
|
||||
}
|
||||
}
|
||||
}
|
56
src/com/boydti/fawe/object/ChunkLoc.java
Normal file
56
src/com/boydti/fawe/object/ChunkLoc.java
Normal file
@ -0,0 +1,56 @@
|
||||
package com.boydti.fawe.object;
|
||||
|
||||
public class ChunkLoc {
|
||||
public final int x;
|
||||
public final int z;
|
||||
public final String world;
|
||||
|
||||
public ChunkLoc(final String world, final int x, final int z) {
|
||||
this.world = world;
|
||||
this.x = x;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result;
|
||||
if (x >= 0) {
|
||||
if (z >= 0) {
|
||||
result = (x * x) + (3 * x) + (2 * x * z) + z + (z * z);
|
||||
} else {
|
||||
final int y1 = -z;
|
||||
result = (x * x) + (3 * x) + (2 * x * y1) + y1 + (y1 * y1) + 1;
|
||||
}
|
||||
} else {
|
||||
final int x1 = -x;
|
||||
if (z >= 0) {
|
||||
result = -((x1 * x1) + (3 * x1) + (2 * x1 * z) + z + (z * z));
|
||||
} else {
|
||||
final int y1 = -z;
|
||||
result = -((x1 * x1) + (3 * x1) + (2 * x1 * y1) + y1 + (y1 * y1) + 1);
|
||||
}
|
||||
}
|
||||
result = (result * 31) + world.hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final ChunkLoc other = (ChunkLoc) obj;
|
||||
return ((x == other.x) && (z == other.z) && (world.equals(other.world)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return world + ":" + x + "," + z;
|
||||
}
|
||||
}
|
32
src/com/boydti/fawe/object/EditSessionWrapper.java
Normal file
32
src/com/boydti/fawe/object/EditSessionWrapper.java
Normal file
@ -0,0 +1,32 @@
|
||||
package com.boydti.fawe.object;
|
||||
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.blocks.BlockType;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.history.changeset.ChangeSet;
|
||||
|
||||
public class EditSessionWrapper {
|
||||
|
||||
public final EditSession session;
|
||||
|
||||
public EditSessionWrapper(final EditSession session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
public int getHighestTerrainBlock(final int x, final int z, final int minY, final int maxY, final boolean naturalOnly) {
|
||||
for (int y = maxY; y >= minY; --y) {
|
||||
final Vector pt = new Vector(x, y, z);
|
||||
final int id = session.getBlockType(pt);
|
||||
final int data = session.getBlockData(pt);
|
||||
if (naturalOnly ? BlockType.isNaturalTerrainBlock(id, data) : !BlockType.canPassThrough(id, data)) {
|
||||
return y;
|
||||
}
|
||||
}
|
||||
return minY;
|
||||
}
|
||||
|
||||
public Extent getHistoryExtent(Extent parent, ChangeSet set, FawePlayer<?> player) {
|
||||
return new HistoryExtent(parent, set);
|
||||
}
|
||||
}
|
186
src/com/boydti/fawe/object/FastWorldEditExtent.java
Normal file
186
src/com/boydti/fawe/object/FastWorldEditExtent.java
Normal file
@ -0,0 +1,186 @@
|
||||
package com.boydti.fawe.object;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.boydti.fawe.util.SetBlockQueue;
|
||||
import com.sk89q.worldedit.BlockVector;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.Vector2D;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.entity.Entity;
|
||||
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.util.Location;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
|
||||
public class FastWorldEditExtent extends AbstractDelegateExtent {
|
||||
|
||||
private final String world;
|
||||
private final Thread thread;
|
||||
|
||||
public FastWorldEditExtent(World world, Thread thread) {
|
||||
super(world);
|
||||
this.thread = thread;
|
||||
this.world = world.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entity createEntity(Location location, BaseEntity entity) {
|
||||
synchronized (thread) {
|
||||
return super.createEntity(location, entity);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBiome getBiome(Vector2D position) {
|
||||
synchronized (thread) {
|
||||
return super.getBiome(position);
|
||||
}
|
||||
}
|
||||
|
||||
private BaseBlock lastBlock;
|
||||
private BlockVector lastVector;
|
||||
|
||||
@Override
|
||||
public BaseBlock getLazyBlock(Vector position) {
|
||||
if (lastBlock != null && lastVector.equals(position.toBlockVector())) {
|
||||
return lastBlock;
|
||||
}
|
||||
synchronized (thread) {
|
||||
lastVector = position.toBlockVector();
|
||||
return lastBlock = super.getLazyBlock(position);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends Entity> getEntities() {
|
||||
synchronized (thread) {
|
||||
return super.getEntities();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends Entity> getEntities(Region region) {
|
||||
synchronized (thread) {
|
||||
return super.getEntities(region);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getBlock(Vector position) {
|
||||
synchronized (thread) {
|
||||
return super.getLazyBlock(position);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBiome(Vector2D position, BaseBiome biome) {
|
||||
SetBlockQueue.IMP.setBiome(world, position.getBlockX(), position.getBlockZ(), biome);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(Vector location, BaseBlock block) throws WorldEditException {
|
||||
short id = (short) block.getId();
|
||||
int x = location.getBlockX();
|
||||
int y = location.getBlockY();
|
||||
int z = location.getBlockZ();
|
||||
switch (id) {
|
||||
case 0:
|
||||
case 2:
|
||||
case 4:
|
||||
case 13:
|
||||
case 14:
|
||||
case 15:
|
||||
case 20:
|
||||
case 21:
|
||||
case 22:
|
||||
case 25:
|
||||
case 30:
|
||||
case 32:
|
||||
case 37:
|
||||
case 39:
|
||||
case 40:
|
||||
case 41:
|
||||
case 42:
|
||||
case 45:
|
||||
case 46:
|
||||
case 47:
|
||||
case 48:
|
||||
case 49:
|
||||
case 50:
|
||||
case 51:
|
||||
case 52:
|
||||
case 54:
|
||||
case 55:
|
||||
case 56:
|
||||
case 57:
|
||||
case 58:
|
||||
case 60:
|
||||
case 61:
|
||||
case 62:
|
||||
case 7:
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
case 73:
|
||||
case 74:
|
||||
case 75:
|
||||
case 76:
|
||||
case 78:
|
||||
case 79:
|
||||
case 80:
|
||||
case 81:
|
||||
case 82:
|
||||
case 83:
|
||||
case 84:
|
||||
case 85:
|
||||
case 87:
|
||||
case 88:
|
||||
case 101:
|
||||
case 102:
|
||||
case 103:
|
||||
case 110:
|
||||
case 112:
|
||||
case 113:
|
||||
case 117:
|
||||
case 121:
|
||||
case 122:
|
||||
case 123:
|
||||
case 124:
|
||||
case 129:
|
||||
case 133:
|
||||
case 138:
|
||||
case 137:
|
||||
case 140:
|
||||
case 165:
|
||||
case 166:
|
||||
case 169:
|
||||
case 170:
|
||||
case 172:
|
||||
case 173:
|
||||
case 174:
|
||||
case 176:
|
||||
case 177:
|
||||
case 181:
|
||||
case 182:
|
||||
case 188:
|
||||
case 189:
|
||||
case 190:
|
||||
case 191:
|
||||
case 192: {
|
||||
SetBlockQueue.IMP.setBlock(world, x, y, z, id);
|
||||
return true;
|
||||
}
|
||||
default: {
|
||||
SetBlockQueue.IMP.setBlock(world, x, y, z, id, (byte) block.getData());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
44
src/com/boydti/fawe/object/FaweChangeSet.java
Normal file
44
src/com/boydti/fawe/object/FaweChangeSet.java
Normal file
@ -0,0 +1,44 @@
|
||||
package com.boydti.fawe.object;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.sk89q.worldedit.history.change.BlockChange;
|
||||
import com.sk89q.worldedit.history.change.Change;
|
||||
import com.sk89q.worldedit.history.changeset.ChangeSet;
|
||||
|
||||
public class FaweChangeSet implements ChangeSet {
|
||||
|
||||
private final ArrayDeque<Change> changes = new ArrayDeque<>();
|
||||
|
||||
@Override
|
||||
public void add(final Change change) {
|
||||
if (change.getClass() == BlockChange.class) {
|
||||
final BlockChange bc = (BlockChange) change;
|
||||
bc.getCurrent();
|
||||
// BaseBlock previous = bc.getPrevious();
|
||||
// BlockVector pos = bc.getPosition();
|
||||
// int x = pos.getBlockX();
|
||||
// int y = pos.getBlockY();
|
||||
// int z = pos.getBlockZ();
|
||||
changes.add(bc);
|
||||
} else {
|
||||
changes.add(change);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Change> backwardIterator() {
|
||||
return changes.descendingIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Change> forwardIterator() {
|
||||
return changes.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return changes.size();
|
||||
}
|
||||
}
|
65
src/com/boydti/fawe/object/FaweChunk.java
Normal file
65
src/com/boydti/fawe/object/FaweChunk.java
Normal file
@ -0,0 +1,65 @@
|
||||
package com.boydti.fawe.object;
|
||||
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.util.SetBlockQueue;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
|
||||
public abstract class FaweChunk<T> {
|
||||
|
||||
private ChunkLoc chunk;
|
||||
|
||||
/**
|
||||
* A FaweSections object represents a chunk and the blocks that you wish to change in it.
|
||||
*/
|
||||
public FaweChunk(final ChunkLoc chunk) {
|
||||
this.chunk = chunk;
|
||||
}
|
||||
|
||||
public void setChunkLoc(final ChunkLoc loc) {
|
||||
this.chunk = loc;
|
||||
}
|
||||
|
||||
public ChunkLoc getChunkLoc() {
|
||||
return this.chunk;
|
||||
}
|
||||
|
||||
public void addToQueue() {
|
||||
if (chunk == null) {
|
||||
throw new IllegalArgumentException("Chunk location cannot be null!");
|
||||
}
|
||||
SetBlockQueue.IMP.queue.setChunk(this);
|
||||
}
|
||||
|
||||
public void fixLighting() {
|
||||
SetBlockQueue.IMP.queue.fixLighting(this, Settings.FIX_ALL_LIGHTING);
|
||||
}
|
||||
|
||||
public void fill(int id, byte data) {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
for (int y = 0; y < 256; y++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
setBlock(x, y, z, id, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract T getChunk();
|
||||
|
||||
public abstract void setBlock(final int x, final int y, final int z, final int id, final byte data);
|
||||
|
||||
public abstract void setBiome(int x, int z, BaseBiome biome);
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return chunk.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null || !(obj instanceof FaweChunk)) {
|
||||
return false;
|
||||
}
|
||||
return chunk.equals(((FaweChunk) obj).chunk);
|
||||
}
|
||||
}
|
15
src/com/boydti/fawe/object/FaweCommand.java
Normal file
15
src/com/boydti/fawe/object/FaweCommand.java
Normal file
@ -0,0 +1,15 @@
|
||||
package com.boydti.fawe.object;
|
||||
|
||||
public abstract class FaweCommand<T> {
|
||||
public final String perm;
|
||||
|
||||
public FaweCommand(final String perm) {
|
||||
this.perm = perm;
|
||||
}
|
||||
|
||||
public String getPerm() {
|
||||
return perm;
|
||||
}
|
||||
|
||||
public abstract boolean execute(final FawePlayer<T> player, final String... args);
|
||||
}
|
45
src/com/boydti/fawe/object/FaweLocation.java
Normal file
45
src/com/boydti/fawe/object/FaweLocation.java
Normal file
@ -0,0 +1,45 @@
|
||||
package com.boydti.fawe.object;
|
||||
|
||||
import com.boydti.fawe.util.SetBlockQueue;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class FaweLocation {
|
||||
|
||||
|
||||
public final int x;
|
||||
public final int y;
|
||||
public final int z;
|
||||
public final String world;
|
||||
|
||||
public FaweLocation(String world, int x, int y, int z) {
|
||||
this.world = world;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final FaweLocation other = (FaweLocation) obj;
|
||||
return ((x == other.x) && (y == other.y) && (z == other.z) && (world.equals(other.world)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return x << 8 + z << 4 + y;
|
||||
}
|
||||
|
||||
public void setBlockAsync(short id, byte data) {
|
||||
SetBlockQueue.IMP.setBlock(world, x, y, z, id, data);
|
||||
}
|
||||
}
|
87
src/com/boydti/fawe/object/FawePlayer.java
Normal file
87
src/com/boydti/fawe/object/FawePlayer.java
Normal file
@ -0,0 +1,87 @@
|
||||
package com.boydti.fawe.object;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.util.WEManager;
|
||||
import com.sk89q.worldedit.IncompleteRegionException;
|
||||
import com.sk89q.worldedit.LocalSession;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.regions.RegionSelector;
|
||||
import com.sk89q.worldedit.regions.selector.CuboidRegionSelector;
|
||||
|
||||
public abstract class FawePlayer<T> {
|
||||
|
||||
public final T parent;
|
||||
private LocalSession session;
|
||||
|
||||
public static <T> FawePlayer<T> wrap(final Object obj) {
|
||||
return Fawe.imp().wrap(obj);
|
||||
}
|
||||
|
||||
public FawePlayer(final T parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public abstract String getName();
|
||||
|
||||
public abstract UUID getUUID();
|
||||
|
||||
public abstract boolean hasPermission(final String perm);
|
||||
|
||||
public abstract void setPermission(final String perm, final boolean flag);
|
||||
|
||||
public abstract void sendMessage(final String message);
|
||||
|
||||
public abstract void executeCommand(final String substring);
|
||||
|
||||
public abstract FaweLocation getLocation();
|
||||
|
||||
public abstract Player getPlayer();
|
||||
|
||||
public Region getSelection() {
|
||||
try {
|
||||
return getSession().getSelection(getPlayer().getWorld());
|
||||
} catch (IncompleteRegionException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public LocalSession getSession() {
|
||||
return session != null ? session : Fawe.get().getWorldEdit().getSession(getPlayer());
|
||||
}
|
||||
|
||||
public HashSet<RegionWrapper> getCurrentRegions() {
|
||||
return WEManager.IMP.getMask(this);
|
||||
}
|
||||
|
||||
public void setSelection(RegionWrapper region) {
|
||||
Player player = getPlayer();
|
||||
RegionSelector selector = new CuboidRegionSelector(player.getWorld(), region.getBottomVector(), region.getTopVector());
|
||||
getSession().setRegionSelector(player.getWorld(), selector);
|
||||
}
|
||||
|
||||
public RegionWrapper getLargestRegion() {
|
||||
int area = 0;
|
||||
RegionWrapper max = null;
|
||||
for (RegionWrapper region : getCurrentRegions()) {
|
||||
int tmp = (region.maxX - region.minX) * (region.maxZ - region.minZ);
|
||||
if (tmp > area) {
|
||||
area = tmp;
|
||||
max = region;
|
||||
}
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
public boolean hasWorldEditBypass() {
|
||||
return hasPermission("fawe.bypass");
|
||||
}
|
||||
}
|
221
src/com/boydti/fawe/object/HistoryExtent.java
Normal file
221
src/com/boydti/fawe/object/HistoryExtent.java
Normal file
@ -0,0 +1,221 @@
|
||||
package com.boydti.fawe.object;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.entity.Entity;
|
||||
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.history.change.BlockChange;
|
||||
import com.sk89q.worldedit.history.change.EntityCreate;
|
||||
import com.sk89q.worldedit.history.change.EntityRemove;
|
||||
import com.sk89q.worldedit.history.changeset.ChangeSet;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.util.Location;
|
||||
|
||||
/**
|
||||
* Stores changes to a {@link ChangeSet}.
|
||||
*/
|
||||
public class HistoryExtent extends AbstractDelegateExtent {
|
||||
|
||||
private final ChangeSet changeSet;
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param extent the extent
|
||||
* @param changeSet the change set
|
||||
* @param thread
|
||||
*/
|
||||
public HistoryExtent(final Extent extent, final ChangeSet changeSet) {
|
||||
super(extent);
|
||||
checkNotNull(changeSet);
|
||||
this.changeSet = changeSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean setBlock(final Vector location, final BaseBlock block) throws WorldEditException {
|
||||
if (super.setBlock(location, block)) {
|
||||
BaseBlock previous;
|
||||
try {
|
||||
previous = getBlock(location);
|
||||
} catch (final Exception e) {
|
||||
previous = getBlock(location);
|
||||
}
|
||||
final int id_p = previous.getId();
|
||||
final int id_b = block.getId();
|
||||
if (id_p == id_b) {
|
||||
switch (id_p) {
|
||||
case 0:
|
||||
case 2:
|
||||
case 4:
|
||||
case 13:
|
||||
case 14:
|
||||
case 15:
|
||||
case 20:
|
||||
case 21:
|
||||
case 22:
|
||||
case 25:
|
||||
case 30:
|
||||
case 32:
|
||||
case 37:
|
||||
case 39:
|
||||
case 40:
|
||||
case 41:
|
||||
case 42:
|
||||
case 45:
|
||||
case 46:
|
||||
case 47:
|
||||
case 48:
|
||||
case 49:
|
||||
case 50:
|
||||
case 51:
|
||||
case 52:
|
||||
case 54:
|
||||
case 55:
|
||||
case 56:
|
||||
case 57:
|
||||
case 58:
|
||||
case 60:
|
||||
case 61:
|
||||
case 62:
|
||||
case 7:
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
case 73:
|
||||
case 74:
|
||||
case 75:
|
||||
case 76:
|
||||
case 78:
|
||||
case 79:
|
||||
case 80:
|
||||
case 81:
|
||||
case 82:
|
||||
case 83:
|
||||
case 84:
|
||||
case 85:
|
||||
case 87:
|
||||
case 88:
|
||||
case 101:
|
||||
case 102:
|
||||
case 103:
|
||||
case 110:
|
||||
case 112:
|
||||
case 113:
|
||||
case 117:
|
||||
case 121:
|
||||
case 122:
|
||||
case 123:
|
||||
case 124:
|
||||
case 129:
|
||||
case 133:
|
||||
case 138:
|
||||
case 137:
|
||||
case 140:
|
||||
case 165:
|
||||
case 166:
|
||||
case 169:
|
||||
case 170:
|
||||
case 172:
|
||||
case 173:
|
||||
case 174:
|
||||
case 176:
|
||||
case 177:
|
||||
case 181:
|
||||
case 182:
|
||||
case 188:
|
||||
case 189:
|
||||
case 190:
|
||||
case 191:
|
||||
case 192:
|
||||
return false;
|
||||
default:
|
||||
if (block.getData() == previous.getData()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
changeSet.add(new BlockChange(location.toBlockVector(), previous, block));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Entity createEntity(final Location location, final BaseEntity state) {
|
||||
final Entity entity = super.createEntity(location, state);
|
||||
if (state != null) {
|
||||
changeSet.add(new EntityCreate(location, state, entity));
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends Entity> getEntities() {
|
||||
return wrapEntities(super.getEntities());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends Entity> getEntities(final Region region) {
|
||||
return wrapEntities(super.getEntities(region));
|
||||
}
|
||||
|
||||
private List<? extends Entity> wrapEntities(final List<? extends Entity> entities) {
|
||||
final List<Entity> newList = new ArrayList<Entity>(entities.size());
|
||||
for (final Entity entity : entities) {
|
||||
newList.add(new TrackedEntity(entity));
|
||||
}
|
||||
return newList;
|
||||
}
|
||||
|
||||
private class TrackedEntity implements Entity {
|
||||
private final Entity entity;
|
||||
|
||||
private TrackedEntity(final Entity entity) {
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseEntity getState() {
|
||||
return entity.getState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location getLocation() {
|
||||
return entity.getLocation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Extent getExtent() {
|
||||
return entity.getExtent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove() {
|
||||
final Location location = entity.getLocation();
|
||||
final BaseEntity state = entity.getState();
|
||||
final boolean success = entity.remove();
|
||||
if ((state != null) && success) {
|
||||
changeSet.add(new EntityRemove(location, state));
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public <T> T getFacet(final Class<? extends T> cls) {
|
||||
return entity.getFacet(cls);
|
||||
}
|
||||
}
|
||||
}
|
50
src/com/boydti/fawe/object/IntegerPair.java
Normal file
50
src/com/boydti/fawe/object/IntegerPair.java
Normal file
@ -0,0 +1,50 @@
|
||||
package com.boydti.fawe.object;
|
||||
|
||||
public class IntegerPair {
|
||||
public int x;
|
||||
public int z;
|
||||
|
||||
public IntegerPair(final int x, final int z) {
|
||||
this.x = x;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
int hash;
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
if (hash == 0) {
|
||||
long val = 0;
|
||||
if (x >= 0) {
|
||||
if (z >= 0) {
|
||||
val = (x * x) + (3 * x) + (2 * x * z) + z + (z * z);
|
||||
} else {
|
||||
final int z1 = -z;
|
||||
val = (x * x) + (3 * x) + (2 * x * z1) + z1 + (z1 * z1) + 1;
|
||||
}
|
||||
} else {
|
||||
final int x1 = -x;
|
||||
if (z >= 0) {
|
||||
val = -((x1 * x1) + (3 * x1) + (2 * x1 * z) + z + (z * z));
|
||||
} else {
|
||||
final int z1 = -z;
|
||||
val = -((x1 * x1) + (3 * x1) + (2 * x1 * z1) + z1 + (z1 * z1) + 1);
|
||||
}
|
||||
}
|
||||
hash = (int) (val % Integer.MAX_VALUE);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if ((obj == null) || (hashCode() != obj.hashCode()) || (getClass() != obj.getClass())) {
|
||||
return false;
|
||||
}
|
||||
final IntegerPair other = (IntegerPair) obj;
|
||||
return ((x == other.x) && (z == other.z));
|
||||
}
|
||||
}
|
79
src/com/boydti/fawe/object/NullExtent.java
Normal file
79
src/com/boydti/fawe/object/NullExtent.java
Normal file
@ -0,0 +1,79 @@
|
||||
package com.boydti.fawe.object;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.Vector2D;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.entity.Entity;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.function.operation.Operation;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.util.Location;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
|
||||
public class NullExtent implements Extent {
|
||||
|
||||
private final BaseBiome nullBiome = new BaseBiome(0);
|
||||
|
||||
private final BaseBlock nullBlock = new BaseBlock(0);
|
||||
|
||||
@Override
|
||||
public BaseBiome getBiome(final Vector2D arg0) {
|
||||
return nullBiome;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getBlock(final Vector arg0) {
|
||||
return nullBlock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getLazyBlock(final Vector arg0) {
|
||||
return nullBlock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Operation commit() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBiome(final Vector2D arg0, final BaseBiome arg1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(final Vector arg0, final BaseBlock arg1) throws WorldEditException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entity createEntity(final Location arg0, final BaseEntity arg1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends Entity> getEntities() {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends Entity> getEntities(final Region arg0) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector getMaximumPoint() {
|
||||
return new Vector(0, 0, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector getMinimumPoint() {
|
||||
return new Vector(0, 0, 0);
|
||||
}
|
||||
|
||||
}
|
297
src/com/boydti/fawe/object/ProcessedWEExtent.java
Normal file
297
src/com/boydti/fawe/object/ProcessedWEExtent.java
Normal file
@ -0,0 +1,297 @@
|
||||
package com.boydti.fawe.object;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
import com.boydti.fawe.config.BBC;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.boydti.fawe.util.SetBlockQueue;
|
||||
import com.boydti.fawe.util.WEManager;
|
||||
import com.sk89q.worldedit.BlockVector;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.Vector2D;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.entity.Entity;
|
||||
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.util.Location;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
|
||||
public class ProcessedWEExtent extends AbstractDelegateExtent {
|
||||
private Extent parent;
|
||||
|
||||
private boolean BSblocked = false;
|
||||
private boolean Eblocked = false;
|
||||
private int BScount = 0;
|
||||
private int Ecount = 0;
|
||||
private int count = 0;
|
||||
|
||||
private int max;
|
||||
private final FawePlayer<?> user;
|
||||
private final String world;
|
||||
private final HashSet<RegionWrapper> mask;
|
||||
private final Thread thread;
|
||||
|
||||
public ProcessedWEExtent(World world, Thread thread, FawePlayer<?> player, HashSet<RegionWrapper> mask, int max) {
|
||||
super(world);
|
||||
this.user = player;
|
||||
this.world = world.getName();
|
||||
this.max = max != -1 ? max : Integer.MAX_VALUE;
|
||||
this.mask = mask;
|
||||
this.thread = thread;
|
||||
}
|
||||
|
||||
public void setMax(int max) {
|
||||
this.max = max != -1 ? max : Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
public void setParent(Extent parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entity createEntity(Location location, BaseEntity entity) {
|
||||
if (Eblocked) {
|
||||
return null;
|
||||
}
|
||||
Ecount++;
|
||||
if (Ecount > Settings.MAX_ENTITIES) {
|
||||
Eblocked = true;
|
||||
MainUtil.sendAdmin(BBC.WORLDEDIT_DANGEROUS_WORLDEDIT.format(world + ": " + location.getBlockX() + "," + location.getBlockY() + "," + location.getBlockZ(), user));
|
||||
}
|
||||
if (WEManager.IMP.maskContains(mask, location.getBlockX(), location.getBlockZ())) {
|
||||
synchronized (thread) {
|
||||
return super.createEntity(location, entity);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBiome getBiome(Vector2D position) {
|
||||
synchronized (thread) {
|
||||
return super.getBiome(position);
|
||||
}
|
||||
}
|
||||
|
||||
private BaseBlock lastBlock;
|
||||
private BlockVector lastVector;
|
||||
|
||||
@Override
|
||||
public BaseBlock getLazyBlock(Vector position) {
|
||||
if (lastBlock != null && lastVector.equals(position.toBlockVector())) {
|
||||
return lastBlock;
|
||||
}
|
||||
synchronized (thread) {
|
||||
lastVector = position.toBlockVector();
|
||||
return lastBlock = super.getLazyBlock(position);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends Entity> getEntities() {
|
||||
synchronized (thread) {
|
||||
return super.getEntities();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends Entity> getEntities(Region region) {
|
||||
synchronized (thread) {
|
||||
return super.getEntities(region);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getBlock(Vector position) {
|
||||
synchronized (thread) {
|
||||
return super.getLazyBlock(position);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(final Vector location, final BaseBlock block) throws WorldEditException {
|
||||
final short id = (short) block.getType();
|
||||
switch (id) {
|
||||
case 54:
|
||||
case 130:
|
||||
case 142:
|
||||
case 27:
|
||||
case 137:
|
||||
case 52:
|
||||
case 154:
|
||||
case 84:
|
||||
case 25:
|
||||
case 144:
|
||||
case 138:
|
||||
case 176:
|
||||
case 177:
|
||||
case 63:
|
||||
case 119:
|
||||
case 68:
|
||||
case 323:
|
||||
case 117:
|
||||
case 116:
|
||||
case 28:
|
||||
case 66:
|
||||
case 157:
|
||||
case 61:
|
||||
case 62:
|
||||
case 140:
|
||||
case 146:
|
||||
case 149:
|
||||
case 150:
|
||||
case 158:
|
||||
case 23:
|
||||
case 123:
|
||||
case 124:
|
||||
case 29:
|
||||
case 33:
|
||||
case 151:
|
||||
case 178: {
|
||||
if (BSblocked) {
|
||||
return false;
|
||||
}
|
||||
BScount++;
|
||||
if (BScount > Settings.MAX_BLOCKSTATES) {
|
||||
BSblocked = true;
|
||||
MainUtil.sendAdmin(BBC.WORLDEDIT_DANGEROUS_WORLDEDIT.format(world + ": " + location.getBlockX() + "," + location.getBlockY() + "," + location.getBlockZ(), user));
|
||||
}
|
||||
final int x = location.getBlockX();
|
||||
final int z = location.getBlockZ();
|
||||
if (WEManager.IMP.maskContains(mask, x, z)) {
|
||||
if (count++ > max) {
|
||||
if (parent != null) {
|
||||
WEManager.IMP.cancelEdit(parent);
|
||||
parent = null;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
SetBlockQueue.IMP.setBlock(world, x, location.getBlockY(), z, id, (byte) block.getData());
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
final int x = location.getBlockX();
|
||||
final int y = location.getBlockY();
|
||||
final int z = location.getBlockZ();
|
||||
if (WEManager.IMP.maskContains(mask, location.getBlockX(), location.getBlockZ())) {
|
||||
if (count++ > max) {
|
||||
WEManager.IMP.cancelEdit(parent);
|
||||
parent = null;
|
||||
return false;
|
||||
}
|
||||
switch (id) {
|
||||
case 0:
|
||||
case 2:
|
||||
case 4:
|
||||
case 13:
|
||||
case 14:
|
||||
case 15:
|
||||
case 20:
|
||||
case 21:
|
||||
case 22:
|
||||
case 25:
|
||||
case 30:
|
||||
case 32:
|
||||
case 37:
|
||||
case 39:
|
||||
case 40:
|
||||
case 41:
|
||||
case 42:
|
||||
case 45:
|
||||
case 46:
|
||||
case 47:
|
||||
case 48:
|
||||
case 49:
|
||||
case 50:
|
||||
case 51:
|
||||
case 52:
|
||||
case 54:
|
||||
case 55:
|
||||
case 56:
|
||||
case 57:
|
||||
case 58:
|
||||
case 60:
|
||||
case 61:
|
||||
case 62:
|
||||
case 7:
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
case 73:
|
||||
case 74:
|
||||
case 75:
|
||||
case 76:
|
||||
case 78:
|
||||
case 79:
|
||||
case 80:
|
||||
case 81:
|
||||
case 82:
|
||||
case 83:
|
||||
case 84:
|
||||
case 85:
|
||||
case 87:
|
||||
case 88:
|
||||
case 101:
|
||||
case 102:
|
||||
case 103:
|
||||
case 110:
|
||||
case 112:
|
||||
case 113:
|
||||
case 117:
|
||||
case 121:
|
||||
case 122:
|
||||
case 123:
|
||||
case 124:
|
||||
case 129:
|
||||
case 133:
|
||||
case 138:
|
||||
case 137:
|
||||
case 140:
|
||||
case 165:
|
||||
case 166:
|
||||
case 169:
|
||||
case 170:
|
||||
case 172:
|
||||
case 173:
|
||||
case 174:
|
||||
case 176:
|
||||
case 177:
|
||||
case 181:
|
||||
case 182:
|
||||
case 188:
|
||||
case 189:
|
||||
case 190:
|
||||
case 191:
|
||||
case 192: {
|
||||
SetBlockQueue.IMP.setBlock(world, x, y, z, id);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
SetBlockQueue.IMP.setBlock(world, x, y, z, id, (byte) block.getData());
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBiome(final Vector2D position, final BaseBiome biome) {
|
||||
if (WEManager.IMP.maskContains(mask, position.getBlockX(), position.getBlockZ())) {
|
||||
SetBlockQueue.IMP.setBiome(world, position.getBlockX(), position.getBlockZ(), biome);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
34
src/com/boydti/fawe/object/PseudoRandom.java
Normal file
34
src/com/boydti/fawe/object/PseudoRandom.java
Normal file
@ -0,0 +1,34 @@
|
||||
package com.boydti.fawe.object;
|
||||
|
||||
public class PseudoRandom {
|
||||
private long state;
|
||||
|
||||
public PseudoRandom() {
|
||||
state = System.nanoTime();
|
||||
}
|
||||
|
||||
public PseudoRandom(final long state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public long nextLong() {
|
||||
final long a = state;
|
||||
state = xorShift64(a);
|
||||
return a;
|
||||
}
|
||||
|
||||
public long xorShift64(long a) {
|
||||
a ^= (a << 21);
|
||||
a ^= (a >>> 35);
|
||||
a ^= (a << 4);
|
||||
return a;
|
||||
}
|
||||
|
||||
public int random(final int n) {
|
||||
if (n == 1) {
|
||||
return 0;
|
||||
}
|
||||
final long r = ((nextLong() >>> 32) * n) >> 32;
|
||||
return (int) r;
|
||||
}
|
||||
}
|
41
src/com/boydti/fawe/object/RegionWrapper.java
Normal file
41
src/com/boydti/fawe/object/RegionWrapper.java
Normal file
@ -0,0 +1,41 @@
|
||||
package com.boydti.fawe.object;
|
||||
|
||||
import com.sk89q.worldedit.Vector;
|
||||
|
||||
public class RegionWrapper {
|
||||
public int minX;
|
||||
public int maxX;
|
||||
public int minZ;
|
||||
public int maxZ;
|
||||
|
||||
public RegionWrapper(final int minX, final int maxX, final int minZ, final int maxZ) {
|
||||
this.maxX = maxX;
|
||||
this.minX = minX;
|
||||
this.maxZ = maxZ;
|
||||
this.minZ = minZ;
|
||||
}
|
||||
|
||||
public RegionWrapper(Vector pos1, Vector pos2) {
|
||||
this.minX = Math.min(pos1.getBlockX(), pos2.getBlockX());
|
||||
this.minZ = Math.min(pos1.getBlockZ(), pos2.getBlockZ());
|
||||
this.maxX = Math.max(pos1.getBlockX(), pos2.getBlockX());
|
||||
this.maxZ = Math.max(pos1.getBlockZ(), pos2.getBlockZ());
|
||||
}
|
||||
|
||||
public boolean isIn(final int x, final int z) {
|
||||
return ((x >= minX) && (x <= maxX) && (z >= minZ) && (z <= maxZ));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return minX + "," + minZ + "->" + maxX + "," + maxZ;
|
||||
}
|
||||
|
||||
public Vector getBottomVector() {
|
||||
return new Vector(minX, 1, minZ);
|
||||
}
|
||||
|
||||
public Vector getTopVector() {
|
||||
return new Vector(maxX, 255, maxZ);
|
||||
}
|
||||
}
|
10
src/com/boydti/fawe/object/SendChunk.java
Normal file
10
src/com/boydti/fawe/object/SendChunk.java
Normal file
@ -0,0 +1,10 @@
|
||||
package com.boydti.fawe.object;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public abstract class SendChunk {
|
||||
|
||||
public abstract void fixLighting(final Collection<ChunkLoc> locs);
|
||||
|
||||
public abstract void update(final Collection<ChunkLoc> locs);
|
||||
}
|
23
src/com/boydti/fawe/regions/FaweMaskManager.java
Normal file
23
src/com/boydti/fawe/regions/FaweMaskManager.java
Normal file
@ -0,0 +1,23 @@
|
||||
package com.boydti.fawe.regions;
|
||||
|
||||
import com.boydti.fawe.bukkit.regions.FaweMask;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
|
||||
public abstract class FaweMaskManager<T> {
|
||||
private final String key;
|
||||
|
||||
public FaweMaskManager(String plugin) {
|
||||
this.key = plugin.toLowerCase();
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return this.key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.key;
|
||||
}
|
||||
|
||||
public abstract FaweMask getMask(final FawePlayer<T> player);
|
||||
}
|
11
src/com/boydti/fawe/util/ExtentWrapper.java
Normal file
11
src/com/boydti/fawe/util/ExtentWrapper.java
Normal file
@ -0,0 +1,11 @@
|
||||
package com.boydti.fawe.util;
|
||||
|
||||
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
|
||||
public class ExtentWrapper extends AbstractDelegateExtent {
|
||||
|
||||
public ExtentWrapper(final Extent extent) {
|
||||
super(extent);
|
||||
}
|
||||
}
|
40
src/com/boydti/fawe/util/FaweQueue.java
Normal file
40
src/com/boydti/fawe/util/FaweQueue.java
Normal file
@ -0,0 +1,40 @@
|
||||
package com.boydti.fawe.util;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.config.BBC;
|
||||
import com.boydti.fawe.object.ChunkLoc;
|
||||
import com.boydti.fawe.object.FaweChunk;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
|
||||
public abstract class FaweQueue {
|
||||
public abstract boolean setBlock(final String world, final int x, final int y, final int z, final short id, final byte data);
|
||||
|
||||
public abstract boolean setBiome(final String world, final int x, final int z, final BaseBiome biome);
|
||||
|
||||
public abstract FaweChunk<?> getChunk(ChunkLoc wrap);
|
||||
|
||||
public abstract void setChunk(FaweChunk<?> chunk);
|
||||
|
||||
public abstract boolean fixLighting(FaweChunk<?> chunk, boolean fixAll);
|
||||
|
||||
/**
|
||||
* Gets the FaweChunk and sets the requested blocks
|
||||
* @return
|
||||
*/
|
||||
public abstract FaweChunk next();
|
||||
|
||||
public void saveMemory() {
|
||||
MainUtil.sendAdmin(BBC.OOM.s());
|
||||
// Set memory limited
|
||||
MemUtil.memoryLimitedTask();
|
||||
// Clear block placement
|
||||
SetBlockQueue.IMP.queue.clear();
|
||||
Fawe.get().getWorldEdit().clearSessions();
|
||||
// GC
|
||||
System.gc();
|
||||
System.gc();
|
||||
// Unload chunks
|
||||
}
|
||||
|
||||
protected abstract void clear();
|
||||
}
|
81
src/com/boydti/fawe/util/Lag.java
Normal file
81
src/com/boydti/fawe/util/Lag.java
Normal file
@ -0,0 +1,81 @@
|
||||
package com.boydti.fawe.util;
|
||||
|
||||
/**
|
||||
* TPS and Lag Checker.
|
||||
*/
|
||||
public class Lag implements Runnable {
|
||||
/**
|
||||
* Ticks
|
||||
*/
|
||||
public static final long[] T = new long[600];
|
||||
/**
|
||||
* Tick count
|
||||
*/
|
||||
public static int TC = 0;
|
||||
/**
|
||||
* something :_:
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static long LT = 0L;
|
||||
|
||||
/**
|
||||
* Get the server TPS
|
||||
*
|
||||
* @return server tick per second
|
||||
*/
|
||||
public static double getTPS() {
|
||||
return Math.round(getTPS(100)) > 20.0D ? 20.0D : Math.round(getTPS(100));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the tick per second (measured in $ticks)
|
||||
*
|
||||
* @param ticks Ticks
|
||||
*
|
||||
* @return ticks per second
|
||||
*/
|
||||
public static double getTPS(final int ticks) {
|
||||
if (TC < ticks) {
|
||||
return 20.0D;
|
||||
}
|
||||
final int t = (TC - 1 - ticks) % T.length;
|
||||
final long e = System.currentTimeMillis() - T[t];
|
||||
return ticks / (e / 1000.0D);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get number of ticks since
|
||||
*
|
||||
* @param tI Ticks <
|
||||
*
|
||||
* @return number of ticks since $tI
|
||||
*/
|
||||
public static long getElapsed(final int tI) {
|
||||
final long t = T[tI % T.length];
|
||||
return System.currentTimeMillis() - t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get lag percentage
|
||||
*
|
||||
* @return lag percentage
|
||||
*/
|
||||
public static double getPercentage() {
|
||||
return Math.round((1.0D - (Lag.getTPS() / 20.0D)) * 100.0D);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get TPS percentage (of 20)
|
||||
*
|
||||
* @return TPS percentage
|
||||
*/
|
||||
public static double getFullPercentage() {
|
||||
return getTPS() * 5.0D;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
T[TC % T.length] = System.currentTimeMillis();
|
||||
TC++;
|
||||
}
|
||||
}
|
32
src/com/boydti/fawe/util/MainUtil.java
Normal file
32
src/com/boydti/fawe/util/MainUtil.java
Normal file
@ -0,0 +1,32 @@
|
||||
package com.boydti.fawe.util;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
|
||||
public class MainUtil {
|
||||
/*
|
||||
* Generic non plugin related utils
|
||||
* e.g. sending messages
|
||||
*/
|
||||
public static void sendMessage(final FawePlayer<?> player, String message) {
|
||||
message = ChatColor.translateAlternateColorCodes('&', message);
|
||||
if (player == null) {
|
||||
Fawe.debug(message);
|
||||
} else {
|
||||
player.sendMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
public static void sendAdmin(final String s) {
|
||||
for (final Player player : Bukkit.getOnlinePlayers()) {
|
||||
if (player.hasPermission("fawe.admin")) {
|
||||
player.sendMessage(s);
|
||||
}
|
||||
}
|
||||
Fawe.debug(s);
|
||||
}
|
||||
}
|
41
src/com/boydti/fawe/util/MemUtil.java
Normal file
41
src/com/boydti/fawe/util/MemUtil.java
Normal file
@ -0,0 +1,41 @@
|
||||
package com.boydti.fawe.util;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import com.boydti.fawe.config.Settings;
|
||||
|
||||
public class MemUtil {
|
||||
|
||||
private static AtomicBoolean memory = new AtomicBoolean(false);
|
||||
|
||||
public static boolean isMemoryFree() {
|
||||
return !memory.get();
|
||||
}
|
||||
|
||||
public static boolean isMemoryLimited() {
|
||||
return memory.get();
|
||||
}
|
||||
|
||||
public static int calculateMemory() {
|
||||
final long heapSize = Runtime.getRuntime().totalMemory();
|
||||
final long heapMaxSize = Runtime.getRuntime().maxMemory();
|
||||
if (heapSize < heapMaxSize) {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
final long heapFreeSize = Runtime.getRuntime().freeMemory();
|
||||
final int size = (int) ((heapFreeSize * 100) / heapMaxSize);
|
||||
if (size > (100 - Settings.MEM_FREE)) {
|
||||
memoryPlentifulTask();
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
public static void memoryLimitedTask() {
|
||||
memory.set(true);
|
||||
}
|
||||
|
||||
public static void memoryPlentifulTask() {
|
||||
memory.set(false);
|
||||
}
|
||||
}
|
44
src/com/boydti/fawe/util/Perm.java
Normal file
44
src/com/boydti/fawe/util/Perm.java
Normal file
@ -0,0 +1,44 @@
|
||||
package com.boydti.fawe.util;
|
||||
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
|
||||
public enum Perm {
|
||||
/*
|
||||
* Permission related functions
|
||||
*/
|
||||
ADMIN("fawe.admin", "admin");
|
||||
|
||||
public String s;
|
||||
public String cat;
|
||||
|
||||
Perm(final String perm, final String cat) {
|
||||
s = perm;
|
||||
this.cat = cat;
|
||||
}
|
||||
|
||||
public boolean has(final FawePlayer<?> player) {
|
||||
return hasPermission(player, this);
|
||||
}
|
||||
|
||||
public boolean hasPermission(final FawePlayer<?> player, final Perm perm) {
|
||||
return hasPermission(player, perm.s);
|
||||
}
|
||||
|
||||
public static boolean hasPermission(final FawePlayer<?> player, final String perm) {
|
||||
if ((player == null) || player.hasPermission(ADMIN.s)) {
|
||||
return true;
|
||||
}
|
||||
if (player.hasPermission(perm)) {
|
||||
return true;
|
||||
}
|
||||
final String[] nodes = perm.split("\\.");
|
||||
final StringBuilder n = new StringBuilder();
|
||||
for (int i = 0; i < (nodes.length - 1); i++) {
|
||||
n.append(nodes[i] + ("."));
|
||||
if (player.hasPermission(n + "*")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
706
src/com/boydti/fawe/util/ReflectionUtils.java
Normal file
706
src/com/boydti/fawe/util/ReflectionUtils.java
Normal file
@ -0,0 +1,706 @@
|
||||
package com.boydti.fawe.util;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Server;
|
||||
|
||||
/**
|
||||
* @author DPOH-VAR
|
||||
* @version 1.0
|
||||
*/
|
||||
@SuppressWarnings({ "UnusedDeclaration", "rawtypes" })
|
||||
public class ReflectionUtils {
|
||||
/**
|
||||
* prefix of bukkit classes
|
||||
*/
|
||||
private static String preClassB = "org.bukkit.craftbukkit";
|
||||
/**
|
||||
* prefix of minecraft classes
|
||||
*/
|
||||
private static String preClassM = "net.minecraft.server";
|
||||
/**
|
||||
* boolean value, TRUE if server uses forge or MCPC+
|
||||
*/
|
||||
private static boolean forge = false;
|
||||
/** check server version and class names */
|
||||
static {
|
||||
if (Bukkit.getServer() != null) {
|
||||
if (Bukkit.getVersion().contains("MCPC") || Bukkit.getVersion().contains("Forge")) {
|
||||
forge = true;
|
||||
}
|
||||
final Server server = Bukkit.getServer();
|
||||
final Class<?> bukkitServerClass = server.getClass();
|
||||
String[] pas = bukkitServerClass.getName().split("\\.");
|
||||
if (pas.length == 5) {
|
||||
final String verB = pas[3];
|
||||
preClassB += "." + verB;
|
||||
}
|
||||
try {
|
||||
final Method getHandle = bukkitServerClass.getDeclaredMethod("getHandle");
|
||||
final Object handle = getHandle.invoke(server);
|
||||
final Class handleServerClass = handle.getClass();
|
||||
pas = handleServerClass.getName().split("\\.");
|
||||
if (pas.length == 5) {
|
||||
final String verM = pas[3];
|
||||
preClassM += "." + verM;
|
||||
}
|
||||
} catch (final Exception ignored) {}
|
||||
}
|
||||
}
|
||||
|
||||
public static Class<?> getNmsClass(final String name) {
|
||||
final String className = "net.minecraft.server." + getVersion() + "." + name;
|
||||
return getClass(className);
|
||||
}
|
||||
|
||||
public static Class<?> getCbClass(final String name) {
|
||||
final String className = "org.bukkit.craftbukkit." + getVersion() + "." + name;
|
||||
return getClass(className);
|
||||
}
|
||||
|
||||
public static Class<?> getUtilClass(final String name) {
|
||||
try {
|
||||
return Class.forName(name); //Try before 1.8 first
|
||||
} catch (final ClassNotFoundException ex) {
|
||||
try {
|
||||
return Class.forName("net.minecraft.util." + name); //Not 1.8
|
||||
} catch (final ClassNotFoundException ex2) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static String getVersion() {
|
||||
final String packageName = Bukkit.getServer().getClass().getPackage().getName();
|
||||
return packageName.substring(packageName.lastIndexOf('.') + 1);
|
||||
}
|
||||
|
||||
public static Object getHandle(final Object wrapper) {
|
||||
final Method getHandle = makeMethod(wrapper.getClass(), "getHandle");
|
||||
return callMethod(getHandle, wrapper);
|
||||
}
|
||||
|
||||
//Utils
|
||||
public static Method makeMethod(final Class<?> clazz, final String methodName, final Class<?>... paramaters) {
|
||||
try {
|
||||
return clazz.getDeclaredMethod(methodName, paramaters);
|
||||
} catch (final NoSuchMethodException ex) {
|
||||
return null;
|
||||
} catch (final Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T callMethod(final Method method, final Object instance, final Object... paramaters) {
|
||||
if (method == null) {
|
||||
throw new RuntimeException("No such method");
|
||||
}
|
||||
method.setAccessible(true);
|
||||
try {
|
||||
return (T) method.invoke(instance, paramaters);
|
||||
} catch (final InvocationTargetException ex) {
|
||||
throw new RuntimeException(ex.getCause());
|
||||
} catch (final Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> Constructor<T> makeConstructor(final Class<?> clazz, final Class<?>... paramaterTypes) {
|
||||
try {
|
||||
return (Constructor<T>) clazz.getConstructor(paramaterTypes);
|
||||
} catch (final NoSuchMethodException ex) {
|
||||
return null;
|
||||
} catch (final Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T callConstructor(final Constructor<T> constructor, final Object... paramaters) {
|
||||
if (constructor == null) {
|
||||
throw new RuntimeException("No such constructor");
|
||||
}
|
||||
constructor.setAccessible(true);
|
||||
try {
|
||||
return constructor.newInstance(paramaters);
|
||||
} catch (final InvocationTargetException ex) {
|
||||
throw new RuntimeException(ex.getCause());
|
||||
} catch (final Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static Field makeField(final Class<?> clazz, final String name) {
|
||||
try {
|
||||
return clazz.getDeclaredField(name);
|
||||
} catch (final NoSuchFieldException ex) {
|
||||
return null;
|
||||
} catch (final Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T getField(final Field field, final Object instance) {
|
||||
if (field == null) {
|
||||
throw new RuntimeException("No such field");
|
||||
}
|
||||
field.setAccessible(true);
|
||||
try {
|
||||
return (T) field.get(instance);
|
||||
} catch (final Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static void setField(final Field field, final Object instance, final Object value) {
|
||||
if (field == null) {
|
||||
throw new RuntimeException("No such field");
|
||||
}
|
||||
field.setAccessible(true);
|
||||
try {
|
||||
field.set(instance, value);
|
||||
} catch (final Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static Class<?> getClass(final String name) {
|
||||
try {
|
||||
return Class.forName(name);
|
||||
} catch (final ClassNotFoundException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> Class<? extends T> getClass(final String name, final Class<T> superClass) {
|
||||
try {
|
||||
return Class.forName(name).asSubclass(superClass);
|
||||
} catch (ClassCastException | ClassNotFoundException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if server has forge classes
|
||||
*/
|
||||
public static boolean isForge() {
|
||||
return forge;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get class for name. Replace {nms} to net.minecraft.server.V*. Replace {cb} to org.bukkit.craftbukkit.V*. Replace
|
||||
* {nm} to net.minecraft
|
||||
*
|
||||
* @param classes possible class paths
|
||||
*
|
||||
* @return RefClass object
|
||||
*
|
||||
* @throws RuntimeException if no class found
|
||||
*/
|
||||
public static RefClass getRefClass(final String... classes) throws RuntimeException {
|
||||
for (String className : classes) {
|
||||
try {
|
||||
className = className.replace("{cb}", preClassB).replace("{nms}", preClassM).replace("{nm}", "net.minecraft");
|
||||
return getRefClass(Class.forName(className));
|
||||
} catch (final ClassNotFoundException ignored) {}
|
||||
}
|
||||
throw new RuntimeException("no class found");
|
||||
}
|
||||
|
||||
/**
|
||||
* get RefClass object by real class
|
||||
*
|
||||
* @param clazz class
|
||||
*
|
||||
* @return RefClass based on passed class
|
||||
*/
|
||||
public static RefClass getRefClass(final Class clazz) {
|
||||
return new RefClass(clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* RefClass - utility to simplify work with reflections.
|
||||
*/
|
||||
public static class RefClass {
|
||||
private final Class<?> clazz;
|
||||
|
||||
private RefClass(final Class<?> clazz) {
|
||||
this.clazz = clazz;
|
||||
}
|
||||
|
||||
/**
|
||||
* get passed class
|
||||
*
|
||||
* @return class
|
||||
*/
|
||||
public Class<?> getRealClass() {
|
||||
return clazz;
|
||||
}
|
||||
|
||||
/**
|
||||
* see {@link Class#isInstance(Object)}
|
||||
*
|
||||
* @param object the object to check
|
||||
*
|
||||
* @return true if object is an instance of this class
|
||||
*/
|
||||
public boolean isInstance(final Object object) {
|
||||
return clazz.isInstance(object);
|
||||
}
|
||||
|
||||
/**
|
||||
* get existing method by name and types
|
||||
*
|
||||
* @param name name
|
||||
* @param types method parameters. can be Class or RefClass
|
||||
*
|
||||
* @return RefMethod object
|
||||
*
|
||||
* @throws RuntimeException if method not found
|
||||
*/
|
||||
public RefMethod getMethod(final String name, final Object... types) throws NoSuchMethodException {
|
||||
try {
|
||||
final Class[] classes = new Class[types.length];
|
||||
int i = 0;
|
||||
for (final Object e : types) {
|
||||
if (e instanceof Class) {
|
||||
classes[i++] = (Class) e;
|
||||
} else if (e instanceof RefClass) {
|
||||
classes[i++] = ((RefClass) e).getRealClass();
|
||||
} else {
|
||||
classes[i++] = e.getClass();
|
||||
}
|
||||
}
|
||||
try {
|
||||
return new RefMethod(clazz.getMethod(name, classes));
|
||||
} catch (final NoSuchMethodException ignored) {
|
||||
return new RefMethod(clazz.getDeclaredMethod(name, classes));
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get existing constructor by types
|
||||
*
|
||||
* @param types parameters. can be Class or RefClass
|
||||
*
|
||||
* @return RefMethod object
|
||||
*
|
||||
* @throws RuntimeException if constructor not found
|
||||
*/
|
||||
public RefConstructor getConstructor(final Object... types) {
|
||||
try {
|
||||
final Class[] classes = new Class[types.length];
|
||||
int i = 0;
|
||||
for (final Object e : types) {
|
||||
if (e instanceof Class) {
|
||||
classes[i++] = (Class) e;
|
||||
} else if (e instanceof RefClass) {
|
||||
classes[i++] = ((RefClass) e).getRealClass();
|
||||
} else {
|
||||
classes[i++] = e.getClass();
|
||||
}
|
||||
}
|
||||
try {
|
||||
return new RefConstructor(clazz.getConstructor(classes));
|
||||
} catch (final NoSuchMethodException ignored) {
|
||||
return new RefConstructor(clazz.getDeclaredConstructor(classes));
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* find method by type parameters
|
||||
*
|
||||
* @param types parameters. can be Class or RefClass
|
||||
*
|
||||
* @return RefMethod object
|
||||
*
|
||||
* @throws RuntimeException if method not found
|
||||
*/
|
||||
public RefMethod findMethod(final Object... types) {
|
||||
final Class[] classes = new Class[types.length];
|
||||
int t = 0;
|
||||
for (final Object e : types) {
|
||||
if (e instanceof Class) {
|
||||
classes[t++] = (Class) e;
|
||||
} else if (e instanceof RefClass) {
|
||||
classes[t++] = ((RefClass) e).getRealClass();
|
||||
} else {
|
||||
classes[t++] = e.getClass();
|
||||
}
|
||||
}
|
||||
final List<Method> methods = new ArrayList<>();
|
||||
Collections.addAll(methods, clazz.getMethods());
|
||||
Collections.addAll(methods, clazz.getDeclaredMethods());
|
||||
findMethod: for (final Method m : methods) {
|
||||
final Class<?>[] methodTypes = m.getParameterTypes();
|
||||
if (methodTypes.length != classes.length) {
|
||||
continue;
|
||||
}
|
||||
for (final Class aClass : classes) {
|
||||
if (!Arrays.equals(classes, methodTypes)) {
|
||||
continue findMethod;
|
||||
}
|
||||
return new RefMethod(m);
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("no such method");
|
||||
}
|
||||
|
||||
/**
|
||||
* find method by name
|
||||
*
|
||||
* @param names possible names of method
|
||||
*
|
||||
* @return RefMethod object
|
||||
*
|
||||
* @throws RuntimeException if method not found
|
||||
*/
|
||||
public RefMethod findMethodByName(final String... names) {
|
||||
final List<Method> methods = new ArrayList<>();
|
||||
Collections.addAll(methods, clazz.getMethods());
|
||||
Collections.addAll(methods, clazz.getDeclaredMethods());
|
||||
for (final Method m : methods) {
|
||||
for (final String name : names) {
|
||||
if (m.getName().equals(name)) {
|
||||
return new RefMethod(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("no such method");
|
||||
}
|
||||
|
||||
/**
|
||||
* find method by return value
|
||||
*
|
||||
* @param type type of returned value
|
||||
*
|
||||
* @return RefMethod
|
||||
*
|
||||
* @throws RuntimeException if method not found
|
||||
*/
|
||||
public RefMethod findMethodByReturnType(final RefClass type) {
|
||||
return findMethodByReturnType(type.clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* find method by return value
|
||||
*
|
||||
* @param type type of returned value
|
||||
*
|
||||
* @return RefMethod
|
||||
*
|
||||
* @throws RuntimeException if method not found
|
||||
*/
|
||||
public RefMethod findMethodByReturnType(Class type) {
|
||||
if (type == null) {
|
||||
type = void.class;
|
||||
}
|
||||
final List<Method> methods = new ArrayList<>();
|
||||
Collections.addAll(methods, clazz.getMethods());
|
||||
Collections.addAll(methods, clazz.getDeclaredMethods());
|
||||
for (final Method m : methods) {
|
||||
if (type.equals(m.getReturnType())) {
|
||||
return new RefMethod(m);
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("no such method");
|
||||
}
|
||||
|
||||
/**
|
||||
* find constructor by number of arguments
|
||||
*
|
||||
* @param number number of arguments
|
||||
*
|
||||
* @return RefConstructor
|
||||
*
|
||||
* @throws RuntimeException if constructor not found
|
||||
*/
|
||||
public RefConstructor findConstructor(final int number) {
|
||||
final List<Constructor> constructors = new ArrayList<>();
|
||||
Collections.addAll(constructors, clazz.getConstructors());
|
||||
Collections.addAll(constructors, clazz.getDeclaredConstructors());
|
||||
for (final Constructor m : constructors) {
|
||||
if (m.getParameterTypes().length == number) {
|
||||
return new RefConstructor(m);
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("no such constructor");
|
||||
}
|
||||
|
||||
/**
|
||||
* get field by name
|
||||
*
|
||||
* @param name field name
|
||||
*
|
||||
* @return RefField
|
||||
*
|
||||
* @throws RuntimeException if field not found
|
||||
*/
|
||||
public RefField getField(final String name) {
|
||||
try {
|
||||
try {
|
||||
return new RefField(clazz.getField(name));
|
||||
} catch (final NoSuchFieldException ignored) {
|
||||
return new RefField(clazz.getDeclaredField(name));
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* find field by type
|
||||
*
|
||||
* @param type field type
|
||||
*
|
||||
* @return RefField
|
||||
*
|
||||
* @throws RuntimeException if field not found
|
||||
*/
|
||||
public RefField findField(final RefClass type) {
|
||||
return findField(type.clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* find field by type
|
||||
*
|
||||
* @param type field type
|
||||
*
|
||||
* @return RefField
|
||||
*
|
||||
* @throws RuntimeException if field not found
|
||||
*/
|
||||
public RefField findField(Class type) {
|
||||
if (type == null) {
|
||||
type = void.class;
|
||||
}
|
||||
final List<Field> fields = new ArrayList<>();
|
||||
Collections.addAll(fields, clazz.getFields());
|
||||
Collections.addAll(fields, clazz.getDeclaredFields());
|
||||
for (final Field f : fields) {
|
||||
if (type.equals(f.getType())) {
|
||||
return new RefField(f);
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("no such field");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method wrapper
|
||||
*/
|
||||
public static class RefMethod {
|
||||
private final Method method;
|
||||
|
||||
private RefMethod(final Method method) {
|
||||
this.method = method;
|
||||
method.setAccessible(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return passed method
|
||||
*/
|
||||
public Method getRealMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return owner class of method
|
||||
*/
|
||||
public RefClass getRefClass() {
|
||||
return new RefClass(method.getDeclaringClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return class of method return type
|
||||
*/
|
||||
public RefClass getReturnRefClass() {
|
||||
return new RefClass(method.getReturnType());
|
||||
}
|
||||
|
||||
/**
|
||||
* apply method to object
|
||||
*
|
||||
* @param e object to which the method is applied
|
||||
*
|
||||
* @return RefExecutor with method call(...)
|
||||
*/
|
||||
public RefExecutor of(final Object e) {
|
||||
return new RefExecutor(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* call static method
|
||||
*
|
||||
* @param params sent parameters
|
||||
*
|
||||
* @return return value
|
||||
*/
|
||||
public Object call(final Object... params) {
|
||||
try {
|
||||
return method.invoke(null, params);
|
||||
} catch (final Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public class RefExecutor {
|
||||
final Object e;
|
||||
|
||||
public RefExecutor(final Object e) {
|
||||
this.e = e;
|
||||
}
|
||||
|
||||
/**
|
||||
* apply method for selected object
|
||||
*
|
||||
* @param params sent parameters
|
||||
*
|
||||
* @return return value
|
||||
*
|
||||
* @throws RuntimeException if something went wrong
|
||||
*/
|
||||
public Object call(final Object... params) {
|
||||
try {
|
||||
return method.invoke(e, params);
|
||||
} catch (final Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor wrapper
|
||||
*/
|
||||
public static class RefConstructor {
|
||||
private final Constructor constructor;
|
||||
|
||||
private RefConstructor(final Constructor constructor) {
|
||||
this.constructor = constructor;
|
||||
constructor.setAccessible(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return passed constructor
|
||||
*/
|
||||
public Constructor getRealConstructor() {
|
||||
return constructor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return owner class of method
|
||||
*/
|
||||
public RefClass getRefClass() {
|
||||
return new RefClass(constructor.getDeclaringClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* create new instance with constructor
|
||||
*
|
||||
* @param params parameters for constructor
|
||||
*
|
||||
* @return new object
|
||||
*
|
||||
* @throws RuntimeException if something went wrong
|
||||
*/
|
||||
public Object create(final Object... params) {
|
||||
try {
|
||||
return constructor.newInstance(params);
|
||||
} catch (final Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class RefField {
|
||||
private final Field field;
|
||||
|
||||
private RefField(final Field field) {
|
||||
this.field = field;
|
||||
field.setAccessible(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return passed field
|
||||
*/
|
||||
public Field getRealField() {
|
||||
return field;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return owner class of field
|
||||
*/
|
||||
public RefClass getRefClass() {
|
||||
return new RefClass(field.getDeclaringClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return type of field
|
||||
*/
|
||||
public RefClass getFieldRefClass() {
|
||||
return new RefClass(field.getType());
|
||||
}
|
||||
|
||||
/**
|
||||
* apply fiend for object
|
||||
*
|
||||
* @param e applied object
|
||||
*
|
||||
* @return RefExecutor with getter and setter
|
||||
*/
|
||||
public RefExecutor of(final Object e) {
|
||||
return new RefExecutor(e);
|
||||
}
|
||||
|
||||
public class RefExecutor {
|
||||
final Object e;
|
||||
|
||||
public RefExecutor(final Object e) {
|
||||
this.e = e;
|
||||
}
|
||||
|
||||
/**
|
||||
* set field value for applied object
|
||||
*
|
||||
* @param param value
|
||||
*/
|
||||
public void set(final Object param) {
|
||||
try {
|
||||
field.set(e, param);
|
||||
} catch (final Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get field value for applied object
|
||||
*
|
||||
* @return value of field
|
||||
*/
|
||||
public Object get() {
|
||||
try {
|
||||
return field.get(e);
|
||||
} catch (final Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
36
src/com/boydti/fawe/util/SafeExtentWrapper.java
Normal file
36
src/com/boydti/fawe/util/SafeExtentWrapper.java
Normal file
@ -0,0 +1,36 @@
|
||||
package com.boydti.fawe.util;
|
||||
|
||||
import com.boydti.fawe.config.BBC;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
|
||||
public class SafeExtentWrapper extends AbstractDelegateExtent {
|
||||
private final FawePlayer<?> player;
|
||||
|
||||
public SafeExtentWrapper(final FawePlayer<?> player, final Extent extent) {
|
||||
super(extent);
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(final Vector location, final BaseBlock block) throws WorldEditException {
|
||||
if (super.setBlock(location, block)) {
|
||||
if (MemUtil.isMemoryLimited()) {
|
||||
if (player != null) {
|
||||
BBC.WORLDEDIT_OOM.send(player);
|
||||
if (Perm.hasPermission(player, "worldedit.fast")) {
|
||||
BBC.WORLDEDIT_OOM_ADMIN.send(player);
|
||||
}
|
||||
}
|
||||
WEManager.IMP.cancelEdit(this);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
143
src/com/boydti/fawe/util/SetBlockQueue.java
Normal file
143
src/com/boydti/fawe/util/SetBlockQueue.java
Normal file
@ -0,0 +1,143 @@
|
||||
package com.boydti.fawe.util;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import com.boydti.fawe.object.FaweChunk;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
|
||||
public class SetBlockQueue {
|
||||
|
||||
public static final SetBlockQueue IMP = new SetBlockQueue();
|
||||
|
||||
public FaweQueue queue;
|
||||
|
||||
private final AtomicInteger time_waiting = new AtomicInteger(2);
|
||||
private final AtomicInteger time_current = new AtomicInteger(0);
|
||||
private final ArrayDeque<Runnable> runnables = new ArrayDeque<>();
|
||||
private long last;
|
||||
private long last2;
|
||||
|
||||
public SetBlockQueue() {
|
||||
TaskManager.IMP.repeat(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!MemUtil.isMemoryFree()) {
|
||||
final int mem = MemUtil.calculateMemory();
|
||||
if (mem != Integer.MAX_VALUE) {
|
||||
if (mem <= 1) {
|
||||
queue.saveMemory();
|
||||
return;
|
||||
}
|
||||
if (forceChunkSet()) {
|
||||
System.gc();
|
||||
} else {
|
||||
time_current.incrementAndGet();
|
||||
tasks();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
long free = 50 + Math.min(50 + last - (last = System.currentTimeMillis()), last2 - System.currentTimeMillis());
|
||||
time_current.incrementAndGet();
|
||||
do {
|
||||
if (isWaiting()) {
|
||||
return;
|
||||
}
|
||||
final FaweChunk<?> current = queue.next();
|
||||
if (current == null) {
|
||||
time_waiting.set(Math.max(time_waiting.get(), time_current.get() - 2));
|
||||
tasks();
|
||||
return;
|
||||
}
|
||||
} while ((last2 = System.currentTimeMillis()) - last < free);
|
||||
time_waiting.set(time_current.get() - 1);
|
||||
}
|
||||
}, 1);
|
||||
}
|
||||
|
||||
public boolean forceChunkSet() {
|
||||
final FaweChunk<?> set = queue.next();
|
||||
return set != null;
|
||||
}
|
||||
|
||||
public boolean isWaiting() {
|
||||
return time_waiting.get() >= time_current.get();
|
||||
}
|
||||
|
||||
public boolean isDone() {
|
||||
return (time_waiting.get() + 1) < time_current.get();
|
||||
}
|
||||
|
||||
public void setWaiting() {
|
||||
time_waiting.set(time_current.get() + 1);
|
||||
}
|
||||
|
||||
public boolean addTask(final Runnable whenDone) {
|
||||
if (isDone()) {
|
||||
// Run
|
||||
tasks();
|
||||
if (whenDone != null) {
|
||||
whenDone.run();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (whenDone != null) {
|
||||
runnables.add(whenDone);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean tasks() {
|
||||
if (runnables.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
final ArrayDeque<Runnable> tmp = runnables.clone();
|
||||
runnables.clear();
|
||||
for (final Runnable runnable : tmp) {
|
||||
runnable.run();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param world
|
||||
* @param x
|
||||
* @param y
|
||||
* @param z
|
||||
* @param id
|
||||
* @param data
|
||||
* @return
|
||||
*/
|
||||
public boolean setBlock(final String world, final int x, final int y, final int z, final short id, final byte data) {
|
||||
SetBlockQueue.IMP.setWaiting();
|
||||
return queue.setBlock(world, x, y, z, id, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param world
|
||||
* @param x
|
||||
* @param y
|
||||
* @param z
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
public boolean setBlock(final String world, final int x, final int y, final int z, final short id) {
|
||||
SetBlockQueue.IMP.setWaiting();
|
||||
return queue.setBlock(world, x, y, z, id, (byte) 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param world
|
||||
* @param x
|
||||
* @param y
|
||||
* @param z
|
||||
* @param id
|
||||
* @param data
|
||||
* @return
|
||||
*/
|
||||
public boolean setBiome(final String world, final int x, final int z, BaseBiome biome) {
|
||||
SetBlockQueue.IMP.setWaiting();
|
||||
return queue.setBiome(world, x, z, biome);
|
||||
}
|
||||
}
|
269
src/com/boydti/fawe/util/StringMan.java
Normal file
269
src/com/boydti/fawe/util/StringMan.java
Normal file
@ -0,0 +1,269 @@
|
||||
package com.boydti.fawe.util;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
public class StringMan {
|
||||
public static String replaceFromMap(final String string, final Map<String, String> replacements) {
|
||||
final StringBuilder sb = new StringBuilder(string);
|
||||
int size = string.length();
|
||||
for (final Entry<String, String> entry : replacements.entrySet()) {
|
||||
if (size == 0) {
|
||||
break;
|
||||
}
|
||||
final String key = entry.getKey();
|
||||
final String value = entry.getValue();
|
||||
int start = sb.indexOf(key, 0);
|
||||
while (start > -1) {
|
||||
final int end = start + key.length();
|
||||
final int nextSearchStart = start + value.length();
|
||||
sb.replace(start, end, value);
|
||||
size -= end - start;
|
||||
start = sb.indexOf(key, nextSearchStart);
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static int intersection(Set<String> options, String[] toCheck) {
|
||||
int count = 0;
|
||||
for (String check : toCheck) {
|
||||
if (options.contains(check)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public static String getString(final Object obj) {
|
||||
if (obj == null) {
|
||||
return "null";
|
||||
}
|
||||
if (obj.getClass() == String.class) {
|
||||
return (String) obj;
|
||||
}
|
||||
if (obj.getClass().isArray()) {
|
||||
String result = "";
|
||||
String prefix = "";
|
||||
|
||||
for (int i = 0; i < Array.getLength(obj); i++) {
|
||||
result += prefix + getString(Array.get(obj, i));
|
||||
prefix = ",";
|
||||
}
|
||||
return "( " + result + " )";
|
||||
} else if (obj instanceof Collection<?>) {
|
||||
String result = "";
|
||||
String prefix = "";
|
||||
for (final Object element : (Collection<?>) obj) {
|
||||
result += prefix + getString(element);
|
||||
prefix = ",";
|
||||
}
|
||||
return "[ " + result + " ]";
|
||||
} else {
|
||||
return obj.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public static String replaceFirst(final char c, final String s) {
|
||||
if (s == null) {
|
||||
return "";
|
||||
}
|
||||
if (s.isEmpty()) {
|
||||
return s;
|
||||
}
|
||||
char[] chars = s.toCharArray();
|
||||
final char[] newChars = new char[chars.length];
|
||||
int used = 0;
|
||||
boolean found = false;
|
||||
for (final char cc : chars) {
|
||||
if (!found && (c == cc)) {
|
||||
found = true;
|
||||
} else {
|
||||
newChars[used++] = cc;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
chars = new char[newChars.length - 1];
|
||||
System.arraycopy(newChars, 0, chars, 0, chars.length);
|
||||
return String.valueOf(chars);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
public static String replaceAll(final String string, final Object... pairs) {
|
||||
final StringBuilder sb = new StringBuilder(string);
|
||||
for (int i = 0; i < pairs.length; i += 2) {
|
||||
final String key = pairs[i] + "";
|
||||
final String value = pairs[i + 1] + "";
|
||||
int start = sb.indexOf(key, 0);
|
||||
while (start > -1) {
|
||||
final int end = start + key.length();
|
||||
final int nextSearchStart = start + value.length();
|
||||
sb.replace(start, end, value);
|
||||
start = sb.indexOf(key, nextSearchStart);
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static boolean isAlphanumeric(final String str) {
|
||||
for (int i = 0; i < str.length(); i++) {
|
||||
final char c = str.charAt(i);
|
||||
if ((c < 0x30) || ((c >= 0x3a) && (c <= 0x40)) || ((c > 0x5a) && (c <= 0x60)) || (c > 0x7a)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean isAlphanumericUnd(final String str) {
|
||||
for (int i = 0; i < str.length(); i++) {
|
||||
final char c = str.charAt(i);
|
||||
if ((c < 0x30) || ((c >= 0x3a) && (c <= 0x40)) || ((c > 0x5a) && (c <= 0x60)) || (c > 0x7a) || (c == '_')) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean isAlpha(final String str) {
|
||||
for (int i = 0; i < str.length(); i++) {
|
||||
final char c = str.charAt(i);
|
||||
if ((c <= 0x40) || ((c > 0x5a) && (c <= 0x60)) || (c > 0x7a)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static String join(final Collection<?> collection, final String delimiter) {
|
||||
return join(collection.toArray(), delimiter);
|
||||
}
|
||||
|
||||
public static String joinOrdered(final Collection<?> collection, final String delimiter) {
|
||||
final Object[] array = collection.toArray();
|
||||
Arrays.sort(array, new Comparator<Object>() {
|
||||
@Override
|
||||
public int compare(final Object a, final Object b) {
|
||||
return a.hashCode() - b.hashCode();
|
||||
}
|
||||
|
||||
});
|
||||
return join(array, delimiter);
|
||||
}
|
||||
|
||||
public static String join(final Collection<?> collection, final char delimiter) {
|
||||
return join(collection.toArray(), delimiter + "");
|
||||
}
|
||||
|
||||
public static boolean isAsciiPrintable(final char c) {
|
||||
return (c >= ' ') && (c < '');
|
||||
}
|
||||
|
||||
public static boolean isAsciiPrintable(final String s) {
|
||||
for (final char c : s.toCharArray()) {
|
||||
if (!isAsciiPrintable(c)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static int getLevenshteinDistance(String s, String t) {
|
||||
int n = s.length();
|
||||
int m = t.length();
|
||||
if (n == 0) {
|
||||
return m;
|
||||
} else if (m == 0) {
|
||||
return n;
|
||||
}
|
||||
if (n > m) {
|
||||
final String tmp = s;
|
||||
s = t;
|
||||
t = tmp;
|
||||
n = m;
|
||||
m = t.length();
|
||||
}
|
||||
int p[] = new int[n + 1];
|
||||
int d[] = new int[n + 1];
|
||||
int _d[];
|
||||
int i;
|
||||
int j;
|
||||
char t_j;
|
||||
int cost;
|
||||
for (i = 0; i <= n; i++) {
|
||||
p[i] = i;
|
||||
}
|
||||
for (j = 1; j <= m; j++) {
|
||||
t_j = t.charAt(j - 1);
|
||||
d[0] = j;
|
||||
|
||||
for (i = 1; i <= n; i++) {
|
||||
cost = s.charAt(i - 1) == t_j ? 0 : 1;
|
||||
d[i] = Math.min(Math.min(d[i - 1] + 1, p[i] + 1), p[i - 1] + cost);
|
||||
}
|
||||
_d = p;
|
||||
p = d;
|
||||
d = _d;
|
||||
}
|
||||
return p[n];
|
||||
}
|
||||
|
||||
public static String join(final Object[] array, final String delimiter) {
|
||||
final StringBuilder result = new StringBuilder();
|
||||
for (int i = 0, j = array.length; i < j; i++) {
|
||||
if (i > 0) {
|
||||
result.append(delimiter);
|
||||
}
|
||||
result.append(array[i]);
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
public static String join(final int[] array, final String delimiter) {
|
||||
final Integer[] wrapped = new Integer[array.length];
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
wrapped[i] = array[i];
|
||||
}
|
||||
return join(wrapped, delimiter);
|
||||
}
|
||||
|
||||
public static boolean isEqualToAny(final String a, final String... args) {
|
||||
for (final String arg : args) {
|
||||
if (StringMan.isEqual(a, arg)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isEqualIgnoreCaseToAny(final String a, final String... args) {
|
||||
for (final String arg : args) {
|
||||
if (StringMan.isEqualIgnoreCase(a, arg)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isEqual(final String a, final String b) {
|
||||
return ((a == b) || ((a != null) && (b != null) && (a.length() == b.length()) && (a.hashCode() == b.hashCode()) && a.equals(b)));
|
||||
}
|
||||
|
||||
public static boolean isEqualIgnoreCase(final String a, final String b) {
|
||||
return ((a == b) || ((a != null) && (b != null) && (a.length() == b.length()) && a.equalsIgnoreCase(b)));
|
||||
}
|
||||
|
||||
public static String repeat(final String s, final int n) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < n; i++) {
|
||||
sb.append(s);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
20
src/com/boydti/fawe/util/TaskManager.java
Normal file
20
src/com/boydti/fawe/util/TaskManager.java
Normal file
@ -0,0 +1,20 @@
|
||||
package com.boydti.fawe.util;
|
||||
|
||||
public abstract class TaskManager {
|
||||
|
||||
public static TaskManager IMP;
|
||||
|
||||
public abstract int repeat(final Runnable r, final int interval);
|
||||
|
||||
public abstract int repeatAsync(final Runnable r, final int interval);
|
||||
|
||||
public abstract void async(final Runnable r);
|
||||
|
||||
public abstract void task(final Runnable r);
|
||||
|
||||
public abstract void later(final Runnable r, final int delay);
|
||||
|
||||
public abstract void laterAsync(final Runnable r, final int delay);
|
||||
|
||||
public abstract void cancel(final int task);
|
||||
}
|
130
src/com/boydti/fawe/util/WEManager.java
Normal file
130
src/com/boydti/fawe/util/WEManager.java
Normal file
@ -0,0 +1,130 @@
|
||||
package com.boydti.fawe.util;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.HashSet;
|
||||
|
||||
import com.boydti.fawe.bukkit.regions.FaweMask;
|
||||
import com.boydti.fawe.config.BBC;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.object.NullExtent;
|
||||
import com.boydti.fawe.object.RegionWrapper;
|
||||
import com.boydti.fawe.regions.FaweMaskManager;
|
||||
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
|
||||
public class WEManager {
|
||||
|
||||
public final static WEManager IMP = new WEManager();
|
||||
|
||||
public final ArrayDeque<FaweMaskManager> managers = new ArrayDeque<>();
|
||||
|
||||
public void cancelEdit(Extent parent) {
|
||||
try {
|
||||
final Field field = AbstractDelegateExtent.class.getDeclaredField("extent");
|
||||
field.setAccessible(true);
|
||||
field.set(parent, new NullExtent());
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
parent = null;
|
||||
}
|
||||
|
||||
public boolean maskContains(final HashSet<RegionWrapper> mask, final int x, final int z) {
|
||||
for (final RegionWrapper region : mask) {
|
||||
if ((x >= region.minX) && (x <= region.maxX) && (z >= region.minZ) && (z <= region.maxZ)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public HashSet<RegionWrapper> getMask(final FawePlayer<?> player) {
|
||||
final HashSet<RegionWrapper> regions = new HashSet<>();
|
||||
if (player.hasPermission("fawe.bypass")) {
|
||||
regions.add(new RegionWrapper(Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE));
|
||||
return regions;
|
||||
}
|
||||
for (final FaweMaskManager manager : managers) {
|
||||
if (player.hasPermission("fawe." + manager.getKey())) {
|
||||
final FaweMask mask = manager.getMask(player);
|
||||
if (mask != null) {
|
||||
regions.addAll(mask.getRegions());
|
||||
}
|
||||
}
|
||||
}
|
||||
return regions;
|
||||
}
|
||||
|
||||
public boolean intersects(final RegionWrapper region1, final RegionWrapper region2) {
|
||||
return (region1.minX <= region2.maxX) && (region1.maxX >= region2.minX) && (region1.minZ <= region2.maxZ) && (region1.maxZ >= region2.minZ);
|
||||
}
|
||||
|
||||
public boolean regionContains(final RegionWrapper selection, final HashSet<RegionWrapper> mask) {
|
||||
for (final RegionWrapper region : mask) {
|
||||
if (intersects(region, selection)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean delay(final FawePlayer<?> player, final String command) {
|
||||
final long start = System.currentTimeMillis();
|
||||
return delay(player, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if ((System.currentTimeMillis() - start) > 1000) {
|
||||
BBC.WORLDEDIT_RUN.send(FawePlayer.wrap(player));
|
||||
}
|
||||
TaskManager.IMP.task(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final long start = System.currentTimeMillis();
|
||||
player.executeCommand(command.substring(1));
|
||||
TaskManager.IMP.later(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
SetBlockQueue.IMP.addTask(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if ((System.currentTimeMillis() - start) > 1000) {
|
||||
BBC.WORLDEDIT_COMPLETE.send(FawePlayer.wrap(player));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}, 2);
|
||||
}
|
||||
});
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}, false, false);
|
||||
}
|
||||
|
||||
public boolean delay(final FawePlayer<?> player, final Runnable whenDone, final boolean delayed, final boolean onlyDelayedExecution) {
|
||||
final boolean free = SetBlockQueue.IMP.addTask(null);
|
||||
if (free) {
|
||||
if (delayed) {
|
||||
if (whenDone != null) {
|
||||
whenDone.run();
|
||||
}
|
||||
} else {
|
||||
if ((whenDone != null) && !onlyDelayedExecution) {
|
||||
whenDone.run();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!delayed && (player != null)) {
|
||||
BBC.WORLDEDIT_DELAYED.send(player);
|
||||
}
|
||||
SetBlockQueue.IMP.addTask(whenDone);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
12
src/com/boydti/fawe/util/WESubscriber.java
Normal file
12
src/com/boydti/fawe/util/WESubscriber.java
Normal file
@ -0,0 +1,12 @@
|
||||
package com.boydti.fawe.util;
|
||||
|
||||
import com.sk89q.worldedit.event.extent.EditSessionEvent;
|
||||
import com.sk89q.worldedit.util.eventbus.EventHandler.Priority;
|
||||
import com.sk89q.worldedit.util.eventbus.Subscribe;
|
||||
|
||||
public class WESubscriber {
|
||||
|
||||
@Subscribe(priority = Priority.VERY_EARLY)
|
||||
public void onEditSession(final EditSessionEvent event) {
|
||||
}
|
||||
}
|
2559
src/com/sk89q/worldedit/EditSession.java
Normal file
2559
src/com/sk89q/worldedit/EditSession.java
Normal file
File diff suppressed because it is too large
Load Diff
115
src/com/sk89q/worldedit/command/DispatcherWrapper.java
Normal file
115
src/com/sk89q/worldedit/command/DispatcherWrapper.java
Normal file
@ -0,0 +1,115 @@
|
||||
package com.sk89q.worldedit.command;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.sk89q.minecraft.util.commands.CommandException;
|
||||
import com.sk89q.minecraft.util.commands.CommandLocals;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.extension.platform.CommandManager;
|
||||
import com.sk89q.worldedit.extension.platform.PlatformManager;
|
||||
import com.sk89q.worldedit.util.command.CommandCallable;
|
||||
import com.sk89q.worldedit.util.command.CommandMapping;
|
||||
import com.sk89q.worldedit.util.command.Description;
|
||||
import com.sk89q.worldedit.util.command.Dispatcher;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author SBPrime
|
||||
*/
|
||||
public class DispatcherWrapper implements Dispatcher {
|
||||
private final Dispatcher parent;
|
||||
|
||||
public final Dispatcher getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
public DispatcherWrapper(Dispatcher parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerCommand(CommandCallable callable, String... alias) {
|
||||
parent.registerCommand(callable, alias);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<CommandMapping> getCommands() {
|
||||
return parent.getCommands();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getPrimaryAliases() {
|
||||
return parent.getPrimaryAliases();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getAliases() {
|
||||
return parent.getAliases();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandMapping get(String alias) {
|
||||
return parent.get(alias);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(String alias) {
|
||||
return parent.contains(alias);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean call(final String arguments, final CommandLocals locals, final String[] parentCommands) throws CommandException {
|
||||
TaskManager.IMP.async(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
parent.call(arguments, locals, parentCommands);
|
||||
} catch (CommandException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Description getDescription() {
|
||||
return parent.getDescription();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean testPermission(CommandLocals locals) {
|
||||
return parent.testPermission(locals);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getSuggestions(String arguments, CommandLocals locals) throws CommandException {
|
||||
return parent.getSuggestions(arguments, locals);
|
||||
}
|
||||
|
||||
public static void inject() {
|
||||
// Delayed injection
|
||||
TaskManager.IMP.task(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
PlatformManager platform = WorldEdit.getInstance().getPlatformManager();
|
||||
CommandManager command = platform.getCommandManager();
|
||||
Class<? extends CommandManager> clazz = command.getClass();
|
||||
Field field = clazz.getDeclaredField("dispatcher");
|
||||
field.setAccessible(true);
|
||||
Dispatcher parent = (Dispatcher) field.get(command);
|
||||
DispatcherWrapper dispatcher = new DispatcherWrapper(parent);
|
||||
field.set(command, dispatcher);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
139
src/com/sk89q/worldedit/command/FlattenedClipboardTransform.java
Normal file
139
src/com/sk89q/worldedit/command/FlattenedClipboardTransform.java
Normal file
@ -0,0 +1,139 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.command;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import com.sk89q.worldedit.extent.transform.BlockTransformExtent;
|
||||
import com.sk89q.worldedit.function.operation.ForwardExtentCopy;
|
||||
import com.sk89q.worldedit.function.operation.Operation;
|
||||
import com.sk89q.worldedit.math.transform.AffineTransform;
|
||||
import com.sk89q.worldedit.math.transform.CombinedTransform;
|
||||
import com.sk89q.worldedit.math.transform.Transform;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.world.registry.WorldData;
|
||||
|
||||
/**
|
||||
* Helper class to 'bake' a transform into a clipboard.
|
||||
*
|
||||
* <p>This class needs a better name and may need to be made more generic.</p>
|
||||
*
|
||||
* @see Clipboard
|
||||
* @see Transform
|
||||
*/
|
||||
public class FlattenedClipboardTransform {
|
||||
|
||||
private final Clipboard original;
|
||||
private final Transform transform;
|
||||
private final WorldData worldData;
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param original the original clipboard
|
||||
* @param transform the transform
|
||||
* @param worldData the world data instance
|
||||
*/
|
||||
private FlattenedClipboardTransform(final Clipboard original, final Transform transform, final WorldData worldData) {
|
||||
checkNotNull(original);
|
||||
checkNotNull(transform);
|
||||
checkNotNull(worldData);
|
||||
this.original = original;
|
||||
this.transform = transform;
|
||||
this.worldData = worldData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the transformed region.
|
||||
*
|
||||
* @return the transformed region
|
||||
*/
|
||||
public Region getTransformedRegion() {
|
||||
final Region region = original.getRegion();
|
||||
final Vector minimum = region.getMinimumPoint();
|
||||
final Vector maximum = region.getMaximumPoint();
|
||||
|
||||
final Transform transformAround = new CombinedTransform(new AffineTransform().translate(original.getOrigin().multiply(-1)), transform, new AffineTransform().translate(original.getOrigin()));
|
||||
|
||||
final Vector[] corners = new Vector[] {
|
||||
minimum,
|
||||
maximum,
|
||||
minimum.setX(maximum.getX()),
|
||||
minimum.setY(maximum.getY()),
|
||||
minimum.setZ(maximum.getZ()),
|
||||
maximum.setX(minimum.getX()),
|
||||
maximum.setY(minimum.getY()),
|
||||
maximum.setZ(minimum.getZ()) };
|
||||
|
||||
for (int i = 0; i < corners.length; i++) {
|
||||
corners[i] = transformAround.apply(corners[i]);
|
||||
}
|
||||
|
||||
Vector newMinimum = corners[0];
|
||||
Vector newMaximum = corners[0];
|
||||
|
||||
for (int i = 1; i < corners.length; i++) {
|
||||
newMinimum = Vector.getMinimum(newMinimum, corners[i]);
|
||||
newMaximum = Vector.getMaximum(newMaximum, corners[i]);
|
||||
}
|
||||
|
||||
// After transformation, the points may not really sit on a block,
|
||||
// so we should expand the region for edge cases
|
||||
newMinimum = newMinimum.setX(Math.floor(newMinimum.getX()));
|
||||
newMinimum = newMinimum.setY(Math.floor(newMinimum.getY()));
|
||||
newMinimum = newMinimum.setZ(Math.floor(newMinimum.getZ()));
|
||||
|
||||
newMaximum = newMaximum.setX(Math.ceil(newMaximum.getX()));
|
||||
newMaximum = newMaximum.setY(Math.ceil(newMaximum.getY()));
|
||||
newMaximum = newMaximum.setZ(Math.ceil(newMaximum.getZ()));
|
||||
|
||||
return new CuboidRegion(newMinimum, newMaximum);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an operation to copy from the original clipboard to the given extent.
|
||||
*
|
||||
* @param target the target
|
||||
* @return the operation
|
||||
*/
|
||||
public Operation copyTo(final Extent target) {
|
||||
final BlockTransformExtent extent = new BlockTransformExtent(original, transform, worldData.getBlockRegistry());
|
||||
final ForwardExtentCopy copy = new ForwardExtentCopy(extent, original.getRegion(), original.getOrigin(), target, original.getOrigin());
|
||||
copy.setTransform(transform);
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance to bake the transform with.
|
||||
*
|
||||
* @param original the original clipboard
|
||||
* @param transform the transform
|
||||
* @param worldData the world data instance
|
||||
* @return a builder
|
||||
*/
|
||||
public static FlattenedClipboardTransform transform(final Clipboard original, final Transform transform, final WorldData worldData) {
|
||||
return new FlattenedClipboardTransform(original, transform, worldData);
|
||||
}
|
||||
|
||||
}
|
320
src/com/sk89q/worldedit/command/SchematicCommands.java
Normal file
320
src/com/sk89q/worldedit/command/SchematicCommands.java
Normal file
@ -0,0 +1,320 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.command;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.boydti.fawe.util.SetBlockQueue;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
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.EditSession;
|
||||
import com.sk89q.worldedit.LocalConfiguration;
|
||||
import com.sk89q.worldedit.LocalSession;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter;
|
||||
import com.sk89q.worldedit.function.operation.Operations;
|
||||
import com.sk89q.worldedit.math.transform.Transform;
|
||||
import com.sk89q.worldedit.session.ClipboardHolder;
|
||||
import com.sk89q.worldedit.util.command.parametric.Optional;
|
||||
import com.sk89q.worldedit.util.io.Closer;
|
||||
import com.sk89q.worldedit.util.io.file.FilenameException;
|
||||
import com.sk89q.worldedit.util.io.file.FilenameResolutionException;
|
||||
import com.sk89q.worldedit.world.registry.WorldData;
|
||||
|
||||
/**
|
||||
* Commands that work with schematic files.
|
||||
*/
|
||||
public class SchematicCommands {
|
||||
|
||||
private static final Logger log = Logger.getLogger(SchematicCommands.class.getCanonicalName());
|
||||
private final WorldEdit worldEdit;
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param worldEdit reference to WorldEdit
|
||||
*/
|
||||
public SchematicCommands(final WorldEdit worldEdit) {
|
||||
checkNotNull(worldEdit);
|
||||
this.worldEdit = worldEdit;
|
||||
}
|
||||
|
||||
@Command(aliases = { "load" }, usage = "[<format>] <filename>", desc = "Load a schematic into your clipboard")
|
||||
@Deprecated
|
||||
@CommandPermissions({ "worldedit.clipboard.load", "worldedit.schematic.load" })
|
||||
public void load(final Player player, final LocalSession session, @Optional("schematic") final String formatName, final String filename) throws FilenameException {
|
||||
final LocalConfiguration config = worldEdit.getConfiguration();
|
||||
|
||||
final File dir = worldEdit.getWorkingDirectoryFile(config.saveDir);
|
||||
final File f = worldEdit.getSafeOpenFile(player, dir, filename, "schematic", "schematic");
|
||||
|
||||
if (!f.exists()) {
|
||||
player.printError("Schematic " + filename + " does not exist!");
|
||||
return;
|
||||
}
|
||||
|
||||
final ClipboardFormat format = ClipboardFormat.findByAlias(formatName);
|
||||
if (format == null) {
|
||||
player.printError("Unknown schematic format: " + formatName);
|
||||
return;
|
||||
}
|
||||
|
||||
SetBlockQueue.IMP.addTask(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
TaskManager.IMP.async(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final Closer closer = Closer.create();
|
||||
try {
|
||||
final String filePath = f.getCanonicalPath();
|
||||
final String dirPath = dir.getCanonicalPath();
|
||||
|
||||
if (!filePath.substring(0, dirPath.length()).equals(dirPath)) {
|
||||
player.printError("Clipboard file could not read or it does not exist.");
|
||||
} else {
|
||||
final FileInputStream fis = closer.register(new FileInputStream(f));
|
||||
final BufferedInputStream bis = closer.register(new BufferedInputStream(fis));
|
||||
final ClipboardReader reader = format.getReader(bis);
|
||||
|
||||
final WorldData worldData = player.getWorld().getWorldData();
|
||||
final Clipboard clipboard = reader.read(player.getWorld().getWorldData());
|
||||
session.setClipboard(new ClipboardHolder(clipboard, worldData));
|
||||
|
||||
log.info(player.getName() + " loaded " + filePath);
|
||||
player.print(filename + " loaded. Paste it with //paste");
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
player.printError("Schematic could not read or it does not exist: " + e.getMessage());
|
||||
log.log(Level.WARNING, "Failed to load a saved clipboard", e);
|
||||
} finally {
|
||||
try {
|
||||
closer.close();
|
||||
} catch (final IOException ignored) {}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Command(aliases = { "save" }, usage = "[<format>] <filename>", desc = "Save a schematic into your clipboard")
|
||||
@Deprecated
|
||||
@CommandPermissions({ "worldedit.clipboard.save", "worldedit.schematic.save" })
|
||||
public void save(final Player player, final LocalSession session, @Optional("schematic") final String formatName, final String filename) throws CommandException, WorldEditException {
|
||||
final LocalConfiguration config = worldEdit.getConfiguration();
|
||||
|
||||
final File dir = worldEdit.getWorkingDirectoryFile(config.saveDir);
|
||||
final File f = worldEdit.getSafeSaveFile(player, dir, filename, "schematic", "schematic");
|
||||
|
||||
final ClipboardFormat format = ClipboardFormat.findByAlias(formatName);
|
||||
if (format == null) {
|
||||
player.printError("Unknown schematic format: " + formatName);
|
||||
return;
|
||||
}
|
||||
|
||||
final ClipboardHolder holder = session.getClipboard();
|
||||
final Clipboard clipboard = holder.getClipboard();
|
||||
final Transform transform = holder.getTransform();
|
||||
final Clipboard target;
|
||||
|
||||
// If we have a transform, bake it into the copy
|
||||
if (!transform.isIdentity()) {
|
||||
final FlattenedClipboardTransform result = FlattenedClipboardTransform.transform(clipboard, transform, holder.getWorldData());
|
||||
target = new BlockArrayClipboard(result.getTransformedRegion());
|
||||
target.setOrigin(clipboard.getOrigin());
|
||||
Operations.completeLegacy(result.copyTo(target));
|
||||
} else {
|
||||
target = clipboard;
|
||||
}
|
||||
|
||||
SetBlockQueue.IMP.addTask(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
TaskManager.IMP.async(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final Closer closer = Closer.create();
|
||||
try {
|
||||
// Create parent directories
|
||||
final File parent = f.getParentFile();
|
||||
if ((parent != null) && !parent.exists()) {
|
||||
if (!parent.mkdirs()) {
|
||||
log.info("Could not create folder for schematics!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
final FileOutputStream fos = closer.register(new FileOutputStream(f));
|
||||
final BufferedOutputStream bos = closer.register(new BufferedOutputStream(fos));
|
||||
final ClipboardWriter writer = closer.register(format.getWriter(bos));
|
||||
writer.write(target, holder.getWorldData());
|
||||
log.info(player.getName() + " saved " + f.getCanonicalPath());
|
||||
player.print(filename + " saved.");
|
||||
} catch (final IOException e) {
|
||||
player.printError("Schematic could not written: " + e.getMessage());
|
||||
log.log(Level.WARNING, "Failed to write a saved clipboard", e);
|
||||
} finally {
|
||||
try {
|
||||
closer.close();
|
||||
} catch (final IOException ignored) {}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Command(aliases = { "delete", "d" }, usage = "<filename>", desc = "Delete a saved schematic", help = "Delete a schematic from the schematic list", min = 1, max = 1)
|
||||
@CommandPermissions("worldedit.schematic.delete")
|
||||
public void delete(final Player player, final LocalSession session, final EditSession editSession, final CommandContext args) throws WorldEditException {
|
||||
final LocalConfiguration config = worldEdit.getConfiguration();
|
||||
final String filename = args.getString(0);
|
||||
|
||||
final File dir = worldEdit.getWorkingDirectoryFile(config.saveDir);
|
||||
final File f = worldEdit.getSafeSaveFile(player, dir, filename, "schematic", "schematic");
|
||||
TaskManager.IMP.async(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!f.exists()) {
|
||||
player.printError("Schematic " + filename + " does not exist!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!f.delete()) {
|
||||
player.printError("Deletion of " + filename + " failed! Maybe it is read-only.");
|
||||
return;
|
||||
}
|
||||
|
||||
player.print(filename + " has been deleted.");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Command(aliases = { "formats", "listformats", "f" }, desc = "List available formats", max = 0)
|
||||
@CommandPermissions("worldedit.schematic.formats")
|
||||
public void formats(final Actor actor) throws WorldEditException {
|
||||
actor.print("Available clipboard formats (Name: Lookup names)");
|
||||
StringBuilder builder;
|
||||
boolean first = true;
|
||||
for (final ClipboardFormat format : ClipboardFormat.values()) {
|
||||
builder = new StringBuilder();
|
||||
builder.append(format.name()).append(": ");
|
||||
for (final String lookupName : format.getAliases()) {
|
||||
if (!first) {
|
||||
builder.append(", ");
|
||||
}
|
||||
builder.append(lookupName);
|
||||
first = false;
|
||||
}
|
||||
first = true;
|
||||
actor.print(builder.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Command(aliases = { "list", "all", "ls" }, desc = "List saved schematics", max = 0, flags = "dn", help = "List all schematics in the schematics directory\n"
|
||||
+ " -d sorts by date, oldest first\n"
|
||||
+ " -n sorts by date, newest first\n")
|
||||
@CommandPermissions("worldedit.schematic.list")
|
||||
public void list(final Actor actor, final CommandContext args) throws WorldEditException {
|
||||
final File dir = worldEdit.getWorkingDirectoryFile(worldEdit.getConfiguration().saveDir);
|
||||
final File[] files = dir.listFiles(new FileFilter() {
|
||||
@Override
|
||||
public boolean accept(final File file) {
|
||||
// sort out directories from the schematic list
|
||||
// if WE supports sub-directories in the future,
|
||||
// this will have to be changed
|
||||
return file.isFile();
|
||||
}
|
||||
});
|
||||
if (files == null) {
|
||||
throw new FilenameResolutionException(dir.getPath(), "Schematics directory invalid or not found.");
|
||||
}
|
||||
|
||||
final int sortType = args.hasFlag('d') ? -1 : args.hasFlag('n') ? 1 : 0;
|
||||
// cleanup file list
|
||||
Arrays.sort(files, new Comparator<File>() {
|
||||
@Override
|
||||
public int compare(final File f1, final File f2) {
|
||||
// this should no longer happen, as directory-ness is checked before
|
||||
// however, if a directory slips through, this will break the contract
|
||||
// of comparator transitivity
|
||||
if (!f1.isFile() || !f2.isFile()) {
|
||||
return -1;
|
||||
}
|
||||
// http://stackoverflow.com/questions/203030/best-way-to-list-files-in-java-sorted-by-date-modified
|
||||
int result = sortType == 0 ? f1.getName().compareToIgnoreCase(f2.getName()) : // use name by default
|
||||
Long.valueOf(f1.lastModified()).compareTo(f2.lastModified()); // use date if there is a flag
|
||||
if (sortType == 1) {
|
||||
result = -result; // flip date for newest first instead of oldest first
|
||||
}
|
||||
return result;
|
||||
}
|
||||
});
|
||||
|
||||
actor.print("Available schematics (Filename (Format)):");
|
||||
actor.print(listFiles("", files));
|
||||
}
|
||||
|
||||
private String listFiles(final String prefix, final File[] files) {
|
||||
final StringBuilder build = new StringBuilder();
|
||||
for (final File file : files) {
|
||||
if (file.isDirectory()) {
|
||||
build.append(listFiles(prefix + file.getName() + "/", file.listFiles()));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!file.isFile()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
build.append("\n\u00a79");
|
||||
final ClipboardFormat format = ClipboardFormat.findByFile(file);
|
||||
build.append(prefix).append(file.getName()).append(": ").append(format == null ? "Unknown" : format.name());
|
||||
}
|
||||
return build.toString();
|
||||
}
|
||||
|
||||
public static Class<?> inject() {
|
||||
return SchematicCommands.class;
|
||||
}
|
||||
}
|
130
src/com/sk89q/worldedit/command/ScriptingCommands.java
Normal file
130
src/com/sk89q/worldedit/command/ScriptingCommands.java
Normal file
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.command;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.sk89q.minecraft.util.commands.Logging.LogMode.ALL;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import com.boydti.fawe.util.SetBlockQueue;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.sk89q.minecraft.util.commands.Command;
|
||||
import com.sk89q.minecraft.util.commands.CommandContext;
|
||||
import com.sk89q.minecraft.util.commands.CommandPermissions;
|
||||
import com.sk89q.minecraft.util.commands.Logging;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.LocalSession;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
|
||||
/**
|
||||
* Commands related to scripting.
|
||||
*/
|
||||
public class ScriptingCommands {
|
||||
|
||||
private final WorldEdit worldEdit;
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param worldEdit reference to WorldEdit
|
||||
*/
|
||||
public ScriptingCommands(final WorldEdit worldEdit) {
|
||||
checkNotNull(worldEdit);
|
||||
this.worldEdit = worldEdit;
|
||||
}
|
||||
|
||||
@Command(aliases = { "cs" }, usage = "<filename> [args...]", desc = "Execute a CraftScript", min = 1, max = -1)
|
||||
@CommandPermissions("worldedit.scripting.execute")
|
||||
@Logging(ALL)
|
||||
public void execute(final Player player, final LocalSession session, final EditSession editSession, final CommandContext args) throws WorldEditException {
|
||||
final String[] scriptArgs = args.getSlice(1);
|
||||
final String name = args.getString(0);
|
||||
|
||||
if (!player.hasPermission("worldedit.scripting.execute." + name)) {
|
||||
player.printError("You don't have permission to use that script.");
|
||||
return;
|
||||
}
|
||||
|
||||
session.setLastScript(name);
|
||||
|
||||
final File dir = worldEdit.getWorkingDirectoryFile(worldEdit.getConfiguration().scriptsDir);
|
||||
final File f = worldEdit.getSafeOpenFile(player, dir, name, "js", "js");
|
||||
SetBlockQueue.IMP.addTask(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
TaskManager.IMP.async(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
worldEdit.runScript(player, f, scriptArgs);
|
||||
} catch (final WorldEditException ex) {
|
||||
player.printError("Error while executing CraftScript.");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Command(aliases = { ".s" }, usage = "[args...]", desc = "Execute last CraftScript", min = 0, max = -1)
|
||||
@CommandPermissions("worldedit.scripting.execute")
|
||||
@Logging(ALL)
|
||||
public void executeLast(final Player player, final LocalSession session, final EditSession editSession, final CommandContext args) throws WorldEditException {
|
||||
final String lastScript = session.getLastScript();
|
||||
|
||||
if (!player.hasPermission("worldedit.scripting.execute." + lastScript)) {
|
||||
player.printError("You don't have permission to use that script.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (lastScript == null) {
|
||||
player.printError("Use /cs with a script name first.");
|
||||
return;
|
||||
}
|
||||
|
||||
final String[] scriptArgs = args.getSlice(0);
|
||||
|
||||
final File dir = worldEdit.getWorkingDirectoryFile(worldEdit.getConfiguration().scriptsDir);
|
||||
final File f = worldEdit.getSafeOpenFile(player, dir, lastScript, "js", "js");
|
||||
|
||||
SetBlockQueue.IMP.addTask(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
TaskManager.IMP.async(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
worldEdit.runScript(player, f, scriptArgs);
|
||||
} catch (final WorldEditException ex) {
|
||||
player.printError("Error while executing CraftScript.");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static Class<?> inject() {
|
||||
return ScriptingCommands.class;
|
||||
}
|
||||
}
|
112
src/com/sk89q/worldedit/function/operation/Operations.java
Normal file
112
src/com/sk89q/worldedit/function/operation/Operations.java
Normal file
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.function.operation;
|
||||
|
||||
import com.boydti.fawe.util.SetBlockQueue;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.sk89q.worldedit.MaxChangedBlocksException;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
|
||||
/**
|
||||
* Operation helper methods.
|
||||
*/
|
||||
public final class Operations {
|
||||
|
||||
private Operations() {}
|
||||
|
||||
/**
|
||||
* Complete a given operation synchronously until it completes.
|
||||
*
|
||||
* @param op operation to execute
|
||||
* @throws WorldEditException WorldEdit exception
|
||||
*/
|
||||
public static void complete(Operation operation) throws WorldEditException {
|
||||
while (operation != null) {
|
||||
operation = operation.resume(new RunContext());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete a given operation synchronously until it completes. Catch all
|
||||
* errors that is not {@link MaxChangedBlocksException} for legacy reasons.
|
||||
*
|
||||
* @param op operation to execute
|
||||
* @throws MaxChangedBlocksException thrown when too many blocks have been changed
|
||||
*/
|
||||
public static void completeLegacy(Operation operation) throws MaxChangedBlocksException {
|
||||
try {
|
||||
while (operation != null) {
|
||||
operation = operation.resume(new RunContext());
|
||||
}
|
||||
} catch (final WorldEditException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete a given operation synchronously until it completes. Re-throw all
|
||||
* {@link com.sk89q.worldedit.WorldEditException} exceptions as
|
||||
* {@link java.lang.RuntimeException}s.
|
||||
*
|
||||
* @param op operation to execute
|
||||
*/
|
||||
public static void completeBlindly(Operation operation) {
|
||||
try {
|
||||
while (operation != null) {
|
||||
operation = operation.resume(new RunContext());
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static void completeSmart(final Operation op, final Runnable whenDone, final boolean threadsafe) {
|
||||
if (!threadsafe) {
|
||||
completeBlindly(op);
|
||||
if (whenDone != null) {
|
||||
whenDone.run();
|
||||
}
|
||||
return;
|
||||
}
|
||||
SetBlockQueue.IMP.addTask(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
TaskManager.IMP.async(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Operation operation = op;
|
||||
while (operation != null) {
|
||||
try {
|
||||
operation = operation.resume(new RunContext());
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
TaskManager.IMP.task(whenDone);
|
||||
}
|
||||
});
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
public static Class<?> inject() {
|
||||
return Operations.class;
|
||||
}
|
||||
}
|
187
src/com/sk89q/worldedit/function/visitor/BreadthFirstSearch.java
Normal file
187
src/com/sk89q/worldedit/function/visitor/BreadthFirstSearch.java
Normal file
@ -0,0 +1,187 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.function.visitor;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
|
||||
import com.sk89q.worldedit.BlockVector;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.function.RegionFunction;
|
||||
import com.sk89q.worldedit.function.operation.Operation;
|
||||
import com.sk89q.worldedit.function.operation.Operations;
|
||||
import com.sk89q.worldedit.function.operation.RunContext;
|
||||
|
||||
/**
|
||||
* Performs a breadth-first search starting from points added with
|
||||
* {@link #visit(com.sk89q.worldedit.Vector)}. The search continues
|
||||
* to a certain adjacent point provided that the method
|
||||
* {@link #isVisitable(com.sk89q.worldedit.Vector, com.sk89q.worldedit.Vector)}
|
||||
* returns true for that point.
|
||||
*
|
||||
* <p>As an abstract implementation, this class can be used to implement
|
||||
* functionality that starts at certain points and extends outward from
|
||||
* those points.</p>
|
||||
*/
|
||||
public abstract class BreadthFirstSearch implements Operation {
|
||||
|
||||
private final RegionFunction function;
|
||||
private final Queue<BlockVector> queue = new ArrayDeque<BlockVector>();
|
||||
private final Set<BlockVector> visited = new HashSet<BlockVector>();
|
||||
private final List<Vector> directions = new ArrayList<Vector>();
|
||||
private int affected = 0;
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param function the function to apply to visited blocks
|
||||
*/
|
||||
protected BreadthFirstSearch(final RegionFunction function) {
|
||||
checkNotNull(function);
|
||||
this.function = function;
|
||||
addAxes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of directions will be visited.
|
||||
*
|
||||
* <p>Directions are {@link com.sk89q.worldedit.Vector}s that determine
|
||||
* what adjacent points area available. Vectors should not be
|
||||
* unit vectors. An example of a valid direction is
|
||||
* {@code new Vector(1, 0, 1)}.</p>
|
||||
*
|
||||
* <p>The list of directions can be cleared.</p>
|
||||
*
|
||||
* @return the list of directions
|
||||
*/
|
||||
protected Collection<Vector> getDirections() {
|
||||
return directions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the directions along the axes as directions to visit.
|
||||
*/
|
||||
protected void addAxes() {
|
||||
directions.add(new Vector(0, -1, 0));
|
||||
directions.add(new Vector(0, 1, 0));
|
||||
directions.add(new Vector(-1, 0, 0));
|
||||
directions.add(new Vector(1, 0, 0));
|
||||
directions.add(new Vector(0, 0, -1));
|
||||
directions.add(new Vector(0, 0, 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the diagonal directions as directions to visit.
|
||||
*/
|
||||
protected void addDiagonal() {
|
||||
directions.add(new Vector(1, 0, 1));
|
||||
directions.add(new Vector(-1, 0, -1));
|
||||
directions.add(new Vector(1, 0, -1));
|
||||
directions.add(new Vector(-1, 0, 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given location to the list of locations to visit, provided
|
||||
* that it has not been visited. The position passed to this method
|
||||
* will still be visited even if it fails
|
||||
* {@link #isVisitable(com.sk89q.worldedit.Vector, com.sk89q.worldedit.Vector)}.
|
||||
*
|
||||
* <p>This method should be used before the search begins, because if
|
||||
* the position <em>does</em> fail the test, and the search has already
|
||||
* visited it (because it is connected to another root point),
|
||||
* the search will mark the position as "visited" and a call to this
|
||||
* method will do nothing.</p>
|
||||
*
|
||||
* @param position the position
|
||||
*/
|
||||
public void visit(final Vector position) {
|
||||
final BlockVector blockVector = position.toBlockVector();
|
||||
if (!visited.contains(blockVector)) {
|
||||
queue.add(blockVector);
|
||||
visited.add(blockVector);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to visit the given 'to' location.
|
||||
*
|
||||
* @param from the origin block
|
||||
* @param to the block under question
|
||||
*/
|
||||
private void visit(final Vector from, final Vector to) {
|
||||
final BlockVector blockVector = to.toBlockVector();
|
||||
if (!visited.contains(blockVector)) {
|
||||
visited.add(blockVector);
|
||||
if (isVisitable(from, to)) {
|
||||
queue.add(blockVector);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the given 'to' block should be visited, starting from the
|
||||
* 'from' block.
|
||||
*
|
||||
* @param from the origin block
|
||||
* @param to the block under question
|
||||
* @return true if the 'to' block should be visited
|
||||
*/
|
||||
protected abstract boolean isVisitable(final Vector from, final Vector to);
|
||||
|
||||
/**
|
||||
* Get the number of affected objects.
|
||||
*
|
||||
* @return the number of affected
|
||||
*/
|
||||
public int getAffected() {
|
||||
return affected;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Operation resume(final RunContext run) throws WorldEditException {
|
||||
Vector position;
|
||||
while ((position = queue.poll()) != null) {
|
||||
if (function.apply(position)) {
|
||||
affected++;
|
||||
}
|
||||
|
||||
for (final Vector dir : directions) {
|
||||
visit(position, position.add(dir));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {}
|
||||
|
||||
public static Class<?> inject() {
|
||||
return Operations.class;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.function.visitor;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.function.RegionFunction;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.function.operation.Operations;
|
||||
|
||||
/**
|
||||
* Visits adjacent points on the same X-Z plane as long as the points
|
||||
* pass the given mask, and then executes the provided region
|
||||
* function on the entire column.
|
||||
*
|
||||
* <p>This is used by {@code //fill}.</p>
|
||||
*/
|
||||
public class DownwardVisitor extends RecursiveVisitor {
|
||||
|
||||
private final int baseY;
|
||||
|
||||
/**
|
||||
* Create a new visitor.
|
||||
*
|
||||
* @param mask the mask
|
||||
* @param function the function
|
||||
* @param baseY the base Y
|
||||
*/
|
||||
public DownwardVisitor(final Mask mask, final RegionFunction function, final int baseY) {
|
||||
super(mask, function);
|
||||
checkNotNull(mask);
|
||||
|
||||
this.baseY = baseY;
|
||||
|
||||
final Collection<Vector> directions = getDirections();
|
||||
directions.clear();
|
||||
directions.add(new Vector(1, 0, 0));
|
||||
directions.add(new Vector(-1, 0, 0));
|
||||
directions.add(new Vector(0, 0, 1));
|
||||
directions.add(new Vector(0, 0, -1));
|
||||
directions.add(new Vector(0, -1, 0));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isVisitable(final Vector from, final Vector to) {
|
||||
final int fromY = from.getBlockY();
|
||||
return ((fromY == baseY) || (to.subtract(from).getBlockY() < 0)) && super.isVisitable(from, to);
|
||||
}
|
||||
|
||||
public static Class<?> inject() {
|
||||
return Operations.class;
|
||||
}
|
||||
}
|
80
src/com/sk89q/worldedit/function/visitor/EntityVisitor.java
Normal file
80
src/com/sk89q/worldedit/function/visitor/EntityVisitor.java
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.function.visitor;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.entity.Entity;
|
||||
import com.sk89q.worldedit.function.EntityFunction;
|
||||
import com.sk89q.worldedit.function.operation.Operation;
|
||||
import com.sk89q.worldedit.function.operation.Operations;
|
||||
import com.sk89q.worldedit.function.operation.RunContext;
|
||||
|
||||
/**
|
||||
* Visits entities as provided by an {@code Iterator}.
|
||||
*/
|
||||
public class EntityVisitor implements Operation {
|
||||
|
||||
private final EntityFunction function;
|
||||
private final int affected = 0;
|
||||
private final Iterator<? extends Entity> iterator;
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param iterator the iterator
|
||||
* @param function the function
|
||||
*/
|
||||
public EntityVisitor(final Iterator<? extends Entity> iterator, final EntityFunction function) {
|
||||
checkNotNull(iterator);
|
||||
checkNotNull(function);
|
||||
|
||||
this.function = function;
|
||||
this.iterator = iterator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of affected objects.
|
||||
*
|
||||
* @return the number of affected
|
||||
*/
|
||||
public int getAffected() {
|
||||
return affected;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Operation resume(final RunContext run) throws WorldEditException {
|
||||
while (iterator.hasNext()) {
|
||||
function.apply(iterator.next());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {}
|
||||
|
||||
public static Class<?> inject() {
|
||||
return Operations.class;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.function.visitor;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.sk89q.worldedit.Vector2D;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.function.FlatRegionFunction;
|
||||
import com.sk89q.worldedit.function.operation.Operation;
|
||||
import com.sk89q.worldedit.function.operation.Operations;
|
||||
import com.sk89q.worldedit.function.operation.RunContext;
|
||||
import com.sk89q.worldedit.regions.FlatRegion;
|
||||
|
||||
/**
|
||||
* Applies region functions to columns in a {@link FlatRegion}.
|
||||
*/
|
||||
public class FlatRegionVisitor implements Operation {
|
||||
|
||||
private final FlatRegionFunction function;
|
||||
private final int affected = 0;
|
||||
private final Iterable<Vector2D> iterator;
|
||||
|
||||
/**
|
||||
* Create a new visitor.
|
||||
*
|
||||
* @param flatRegion a flat region
|
||||
* @param function a function to apply to columns
|
||||
*/
|
||||
public FlatRegionVisitor(final FlatRegion flatRegion, final FlatRegionFunction function) {
|
||||
checkNotNull(flatRegion);
|
||||
checkNotNull(function);
|
||||
this.function = function;
|
||||
iterator = flatRegion.asFlatRegion();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of affected objects.
|
||||
*
|
||||
* @return the number of affected
|
||||
*/
|
||||
public int getAffected() {
|
||||
return affected;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Operation resume(final RunContext run) throws WorldEditException {
|
||||
for (final Vector2D pt : iterator) {
|
||||
function.apply(pt);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {}
|
||||
|
||||
public static Class<?> inject() {
|
||||
return Operations.class;
|
||||
}
|
||||
|
||||
}
|
130
src/com/sk89q/worldedit/function/visitor/LayerVisitor.java
Normal file
130
src/com/sk89q/worldedit/function/visitor/LayerVisitor.java
Normal file
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.function.visitor;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.Vector2D;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.function.LayerFunction;
|
||||
import com.sk89q.worldedit.function.mask.Mask2D;
|
||||
import com.sk89q.worldedit.function.mask.Masks;
|
||||
import com.sk89q.worldedit.function.operation.Operation;
|
||||
import com.sk89q.worldedit.function.operation.Operations;
|
||||
import com.sk89q.worldedit.function.operation.RunContext;
|
||||
import com.sk89q.worldedit.regions.FlatRegion;
|
||||
|
||||
/**
|
||||
* Visits the layers within a region.
|
||||
*
|
||||
* <p>This class works by iterating over all the columns in a {@link FlatRegion},
|
||||
* finding the first ground block in each column (searching from a given
|
||||
* maximum Y down to a minimum Y), and then applies a {@link LayerFunction} to
|
||||
* each layer.</p>
|
||||
*/
|
||||
public class LayerVisitor implements Operation {
|
||||
|
||||
private final LayerFunction function;
|
||||
private Mask2D mask = Masks.alwaysTrue2D();
|
||||
private final int minY;
|
||||
private final int maxY;
|
||||
private final Iterable<Vector2D> iterator;
|
||||
|
||||
/**
|
||||
* Create a new visitor.
|
||||
*
|
||||
* @param flatRegion the flat region to visit
|
||||
* @param minY the minimum Y to stop the search at
|
||||
* @param maxY the maximum Y to begin the search at
|
||||
* @param function the layer function to apply t blocks
|
||||
*/
|
||||
public LayerVisitor(final FlatRegion flatRegion, final int minY, final int maxY, final LayerFunction function) {
|
||||
checkNotNull(flatRegion);
|
||||
checkArgument(minY <= maxY, "minY <= maxY required");
|
||||
checkNotNull(function);
|
||||
this.minY = minY;
|
||||
this.maxY = maxY;
|
||||
this.function = function;
|
||||
iterator = flatRegion.asFlatRegion();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mask that determines which columns within the flat region
|
||||
* will be visited.
|
||||
*
|
||||
* @return a 2D mask
|
||||
*/
|
||||
public Mask2D getMask() {
|
||||
return mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the mask that determines which columns within the flat region
|
||||
* will be visited.
|
||||
*
|
||||
* @param mask a 2D mask
|
||||
*/
|
||||
public void setMask(final Mask2D mask) {
|
||||
checkNotNull(mask);
|
||||
this.mask = mask;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Operation resume(final RunContext run) throws WorldEditException {
|
||||
for (final Vector2D column : iterator) {
|
||||
if (!mask.test(column)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Abort if we are underground
|
||||
if (function.isGround(column.toVector(maxY + 1))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
boolean found = false;
|
||||
int groundY = 0;
|
||||
for (int y = maxY; y >= minY; --y) {
|
||||
final Vector test = column.toVector(y);
|
||||
if (!found) {
|
||||
if (function.isGround(test)) {
|
||||
found = true;
|
||||
groundY = y;
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
if (!function.apply(test, groundY - y)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {}
|
||||
|
||||
public static Class<?> inject() {
|
||||
return Operations.class;
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.function.visitor;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.function.RegionFunction;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.function.operation.Operations;
|
||||
|
||||
/**
|
||||
* A {@link RecursiveVisitor} that goes orthogonally to the side and down, but never up.
|
||||
*/
|
||||
public class NonRisingVisitor extends RecursiveVisitor {
|
||||
|
||||
/**
|
||||
* Create a new recursive visitor.
|
||||
*
|
||||
* @param mask the mask
|
||||
* @param function the function
|
||||
*/
|
||||
public NonRisingVisitor(final Mask mask, final RegionFunction function) {
|
||||
super(mask, function);
|
||||
final Collection<Vector> directions = getDirections();
|
||||
directions.clear();
|
||||
directions.add(new Vector(1, 0, 0));
|
||||
directions.add(new Vector(-1, 0, 0));
|
||||
directions.add(new Vector(0, 0, 1));
|
||||
directions.add(new Vector(0, 0, -1));
|
||||
directions.add(new Vector(0, -1, 0));
|
||||
}
|
||||
|
||||
public static Class<?> inject() {
|
||||
return Operations.class;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.function.visitor;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.function.RegionFunction;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.function.operation.Operations;
|
||||
|
||||
/**
|
||||
* An implementation of an {@link BreadthFirstSearch} that uses a mask to
|
||||
* determine where a block should be visited.
|
||||
*/
|
||||
public class RecursiveVisitor extends BreadthFirstSearch {
|
||||
|
||||
private final Mask mask;
|
||||
|
||||
/**
|
||||
* Create a new recursive visitor.
|
||||
*
|
||||
* @param mask the mask
|
||||
* @param function the function
|
||||
*/
|
||||
public RecursiveVisitor(final Mask mask, final RegionFunction function) {
|
||||
super(function);
|
||||
checkNotNull(mask);
|
||||
this.mask = mask;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isVisitable(final Vector from, final Vector to) {
|
||||
return mask.test(to);
|
||||
}
|
||||
|
||||
public static Class<?> inject() {
|
||||
return Operations.class;
|
||||
}
|
||||
}
|
72
src/com/sk89q/worldedit/function/visitor/RegionVisitor.java
Normal file
72
src/com/sk89q/worldedit/function/visitor/RegionVisitor.java
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.function.visitor;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.sk89q.worldedit.BlockVector;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.function.RegionFunction;
|
||||
import com.sk89q.worldedit.function.operation.Operation;
|
||||
import com.sk89q.worldedit.function.operation.Operations;
|
||||
import com.sk89q.worldedit.function.operation.RunContext;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
|
||||
/**
|
||||
* Utility class to apply region functions to {@link com.sk89q.worldedit.regions.Region}.
|
||||
*/
|
||||
public class RegionVisitor implements Operation {
|
||||
|
||||
private final RegionFunction function;
|
||||
private final int affected = 0;
|
||||
|
||||
private final Iterator<BlockVector> iterator;
|
||||
|
||||
public RegionVisitor(final Region region, final RegionFunction function) {
|
||||
this.function = function;
|
||||
iterator = region.iterator();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of affected objects.
|
||||
*
|
||||
* @return the number of affected
|
||||
*/
|
||||
public int getAffected() {
|
||||
return affected;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Operation resume(final RunContext run) throws WorldEditException {
|
||||
while (iterator.hasNext()) {
|
||||
function.apply(iterator.next());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {}
|
||||
|
||||
public static Class<?> inject() {
|
||||
return Operations.class;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user