Finish with sponge depend

Also fix 1.8 issue for kh498
This commit is contained in:
Jesse Boyd 2016-04-03 02:50:50 +10:00
parent fb8863cd06
commit 789098dc79
56 changed files with 4373 additions and 507 deletions

View File

@ -10,7 +10,7 @@ buildscript {
}
group = 'com.boydti.fawe'
version = '3.3.4'
version = '3.3.5'
description = """FastAsyncWorldEdit"""
subprojects {

View File

@ -1,6 +1,6 @@
name: FastAsyncWorldEdit
main: com.boydti.fawe.bukkit.FaweBukkit
version: 3.3.4
version: 3.3.5
description: Fast Async WorldEdit plugin
authors: [Empire92]
loadbefore: [WorldEdit]

View File

@ -28,13 +28,18 @@ import java.io.File;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;
public class FaweBukkit extends JavaPlugin implements IFawe {
public class FaweBukkit extends JavaPlugin implements IFawe, Listener {
private VaultUtil vault;
private WorldEditPlugin worldedit;
@ -53,6 +58,7 @@ public class FaweBukkit extends JavaPlugin implements IFawe {
@Override
public void onEnable() {
try {
Bukkit.getPluginManager().registerEvents(this, this);
Fawe.set(this);
try {
final Class<?> clazz = Class.forName("org.spigotmc.AsyncCatcher");
@ -85,9 +91,16 @@ public class FaweBukkit extends JavaPlugin implements IFawe {
@Override
public FawePlayer<Player> wrap(final Object obj) {
if (obj.getClass() == String.class) {
return new BukkitPlayer(Bukkit.getPlayer((String) obj));
String name = (String) obj;
FawePlayer existing = Fawe.get().getCachedPlayer(name);
if (existing != null) {
return existing;
}
return new BukkitPlayer(Bukkit.getPlayer(name));
} else if (obj instanceof Player) {
return new BukkitPlayer((Player) obj);
Player player = (Player) obj;
FawePlayer existing = Fawe.get().getCachedPlayer(player.getName());
return existing != null ? existing : new BukkitPlayer(player);
} else {
return null;
}
@ -100,6 +113,15 @@ public class FaweBukkit extends JavaPlugin implements IFawe {
debug("&6Metrics enabled.");
}
@Override
public Set<FawePlayer> getPlayers() {
HashSet<FawePlayer> players = new HashSet<>();
for (Player player : Bukkit.getServer().getOnlinePlayers()) {
players.add(wrap(player));
}
return players;
}
/**
* Kinda a really messy class I just copied over from an old project<br>
* - Still works, so cbf cleaning it up<br>
@ -300,4 +322,9 @@ public class FaweBukkit extends JavaPlugin implements IFawe {
}
return managers;
}
@EventHandler
public void onPlayerQuit(PlayerQuitEvent event) {
Fawe.get().unregister(event.getPlayer().getName());
}
}

View File

@ -1,13 +1,12 @@
package com.boydti.fawe.logging;
import org.PrimeSoft.blocksHub.BlocksHub;
import org.PrimeSoft.blocksHub.IBlocksHubApi;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
package com.boydti.fawe.bukkit.logging;
import com.boydti.fawe.object.FawePlayer;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.history.changeset.ChangeSet;
import org.PrimeSoft.blocksHub.BlocksHub;
import org.PrimeSoft.blocksHub.IBlocksHubApi;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
public class BlocksHubHook {
private final BlocksHub hub;

View File

@ -1,15 +1,4 @@
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;
package com.boydti.fawe.bukkit.logging;
import com.boydti.fawe.object.FawePlayer;
import com.sk89q.worldedit.Vector;
@ -25,9 +14,18 @@ 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;
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 static com.google.common.base.Preconditions.checkNotNull;
/**
* Stores changes to a {@link ChangeSet}.
* Stores changes to a {@link com.sk89q.worldedit.history.changeset.ChangeSet}.
* Logs changes to BlocksHub
*/
public class LoggingExtent extends AbstractDelegateExtent {

View File

@ -1,11 +1,11 @@
package com.boydti.fawe.bukkit.v0;
import com.boydti.fawe.logging.BlocksHubHook;
import com.boydti.fawe.bukkit.logging.BlocksHubHook;
import com.boydti.fawe.object.EditSessionWrapper;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.changeset.FaweChangeSet;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.history.changeset.ChangeSet;
public class BukkitEditSessionWrapper_0 extends EditSessionWrapper {
@ -20,7 +20,7 @@ public class BukkitEditSessionWrapper_0 extends EditSessionWrapper {
}
@Override
public Extent getHistoryExtent(final Extent parent, final ChangeSet set, final FawePlayer<?> player) {
public Extent getHistoryExtent(final Extent parent, final FaweChangeSet set, final FawePlayer<?> player) {
if (this.hook != null) {
// If we are doing logging, return a custom logging extent
return this.hook.getLoggingExtent(parent, set, player);

View File

@ -1,31 +1,5 @@
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;
@ -40,11 +14,36 @@ 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.boydti.fawe.util.TaskManager;
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;
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.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 static com.boydti.fawe.util.ReflectionUtils.getRefClass;
public class BukkitQueue_1_8 extends BukkitQueue_0 {
@ -116,60 +115,35 @@ public class BukkitQueue_1_8 extends BukkitQueue_0 {
@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) {
final 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);
sendChunk(fc);
}
return new ArrayList<>();
}
public void sendChunk(FaweChunk<Chunk> fc) {
fixLighting(fc, Settings.FIX_ALL_LIGHTING);
Chunk chunk = fc.getChunk();
World world = chunk.getWorld();
final int view = Bukkit.getServer().getViewDistance();
int cx = chunk.getX();
int cz = chunk.getZ();
for (final Player player : Bukkit.getOnlinePlayers()) {
final String world = player.getWorld().getName();
final ArrayList<FaweChunk<Chunk>> list = map.get(world);
if (list == null) {
if (!player.getWorld().equals(world)) {
continue;
}
final Location loc = player.getLocation();
final int cx = loc.getBlockX() >> 4;
final int cz = loc.getBlockZ() >> 4;
final int px = loc.getBlockX() >> 4;
final int pz = loc.getBlockZ() >> 4;
if ((Math.abs(cx - px) > view) || (Math.abs(cz - pz) > view)) {
continue;
}
final Object entity = this.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;
}
final RefExecutor con = this.send.of(this.connection.of(entity).get());
Object packet = packets.get(fc);
if (packet == null) {
final Object c = this.methodGetHandleChunk.of(fc.getChunk()).call();
packet = this.MapChunk.create(c, true, 65535);
packets.put(fc, packet);
con.call(packet);
} else {
con.call(packet);
}
}
final RefExecutor con = this.send.of(this.connection.of(entity).get());
final Object c = this.methodGetHandleChunk.of(fc.getChunk()).call();
Object packet = this.MapChunk.create(c, false, 65535);
con.call(packet);
}
final HashSet<FaweChunk<Chunk>> chunks = new HashSet<FaweChunk<Chunk>>();
for (final FaweChunk<Chunk> fc : fcs) {
final Chunk chunk = fc.getChunk();
chunk.unload(true, false);
chunk.load();
final ChunkLoc loc = fc.getChunkLoc();
chunk.getWorld().refreshChunk(loc.x, loc.z);
if (!this.fixLighting(fc, Settings.FIX_ALL_LIGHTING)) {
chunks.add(fc);
}
}
return chunks;
}
@Override
@ -424,6 +398,13 @@ public class BukkitQueue_1_8 extends BukkitQueue_0 {
// Clear
fs.clear();
TaskManager.IMP.later(new Runnable() {
@Override
public void run() {
sendChunk(fs);
}
}, 1);
return true;
} catch (final Exception e) {
e.printStackTrace();

View File

@ -1,6 +1,6 @@
name: FastAsyncWorldEdit
main: com.boydti.fawe.bukkit.FaweBukkit
version: 3.3.4
version: 3.3.5
description: Fast Async WorldEdit plugin
authors: [Empire92]
loadbefore: [WorldEdit]

View File

@ -1,23 +1,13 @@
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.object.FawePlayer;
import com.boydti.fawe.regions.general.PlotSquaredFeature;
import com.boydti.fawe.util.Lag;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.MemUtil;
@ -42,6 +32,17 @@ import com.sk89q.worldedit.function.visitor.RecursiveVisitor;
import com.sk89q.worldedit.function.visitor.RegionVisitor;
import com.sk89q.worldedit.history.change.EntityCreate;
import com.sk89q.worldedit.history.change.EntityRemove;
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 java.util.concurrent.ConcurrentHashMap;
import javax.management.InstanceAlreadyExistsException;
import javax.management.Notification;
import javax.management.NotificationEmitter;
import javax.management.NotificationListener;
/**[ WorldEdit action]
* |
@ -159,6 +160,9 @@ public class Fawe {
public void run() {
// worldedit
WEManager.IMP.managers.addAll(Fawe.this.IMP.getMaskManagers());
try {
WEManager.IMP.managers.add(new PlotSquaredFeature());
} catch (Throwable e) {}
Fawe.this.worldedit = WorldEdit.getInstance();
// Events
Fawe.this.setupEvents();
@ -258,6 +262,20 @@ public class Fawe {
return this.thread;
}
private ConcurrentHashMap<String, FawePlayer> players = new ConcurrentHashMap<>();
public <T> void register(FawePlayer<T> player) {
players.put(player.getName(), player);
}
public <T> void unregister(String name) {
players.remove(name);
}
public FawePlayer getCachedPlayer(String name) {
return players.get(name);
}
/*
* TODO FIXME
* - Async packet sending

View File

@ -1,8 +1,5 @@
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;
@ -10,6 +7,9 @@ import com.boydti.fawe.regions.FaweMaskManager;
import com.boydti.fawe.util.FaweQueue;
import com.boydti.fawe.util.TaskManager;
import com.sk89q.worldedit.EditSession;
import java.io.File;
import java.util.Collection;
import java.util.Set;
public interface IFawe {
public void debug(final String s);
@ -35,4 +35,6 @@ public interface IFawe {
public Collection<FaweMaskManager> getMaskManagers();
public void startMetrics();
public Set<FawePlayer> getPlayers();
}

View File

@ -1,17 +1,14 @@
package com.boydti.fawe.config;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.util.StringMan;
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;
import com.boydti.fawe.configuration.file.YamlConfiguration;
public enum BBC {
@ -191,15 +188,6 @@ public enum BBC {
return this.prefix;
}
/**
* @return translated and color decoded
*
* @see org.bukkit.ChatColor#translateAlternateColorCodes(char, String)
*/
public String translated() {
return ChatColor.translateAlternateColorCodes('&', this.s());
}
public String getCat() {
return this.cat;
}

View File

@ -8,7 +8,7 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.bukkit.configuration.file.YamlConfiguration;
import com.boydti.fawe.configuration.file.YamlConfiguration;
import com.sk89q.worldedit.LocalSession;
@ -26,6 +26,7 @@ public class Settings {
public static boolean ENABLE_HARD_LIMIT = true;
public static boolean STORE_HISTORY_ON_DISK = false;
public static boolean COMPRESS_HISTORY = false;
public static boolean METRICS = true;
public static void setup(final File file) {
if (!file.exists()) {
@ -51,6 +52,7 @@ public class Settings {
options.put("fix-all-lighting", FIX_ALL_LIGHTING);
options.put("history.use-disk", STORE_HISTORY_ON_DISK);
options.put("history.compress", COMPRESS_HISTORY);
options.put("metrics", METRICS);
for (final Entry<String, Object> node : options.entrySet()) {
if (!config.contains(node.getKey())) {
@ -67,6 +69,7 @@ public class Settings {
REQUIRE_SELECTION = config.getBoolean("require-selection-in-mask");
WE_BLACKLIST = config.getStringList("command-blacklist");
ENABLE_HARD_LIMIT = config.getBoolean("crash-mitigation");
METRICS = config.getBoolean("metrics");
COMPRESS_HISTORY = config.getBoolean("history.compress");
if (STORE_HISTORY_ON_DISK = config.getBoolean("history.use-disk")) {
LocalSession.MAX_HISTORY_SIZE = Integer.MAX_VALUE;

View File

@ -0,0 +1,86 @@
package com.boydti.fawe.configuration;
import com.boydti.fawe.configuration.ConfigurationOptions;
import com.boydti.fawe.configuration.ConfigurationSection;
import java.util.Map;
/**
* Represents a source of configurable options and settings
*/
public interface Configuration extends ConfigurationSection {
/**
* Sets the default value of the given path as provided.
* <p>
* If no source {@link com.boydti.fawe.configuration.Configuration} was provided as a default
* collection, then a new {@link com.boydti.fawe.configuration.MemoryConfiguration} will be created to
* hold the new default value.
* <p>
* If value is null, the value will be removed from the default
* Configuration source.
*
* @param path Path of the value to set.
* @param value Value to set the default to.
* @throws IllegalArgumentException Thrown if path is null.
*/
@Override void addDefault(final String path, final Object value);
/**
* Sets the default values of the given paths as provided.
* <p>
* If no source {@link com.boydti.fawe.configuration.Configuration} was provided as a default
* collection, then a new {@link com.boydti.fawe.configuration.MemoryConfiguration} will be created to
* hold the new default values.
*
* @param defaults A map of Path->Values to add to defaults.
* @throws IllegalArgumentException Thrown if defaults is null.
*/
void addDefaults(final Map<String, Object> defaults);
/**
* Sets the default values of the given paths as provided.
* <p>
* If no source {@link com.boydti.fawe.configuration.Configuration} was provided as a default
* collection, then a new {@link com.boydti.fawe.configuration.MemoryConfiguration} will be created to
* hold the new default value.
* <p>
* This method will not hold a reference to the specified Configuration,
* nor will it automatically update if that Configuration ever changes. If
* you require this, you should set the default source with {@link
* #setDefaults(com.boydti.fawe.configuration.Configuration)}.
*
* @param defaults A configuration holding a list of defaults to copy.
* @throws IllegalArgumentException Thrown if defaults is null or this.
*/
void addDefaults(final com.boydti.fawe.configuration.Configuration defaults);
/**
* Sets the source of all default values for this {@link com.boydti.fawe.configuration.Configuration}.
* <p>
* If a previous source was set, or previous default values were defined,
* then they will not be copied to the new source.
*
* @param defaults New source of default values for this configuration.
* @throws IllegalArgumentException Thrown if defaults is null or this.
*/
void setDefaults(final com.boydti.fawe.configuration.Configuration defaults);
/**
* Gets the source {@link com.boydti.fawe.configuration.Configuration} for this configuration.
* <p>
* If no configuration source was set, but default values were added, then
* a {@link com.boydti.fawe.configuration.MemoryConfiguration} will be returned. If no source was set
* and no defaults were set, then this method will return null.
*
* @return Configuration source for default values, or null if none exist.
*/
com.boydti.fawe.configuration.Configuration getDefaults();
/**
* Gets the {@link com.boydti.fawe.configuration.ConfigurationOptions} for this {@link com.boydti.fawe.configuration.Configuration}.
* <p>
* All setters through this method are chainable.
*
* @return Options for this configuration
*/
ConfigurationOptions options();
}

View File

@ -0,0 +1,92 @@
package com.boydti.fawe.configuration;
import com.boydti.fawe.configuration.Configuration;
/**
* Various settings for controlling the input and output of a {@link
* com.boydti.fawe.configuration.Configuration}
*/
public class ConfigurationOptions {
private char pathSeparator = '.';
private boolean copyDefaults = false;
private final Configuration configuration;
protected ConfigurationOptions(final Configuration configuration) {
this.configuration = configuration;
}
/**
* Returns the {@link com.boydti.fawe.configuration.Configuration} that this object is responsible for.
*
* @return Parent configuration
*/
public Configuration configuration() {
return configuration;
}
/**
* Gets the char that will be used to separate {@link
* com.boydti.fawe.configuration.ConfigurationSection}s
* <p>
* This value does not affect how the {@link com.boydti.fawe.configuration.Configuration} is stored,
* only in how you access the data. The default value is '.'.
*
* @return Path separator
*/
public char pathSeparator() {
return pathSeparator;
}
/**
* Sets the char that will be used to separate {@link
* com.boydti.fawe.configuration.ConfigurationSection}s
* <p>
* This value does not affect how the {@link com.boydti.fawe.configuration.Configuration} is stored,
* only in how you access the data. The default value is '.'.
*
* @param value Path separator
* @return This object, for chaining
*/
public com.boydti.fawe.configuration.ConfigurationOptions pathSeparator(final char value) {
pathSeparator = value;
return this;
}
/**
* Checks if the {@link com.boydti.fawe.configuration.Configuration} should copy values from its default
* {@link com.boydti.fawe.configuration.Configuration} directly.
* <p>
* If this is true, all values in the default Configuration will be
* directly copied, making it impossible to distinguish between values
* that were set and values that are provided by default. As a result,
* {@link com.boydti.fawe.configuration.ConfigurationSection#contains(String)} will always
* return the same value as {@link
* com.boydti.fawe.configuration.ConfigurationSection#isSet(String)}. The default value is
* false.
*
* @return Whether or not defaults are directly copied
*/
public boolean copyDefaults() {
return copyDefaults;
}
/**
* Sets if the {@link com.boydti.fawe.configuration.Configuration} should copy values from its default
* {@link com.boydti.fawe.configuration.Configuration} directly.
* <p>
* If this is true, all values in the default Configuration will be
* directly copied, making it impossible to distinguish between values
* that were set and values that are provided by default. As a result,
* {@link com.boydti.fawe.configuration.ConfigurationSection#contains(String)} will always
* return the same value as {@link
* com.boydti.fawe.configuration.ConfigurationSection#isSet(String)}. The default value is
* false.
*
* @param value Whether or not defaults are directly copied
* @return This object, for chaining
*/
public com.boydti.fawe.configuration.ConfigurationOptions copyDefaults(final boolean value) {
copyDefaults = value;
return this;
}
}

View File

@ -0,0 +1,646 @@
package com.boydti.fawe.configuration;
import com.boydti.fawe.configuration.Configuration;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Represents a section of a {@link com.boydti.fawe.configuration.Configuration}
*/
public interface ConfigurationSection {
/**
* Gets a set containing all keys in this section.
* <p>
* If deep is set to true, then this will contain all the keys within any
* child {@link com.boydti.fawe.configuration.ConfigurationSection}s (and their children, etc). These
* will be in a valid path notation for you to use.
* <p>
* If deep is set to false, then this will contain only the keys of any
* direct children, and not their own children.
*
* @param deep Whether or not to get a deep list, as opposed to a shallow
* list.
* @return Set of keys contained within this ConfigurationSection.
*/
Set<String> getKeys(boolean deep);
/**
* Gets a Map containing all keys and their values for this section.
* <p>
* If deep is set to true, then this will contain all the keys and values
* within any child {@link com.boydti.fawe.configuration.ConfigurationSection}s (and their children,
* etc). These keys will be in a valid path notation for you to use.
* <p>
* If deep is set to false, then this will contain only the keys and
* values of any direct children, and not their own children.
*
* @param deep Whether or not to get a deep list, as opposed to a shallow
* list.
* @return Map of keys and values of this section.
*/
Map<String, Object> getValues(boolean deep);
/**
* Checks if this {@link com.boydti.fawe.configuration.ConfigurationSection} contains the given path.
* <p>
* If the value for the requested path does not exist but a default value
* has been specified, this will return true.
*
* @param path Path to check for existence.
* @return True if this section contains the requested path, either via
* default or being set.
* @throws IllegalArgumentException Thrown when path is null.
*/
boolean contains(String path);
/**
* Checks if this {@link com.boydti.fawe.configuration.ConfigurationSection} has a value set for the
* given path.
* <p>
* If the value for the requested path does not exist but a default value
* has been specified, this will still return false.
*
* @param path Path to check for existence.
* @return True if this section contains the requested path, regardless of
* having a default.
* @throws IllegalArgumentException Thrown when path is null.
*/
boolean isSet(String path);
/**
* Gets the path of this {@link com.boydti.fawe.configuration.ConfigurationSection} from its root {@link
* com.boydti.fawe.configuration.Configuration}
* <p>
* For any {@link com.boydti.fawe.configuration.Configuration} themselves, this will return an empty
* string.
* <p>
* If the section is no longer contained within its root for any reason,
* such as being replaced with a different value, this may return null.
* <p>
* To retrieve the single name of this section, that is, the final part of
* the path returned by this method, you may use {@link #getName()}.
*
* @return Path of this section relative to its root
*/
String getCurrentPath();
/**
* Gets the name of this individual {@link com.boydti.fawe.configuration.ConfigurationSection}, in the
* path.
* <p>
* This will always be the final part of {@link #getCurrentPath()}, unless
* the section is orphaned.
*
* @return Name of this section
*/
String getName();
/**
* Gets the root {@link com.boydti.fawe.configuration.Configuration} that contains this {@link
* com.boydti.fawe.configuration.ConfigurationSection}
* <p>
* For any {@link com.boydti.fawe.configuration.Configuration} themselves, this will return its own
* object.
* <p>
* If the section is no longer contained within its root for any reason,
* such as being replaced with a different value, this may return null.
*
* @return Root configuration containing this section.
*/
Configuration getRoot();
/**
* Gets the parent {@link com.boydti.fawe.configuration.ConfigurationSection} that directly contains
* this {@link com.boydti.fawe.configuration.ConfigurationSection}.
* <p>
* For any {@link com.boydti.fawe.configuration.Configuration} themselves, this will return null.
* <p>
* If the section is no longer contained within its parent for any reason,
* such as being replaced with a different value, this may return null.
*
* @return Parent section containing this section.
*/
com.boydti.fawe.configuration.ConfigurationSection getParent();
/**
* Gets the requested Object by path.
* <p>
* If the Object does not exist but a default value has been specified,
* this will return the default value. If the Object does not exist and no
* default value was specified, this will return null.
*
* @param path Path of the Object to get.
* @return Requested Object.
*/
Object get(String path);
/**
* Gets the requested Object by path, returning a default value if not
* found.
* <p>
* If the Object does not exist then the specified default value will
* returned regardless of if a default has been identified in the root
* {@link com.boydti.fawe.configuration.Configuration}.
*
* @param path Path of the Object to get.
* @param def The default value to return if the path is not found.
* @return Requested Object.
*/
Object get(String path, Object def);
/**
* Sets the specified path to the given value.
* <p>
* If value is null, the entry will be removed. Any existing entry will be
* replaced, regardless of what the new value is.
* <p>
* Some implementations may have limitations on what you may store. See
* their individual javadoc for details. No implementations should allow
* you to store {@link com.boydti.fawe.configuration.Configuration}s or {@link com.boydti.fawe.configuration.ConfigurationSection}s,
* please use {@link #createSection(String)} for that.
*
* @param path Path of the object to set.
* @param value New value to set the path to.
*/
void set(String path, Object value);
/**
* Creates an empty {@link com.boydti.fawe.configuration.ConfigurationSection} at the specified path.
* <p>
* Any value that was previously set at this path will be overwritten. If
* the previous value was itself a {@link com.boydti.fawe.configuration.ConfigurationSection}, it will
* be orphaned.
*
* @param path Path to create the section at.
* @return Newly created section
*/
com.boydti.fawe.configuration.ConfigurationSection createSection(String path);
/**
* Creates a {@link com.boydti.fawe.configuration.ConfigurationSection} at the specified path, with
* specified values.
* <p>
* Any value that was previously set at this path will be overwritten. If
* the previous value was itself a {@link com.boydti.fawe.configuration.ConfigurationSection}, it will
* be orphaned.
*
* @param path Path to create the section at.
* @param map The values to used.
* @return Newly created section
*/
com.boydti.fawe.configuration.ConfigurationSection createSection(String path, Map<?, ?> map);
// Primitives
/**
* Gets the requested String by path.
* <p>
* If the String does not exist but a default value has been specified,
* this will return the default value. If the String does not exist and no
* default value was specified, this will return null.
*
* @param path Path of the String to get.
* @return Requested String.
*/
String getString(String path);
/**
* Gets the requested String by path, returning a default value if not
* found.
* <p>
* If the String does not exist then the specified default value will
* returned regardless of if a default has been identified in the root
* {@link com.boydti.fawe.configuration.Configuration}.
*
* @param path Path of the String to get.
* @param def The default value to return if the path is not found or is
* not a String.
* @return Requested String.
*/
String getString(String path, String def);
/**
* Checks if the specified path is a String.
*
* <p> If the path exists but is not a String, this will return false. If the
* path does not exist, this will return false. If the path does not exist
* but a default value has been specified, this will check if that default
* value is a String and return appropriately.</p>
*
* @param path Path of the String to check.
* @return Whether or not the specified path is a String.
*/
boolean isString(String path);
/**
* Gets the requested int by path.
*
* <p>If the int does not exist but a default value has been specified, this
* will return the default value. If the int does not exist and no default
* value was specified, this will return 0.</p>
*
* @param path Path of the int to get.
* @return Requested int.
*/
int getInt(String path);
/**
* Gets the requested int by path, returning a default value if not found.
*
* <p>If the int does not exist then the specified default value will
* returned regardless of if a default has been identified in the root
* {@link com.boydti.fawe.configuration.Configuration}.</p>
*
* @param path Path of the int to get.
* @param def The default value to return if the path is not found or is
* not an int.
* @return Requested int.
*/
int getInt(String path, int def);
/**
* Checks if the specified path is an int.
*
* <p>If the path exists but is not a int, this will return false. If the
* path does not exist, this will return false. If the path does not exist
* but a default value has been specified, this will check if that default
* value is a int and return appropriately.</p>
*
* @param path Path of the int to check.
* @return Whether or not the specified path is an int.
*/
boolean isInt(String path);
/**
* Gets the requested boolean by path.
* <p>
* If the boolean does not exist but a default value has been specified,
* this will return the default value. If the boolean does not exist and
* no default value was specified, this will return false.
*
* @param path Path of the boolean to get.
* @return Requested boolean.
*/
boolean getBoolean(String path);
/**
* Gets the requested boolean by path, returning a default value if not
* found.
* <p>
* If the boolean does not exist then the specified default value will
* returned regardless of if a default has been identified in the root
* {@link com.boydti.fawe.configuration.Configuration}.
*
* @param path Path of the boolean to get.
* @param def The default value to return if the path is not found or is
* not a boolean.
* @return Requested boolean.
*/
boolean getBoolean(String path, boolean def);
/**
* Checks if the specified path is a boolean.
* <p>
* If the path exists but is not a boolean, this will return false. If the
* path does not exist, this will return false. If the path does not exist
* but a default value has been specified, this will check if that default
* value is a boolean and return appropriately.
*
* @param path Path of the boolean to check.
* @return Whether or not the specified path is a boolean.
*/
boolean isBoolean(String path);
/**
* Gets the requested double by path.
* <p>
* If the double does not exist but a default value has been specified,
* this will return the default value. If the double does not exist and no
* default value was specified, this will return 0.
*
* @param path Path of the double to get.
* @return Requested double.
*/
double getDouble(String path);
/**
* Gets the requested double by path, returning a default value if not
* found.
* <p>
* If the double does not exist then the specified default value will
* returned regardless of if a default has been identified in the root
* {@link com.boydti.fawe.configuration.Configuration}.
*
* @param path Path of the double to get.
* @param def The default value to return if the path is not found or is
* not a double.
* @return Requested double.
*/
double getDouble(String path, double def);
/**
* Checks if the specified path is a double.
* <p>
* If the path exists but is not a double, this will return false. If the
* path does not exist, this will return false. If the path does not exist
* but a default value has been specified, this will check if that default
* value is a double and return appropriately.
*
* @param path Path of the double to check.
* @return Whether or not the specified path is a double.
*/
boolean isDouble(String path);
/**
* Gets the requested long by path.
* <p>
* If the long does not exist but a default value has been specified, this
* will return the default value. If the long does not exist and no
* default value was specified, this will return 0.
*
* @param path Path of the long to get.
* @return Requested long.
*/
long getLong(String path);
/**
* Gets the requested long by path, returning a default value if not
* found.
* <p>
* If the long does not exist then the specified default value will
* returned regardless of if a default has been identified in the root
* {@link com.boydti.fawe.configuration.Configuration}.
*
* @param path Path of the long to get.
* @param def The default value to return if the path is not found or is
* not a long.
* @return Requested long.
*/
long getLong(String path, long def);
/**
* Checks if the specified path is a long.
* <p>
* If the path exists but is not a long, this will return false. If the
* path does not exist, this will return false. If the path does not exist
* but a default value has been specified, this will check if that default
* value is a long and return appropriately.
*
* @param path Path of the long to check.
* @return Whether or not the specified path is a long.
*/
boolean isLong(String path);
// Java
/**
* Gets the requested List by path.
* <p>
* If the List does not exist but a default value has been specified, this
* will return the default value. If the List does not exist and no
* default value was specified, this will return null.
*
* @param path Path of the List to get.
* @return Requested List.
*/
List<?> getList(String path);
/**
* Gets the requested List by path, returning a default value if not
* found.
* <p>
* If the List does not exist then the specified default value will
* returned regardless of if a default has been identified in the root
* {@link com.boydti.fawe.configuration.Configuration}.
*
* @param path Path of the List to get.
* @param def The default value to return if the path is not found or is
* not a List.
* @return Requested List.
*/
List<?> getList(String path, List<?> def);
/**
* Checks if the specified path is a List.
* <p>
* If the path exists but is not a List, this will return false. If the
* path does not exist, this will return false. If the path does not exist
* but a default value has been specified, this will check if that default
* value is a List and return appropriately.
*
* @param path Path of the List to check.
* @return Whether or not the specified path is a List.
*/
boolean isList(String path);
/**
* Gets the requested List of String by path.
* <p>
* If the List does not exist but a default value has been specified, this
* will return the default value. If the List does not exist and no
* default value was specified, this will return an empty List.
* <p>
* This method will attempt to cast any values into a String if possible,
* but may miss any values out if they are not compatible.
*
* @param path Path of the List to get.
* @return Requested List of String.
*/
List<String> getStringList(String path);
/**
* Gets the requested List of Integer by path.
* <p>
* If the List does not exist but a default value has been specified, this
* will return the default value. If the List does not exist and no
* default value was specified, this will return an empty List.
* <p>
* This method will attempt to cast any values into a Integer if possible,
* but may miss any values out if they are not compatible.
*
* @param path Path of the List to get.
* @return Requested List of Integer.
*/
List<Integer> getIntegerList(String path);
/**
* Gets the requested List of Boolean by path.
* <p>
* If the List does not exist but a default value has been specified, this
* will return the default value. If the List does not exist and no
* default value was specified, this will return an empty List.
* <p>
* This method will attempt to cast any values into a Boolean if possible,
* but may miss any values out if they are not compatible.
*
* @param path Path of the List to get.
* @return Requested List of Boolean.
*/
List<Boolean> getBooleanList(String path);
/**
* Gets the requested List of Double by path.
* <p>
* If the List does not exist but a default value has been specified, this
* will return the default value. If the List does not exist and no
* default value was specified, this will return an empty List.
* <p>
* This method will attempt to cast any values into a Double if possible,
* but may miss any values out if they are not compatible.
*
* @param path Path of the List to get.
* @return Requested List of Double.
*/
List<Double> getDoubleList(String path);
/**
* Gets the requested List of Float by path.
* <p>
* If the List does not exist but a default value has been specified, this
* will return the default value. If the List does not exist and no
* default value was specified, this will return an empty List.
* <p>
* This method will attempt to cast any values into a Float if possible,
* but may miss any values out if they are not compatible.
*
* @param path Path of the List to get.
* @return Requested List of Float.
*/
List<Float> getFloatList(String path);
/**
* Gets the requested List of Long by path.
* <p>
* If the List does not exist but a default value has been specified, this
* will return the default value. If the List does not exist and no
* default value was specified, this will return an empty List.
* <p>
* This method will attempt to cast any values into a Long if possible,
* but may miss any values out if they are not compatible.
*
* @param path Path of the List to get.
* @return Requested List of Long.
*/
List<Long> getLongList(String path);
/**
* Gets the requested List of Byte by path.
* <p>
* If the List does not exist but a default value has been specified, this
* will return the default value. If the List does not exist and no
* default value was specified, this will return an empty List.
* <p>
* This method will attempt to cast any values into a Byte if possible,
* but may miss any values out if they are not compatible.
*
* @param path Path of the List to get.
* @return Requested List of Byte.
*/
List<Byte> getByteList(String path);
/**
* Gets the requested List of Character by path.
* <p>
* If the List does not exist but a default value has been specified, this
* will return the default value. If the List does not exist and no
* default value was specified, this will return an empty List.
* <p>
* This method will attempt to cast any values into a Character if
* possible, but may miss any values out if they are not compatible.
*
* @param path Path of the List to get.
* @return Requested List of Character.
*/
List<Character> getCharacterList(String path);
/**
* Gets the requested List of Short by path.
* <p>
* If the List does not exist but a default value has been specified, this
* will return the default value. If the List does not exist and no
* default value was specified, this will return an empty List.
* <p>
* This method will attempt to cast any values into a Short if possible,
* but may miss any values out if they are not compatible.
*
* @param path Path of the List to get.
* @return Requested List of Short.
*/
List<Short> getShortList(String path);
/**
* Gets the requested List of Maps by path.
* <p>
* If the List does not exist but a default value has been specified, this
* will return the default value. If the List does not exist and no
* default value was specified, this will return an empty List.
* <p>
* This method will attempt to cast any values into a Map if possible, but
* may miss any values out if they are not compatible.
*
* @param path Path of the List to get.
* @return Requested List of Maps.
*/
List<Map<?, ?>> getMapList(String path);
/**
* Gets the requested ConfigurationSection by path.
* <p>
* If the ConfigurationSection does not exist but a default value has been
* specified, this will return the default value. If the
* ConfigurationSection does not exist and no default value was specified,
* this will return null.
*
* @param path Path of the ConfigurationSection to get.
* @return Requested ConfigurationSection.
*/
com.boydti.fawe.configuration.ConfigurationSection getConfigurationSection(String path);
/**
* Checks if the specified path is a ConfigurationSection.
* <p>
* If the path exists but is not a ConfigurationSection, this will return
* false. If the path does not exist, this will return false. If the path
* does not exist but a default value has been specified, this will check
* if that default value is a ConfigurationSection and return
* appropriately.
*
* @param path Path of the ConfigurationSection to check.
* @return Whether or not the specified path is a ConfigurationSection.
*/
boolean isConfigurationSection(String path);
/**
* Gets the equivalent {@link com.boydti.fawe.configuration.ConfigurationSection} from the default
* {@link com.boydti.fawe.configuration.Configuration} defined in {@link #getRoot()}.
* <p>
* If the root contains no defaults, or the defaults doesn't contain a
* value for this path, or the value at this path is not a {@link
* com.boydti.fawe.configuration.ConfigurationSection} then this will return null.
*
* @return Equivalent section in root configuration
*/
com.boydti.fawe.configuration.ConfigurationSection getDefaultSection();
/**
* Sets the default value in the root at the given path as provided.
* <p>
* If no source {@link com.boydti.fawe.configuration.Configuration} was provided as a default
* collection, then a new {@link com.boydti.fawe.configuration.MemoryConfiguration} will be created to
* hold the new default value.
* <p>
* If value is null, the value will be removed from the default
* Configuration source.
* <p>
* If the value as returned by {@link #getDefaultSection()} is null, then
* this will create a new section at the path, replacing anything that may
* have existed there previously.
*
* @param path Path of the value to set.
* @param value Value to set the default to.
* @throws IllegalArgumentException Thrown if path is null.
*/
void addDefault(String path, Object value);
}

View File

@ -0,0 +1,45 @@
package com.boydti.fawe.configuration;
/**
* Exception thrown when attempting to load an invalid {@link com.boydti.fawe.configuration.Configuration}
*/
@SuppressWarnings("serial")
public class InvalidConfigurationException extends Exception {
/**
* Creates a new instance of InvalidConfigurationException without a
* message or cause.
*/
public InvalidConfigurationException() {}
/**
* Constructs an instance of InvalidConfigurationException with the
* specified message.
*
* @param msg The details of the exception.
*/
public InvalidConfigurationException(final String msg) {
super(msg);
}
/**
* Constructs an instance of InvalidConfigurationException with the
* specified cause.
*
* @param cause The cause of the exception.
*/
public InvalidConfigurationException(final Throwable cause) {
super(cause);
}
/**
* Constructs an instance of InvalidConfigurationException with the
* specified message and cause.
*
* @param cause The cause of the exception.
* @param msg The details of the exception.
*/
public InvalidConfigurationException(final String msg, final Throwable cause) {
super(msg, cause);
}
}

View File

@ -0,0 +1,93 @@
package com.boydti.fawe.configuration;
import com.boydti.fawe.configuration.Configuration;
import com.boydti.fawe.configuration.ConfigurationSection;
import com.boydti.fawe.configuration.MemoryConfigurationOptions;
import com.boydti.fawe.configuration.MemorySection;
import java.util.Map;
/**
* This is a {@link com.boydti.fawe.configuration.Configuration} implementation that does not save or load
* from any source, and stores all values in memory only.
* This is useful for temporary Configurations for providing defaults.
*/
public class MemoryConfiguration extends MemorySection implements Configuration {
protected Configuration defaults;
protected MemoryConfigurationOptions options;
/**
* Creates an empty {@link com.boydti.fawe.configuration.MemoryConfiguration} with no default values.
*/
public MemoryConfiguration() {}
/**
* Creates an empty {@link com.boydti.fawe.configuration.MemoryConfiguration} using the specified {@link
* com.boydti.fawe.configuration.Configuration} as a source for all default values.
*
* @param defaults Default value provider
* @throws IllegalArgumentException Thrown if defaults is null
*/
public MemoryConfiguration(final Configuration defaults) {
this.defaults = defaults;
}
@Override
public void addDefault(final String path, final Object value) {
if (path == null) {
throw new NullPointerException("Path may not be null");
}
if (defaults == null) {
defaults = new com.boydti.fawe.configuration.MemoryConfiguration();
}
defaults.set(path, value);
}
@Override
public void addDefaults(final Map<String, Object> defaults) {
if (defaults == null) {
throw new NullPointerException("Defaults may not be null");
}
for (final Map.Entry<String, Object> entry : defaults.entrySet()) {
addDefault(entry.getKey(), entry.getValue());
}
}
@Override
public void addDefaults(final Configuration defaults) {
if (defaults == null) {
throw new NullPointerException("Defaults may not be null");
}
addDefaults(defaults.getValues(true));
}
@Override
public void setDefaults(final Configuration defaults) {
if (defaults == null) {
throw new NullPointerException("Defaults may not be null");
}
this.defaults = defaults;
}
@Override
public Configuration getDefaults() {
return defaults;
}
@Override
public ConfigurationSection getParent() {
return null;
}
@Override
public MemoryConfigurationOptions options() {
if (options == null) {
options = new MemoryConfigurationOptions(this);
}
return options;
}
}

View File

@ -0,0 +1,30 @@
package com.boydti.fawe.configuration;
import com.boydti.fawe.configuration.ConfigurationOptions;
/**
* Various settings for controlling the input and output of a {@link
* com.boydti.fawe.configuration.MemoryConfiguration}
*/
public class MemoryConfigurationOptions extends ConfigurationOptions {
protected MemoryConfigurationOptions(final MemoryConfiguration configuration) {
super(configuration);
}
@Override
public MemoryConfiguration configuration() {
return (MemoryConfiguration) super.configuration();
}
@Override
public com.boydti.fawe.configuration.MemoryConfigurationOptions copyDefaults(final boolean value) {
super.copyDefaults(value);
return this;
}
@Override
public com.boydti.fawe.configuration.MemoryConfigurationOptions pathSeparator(final char value) {
super.pathSeparator(value);
return this;
}
}

View File

@ -0,0 +1,847 @@
package com.boydti.fawe.configuration;
import com.boydti.fawe.configuration.ConfigurationSection;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* A type of {@link com.boydti.fawe.configuration.ConfigurationSection} that is stored in memory.
*/
public class MemorySection implements com.boydti.fawe.configuration.ConfigurationSection {
protected final Map<String, Object> map = new LinkedHashMap<>();
private final Configuration root;
private final com.boydti.fawe.configuration.ConfigurationSection parent;
private final String path;
private final String fullPath;
/**
* Creates an empty MemorySection for use as a root {@link com.boydti.fawe.configuration.Configuration}
* section.
* <p>
* Note that calling this without being yourself a {@link com.boydti.fawe.configuration.Configuration}
* will throw an exception!
*
* @throws IllegalStateException Thrown if this is not a {@link
* com.boydti.fawe.configuration.Configuration} root.
*/
protected MemorySection() {
if (!(this instanceof Configuration)) {
throw new IllegalStateException("Cannot construct a root MemorySection when not a Configuration");
}
this.path = "";
this.fullPath = "";
this.parent = null;
this.root = (Configuration) this;
}
/**
* Creates an empty MemorySection with the specified parent and path.
*
* @param parent Parent section that contains this own section.
* @param path Path that you may access this section from via the root
* {@link com.boydti.fawe.configuration.Configuration}.
* @throws IllegalArgumentException Thrown is parent or path is null, or
* if parent contains no root Configuration.
*/
protected MemorySection(com.boydti.fawe.configuration.ConfigurationSection parent, String path) {
if (parent == null) {
throw new NullPointerException("Parent may not be null");
}
if (path == null) {
throw new NullPointerException("Path may not be null");
}
this.path = path;
this.parent = parent;
this.root = parent.getRoot();
if (this.root == null) {
throw new NullPointerException("Path may not be orphaned");
}
this.fullPath = createPath(parent, path);
}
public static double toDouble(Object obj, double def) {
if (obj instanceof Number) {
return ((Number) obj).doubleValue();
}
if (obj instanceof String) {
try {
return Double.parseDouble((String) obj);
} catch (NumberFormatException ignored) {
}
} else if (obj instanceof List) {
List<?> val = (List<?>) obj;
if (!val.isEmpty()) {
return toDouble(val.get(0), def);
}
}
return def;
}
public static int toInt(Object obj, int def) {
if (obj instanceof Number) {
return ((Number) obj).intValue();
}
if (obj instanceof String) {
try {
return Integer.parseInt((String) obj);
} catch (NumberFormatException ignored) {
}
} else if (obj instanceof List) {
List<?> val = (List<?>) obj;
if (!val.isEmpty()) {
return toInt(val.get(0), def);
}
}
return def;
}
public static long toLong(Object obj, long def) {
if (obj instanceof Number) {
return ((Number) obj).longValue();
}
if (obj instanceof String) {
try {
return Long.parseLong((String) obj);
} catch (NumberFormatException ignored) {
}
} else if (obj instanceof List) {
List<?> val = (List<?>) obj;
if (!val.isEmpty()) {
return toLong(val.get(0), def);
}
}
return def;
}
/**
* Creates a full path to the given {@link com.boydti.fawe.configuration.ConfigurationSection} from its
* root {@link com.boydti.fawe.configuration.Configuration}.
* <p>
* You may use this method for any given {@link com.boydti.fawe.configuration.ConfigurationSection}, not
* only {@link com.boydti.fawe.configuration.MemorySection}.
*
* @param section Section to create a path for.
* @param key Name of the specified section.
* @return Full path of the section from its root.
*/
public static String createPath(com.boydti.fawe.configuration.ConfigurationSection section, String key) {
return createPath(section, key, (section == null) ? null : section.getRoot());
}
/**
* Creates a relative path to the given {@link com.boydti.fawe.configuration.ConfigurationSection} from
* the given relative section.
* <p>
* You may use this method for any given {@link com.boydti.fawe.configuration.ConfigurationSection}, not
* only {@link com.boydti.fawe.configuration.MemorySection}.
*
* @param section Section to create a path for.
* @param key Name of the specified section.
* @param relativeTo Section to create the path relative to.
* @return Full path of the section from its root.
*/
public static String createPath(com.boydti.fawe.configuration.ConfigurationSection section, String key, com.boydti.fawe.configuration.ConfigurationSection relativeTo) {
if (section == null) {
throw new NullPointerException("Cannot create path without a section");
}
Configuration root = section.getRoot();
if (root == null) {
throw new IllegalStateException("Cannot create path without a root");
}
char separator = root.options().pathSeparator();
StringBuilder builder = new StringBuilder();
for (com.boydti.fawe.configuration.ConfigurationSection parent = section; (parent != null) && (parent != relativeTo); parent = parent.getParent()) {
if (builder.length() > 0) {
builder.insert(0, separator);
}
builder.insert(0, parent.getName());
}
if ((key != null) && !key.isEmpty()) {
if (builder.length() > 0) {
builder.append(separator);
}
builder.append(key);
}
return builder.toString();
}
@Override
public Set<String> getKeys(boolean deep) {
Set<String> result = new LinkedHashSet<>();
Configuration root = getRoot();
if ((root != null) && root.options().copyDefaults()) {
com.boydti.fawe.configuration.ConfigurationSection defaults = getDefaultSection();
if (defaults != null) {
result.addAll(defaults.getKeys(deep));
}
}
mapChildrenKeys(result, this, deep);
return result;
}
@Override
public Map<String, Object> getValues(boolean deep) {
Map<String, Object> result = new LinkedHashMap<>();
Configuration root = getRoot();
if ((root != null) && root.options().copyDefaults()) {
com.boydti.fawe.configuration.ConfigurationSection defaults = getDefaultSection();
if (defaults != null) {
result.putAll(defaults.getValues(deep));
}
}
mapChildrenValues(result, this, deep);
return result;
}
@Override
public boolean contains(String path) {
return get(path) != null;
}
@Override
public boolean isSet(String path) {
Configuration root = getRoot();
if (root == null) {
return false;
}
if (root.options().copyDefaults()) {
return contains(path);
}
return get(path, null) != null;
}
@Override
public String getCurrentPath() {
return this.fullPath;
}
@Override
public String getName() {
return this.path;
}
@Override
public Configuration getRoot() {
return this.root;
}
@Override
public com.boydti.fawe.configuration.ConfigurationSection getParent() {
return this.parent;
}
@Override
public void addDefault(String path, Object value) {
if (path == null) {
throw new NullPointerException("Path cannot be null");
}
Configuration root = getRoot();
if (root == null) {
throw new IllegalStateException("Cannot add default without root");
}
if (root == this) {
throw new UnsupportedOperationException("Unsupported addDefault(String, Object) implementation");
}
root.addDefault(createPath(this, path), value);
}
@Override
public com.boydti.fawe.configuration.ConfigurationSection getDefaultSection() {
Configuration root = getRoot();
Configuration defaults = root == null ? null : root.getDefaults();
if (defaults != null) {
if (defaults.isConfigurationSection(getCurrentPath())) {
return defaults.getConfigurationSection(getCurrentPath());
}
}
return null;
}
@Override
public void set(String path, Object value) {
if (path == null) {
throw new NullPointerException("Cannot set to an empty path");
}
Configuration root = getRoot();
if (root == null) {
throw new IllegalStateException("Cannot use section without a root");
}
char separator = root.options().pathSeparator();
// i1 is the leading (higher) index
// i2 is the trailing (lower) index
int i1 = -1, i2;
com.boydti.fawe.configuration.ConfigurationSection section = this;
while ((i1 = path.indexOf(separator, i2 = i1 + 1)) != -1) {
String node = path.substring(i2, i1);
com.boydti.fawe.configuration.ConfigurationSection subSection = section.getConfigurationSection(node);
if (subSection == null) {
section = section.createSection(node);
} else {
section = subSection;
}
}
String key = path.substring(i2);
if (section == this) {
if (value == null) {
this.map.remove(key);
} else {
this.map.put(key, value);
}
} else {
section.set(key, value);
}
}
@Override
public Object get(String path) {
return get(path, getDefault(path));
}
@Override
public Object get(String path, Object def) {
if (path == null) {
throw new NullPointerException("Path cannot be null");
}
if (path.isEmpty()) {
return this;
}
Configuration root = getRoot();
if (root == null) {
throw new IllegalStateException("Cannot access section without a root");
}
char separator = root.options().pathSeparator();
// i1 is the leading (higher) index
// i2 is the trailing (lower) index
int i1 = -1;
int i2;
com.boydti.fawe.configuration.ConfigurationSection section = this;
while ((i1 = path.indexOf(separator, i2 = i1 + 1)) != -1) {
section = section.getConfigurationSection(path.substring(i2, i1));
if (section == null) {
return def;
}
}
String key = path.substring(i2);
if (section == this) {
Object result = this.map.get(key);
if (result == null) {
return def;
} else {
return result;
}
}
return section.get(key, def);
}
@Override
public com.boydti.fawe.configuration.ConfigurationSection createSection(String path) {
if (path == null) {
throw new NullPointerException("Cannot create section at empty path");
}
Configuration root = getRoot();
if (root == null) {
throw new IllegalStateException("Cannot create section without a root");
}
char separator = root.options().pathSeparator();
// i1 is the leading (higher) index
// i2 is the trailing (lower) index
int i1 = -1, i2;
com.boydti.fawe.configuration.ConfigurationSection section = this;
while ((i1 = path.indexOf(separator, i2 = i1 + 1)) != -1) {
String node = path.substring(i2, i1);
com.boydti.fawe.configuration.ConfigurationSection subSection = section.getConfigurationSection(node);
if (subSection == null) {
section = section.createSection(node);
} else {
section = subSection;
}
}
String key = path.substring(i2);
if (section == this) {
com.boydti.fawe.configuration.ConfigurationSection result = new com.boydti.fawe.configuration.MemorySection(this, key);
this.map.put(key, result);
return result;
}
return section.createSection(key);
}
@Override
public com.boydti.fawe.configuration.ConfigurationSection createSection(String path, Map<?, ?> map) {
com.boydti.fawe.configuration.ConfigurationSection section = createSection(path);
for (Map.Entry<?, ?> entry : map.entrySet()) {
if (entry.getValue() instanceof Map) {
section.createSection(entry.getKey().toString(), (Map<?, ?>) entry.getValue());
} else {
section.set(entry.getKey().toString(), entry.getValue());
}
}
return section;
}
// Primitives
@Override
public String getString(String path) {
Object def = getDefault(path);
return getString(path, def != null ? def.toString() : null);
}
@Override
public String getString(String path, String def) {
Object val = get(path, def);
if (val != null) {
return val.toString();
} else {
return def;
}
}
@Override
public boolean isString(String path) {
Object val = get(path);
return val instanceof String;
}
@Override
public int getInt(String path) {
Object def = getDefault(path);
return getInt(path, toInt(def, 0));
}
@Override
public int getInt(String path, int def) {
Object val = get(path, def);
return toInt(val, def);
}
@Override
public boolean isInt(String path) {
Object val = get(path);
return val instanceof Integer;
}
@Override
public boolean getBoolean(String path) {
Object def = getDefault(path);
if (def instanceof Boolean) {
return getBoolean(path, (Boolean) def);
} else {
return getBoolean(path, false);
}
}
@Override
public boolean getBoolean(String path, boolean def) {
Object val = get(path, def);
if (val instanceof Boolean) {
return (Boolean) val;
} else {
return def;
}
}
@Override
public boolean isBoolean(String path) {
Object val = get(path);
return val instanceof Boolean;
}
@Override
public double getDouble(String path) {
Object def = getDefault(path);
return getDouble(path, toDouble(def, 0));
}
@Override
public double getDouble(String path, double def) {
Object val = get(path, def);
return toDouble(val, def);
}
@Override
public boolean isDouble(String path) {
Object val = get(path);
return val instanceof Double;
}
@Override
public long getLong(String path) {
Object def = getDefault(path);
return getLong(path, toLong(def, 0));
}
@Override
public long getLong(String path, long def) {
Object val = get(path, def);
return toLong(val, def);
}
@Override
public boolean isLong(String path) {
Object val = get(path);
return val instanceof Long;
}
// Java
@Override
public List<?> getList(String path) {
Object def = getDefault(path);
return getList(path, def instanceof List ? (List<?>) def : null);
}
@Override
public List<?> getList(String path, List<?> def) {
Object val = get(path, def);
return (List<?>) ((val instanceof List) ? val : def);
}
@Override
public boolean isList(String path) {
Object val = get(path);
return val instanceof List;
}
@Override
public List<String> getStringList(String path) {
final List<?> list = getList(path);
if (list == null) {
return new ArrayList<>(0);
}
final List<String> result = new ArrayList<>();
for (final Object object : list) {
if ((object instanceof String) || (isPrimitiveWrapper(object))) {
result.add(String.valueOf(object));
}
}
return result;
}
@Override
public List<Integer> getIntegerList(String path) {
List<?> list = getList(path);
List<Integer> result = new ArrayList<>();
for (Object object : list) {
if (object instanceof Integer) {
result.add((Integer) object);
} else if (object instanceof String) {
try {
result.add(Integer.valueOf((String) object));
} catch (NumberFormatException ignored) {
}
} else if (object instanceof Character) {
result.add((int) (Character) object);
} else if (object instanceof Number) {
result.add(((Number) object).intValue());
}
}
return result;
}
@Override
public List<Boolean> getBooleanList(String path) {
List<?> list = getList(path);
List<Boolean> result = new ArrayList<>();
for (Object object : list) {
if (object instanceof Boolean) {
result.add((Boolean) object);
} else if (object instanceof String) {
if (Boolean.TRUE.toString().equals(object)) {
result.add(true);
} else if (Boolean.FALSE.toString().equals(object)) {
result.add(false);
}
}
}
return result;
}
@Override
public List<Double> getDoubleList(String path) {
List<?> list = getList(path);
List<Double> result = new ArrayList<>();
for (Object object : list) {
if (object instanceof Double) {
result.add((Double) object);
} else if (object instanceof String) {
try {
result.add(Double.valueOf((String) object));
} catch (NumberFormatException ignored) {
}
} else if (object instanceof Character) {
result.add((double) (Character) object);
} else if (object instanceof Number) {
result.add(((Number) object).doubleValue());
}
}
return result;
}
@Override
public List<Float> getFloatList(String path) {
List<?> list = getList(path);
List<Float> result = new ArrayList<>();
for (Object object : list) {
if (object instanceof Float) {
result.add((Float) object);
} else if (object instanceof String) {
try {
result.add(Float.valueOf((String) object));
} catch (NumberFormatException ignored) {
}
} else if (object instanceof Character) {
result.add((float) (Character) object);
} else if (object instanceof Number) {
result.add(((Number) object).floatValue());
}
}
return result;
}
@Override
public List<Long> getLongList(String path) {
List<?> list = getList(path);
List<Long> result = new ArrayList<>();
for (Object object : list) {
if (object instanceof Long) {
result.add((Long) object);
} else if (object instanceof String) {
try {
result.add(Long.valueOf((String) object));
} catch (NumberFormatException ignored) {
}
} else if (object instanceof Character) {
result.add((long) (Character) object);
} else if (object instanceof Number) {
result.add(((Number) object).longValue());
}
}
return result;
}
@Override
public List<Byte> getByteList(String path) {
List<?> list = getList(path);
List<Byte> result = new ArrayList<>();
for (Object object : list) {
if (object instanceof Byte) {
result.add((Byte) object);
} else if (object instanceof String) {
try {
result.add(Byte.valueOf((String) object));
} catch (NumberFormatException ignored) {
}
} else if (object instanceof Character) {
result.add((byte) ((Character) object).charValue());
} else if (object instanceof Number) {
result.add(((Number) object).byteValue());
}
}
return result;
}
@Override
public List<Character> getCharacterList(String path) {
List<?> list = getList(path);
List<Character> result = new ArrayList<>();
for (Object object : list) {
if (object instanceof Character) {
result.add((Character) object);
} else if (object instanceof String) {
String str = (String) object;
if (str.length() == 1) {
result.add(str.charAt(0));
}
} else if (object instanceof Number) {
result.add((char) ((Number) object).intValue());
}
}
return result;
}
@Override
public List<Short> getShortList(String path) {
List<?> list = getList(path);
List<Short> result = new ArrayList<>();
for (Object object : list) {
if (object instanceof Short) {
result.add((Short) object);
} else if (object instanceof String) {
try {
result.add(Short.valueOf((String) object));
} catch (NumberFormatException ignored) {
}
} else if (object instanceof Character) {
result.add((short) ((Character) object).charValue());
} else if (object instanceof Number) {
result.add(((Number) object).shortValue());
}
}
return result;
}
@Override
public List<Map<?, ?>> getMapList(String path) {
List<?> list = getList(path);
List<Map<?, ?>> result = new ArrayList<>();
for (Object object : list) {
if (object instanceof Map) {
result.add((Map<?, ?>) object);
}
}
return result;
}
@Override
public com.boydti.fawe.configuration.ConfigurationSection getConfigurationSection(String path) {
Object val = get(path, null);
if (val != null) {
return (val instanceof com.boydti.fawe.configuration.ConfigurationSection) ? (com.boydti.fawe.configuration.ConfigurationSection) val : null;
}
val = get(path, getDefault(path));
return (val instanceof com.boydti.fawe.configuration.ConfigurationSection) ? createSection(path) : null;
}
@Override
public boolean isConfigurationSection(String path) {
Object val = get(path);
return val instanceof com.boydti.fawe.configuration.ConfigurationSection;
}
protected boolean isPrimitiveWrapper(Object input) {
return (input instanceof Integer)
|| (input instanceof Boolean)
|| (input instanceof Character)
|| (input instanceof Byte)
|| (input instanceof Short)
|| (input instanceof Double)
|| (input instanceof Long)
|| (input instanceof Float);
}
protected Object getDefault(String path) {
if (path == null) {
throw new NullPointerException("Path may not be null");
}
Configuration root = getRoot();
Configuration defaults = root == null ? null : root.getDefaults();
return (defaults == null) ? null : defaults.get(createPath(this, path));
}
protected void mapChildrenKeys(Set<String> output, com.boydti.fawe.configuration.ConfigurationSection section, boolean deep) {
if (section instanceof com.boydti.fawe.configuration.MemorySection) {
com.boydti.fawe.configuration.MemorySection sec = (com.boydti.fawe.configuration.MemorySection) section;
for (Map.Entry<String, Object> entry : sec.map.entrySet()) {
output.add(createPath(section, entry.getKey(), this));
if (deep && (entry.getValue() instanceof com.boydti.fawe.configuration.ConfigurationSection)) {
com.boydti.fawe.configuration.ConfigurationSection subsection = (com.boydti.fawe.configuration.ConfigurationSection) entry.getValue();
mapChildrenKeys(output, subsection, deep);
}
}
} else {
Set<String> keys = section.getKeys(deep);
for (String key : keys) {
output.add(createPath(section, key, this));
}
}
}
protected void mapChildrenValues(Map<String, Object> output, com.boydti.fawe.configuration.ConfigurationSection section, boolean deep) {
if (section instanceof com.boydti.fawe.configuration.MemorySection) {
com.boydti.fawe.configuration.MemorySection sec = (com.boydti.fawe.configuration.MemorySection) section;
for (Map.Entry<String, Object> entry : sec.map.entrySet()) {
output.put(createPath(section, entry.getKey(), this), entry.getValue());
if (entry.getValue() instanceof com.boydti.fawe.configuration.ConfigurationSection) {
if (deep) {
mapChildrenValues(output, (ConfigurationSection) entry.getValue(), deep);
}
}
}
} else {
Map<String, Object> values = section.getValues(deep);
for (Map.Entry<String, Object> entry : values.entrySet()) {
output.put(createPath(section, entry.getKey(), this), entry.getValue());
}
}
}
@Override
public String toString() {
Configuration root = getRoot();
return getClass().getSimpleName() + "[path='" + getCurrentPath() + "', root='" + (root == null ? null : root.getClass().getSimpleName()) +
"']";
}
}

View File

@ -0,0 +1,219 @@
package com.boydti.fawe.configuration.file;
import com.boydti.fawe.configuration.Configuration;
import com.boydti.fawe.configuration.InvalidConfigurationException;
import com.boydti.fawe.configuration.MemoryConfiguration;
import com.boydti.fawe.configuration.file.FileConfigurationOptions;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
/**
* This is a base class for all File based implementations of {@link
* com.boydti.fawe.configuration.Configuration}
*/
public abstract class FileConfiguration extends MemoryConfiguration {
/**
* Creates an empty {@link com.boydti.fawe.configuration.file.FileConfiguration} with no default values.
*/
public FileConfiguration() {
}
/**
* Creates an empty {@link com.boydti.fawe.configuration.file.FileConfiguration} using the specified {@link
* com.boydti.fawe.configuration.Configuration} as a source for all default values.
*
* @param defaults Default value provider
*/
public FileConfiguration(Configuration defaults) {
super(defaults);
}
/**
* Saves this {@link com.boydti.fawe.configuration.file.FileConfiguration} to the specified location.
* <p>
* If the file does not exist, it will be created. If already exists, it
* will be overwritten. If it cannot be overwritten or created, an
* exception will be thrown.
* <p>
* This method will save using the system default encoding, or possibly
* using UTF8.
*
* @param file File to save to.
* @throws java.io.IOException Thrown when the given file cannot be written to for
* any reason.
* @throws IllegalArgumentException Thrown when file is null.
*/
public void save(File file) throws IOException {
if (file == null) {
throw new NullPointerException("File cannot be null");
}
file.getParentFile().mkdirs();
String data = saveToString();
try (Writer writer = new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8)) {
writer.write(data);
}
}
/**
* Saves this {@link com.boydti.fawe.configuration.file.FileConfiguration} to the specified location.
* <p>
* If the file does not exist, it will be created. If already exists, it
* will be overwritten. If it cannot be overwritten or created, an
* exception will be thrown.
* <p>
* This method will save using the system default encoding, or possibly
* using UTF8.
*
* @param file File to save to.
* @throws java.io.IOException Thrown when the given file cannot be written to for
* any reason.
* @throws IllegalArgumentException Thrown when file is null.
*/
public void save(String file) throws IOException {
if (file == null) {
throw new NullPointerException("File cannot be null");
}
save(new File(file));
}
/**
* Saves this {@link com.boydti.fawe.configuration.file.FileConfiguration} to a string, and returns it.
*
* @return String containing this configuration.
*/
public abstract String saveToString();
/**
* Loads this {@link com.boydti.fawe.configuration.file.FileConfiguration} from the specified location.
* <p>
* All the values contained within this configuration will be removed,
* leaving only settings and defaults, and the new values will be loaded
* from the given file.
* <p>
* If the file cannot be loaded for any reason, an exception will be
* thrown.
* <p>
*
* @param file File to load from.
* @throws java.io.FileNotFoundException Thrown when the given file cannot be
* opened.
* @throws java.io.IOException Thrown when the given file cannot be read.
* @throws com.boydti.fawe.configuration.InvalidConfigurationException Thrown when the given file is not
* a valid Configuration.
* @throws IllegalArgumentException Thrown when file is null.
*/
public void load(File file) throws IOException, InvalidConfigurationException {
if (file == null) {
throw new NullPointerException("File cannot be null");
}
FileInputStream stream = new FileInputStream(file);
load(new InputStreamReader(stream, StandardCharsets.UTF_8));
}
/**
* Loads this {@link com.boydti.fawe.configuration.file.FileConfiguration} from the specified reader.
* <p>
* All the values contained within this configuration will be removed,
* leaving only settings and defaults, and the new values will be loaded
* from the given stream.
*
* @param reader the reader to load from
* @throws java.io.IOException thrown when underlying reader throws an IOException
* @throws com.boydti.fawe.configuration.InvalidConfigurationException thrown when the reader does not
* represent a valid Configuration
* @throws IllegalArgumentException thrown when reader is null
*/
public void load(Reader reader) throws IOException, InvalidConfigurationException {
StringBuilder builder = new StringBuilder();
try (BufferedReader input = reader instanceof BufferedReader ? (BufferedReader) reader : new BufferedReader(reader)) {
String line;
while ((line = input.readLine()) != null) {
builder.append(line);
builder.append('\n');
}
}
loadFromString(builder.toString());
}
/**
* Loads this {@link com.boydti.fawe.configuration.file.FileConfiguration} from the specified location.
* <p>
* All the values contained within this configuration will be removed,
* leaving only settings and defaults, and the new values will be loaded
* from the given file.
* <p>
* If the file cannot be loaded for any reason, an exception will be
* thrown.
*
* @param file File to load from.
* @throws java.io.FileNotFoundException Thrown when the given file cannot be
* opened.
* @throws java.io.IOException Thrown when the given file cannot be read.
* @throws com.boydti.fawe.configuration.InvalidConfigurationException Thrown when the given file is not
* a valid Configuration.
* @throws IllegalArgumentException Thrown when file is null.
*/
public void load(String file) throws IOException, InvalidConfigurationException {
if (file == null) {
throw new NullPointerException("File cannot be null");
}
load(new File(file));
}
/**
* Loads this {@link com.boydti.fawe.configuration.file.FileConfiguration} from the specified string, as
* opposed to from file.
* <p>
* All the values contained within this configuration will be removed,
* leaving only settings and defaults, and the new values will be loaded
* from the given string.
* <p>
* If the string is invalid in any way, an exception will be thrown.
*
* @param contents Contents of a Configuration to load.
* @throws com.boydti.fawe.configuration.InvalidConfigurationException Thrown if the specified string is
* invalid.
* @throws IllegalArgumentException Thrown if contents is null.
*/
public abstract void loadFromString(String contents) throws InvalidConfigurationException;
/**
* Compiles the header for this {@link com.boydti.fawe.configuration.file.FileConfiguration} and returns the
* result.
* <p>
* This will use the header from {@link #options()} -> {@link
* com.boydti.fawe.configuration.file.FileConfigurationOptions#header()}, respecting the rules of {@link
* com.boydti.fawe.configuration.file.FileConfigurationOptions#copyHeader()} if set.
*
* @return Compiled header
*/
protected abstract String buildHeader();
@Override
public FileConfigurationOptions options() {
if (this.options == null) {
this.options = new FileConfigurationOptions(this);
}
return (FileConfigurationOptions) this.options;
}
}

View File

@ -0,0 +1,119 @@
package com.boydti.fawe.configuration.file;
import com.boydti.fawe.configuration.MemoryConfiguration;
import com.boydti.fawe.configuration.MemoryConfigurationOptions;
/**
* Various settings for controlling the input and output of a {@link
* com.boydti.fawe.configuration.file.FileConfiguration}
*/
public class FileConfigurationOptions extends MemoryConfigurationOptions {
private String header = null;
private boolean copyHeader = true;
protected FileConfigurationOptions(final MemoryConfiguration configuration) {
super(configuration);
}
@Override
public com.boydti.fawe.configuration.file.FileConfiguration configuration() {
return (com.boydti.fawe.configuration.file.FileConfiguration) super.configuration();
}
@Override
public com.boydti.fawe.configuration.file.FileConfigurationOptions copyDefaults(final boolean value) {
super.copyDefaults(value);
return this;
}
@Override
public com.boydti.fawe.configuration.file.FileConfigurationOptions pathSeparator(final char value) {
super.pathSeparator(value);
return this;
}
/**
* Gets the header that will be applied to the top of the saved output.
* <p>
* This header will be commented out and applied directly at the top of
* the generated output of the {@link com.boydti.fawe.configuration.file.FileConfiguration}. It is not
* required to include a newline at the end of the header as it will
* automatically be applied, but you may include one if you wish for extra
* spacing.
* <p>
* Null is a valid value which will indicate that no header is to be
* applied. The default value is null.
*
* @return Header
*/
public String header() {
return header;
}
/**
* Sets the header that will be applied to the top of the saved output.
* <p>
* This header will be commented out and applied directly at the top of
* the generated output of the {@link com.boydti.fawe.configuration.file.FileConfiguration}. It is not
* required to include a newline at the end of the header as it will
* automatically be applied, but you may include one if you wish for extra
* spacing.
* <p>
* Null is a valid value which will indicate that no header is to be
* applied.
*
* @param value New header
* @return This object, for chaining
*/
public com.boydti.fawe.configuration.file.FileConfigurationOptions header(final String value) {
header = value;
return this;
}
/**
* Gets whether or not the header should be copied from a default source.
* <p>
* If this is true, if a default {@link com.boydti.fawe.configuration.file.FileConfiguration} is passed to
* {@link
* com.boydti.fawe.configuration.file.FileConfiguration#setDefaults(com.boydti.fawe.configuration.Configuration)}
* then upon saving it will use the header from that config, instead of
* the one provided here.
* <p>
* If no default is set on the configuration, or the default is not of
* type FileConfiguration, or that config has no header ({@link #header()}
* returns null) then the header specified in this configuration will be
* used.
* <p>
* Defaults to true.
*
* @return Whether or not to copy the header
*/
public boolean copyHeader() {
return copyHeader;
}
/**
* Sets whether or not the header should be copied from a default source.
* <p>
* If this is true, if a default {@link com.boydti.fawe.configuration.file.FileConfiguration} is passed to
* {@link
* com.boydti.fawe.configuration.file.FileConfiguration#setDefaults(com.boydti.fawe.configuration.Configuration)}
* then upon saving it will use the header from that config, instead of
* the one provided here.
* <p>
* If no default is set on the configuration, or the default is not of
* type FileConfiguration, or that config has no header ({@link #header()}
* returns null) then the header specified in this configuration will be
* used.
* <p>
* Defaults to true.
*
* @param value Whether or not to copy the header
* @return This object, for chaining
*/
public com.boydti.fawe.configuration.file.FileConfigurationOptions copyHeader(final boolean value) {
copyHeader = value;
return this;
}
}

View File

@ -0,0 +1,229 @@
package com.boydti.fawe.configuration.file;
import com.boydti.fawe.configuration.Configuration;
import com.boydti.fawe.configuration.ConfigurationSection;
import com.boydti.fawe.configuration.InvalidConfigurationException;
import java.io.File;
import java.io.IOException;
import java.io.Reader;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.Map;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.error.YAMLException;
import org.yaml.snakeyaml.representer.Representer;
/**
* An implementation of {@link com.boydti.fawe.configuration.Configuration} which saves all files in Yaml.
* Note that this implementation is not synchronized.
*/
public class YamlConfiguration extends FileConfiguration {
protected static final String COMMENT_PREFIX = "# ";
protected static final String BLANK_CONFIG = "{}\n";
private final DumperOptions yamlOptions = new DumperOptions();
private final Representer yamlRepresenter = new YamlRepresenter();
private final Yaml yaml = new Yaml(new YamlConstructor(), yamlRepresenter, yamlOptions);
/**
* Creates a new {@link com.boydti.fawe.configuration.file.YamlConfiguration}, loading from the given file.
* <p>
* Any errors loading the Configuration will be logged and then ignored.
* If the specified input is not a valid config, a blank config will be
* returned.
* <p>
* The encoding used may follow the system dependent default.
*
* @param file Input file
* @return Resulting configuration
* @throws IllegalArgumentException Thrown if file is null
*/
public static com.boydti.fawe.configuration.file.YamlConfiguration loadConfiguration(final File file) {
if (file == null) {
throw new NullPointerException("File cannot be null");
}
final com.boydti.fawe.configuration.file.YamlConfiguration config = new com.boydti.fawe.configuration.file.YamlConfiguration();
try {
config.load(file);
} catch (InvalidConfigurationException | IOException ex) {
try {
file.getAbsolutePath();
File dest = new File(file.getAbsolutePath() + "_broken");
int i = 0;
while (dest.exists()) {
dest = new File(file.getAbsolutePath() + "_broken_" + i++);
}
Files.copy(file.toPath(), dest.toPath(), StandardCopyOption.REPLACE_EXISTING);
System.out.println("&dCould not read: &7" + file);
System.out.println("&dRenamed to: &7" + dest.getName());
System.out.println("&c============ Full stacktrace ============");
ex.printStackTrace();
System.out.println("&c=========================================");
} catch (final IOException e) {
e.printStackTrace();
}
}
return config;
}
/**
* Creates a new {@link com.boydti.fawe.configuration.file.YamlConfiguration}, loading from the given reader.
* <p>
* Any errors loading the Configuration will be logged and then ignored.
* If the specified input is not a valid config, a blank config will be
* returned.
*
* @param reader input
* @return resulting configuration
* @throws IllegalArgumentException Thrown if stream is null
*/
public static com.boydti.fawe.configuration.file.YamlConfiguration loadConfiguration(final Reader reader) {
if (reader == null) {
throw new NullPointerException("Reader cannot be null");
}
final com.boydti.fawe.configuration.file.YamlConfiguration config = new com.boydti.fawe.configuration.file.YamlConfiguration();
try {
config.load(reader);
} catch (final IOException | InvalidConfigurationException ex) {
System.out.println("Cannot load configuration from stream");
ex.printStackTrace();
}
return config;
}
@Override
public String saveToString() {
yamlOptions.setIndent(options().indent());
yamlOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
yamlRepresenter.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
final String header = buildHeader();
String dump = yaml.dump(getValues(false));
if (dump.equals(BLANK_CONFIG)) {
dump = "";
}
return header + dump;
}
@Override
public void loadFromString(final String contents) throws InvalidConfigurationException {
if (contents == null) {
throw new NullPointerException("Contents cannot be null");
}
Map<?, ?> input;
try {
input = (Map<?, ?>) yaml.load(contents);
} catch (final YAMLException e) {
throw new InvalidConfigurationException(e);
} catch (final ClassCastException e) {
throw new InvalidConfigurationException("Top level is not a Map.");
}
final String header = parseHeader(contents);
if (!header.isEmpty()) {
options().header(header);
}
if (input != null) {
convertMapsToSections(input, this);
}
}
protected void convertMapsToSections(final Map<?, ?> input, final ConfigurationSection section) {
for (final Map.Entry<?, ?> entry : input.entrySet()) {
final String key = entry.getKey().toString();
final Object value = entry.getValue();
if (value instanceof Map) {
convertMapsToSections((Map<?, ?>) value, section.createSection(key));
} else {
section.set(key, value);
}
}
}
protected String parseHeader(final String input) {
final String[] lines = input.split("\r?\n", -1);
final StringBuilder result = new StringBuilder();
boolean readingHeader = true;
boolean foundHeader = false;
for (int i = 0; (i < lines.length) && readingHeader; i++) {
final String line = lines[i];
if (line.startsWith(COMMENT_PREFIX)) {
if (i > 0) {
result.append("\n");
}
if (line.length() > COMMENT_PREFIX.length()) {
result.append(line.substring(COMMENT_PREFIX.length()));
}
foundHeader = true;
} else if (foundHeader && line.isEmpty()) {
result.append("\n");
} else if (foundHeader) {
readingHeader = false;
}
}
return result.toString();
}
@Override
protected String buildHeader() {
final String header = options().header();
if (options().copyHeader()) {
final Configuration def = getDefaults();
if (def != null && def instanceof FileConfiguration) {
final FileConfiguration filedefaults = (FileConfiguration) def;
final String defaultsHeader = filedefaults.buildHeader();
if ((defaultsHeader != null) && !defaultsHeader.isEmpty()) {
return defaultsHeader;
}
}
}
if (header == null) {
return "";
}
final StringBuilder builder = new StringBuilder();
final String[] lines = header.split("\r?\n", -1);
boolean startedHeader = false;
for (int i = lines.length - 1; i >= 0; i--) {
builder.insert(0, "\n");
if (startedHeader || !lines[i].isEmpty()) {
builder.insert(0, lines[i]);
builder.insert(0, COMMENT_PREFIX);
startedHeader = true;
}
}
return builder.toString();
}
@Override
public YamlConfigurationOptions options() {
if (options == null) {
options = new YamlConfigurationOptions(this);
}
return (YamlConfigurationOptions) options;
}
}

View File

@ -0,0 +1,76 @@
package com.boydti.fawe.configuration.file;
import com.boydti.fawe.configuration.file.FileConfigurationOptions;
import com.boydti.fawe.configuration.file.YamlConfiguration;
/**
* Various settings for controlling the input and output of a {@link
* com.boydti.fawe.configuration.file.YamlConfiguration}
*/
public class YamlConfigurationOptions extends FileConfigurationOptions {
private int indent = 2;
protected YamlConfigurationOptions(final YamlConfiguration configuration) {
super(configuration);
}
@Override
public YamlConfiguration configuration() {
return (YamlConfiguration) super.configuration();
}
@Override
public com.boydti.fawe.configuration.file.YamlConfigurationOptions copyDefaults(final boolean value) {
super.copyDefaults(value);
return this;
}
@Override
public com.boydti.fawe.configuration.file.YamlConfigurationOptions pathSeparator(final char value) {
super.pathSeparator(value);
return this;
}
@Override
public com.boydti.fawe.configuration.file.YamlConfigurationOptions header(final String value) {
super.header(value);
return this;
}
@Override
public com.boydti.fawe.configuration.file.YamlConfigurationOptions copyHeader(final boolean value) {
super.copyHeader(value);
return this;
}
/**
* Gets how much spaces should be used to indent each line.
* <p>
* The minimum value this may be is 2, and the maximum is 9.
*
* @return How much to indent by
*/
public int indent() {
return indent;
}
/**
* Sets how much spaces should be used to indent each line.
* <p>
* The minimum value this may be is 2, and the maximum is 9.
*
* @param value New indent
* @return This object, for chaining
*/
public com.boydti.fawe.configuration.file.YamlConfigurationOptions indent(final int value) {
if (value < 2) {
throw new IllegalArgumentException("Indent must be at least 2 characters");
}
if (value > 9) {
throw new IllegalArgumentException("Indent cannot be greater than 9 characters");
}
indent = value;
return this;
}
}

View File

@ -0,0 +1,47 @@
package com.boydti.fawe.configuration.file;
import com.boydti.fawe.configuration.serialization.ConfigurationSerialization;
import java.util.LinkedHashMap;
import java.util.Map;
import org.yaml.snakeyaml.constructor.SafeConstructor;
import org.yaml.snakeyaml.error.YAMLException;
import org.yaml.snakeyaml.nodes.Node;
import org.yaml.snakeyaml.nodes.Tag;
public class YamlConstructor extends SafeConstructor {
public YamlConstructor() {
yamlConstructors.put(Tag.MAP, new ConstructCustomObject());
}
private class ConstructCustomObject extends ConstructYamlMap {
@Override
public Object construct(final Node node) {
if (node.isTwoStepsConstruction()) {
throw new YAMLException("Unexpected referential mapping structure. Node: " + node);
}
final Map<?, ?> raw = (Map<?, ?>) super.construct(node);
if (raw.containsKey(ConfigurationSerialization.SERIALIZED_TYPE_KEY)) {
final Map<String, Object> typed = new LinkedHashMap<>(raw.size());
for (final Map.Entry<?, ?> entry : raw.entrySet()) {
typed.put(entry.getKey().toString(), entry.getValue());
}
try {
return ConfigurationSerialization.deserializeObject(typed);
} catch (final IllegalArgumentException ex) {
throw new YAMLException("Could not deserialize object", ex);
}
}
return raw;
}
@Override
public void construct2ndStep(final Node node, final Object object) {
throw new YAMLException("Unexpected referential mapping structure. Node: " + node);
}
}
}

View File

@ -0,0 +1,38 @@
package com.boydti.fawe.configuration.file;
import com.boydti.fawe.configuration.ConfigurationSection;
import com.boydti.fawe.configuration.serialization.ConfigurationSerializable;
import com.boydti.fawe.configuration.serialization.ConfigurationSerialization;
import java.util.LinkedHashMap;
import java.util.Map;
import org.yaml.snakeyaml.nodes.Node;
import org.yaml.snakeyaml.representer.Representer;
public class YamlRepresenter extends Representer {
public YamlRepresenter() {
this.multiRepresenters.put(ConfigurationSection.class, new RepresentConfigurationSection());
this.multiRepresenters.put(ConfigurationSerializable.class, new RepresentConfigurationSerializable());
}
private class RepresentConfigurationSection extends RepresentMap {
@Override
public Node representData(Object data) {
return super.representData(((ConfigurationSection) data).getValues(false));
}
}
private class RepresentConfigurationSerializable extends RepresentMap {
@Override
public Node representData(Object data) {
ConfigurationSerializable serializable = (ConfigurationSerializable) data;
Map<String, Object> values = new LinkedHashMap<>();
values.put(ConfigurationSerialization.SERIALIZED_TYPE_KEY, ConfigurationSerialization.getAlias(serializable.getClass()));
values.putAll(serializable.serialize());
return super.representData(values);
}
}
}

View File

@ -0,0 +1,35 @@
package com.boydti.fawe.configuration.serialization;
import java.util.Map;
/**
* Represents an object that may be serialized.
* <p>
* These objects MUST implement one of the following, in addition to the
* methods as defined by this interface:
* <ul>
* <li>A static method "deserialize" that accepts a single {@link java.util.Map}&lt;
* {@link String}, {@link Object}> and returns the class.</li>
* <li>A static method "valueOf" that accepts a single {@link java.util.Map}&lt;{@link
* String}, {@link Object}> and returns the class.</li>
* <li>A constructor that accepts a single {@link java.util.Map}&lt;{@link String},
* {@link Object}>.</li>
* </ul>
* In addition to implementing this interface, you must register the class
* with {@link com.boydti.fawe.configuration.serialization.ConfigurationSerialization#registerClass(Class)}.
*
* @see com.boydti.fawe.configuration.serialization.DelegateDeserialization
* @see com.boydti.fawe.configuration.serialization.SerializableAs
*/
public interface ConfigurationSerializable {
/**
* Creates a Map representation of this class.
* <p>
* This class must provide a method to restore this class, as defined in
* the {@link com.boydti.fawe.configuration.serialization.ConfigurationSerializable} interface javadoc.
*
* @return Map containing the current state of this class
*/
Map<String, Object> serialize();
}

View File

@ -0,0 +1,264 @@
package com.boydti.fawe.configuration.serialization;
import com.boydti.fawe.configuration.serialization.DelegateDeserialization;
import com.boydti.fawe.configuration.serialization.SerializableAs;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Utility class for storing and retrieving classes for {@link com.boydti.fawe.configuration.Configuration}.
*/
public class ConfigurationSerialization {
public static final String SERIALIZED_TYPE_KEY = "==";
private static final Map<String, Class<? extends ConfigurationSerializable>> aliases =
new HashMap<String, Class<? extends ConfigurationSerializable>>();
private final Class<? extends ConfigurationSerializable> clazz;
protected ConfigurationSerialization(Class<? extends ConfigurationSerializable> clazz) {
this.clazz = clazz;
}
/**
* Attempts to deserialize the given arguments into a new instance of the
* given class.
*
* <p>The class must implement {@link com.boydti.fawe.configuration.serialization.ConfigurationSerializable}, including
* the extra methods as specified in the javadoc of
* ConfigurationSerializable.</p>
*
* <p>If a new instance could not be made, an example being the class not
* fully implementing the interface, null will be returned.</p>
*
* @param args Arguments for deserialization
* @param clazz Class to deserialize into
* @return New instance of the specified class
*/
public static ConfigurationSerializable deserializeObject(Map<String, ?> args, Class<? extends ConfigurationSerializable> clazz) {
return new com.boydti.fawe.configuration.serialization.ConfigurationSerialization(clazz).deserialize(args);
}
/**
* Attempts to deserialize the given arguments into a new instance of the
*
* given class.
* <p>
* The class must implement {@link com.boydti.fawe.configuration.serialization.ConfigurationSerializable}, including
* the extra methods as specified in the javadoc of
* ConfigurationSerializable.</p>
*
* <p>
* If a new instance could not be made, an example being the class not
* fully implementing the interface, null will be returned.</p>
*
* @param args Arguments for deserialization
* @return New instance of the specified class
*/
public static ConfigurationSerializable deserializeObject(Map<String, ?> args) {
Class<? extends ConfigurationSerializable> clazz = null;
if (args.containsKey(SERIALIZED_TYPE_KEY)) {
try {
String alias = (String) args.get(SERIALIZED_TYPE_KEY);
if (alias == null) {
throw new IllegalArgumentException("Cannot have null alias");
}
clazz = getClassByAlias(alias);
if (clazz == null) {
throw new IllegalArgumentException("Specified class does not exist ('" + alias + "')");
}
} catch (ClassCastException ex) {
ex.fillInStackTrace();
throw ex;
}
} else {
throw new IllegalArgumentException("Args doesn't contain type key ('" + SERIALIZED_TYPE_KEY + "')");
}
return new com.boydti.fawe.configuration.serialization.ConfigurationSerialization(clazz).deserialize(args);
}
/**
* Registers the given {@link com.boydti.fawe.configuration.serialization.ConfigurationSerializable} class by its
* alias.
*
* @param clazz Class to register
*/
public static void registerClass(Class<? extends ConfigurationSerializable> clazz) {
com.boydti.fawe.configuration.serialization.DelegateDeserialization delegate = clazz.getAnnotation(com.boydti.fawe.configuration.serialization.DelegateDeserialization.class);
if (delegate == null) {
registerClass(clazz, getAlias(clazz));
registerClass(clazz, clazz.getName());
}
}
/**
* Registers the given alias to the specified {@link
* com.boydti.fawe.configuration.serialization.ConfigurationSerializable} class.
*
* @param clazz Class to register
* @param alias Alias to register as
* @see com.boydti.fawe.configuration.serialization.SerializableAs
*/
public static void registerClass(Class<? extends ConfigurationSerializable> clazz, String alias) {
aliases.put(alias, clazz);
}
/**
* Unregisters the specified alias to a {@link com.boydti.fawe.configuration.serialization.ConfigurationSerializable}
*
* @param alias Alias to unregister
*/
public static void unregisterClass(String alias) {
aliases.remove(alias);
}
/**
* Unregisters any aliases for the specified {@link
* com.boydti.fawe.configuration.serialization.ConfigurationSerializable} class.
*
* @param clazz Class to unregister
*/
public static void unregisterClass(Class<? extends ConfigurationSerializable> clazz) {
while (aliases.values().remove(clazz)) {
}
}
/**
* Attempts to get a registered {@link com.boydti.fawe.configuration.serialization.ConfigurationSerializable} class by
* its alias.
*
* @param alias Alias of the serializable
* @return Registered class, or null if not found
*/
public static Class<? extends ConfigurationSerializable> getClassByAlias(String alias) {
return aliases.get(alias);
}
/**
* Gets the correct alias for the given {@link com.boydti.fawe.configuration.serialization.ConfigurationSerializable}
* class.
*
* @param clazz Class to get alias for
* @return Alias to use for the class
*/
public static String getAlias(Class<? extends ConfigurationSerializable> clazz) {
com.boydti.fawe.configuration.serialization.DelegateDeserialization delegate = clazz.getAnnotation(DelegateDeserialization.class);
if (delegate != null) {
if ((delegate.value() == null) || (delegate.value() == clazz)) {
delegate = null;
} else {
return getAlias(delegate.value());
}
}
SerializableAs alias = clazz.getAnnotation(SerializableAs.class);
if (alias != null) {
return alias.value();
}
return clazz.getName();
}
protected Method getMethod(String name, boolean isStatic) {
try {
Method method = this.clazz.getDeclaredMethod(name, Map.class);
if (!ConfigurationSerializable.class.isAssignableFrom(method.getReturnType())) {
return null;
}
if (Modifier.isStatic(method.getModifiers()) != isStatic) {
return null;
}
return method;
} catch (NoSuchMethodException ex) {
return null;
} catch (SecurityException ex) {
return null;
}
}
protected Constructor<? extends ConfigurationSerializable> getConstructor() {
try {
return this.clazz.getConstructor(Map.class);
} catch (NoSuchMethodException ex) {
return null;
} catch (SecurityException ex) {
return null;
}
}
protected ConfigurationSerializable deserializeViaMethod(Method method, Map<String, ?> args) {
try {
ConfigurationSerializable result = (ConfigurationSerializable) method.invoke(null, args);
if (result == null) {
Logger.getLogger(com.boydti.fawe.configuration.serialization.ConfigurationSerialization.class.getName()).log(Level.SEVERE,
"Could not call method '" + method.toString() + "' of " + this.clazz + " for deserialization: method returned null");
} else {
return result;
}
} catch (Throwable ex) {
Logger.getLogger(com.boydti.fawe.configuration.serialization.ConfigurationSerialization.class.getName())
.log(Level.SEVERE, "Could not call method '" + method.toString() + "' of " + this.clazz
+ " for deserialization",
ex instanceof InvocationTargetException ? ex.getCause() : ex);
}
return null;
}
protected ConfigurationSerializable deserializeViaCtor(Constructor<? extends ConfigurationSerializable> ctor, Map<String, ?> args) {
try {
return ctor.newInstance(args);
} catch (Throwable ex) {
Logger.getLogger(com.boydti.fawe.configuration.serialization.ConfigurationSerialization.class.getName())
.log(Level.SEVERE, "Could not call constructor '" + ctor.toString() + "' of " + this.clazz
+ " for deserialization",
ex instanceof InvocationTargetException ? ex.getCause() : ex);
}
return null;
}
public ConfigurationSerializable deserialize(Map<String, ?> args) {
if (args == null) {
throw new NullPointerException("Args must not be null");
}
ConfigurationSerializable result = null;
Method method = getMethod("deserialize", true);
if (method != null) {
result = deserializeViaMethod(method, args);
}
if (result == null) {
method = getMethod("valueOf", true);
if (method != null) {
result = deserializeViaMethod(method, args);
}
}
if (result == null) {
Constructor<? extends ConfigurationSerializable> constructor = getConstructor();
if (constructor != null) {
result = deserializeViaCtor(constructor, args);
}
}
return result;
}
}

View File

@ -0,0 +1,23 @@
package com.boydti.fawe.configuration.serialization;
import com.boydti.fawe.configuration.serialization.ConfigurationSerializable;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Applies to a {@link com.boydti.fawe.configuration.serialization.ConfigurationSerializable} that will delegate all
* deserialization to another {@link com.boydti.fawe.configuration.serialization.ConfigurationSerializable}.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface DelegateDeserialization {
/**
* Which class should be used as a delegate for this classes
* deserialization
*
* @return Delegate class
*/
Class<? extends ConfigurationSerializable> value();
}

View File

@ -0,0 +1,34 @@
package com.boydti.fawe.configuration.serialization;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Represents an "alias" that a {@link com.boydti.fawe.configuration.serialization.ConfigurationSerializable} may be
* stored as.
* If this is not present on a {@link com.boydti.fawe.configuration.serialization.ConfigurationSerializable} class, it
* will use the fully qualified name of the class.
* <p>
* This value will be stored in the configuration so that the configuration
* deserialization can determine what type it is.
* <p>
* Using this annotation on any other class than a {@link
* com.boydti.fawe.configuration.serialization.ConfigurationSerializable} will have no effect.
*
* @see com.boydti.fawe.configuration.serialization.ConfigurationSerialization#registerClass(Class, String)
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface SerializableAs {
/**
* This is the name your class will be stored and retrieved as.
* <p>
* This name MUST be unique. We recommend using names such as
* "MyPluginThing" instead of "Thing".
*
* @return Name to serialize the class as.
*/
String value();
}

View File

@ -1,10 +1,10 @@
package com.boydti.fawe.object;
import com.boydti.fawe.object.changeset.FaweChangeSet;
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 {
@ -26,7 +26,7 @@ public class EditSessionWrapper {
return minY;
}
public Extent getHistoryExtent(final Extent parent, final ChangeSet set, final FawePlayer<?> player) {
public Extent getHistoryExtent(final Extent parent, FaweChangeSet set, final FawePlayer<?> player) {
return new HistoryExtent(parent, set);
}
}

View File

@ -1,44 +0,0 @@
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();
this.changes.add(bc);
} else {
this.changes.add(change);
}
}
@Override
public Iterator<Change> backwardIterator() {
return this.changes.descendingIterator();
}
@Override
public Iterator<Change> forwardIterator() {
return this.changes.iterator();
}
@Override
public int size() {
return this.changes.size();
}
}

View File

@ -11,18 +11,25 @@ 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;
import java.util.concurrent.ConcurrentHashMap;
public abstract class FawePlayer<T> {
public final T parent;
private LocalSession session;
/**
* The metadata map.
*/
private ConcurrentHashMap<String, Object> meta;
public static <T> FawePlayer<T> wrap(final Object obj) {
return Fawe.imp().wrap(obj);
}
public FawePlayer(final T parent) {
this.parent = parent;
Fawe.get().register(this);
}
public abstract String getName();
@ -84,4 +91,51 @@ public abstract class FawePlayer<T> {
public boolean hasWorldEditBypass() {
return this.hasPermission("fawe.bypass");
}
/**
* Set some session only metadata for the player
* @param key
* @param value
*/
public void setMeta(String key, Object value) {
if (this.meta == null) {
this.meta = new ConcurrentHashMap<>();
}
this.meta.put(key, value);
}
/**
* Get the metadata for a key.
* @param <T>
* @param key
* @return
*/
public <T> T getMeta(String key) {
if (this.meta != null) {
return (T) this.meta.get(key);
}
return null;
}
public <T> T getMeta(String key, T def) {
if (this.meta != null) {
T value = (T) this.meta.get(key);
return value == null ? def : value;
}
return def;
}
/**
* Delete the metadata for a key.
* - metadata is session only
* - deleting other plugin's metadata may cause issues
* @param key
*/
public Object deleteMeta(String key) {
return this.meta == null ? null : this.meta.remove(key);
}
public void unregister() {
Fawe.get().unregister(getName());
}
}

View File

@ -1,12 +1,7 @@
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.boydti.fawe.FaweCache;
import com.boydti.fawe.object.changeset.FaweChangeSet;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock;
@ -14,28 +9,32 @@ 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;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Stores changes to a {@link ChangeSet}.
*/
public class HistoryExtent extends AbstractDelegateExtent {
private final ChangeSet changeSet;
private final com.boydti.fawe.object.changeset.FaweChangeSet changeSet;
/**
* Create a new instance.
*
* @param extent the extent
* @param changeSet the change set
* @param thread
*/
public HistoryExtent(final Extent extent, final ChangeSet changeSet) {
public HistoryExtent(final Extent extent, final FaweChangeSet changeSet) {
super(extent);
checkNotNull(changeSet);
this.changeSet = changeSet;
@ -53,95 +52,15 @@ public class HistoryExtent extends AbstractDelegateExtent {
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 51:
case 52:
case 54:
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 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 (FaweCache.hasData(id_p)) {
if (previous.getData() == block.getData()) {
return false;
default:
if (block.getData() == previous.getData()) {
return false;
}
}
} else {
return false;
}
}
this.changeSet.add(new BlockChange(location.toBlockVector(), previous, block));
this.changeSet.add(location, previous, block);
return true;
}
return false;

View File

@ -1,12 +1,13 @@
package com.boydti.fawe.object;
import com.boydti.fawe.object.changeset.FaweChangeSet;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.history.change.Change;
import java.util.ArrayList;
import java.util.Iterator;
import com.sk89q.worldedit.history.change.Change;
import com.sk89q.worldedit.history.changeset.ChangeSet;
public class NullChangeSet implements ChangeSet {
public class NullChangeSet implements FaweChangeSet {
@Override
public void add(Change change) {}
@ -25,5 +26,10 @@ public class NullChangeSet implements ChangeSet {
public int size() {
return 0;
}
@Override
public void flush() {}
@Override
public void add(Vector location, BaseBlock from, BaseBlock to) {}
}

View File

@ -1,13 +0,0 @@
package com.boydti.fawe.object.changeset;
import com.sk89q.worldedit.history.changeset.BlockOptimizedHistory;
/**
* History optimized for speed
* - Low CPU usage
* - High memory usage
* - No disk usage
*/
public class CPUOptimizedHistory extends BlockOptimizedHistory {
}

View File

@ -1,18 +1,5 @@
package com.boydti.fawe.object.changeset;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.config.Settings;
@ -25,12 +12,25 @@ import com.sk89q.jnbt.NBTOutputStream;
import com.sk89q.jnbt.NamedTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.history.change.BlockChange;
import com.sk89q.worldedit.history.change.Change;
import com.sk89q.worldedit.history.change.EntityCreate;
import com.sk89q.worldedit.history.change.EntityRemove;
import com.sk89q.worldedit.history.changeset.ChangeSet;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
/**
* Store the change on disk
@ -39,7 +39,7 @@ import com.sk89q.worldedit.history.changeset.ChangeSet;
* - Minimal memory usage
* - Slow
*/
public class DiskStorageHistory implements ChangeSet, FlushableChangeSet {
public class DiskStorageHistory implements ChangeSet, FaweChangeSet {
private final File bdFile;
private final File nbtfFile;
@ -108,7 +108,7 @@ public class DiskStorageHistory implements ChangeSet, FlushableChangeSet {
if ((change instanceof BlockChange)) {
add((BlockChange) change);
} else {
System.out.print("[FAWE] Does not support " + change + " yet! (Please bug Empire92)");
Fawe.debug("[FAWE] Does not support " + change + " yet! (Please bug Empire92)");
}
}
@ -136,29 +136,18 @@ public class DiskStorageHistory implements ChangeSet, FlushableChangeSet {
e.printStackTrace();
}
}
public void add(EntityCreate change) {
}
public void add(EntityRemove change) {
@Override
public void add(Vector location, BaseBlock from, BaseBlock to) {
add(location.getBlockX(), location.getBlockY(), location.getBlockZ(), from, to);
}
public void add(BlockChange change) {
public void add(int x, int y, int z, BaseBlock from, BaseBlock to) {
try {
BlockVector loc = change.getPosition();
int x = loc.getBlockX();
int y = loc.getBlockY();
int z = loc.getBlockZ();
BaseBlock from = change.getPrevious();
BaseBlock to = change.getCurrent();
int idfrom = from.getId();
int combinedFrom = (FaweCache.hasData(idfrom) ? ((idfrom << 4) + from.getData()) : (idfrom << 4));
CompoundTag nbtFrom = FaweCache.hasNBT(idfrom) ? from.getNbtData() : null;
int idTo = to.getId();
int combinedTo = (FaweCache.hasData(idTo) ? ((idTo << 4) + to.getData()) : (idTo << 4));
CompoundTag nbtTo = FaweCache.hasNBT(idTo) ? to.getNbtData() : null;
@ -177,7 +166,7 @@ public class DiskStorageHistory implements ChangeSet, FlushableChangeSet {
//to
stream.write((combinedTo) & 0xff);
stream.write(((combinedTo) >> 8) & 0xff);
if (nbtFrom != null && MainUtil.isValidTag(nbtFrom)) {
Map<String, Tag> value = ReflectionUtils.getMap(nbtFrom.getValue());
value.put("x", new IntTag(x));
@ -186,7 +175,7 @@ public class DiskStorageHistory implements ChangeSet, FlushableChangeSet {
NBTOutputStream nbtos = getNBTFOS(x, y, z);
nbtos.writeNamedTag(osNBTFI.getAndIncrement() + "", nbtFrom);
}
if (nbtTo != null && MainUtil.isValidTag(nbtTo)) {
Map<String, Tag> value = ReflectionUtils.getMap(nbtTo.getValue());
value.put("x", new IntTag(x));
@ -199,6 +188,28 @@ public class DiskStorageHistory implements ChangeSet, FlushableChangeSet {
e.printStackTrace();
}
}
public void add(EntityCreate change) {
// TODO
}
public void add(EntityRemove change) {
// TODO
}
public void add(BlockChange change) {
try {
BlockVector loc = change.getPosition();
int x = loc.getBlockX();
int y = loc.getBlockY();
int z = loc.getBlockZ();
BaseBlock from = change.getPrevious();
BaseBlock to = change.getCurrent();
add(x, y, z, from, to);
} catch (Exception e) {
e.printStackTrace();
}
}
private OutputStream getBAOS(int x, int y, int z) throws IOException {
if (osBD != null) {

View File

@ -0,0 +1,11 @@
package com.boydti.fawe.object.changeset;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.history.changeset.ChangeSet;
public interface FaweChangeSet extends ChangeSet {
void flush();
void add(Vector location, BaseBlock from, BaseBlock to);
}

View File

@ -1,5 +0,0 @@
package com.boydti.fawe.object.changeset;
public interface FlushableChangeSet {
public void flush();
}

View File

@ -1,5 +1,6 @@
package com.boydti.fawe.object.changeset;
import com.sk89q.worldedit.Vector;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@ -33,7 +34,7 @@ import com.sk89q.worldedit.history.changeset.ChangeSet;
* - High CPU usage
* - Low memory usage
*/
public class MemoryOptimizedHistory implements ChangeSet, FlushableChangeSet {
public class MemoryOptimizedHistory implements ChangeSet, FaweChangeSet {
private ArrayDeque<CompoundTag> fromTags;
private ArrayDeque<CompoundTag> toTags;
@ -53,67 +54,74 @@ public class MemoryOptimizedHistory implements ChangeSet, FlushableChangeSet {
size = new AtomicInteger();
}
@Override
public void add(Vector location, BaseBlock from, BaseBlock to) {
add(location.getBlockX(), location.getBlockY(), location.getBlockZ(), from, to);
}
public void add(int x, int y, int z, BaseBlock from, BaseBlock to) {
try {
int idfrom = from.getId();
int combinedFrom = (FaweCache.hasData(idfrom) ? ((idfrom << 4) + from.getData()) : (idfrom << 4));
CompoundTag nbtFrom = FaweCache.hasNBT(idfrom) ? from.getNbtData() : null;
int idTo = to.getId();
int combinedTo = (FaweCache.hasData(idTo) ? ((idTo << 4) + to.getData()) : (idTo << 4));
CompoundTag nbtTo = FaweCache.hasNBT(idTo) ? to.getNbtData() : null;
OutputStream stream = getBAOS(x, y, z);
//x
stream.write((x - ox) & 0xff);
stream.write(((x - ox) >> 8) & 0xff);
//z
stream.write((z - oz) & 0xff);
stream.write(((z - oz) >> 8) & 0xff);
//y
stream.write((byte) y);
//from
stream.write((combinedFrom) & 0xff);
stream.write(((combinedFrom) >> 8) & 0xff);
//to
stream.write((combinedTo) & 0xff);
stream.write(((combinedTo) >> 8) & 0xff);
if (nbtFrom != null && MainUtil.isValidTag(nbtFrom)) {
Map<String, Tag> value = ReflectionUtils.getMap(nbtFrom.getValue());
value.put("x", new IntTag(x));
value.put("y", new IntTag(y));
value.put("z", new IntTag(z));
if (fromTags == null) {
fromTags = new ArrayDeque<>();
}
fromTags.add(nbtFrom);
}
if (nbtTo != null && MainUtil.isValidTag(nbtTo)) {
Map<String, Tag> value = ReflectionUtils.getMap(nbtTo.getValue());
value.put("x", new IntTag(x));
value.put("y", new IntTag(y));
value.put("z", new IntTag(z));
if (toTags == null) {
toTags = new ArrayDeque<>();
}
toTags.add(nbtTo);
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void add(Change arg) {
size.incrementAndGet();
if ((arg instanceof BlockChange)) {
try {
BlockChange change = (BlockChange) arg;
BlockVector loc = change.getPosition();
int x = loc.getBlockX();
int y = loc.getBlockY();
int z = loc.getBlockZ();
BaseBlock from = change.getPrevious();
BaseBlock to = change.getCurrent();
int idfrom = from.getId();
int combinedFrom = (FaweCache.hasData(idfrom) ? ((idfrom << 4) + from.getData()) : (idfrom << 4));
CompoundTag nbtFrom = FaweCache.hasNBT(idfrom) ? from.getNbtData() : null;
int idTo = to.getId();
int combinedTo = (FaweCache.hasData(idTo) ? ((idTo << 4) + to.getData()) : (idTo << 4));
CompoundTag nbtTo = FaweCache.hasNBT(idTo) ? to.getNbtData() : null;
OutputStream stream = getBAOS(x, y, z);
//x
stream.write((x - ox) & 0xff);
stream.write(((x - ox) >> 8) & 0xff);
//z
stream.write((z - oz) & 0xff);
stream.write(((z - oz) >> 8) & 0xff);
//y
stream.write((byte) y);
//from
stream.write((combinedFrom) & 0xff);
stream.write(((combinedFrom) >> 8) & 0xff);
//to
stream.write((combinedTo) & 0xff);
stream.write(((combinedTo) >> 8) & 0xff);
if (nbtFrom != null && MainUtil.isValidTag(nbtFrom)) {
Map<String, Tag> value = ReflectionUtils.getMap(nbtFrom.getValue());
value.put("x", new IntTag(x));
value.put("y", new IntTag(y));
value.put("z", new IntTag(z));
if (fromTags == null) {
fromTags = new ArrayDeque<>();
}
fromTags.add(nbtFrom);
}
if (nbtTo != null && MainUtil.isValidTag(nbtTo)) {
Map<String, Tag> value = ReflectionUtils.getMap(nbtTo.getValue());
value.put("x", new IntTag(x));
value.put("y", new IntTag(y));
value.put("z", new IntTag(z));
if (toTags == null) {
toTags = new ArrayDeque<>();
}
toTags.add(nbtTo);
}
} catch (Exception e) {
e.printStackTrace();
}
add(x, y, z, from, to);
} else {
if (entities == null) {
entities = new ArrayDeque<>();

View File

@ -9,6 +9,7 @@ import com.intellectualcrafters.plot.object.Plot;
import com.intellectualcrafters.plot.object.PlotId;
import com.intellectualcrafters.plot.object.PlotPlayer;
import com.intellectualcrafters.plot.object.RegionWrapper;
import com.sk89q.worldedit.BlockVector;
import java.util.HashSet;
public class PlotSquaredFeature extends FaweMaskManager {
@ -48,14 +49,14 @@ public class PlotSquaredFeature extends FaweMaskManager {
RegionWrapper region = plot.getLargestRegion();
HashSet<RegionWrapper> regions = plot.getRegions();
final Location pos1 = new Location(world, region.minX, 0, region.minZ);
final Location pos2 = new Location(world, region.maxX, 256, region.maxZ);
final BlockVector pos1 = new BlockVector(region.minX, 0, region.minZ);
final BlockVector pos2 = new BlockVector(region.maxX, 256, region.maxZ);
final HashSet<com.boydti.fawe.object.RegionWrapper> faweRegions = new HashSet<com.boydti.fawe.object.RegionWrapper>();
for (final com.intellectualcrafters.plot.object.RegionWrapper current : regions) {
faweRegions.add(new com.boydti.fawe.object.RegionWrapper(current.minX, current.maxX, current.minZ, current.maxZ));
}
return new BukkitMask(pos1, pos2) {
return new FaweMask(pos1, pos2) {
@Override
public String getName() {
return "PLOT^2:" + id;

View File

@ -1,18 +1,14 @@
package com.boydti.fawe.util;
import java.io.File;
import java.util.Map.Entry;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.object.FawePlayer;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.EndTag;
import com.sk89q.jnbt.ListTag;
import com.sk89q.jnbt.Tag;
import java.io.File;
import java.util.Map.Entry;
public class MainUtil {
/*
@ -20,7 +16,7 @@ public class MainUtil {
* e.g. sending messages
*/
public static void sendMessage(final FawePlayer<?> player, String message) {
message = ChatColor.translateAlternateColorCodes('&', message);
message = BBC.color(message);
if (player == null) {
Fawe.debug(message);
} else {
@ -29,7 +25,7 @@ public class MainUtil {
}
public static void sendAdmin(final String s) {
for (final Player player : Bukkit.getOnlinePlayers()) {
for (final FawePlayer<?> player : Fawe.imp().getPlayers()) {
if (player.hasPermission("fawe.admin")) {
player.sendMessage(s);
}

View File

@ -9,7 +9,6 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.bukkit.Bukkit;
import org.bukkit.Server;
@ -32,7 +31,7 @@ public class ReflectionUtils {
*/
private static boolean forge = false;
/** check server version and class names */
static {
public static void init() {
if (Bukkit.getServer() != null) {
if (Bukkit.getVersion().contains("MCPC") || Bukkit.getVersion().contains("Forge")) {
forge = true;
@ -221,6 +220,9 @@ public class ReflectionUtils {
* @throws RuntimeException if no class found
*/
public static RefClass getRefClass(final String... classes) throws RuntimeException {
if (preClassM == null) {
init();
}
for (String className : classes) {
try {
className = className.replace("{cb}", preClassB).replace("{nms}", preClassM).replace("{nm}", "net.minecraft");

View File

@ -19,25 +19,6 @@
package com.sk89q.worldedit;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.worldedit.regions.Regions.asFlatRegion;
import static com.sk89q.worldedit.regions.Regions.maximumBlockY;
import static com.sk89q.worldedit.regions.Regions.minimumBlockY;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.config.BBC;
@ -47,6 +28,7 @@ import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.NullChangeSet;
import com.boydti.fawe.object.RegionWrapper;
import com.boydti.fawe.object.changeset.DiskStorageHistory;
import com.boydti.fawe.object.changeset.FaweChangeSet;
import com.boydti.fawe.object.changeset.MemoryOptimizedHistory;
import com.boydti.fawe.object.extent.FastWorldEditExtent;
import com.boydti.fawe.object.extent.NullExtent;
@ -130,6 +112,24 @@ import com.sk89q.worldedit.util.collection.DoubleArrayList;
import com.sk89q.worldedit.util.eventbus.EventBus;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.biome.BaseBiome;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.worldedit.regions.Regions.asFlatRegion;
import static com.sk89q.worldedit.regions.Regions.maximumBlockY;
import static com.sk89q.worldedit.regions.Regions.minimumBlockY;
/**
* An {@link Extent} that handles history, {@link BlockBag}s, change limits,
@ -152,7 +152,7 @@ public class EditSession implements Extent {
}
protected final World world;
private final ChangeSet changeSet;
private final FaweChangeSet changeSet;
private final EditSessionWrapper wrapper;
private MultiStageReorder reorderExtent;
private @Nullable Extent changeSetExtent;

View File

@ -19,18 +19,7 @@
package com.sk89q.worldedit;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Calendar;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.TimeZone;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.annotation.Nullable;
import com.boydti.fawe.object.changeset.FlushableChangeSet;
import com.boydti.fawe.object.changeset.FaweChangeSet;
import com.sk89q.jchronic.Chronic;
import com.sk89q.jchronic.Options;
import com.sk89q.jchronic.utils.Span;
@ -57,6 +46,16 @@ import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.session.request.Request;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.snapshot.Snapshot;
import java.util.Calendar;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.TimeZone;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Stores session information.
@ -200,8 +199,8 @@ public class LocalSession {
history.remove(historyPointer);
}
ChangeSet set = editSession.getChangeSet();
if (set instanceof FlushableChangeSet) {
((FlushableChangeSet) set).flush();
if (set instanceof FaweChangeSet) {
((FaweChangeSet) set).flush();
}
history.add(editSession);
while (history.size() > MAX_HISTORY_SIZE) {

View File

@ -19,16 +19,6 @@
package com.sk89q.worldedit.extension.platform;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.worldedit.util.command.composition.LegacyCommandAdapter.adapt;
import java.io.File;
import java.io.IOException;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import com.boydti.fawe.util.SetQueue;
import com.boydti.fawe.util.TaskManager;
import com.google.common.base.Joiner;
@ -88,6 +78,16 @@ import com.sk89q.worldedit.util.formatting.ColorCodeBuilder;
import com.sk89q.worldedit.util.formatting.component.CommandUsageBox;
import com.sk89q.worldedit.util.logging.DynamicStreamHandler;
import com.sk89q.worldedit.util.logging.LogFormat;
import java.io.File;
import java.io.IOException;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.worldedit.util.command.composition.LegacyCommandAdapter.adapt;
/**
* Handles the registration and invocation of commands.
@ -271,12 +271,12 @@ public final class CommandManager {
if (editSession != null) {
session.remember(editSession);
editSession.flushQueue();
long time = System.currentTimeMillis() - start;
final long time = System.currentTimeMillis() - start;
if (time > 5 && editSession.size() != 0) {
SetQueue.IMP.addTask(new Runnable() {
@Override
public void run() {
actor.print("[FAWE] Action complete");
actor.print("[FAWE] Action completed in " + (time / 1000d) + " seconds");
}
});
}

View File

@ -0,0 +1,93 @@
#################################################
ForgeGradle 2.1-SNAPSHOT-unknown
https://github.com/MinecraftForge/ForgeGradle
#################################################
Powered by MCP unknown
http://modcoderpack.com
by: Searge, ProfMobius, Fesh0r,
R4wk, ZeuX, IngisKahn, bspkrs
#################################################
Version string 'unspecified' does not match SemVer specification
You should try SemVer : http://semver.org/
:forge:deobfCompileDummyTask
:core:compileJava
:forge:deobfProvidedDummyTask
:forge:extractDependencyATs SKIPPED
:forge:extractMcpDatawarning: [options] bootstrap class path not set in conjunction with -source 1.7
SKIPPED
:forge:extractMcpMappings SKIPPED
:forge:genSrgs SKIPPED
:forge:getVersionJson
:forge:downloadServer SKIPPED
:forge:splitServerJarNote: Some input files use or override a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
Note: Some input files use unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
1 warning
:core:processResources UP-TO-DATE
:core:classes
:core:jar
:forge:splitServerJar SKIPPED
:forge:deobfMcMCP SKIPPED
:forge:sourceApiJava UP-TO-DATE
:forge:compileApiJava UP-TO-DATE
:forge:processApiResources UP-TO-DATE
:forge:apiClasses UP-TO-DATE
:forge:sourceMainJava UP-TO-DATE
:forge:compileJavaC:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'modid()' in type 'Mod': class file for net.minecraftforge.fml.common.Mod not found
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'name()' in type 'Mod'
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'version()' in type 'Mod'
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'acceptableRemoteVersions()' in type 'Mod'
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'dependencies()' in type 'Mod'
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'acceptedMinecraftVersions()' in type 'Mod'
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'value()' in type 'Instance': class file for net.minecraftforge.fml.common.Mod$Instance not found
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'serverSide()' in type 'SidedProxy': class file for net.minecraftforge.fml.common.SidedProxy not found
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'clientSide()' in type 'SidedProxy'
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'modid()' in type 'Mod': class file for net.minecraftforge.fml.common.Mod not found
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'name()' in type 'Mod'
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'version()' in type 'Mod'
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'acceptableRemoteVersions()' in type 'Mod'
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'dependencies()' in type 'Mod'
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'acceptedMinecraftVersions()' in type 'Mod'
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'value()' in type 'Instance': class file for net.minecraftforge.fml.common.Mod$Instance not found
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'serverSide()' in type 'SidedProxy': class file for net.minecraftforge.fml.common.SidedProxy not found
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'clientSide()' in type 'SidedProxy'
Note: Writing plugin metadata to file:/C:/Users/Jesse/Desktop/OTHER/GitHub/FastAsyncWorldEdit/forge/build/classes/main/mcmod.info
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'modid()' in type 'Mod': class file for net.minecraftforge.fml.common.Mod not found
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'name()' in type 'Mod'
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'version()' in type 'Mod'
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'acceptableRemoteVersions()' in type 'Mod'
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'dependencies()' in type 'Mod'
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'acceptedMinecraftVersions()' in type 'Mod'
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'value()' in type 'Instance': class file for net.minecraftforge.fml.common.Mod$Instance not found
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'serverSide()' in type 'SidedProxy': class file for net.minecraftforge.fml.common.SidedProxy not found
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'clientSide()' in type 'SidedProxy'
Note: Some input files use or override a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
Note: Some input files use unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
27 warnings
:forge:processResources UP-TO-DATE
:forge:classes
:forge:jar
:forge:sourceTestJava UP-TO-DATE
:forge:compileTestJava UP-TO-DATE
:forge:processTestResources UP-TO-DATE
:forge:testClasses UP-TO-DATE
:forge:test UP-TO-DATE
:forge:reobfJar
:forge:shadowJar
:forge:reobfShadowJar
:forge:extractRangemapReplacedMain
C:\Users\Jesse\Desktop\OTHER\GitHub\FastAsyncWorldEdit\forge\build\sources\main\java
:forge:retromapReplacedMain UP-TO-DATE
:forge:sourceJar UP-TO-DATE
:forge:assemble
:forge:check UP-TO-DATE
:forge:build
BUILD SUCCESSFUL
Total time: 38.081 secs

View File

@ -3,44 +3,36 @@ package com.boydti.fawe.forge;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.IFawe;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.forge.v0.SpongeEditSessionWrapper_0;
import com.boydti.fawe.forge.v1_8.SpongeQueue_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.TaskManager;
import com.google.inject.Inject;
import com.intellectualcrafters.plot.config.C;
import com.intellectualcrafters.plot.config.Settings;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.forge.ForgeWorldEdit;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import org.mcstats.Metrics;
import org.slf4j.Logger;
import org.spongepowered.api.Game;
import org.spongepowered.api.Server;
import org.spongepowered.api.event.Listener;
import org.spongepowered.api.event.game.state.GameAboutToStartServerEvent;
import org.spongepowered.api.plugin.Plugin;
import org.spongepowered.api.plugin.PluginContainer;
import org.spongepowered.api.profile.GameProfileManager;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.entity.living.player.Player;
import org.spongepowered.api.text.serializer.TextSerializers;
@Plugin(id = "com.boydti.fawe", name = "FastAsyncWorldEdit", description = "Lagless WorldEdit, Area restrictions, Memory mangement, Block logging", url = "https://github.com/boy0001/FastAsyncWorldedit", version = "3.3.4")
import static org.spongepowered.api.Sponge.getGame;
public class FaweSponge implements IFawe {
public PluginContainer plugin;
public final SpongeMain plugin;
public FaweSponge instance;
@Inject
private Logger logger;
@Inject
private Game game;
private Server server;
private GameProfileManager resolver;
private ForgeWorldEdit worldedit;
public ForgeWorldEdit getWorldEditPlugin() {
@ -50,46 +42,21 @@ public class FaweSponge implements IFawe {
return this.worldedit;
}
public Game getGame() {
return this.game;
}
public Server getServer() {
return this.server;
}
public GameProfileManager getResolver() {
if (this.resolver == null) {
this.resolver = this.game.getServer().getGameProfileManager();
}
return this.resolver;
}
@Listener
public void onServerAboutToStart(GameAboutToStartServerEvent event) {
debug("FAWE: Server init");
public FaweSponge(SpongeMain plugin) {
instance = this;
plugin = this.game.getPluginManager().fromInstance(this).get();
this.server = this.game.getServer();
this.plugin = plugin;
try {
Fawe.set(this);
} catch (final Throwable e) {
e.printStackTrace();
this.getServer().shutdown();
}
TaskManager.IMP.later(() -> SpongeUtil.initBiomeCache(), 0);
}
@Override
public void debug(String message) {
message = C.format(message, C.replacements);
if (!Settings.CONSOLE_COLOR) {
message = message.replaceAll('\u00a7' + "[a-z|0-9]", "");
}
if (this.server == null) {
this.logger.info(message);
return;
}
this.server.getConsole().sendMessage(TextSerializers.LEGACY_FORMATTING_CODE.deserialize(BBC.color(message)));
message = BBC.color(message);
Sponge.getServer().getConsole().sendMessage(TextSerializers.LEGACY_FORMATTING_CODE.deserialize(BBC.color(message)));
}
@Override
@ -99,57 +66,83 @@ public class FaweSponge implements IFawe {
@Override
public void setupCommand(String label, FaweCommand cmd) {
getGame().getCommandManager().register(plugin, new SpongeCommand(cmd), label);
}
@Override
public FawePlayer wrap(Object obj) {
return null;
if (obj.getClass() == String.class) {
String name = (String) obj;
FawePlayer existing = Fawe.get().getCachedPlayer(name);
if (existing != null) {
return existing;
}
Player player = Sponge.getServer().getPlayer(name).orElseGet(null);
return player != null ? new SpongePlayer(player) : null;
} else if (obj instanceof Player) {
Player player = (Player) obj;
FawePlayer existing = Fawe.get().getCachedPlayer(player.getName());
return existing != null ? existing : new SpongePlayer(player);
} else {
return null;
}
}
@Override
public void setupWEListener() {
// Do nothing
}
@Override
public void setupVault() {
debug("[FAWE] Permission hook not implemented yet!");
}
@Override
public TaskManager getTaskManager() {
return null;
return new SpongeTaskMan(plugin);
}
@Override
public int[] getVersion() {
return new int[0];
debug("[FAWE] Checking minecraft version: Sponge: ");
String version = Sponge.getGame().getPlatform().getMinecraftVersion().getName();
String[] split = version.split("\\.");
return new int[]{Integer.parseInt(split[0]), Integer.parseInt(split[1]), split.length == 3 ? Integer.parseInt(split[2]) : 0};
}
@Override
public FaweQueue getQueue() {
return null;
return new SpongeQueue_1_8();
}
@Override
public EditSessionWrapper getEditSessionWrapper(EditSession session) {
return null;
return new SpongeEditSessionWrapper_0(session);
}
@Override
public Collection<FaweMaskManager> getMaskManagers() {
return null;
return new ArrayList<>();
}
@Override
public void startMetrics() {
try {
Metrics metrics = new Metrics(this.game, this.plugin);
Metrics metrics = new Metrics(Sponge.getGame(), Sponge.getPluginManager().fromInstance(plugin).get());
metrics.start();
debug(C.PREFIX.s() + "&6Metrics enabled.");
debug("[FAWE] &6Metrics enabled.");
} catch (IOException e) {
debug(C.PREFIX.s() + "&cFailed to load up metrics.");
debug("[FAWE] &cFailed to load up metrics.");
}
}
@Override
public Set<FawePlayer> getPlayers() {
HashSet<FawePlayer> players = new HashSet<>();
for (Player player : Sponge.getServer().getOnlinePlayers()) {
players.add(wrap(player));
}
return players;
}
}

View File

@ -0,0 +1,57 @@
package com.boydti.fawe.forge;
import com.boydti.fawe.Fawe;
import com.google.inject.Inject;
import org.slf4j.Logger;
import org.spongepowered.api.Game;
import org.spongepowered.api.Server;
import org.spongepowered.api.entity.living.player.Player;
import org.spongepowered.api.event.Listener;
import org.spongepowered.api.event.game.state.GamePreInitializationEvent;
import org.spongepowered.api.event.network.ClientConnectionEvent;
import org.spongepowered.api.plugin.Plugin;
import org.spongepowered.api.plugin.PluginContainer;
import org.spongepowered.api.profile.GameProfileManager;
@Plugin(id = "com.boydti.fawe", name = "FastAsyncWorldEdit", description = "Lagless WorldEdit, Area restrictions, Memory mangement, Block logging", url = "https://github.com/boy0001/FastAsyncWorldedit", version = "3.3.5")
public class SpongeMain {
public PluginContainer plugin;
@Inject
private Logger logger;
@Inject
private Game game;
private Server server;
private GameProfileManager resolver;
public Game getGame() {
return this.game;
}
public Server getServer() {
return this.server;
}
public GameProfileManager getResolver() {
if (this.resolver == null) {
this.resolver = this.game.getServer().getGameProfileManager();
}
return this.resolver;
}
@Listener
public void onGamePreInit(GamePreInitializationEvent event) {
plugin = this.game.getPluginManager().fromInstance(this).get();
this.server = this.game.getServer();
new FaweSponge(this);
}
@Listener
public void onQuit(ClientConnectionEvent.Disconnect event) {
Player player = event.getTargetEntity();
Fawe.get().unregister(player.getName());
}
}

View File

@ -29,12 +29,13 @@ public class SpongePlayer extends FawePlayer<Player> {
@Override
public boolean hasPermission(final String perm) {
return this.parent.hasPermission(perm);
Object meta = getMeta(perm);
return meta instanceof Boolean ? (boolean) meta : this.parent.hasPermission(perm);
}
@Override
public void setPermission(final String perm, final boolean flag) {
throw new UnsupportedOperationException("WIP NOT IMPLEMENTED YET TODO"); // TODO FIXME
setMeta(perm, flag);
}
@Override
@ -58,4 +59,8 @@ public class SpongePlayer extends FawePlayer<Player> {
return (com.sk89q.worldedit.entity.Player) Fawe.<FaweSponge> imp().getWorldEditPlugin().wrap((EntityPlayerMP) this.parent);
}
@Override
public boolean hasWorldEditBypass() {
return hasPermission("fawe.bypass") || getMeta("fawe.bypass") == Boolean.TRUE;
}
}

View File

@ -0,0 +1,72 @@
package com.boydti.fawe.forge;
import com.boydti.fawe.util.TaskManager;
import java.util.HashMap;
import java.util.concurrent.atomic.AtomicInteger;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.scheduler.Task;
public class SpongeTaskMan extends TaskManager {
private final SpongeMain plugin;
public SpongeTaskMan(SpongeMain plugin) {
this.plugin = plugin;
}
private final AtomicInteger i = new AtomicInteger();
private final HashMap<Integer, Task> tasks = new HashMap<>();
@Override
public int repeat(Runnable runnable, int interval) {
int val = this.i.incrementAndGet();
Task.Builder builder = Sponge.getGame().getScheduler().createTaskBuilder();
Task.Builder built = builder.delayTicks(interval).intervalTicks(interval).execute(runnable);
Task task = built.submit(plugin);
this.tasks.put(val, task);
return val;
}
@Override
public int repeatAsync(Runnable runnable, int interval) {
int val = this.i.incrementAndGet();
Task.Builder builder = Sponge.getGame().getScheduler().createTaskBuilder();
Task.Builder built = builder.delayTicks(interval).async().intervalTicks(interval).execute(runnable);
Task task = built.submit(plugin);
this.tasks.put(val, task);
return val;
}
@Override
public void async(Runnable runnable) {
Task.Builder builder = Sponge.getGame().getScheduler().createTaskBuilder();
builder.async().execute(runnable).submit(plugin);
}
@Override
public void task(Runnable runnable) {
Task.Builder builder = Sponge.getGame().getScheduler().createTaskBuilder();
builder.execute(runnable).submit(plugin);
}
@Override
public void later(Runnable runnable, int delay) {
Task.Builder builder = Sponge.getGame().getScheduler().createTaskBuilder();
builder.delayTicks(delay).execute(runnable).submit(plugin);
}
@Override
public void laterAsync(Runnable runnable, int delay) {
Task.Builder builder = Sponge.getGame().getScheduler().createTaskBuilder();
builder.async().delayTicks(delay).execute(runnable).submit(plugin);
}
@Override
public void cancel(int i) {
Task task = this.tasks.remove(i);
if (task != null) {
task.cancel();
}
}
}

View File

@ -0,0 +1,75 @@
package com.boydti.fawe.forge;
import com.boydti.fawe.Fawe;
import com.sk89q.worldedit.world.biome.BiomeData;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import net.minecraft.world.biome.BiomeGenBase;
import org.spongepowered.api.world.biome.BiomeType;
import org.spongepowered.api.world.biome.BiomeTypes;
/**
* Created by Jesse on 4/2/2016.
*/
public class SpongeUtil {
private static BiomeType[] biomes;
private static HashMap<String, Integer> biomeMap;
public static Map<Integer, BiomeData> biomeData;
public static void initBiomeCache() {
try {
Class<?> clazz = Class.forName("com.sk89q.worldedit.forge.ForgeBiomeRegistry");
Field bdf = clazz.getDeclaredField("biomeData");
bdf.setAccessible(true);
biomeData = (Map<Integer, BiomeData>) bdf.get(null);
biomes = new BiomeType[256];
biomeMap = new HashMap<>();
int lastId = 0;
loop:
for (Map.Entry<Integer, BiomeData> entry : biomeData.entrySet()) {
int id = entry.getKey();
BiomeData data = entry.getValue();
String name = data.getName().toUpperCase().replaceAll(" ", "_").replaceAll("[+]", "_PLUS");
if (name.endsWith("_M") || name.contains("_M_")) {
name = name.replaceAll("_M", "_MOUNTAINS");
}
if (name.endsWith("_F") || name.contains("_F_")) {
name = name.replaceAll("_F", "_FOREST");
}
try {
biomes[id] = (BiomeType) BiomeTypes.class.getField(name).get(null);
biomeMap.put(biomes[id].getId(), id);
lastId = id;
}
catch (Throwable e) {
Field[] fields = BiomeTypes.class.getDeclaredFields();
for (Field field : fields) {
if (field.getName().replaceAll("_", "").equals(name.replaceAll("_", ""))) {
biomes[id] = (BiomeType) field.get(null);
biomeMap.put(biomes[id].getId(), id);
lastId = id;
continue loop;
}
}
Fawe.debug("Unknown biome: " + name);
biomes[id] = biomes[lastId];
biomeMap.put(biomes[lastId].getId(), lastId);
}
}
} catch (Throwable e) {
e.printStackTrace();
}
}
public static BiomeType getBiome(String biome) {
if (biomes == null) {
initBiomeCache();
}
return biomes[biomeMap.get(biome.toUpperCase())];
}
public static BiomeType getBiome(int index) {
return (BiomeType) BiomeGenBase.getBiome(index);
}
}

View File

@ -0,0 +1,13 @@
package com.boydti.fawe.forge.v0;
import com.boydti.fawe.object.EditSessionWrapper;
import com.sk89q.worldedit.EditSession;
/**
* Created by Jesse on 4/2/2016.
*/
public class SpongeEditSessionWrapper_0 extends EditSessionWrapper {
public SpongeEditSessionWrapper_0(EditSession session) {
super(session);
}
}

View File

@ -0,0 +1,142 @@
package com.boydti.fawe.forge.v0;
import com.boydti.fawe.object.ChunkLoc;
import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.util.FaweQueue;
import com.boydti.fawe.util.SetQueue;
import com.sk89q.worldedit.world.biome.BaseBiome;
import java.util.ArrayDeque;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.world.Chunk;
import org.spongepowered.api.world.World;
/**
* Created by Jesse on 4/2/2016.
*/
public abstract class SpongeQueue_0 extends FaweQueue {
/**
* Map of chunks in the queue
*/
private final ConcurrentHashMap<ChunkLoc, FaweChunk<Chunk>> blocks = new ConcurrentHashMap<>();
@Override
public boolean isChunkLoaded(String worldName, int x, int z) {
World world = Sponge.getServer().getWorld(worldName).get();
Chunk chunk = world.getChunk(x << 4, 0, z << 4).orElse(null);
return chunk != null && chunk.isLoaded();
}
@Override
public void addTask(String world, int x, int y, int z, Runnable runnable) {
// TODO Auto-generated method stub
final ChunkLoc wrap = new ChunkLoc(world, x >> 4, z >> 4);
FaweChunk<Chunk> result = this.blocks.get(wrap);
if (result == null) {
throw new IllegalArgumentException("Task must be accompanied by a block change or manually adding to queue!");
}
result.addTask(runnable);
}
@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 = this.blocks.get(wrap);
if (result == null) {
result = this.getChunk(wrap);
result.setBlock(x, y, z, id, data);
final FaweChunk<Chunk> previous = this.blocks.put(wrap, result);
if (previous == null) {
return true;
}
this.blocks.put(wrap, previous);
result = previous;
}
result.setBlock(x, y, z, id, data);
return true;
}
@Override
public boolean setBiome(final String world, int x, int z, final BaseBiome biome) {
final ChunkLoc wrap = new ChunkLoc(world, x >> 4, z >> 4);
x = x & 15;
z = z & 15;
FaweChunk<Chunk> result = this.blocks.get(wrap);
if (result == null) {
result = this.getChunk(wrap);
final FaweChunk<Chunk> previous = this.blocks.put(wrap, result);
if (previous != null) {
this.blocks.put(wrap, previous);
result = previous;
}
}
result.setBiome(x, z, biome);
return true;
}
@Override
public FaweChunk<Chunk> next() {
try {
if (this.blocks.size() == 0) {
return null;
}
final Iterator<Map.Entry<ChunkLoc, FaweChunk<Chunk>>> iter = this.blocks.entrySet().iterator();
final FaweChunk<Chunk> toReturn = iter.next().getValue();
if (SetQueue.IMP.isWaiting()) {
return null;
}
iter.remove();
this.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.loadChunk(true);
// Set blocks / entities / biome
if (!this.setComponents(fc)) {
return false;
}
fc.executeTasks();
return true;
}
@Override
public void clear() {
this.blocks.clear();
}
@Override
public void setChunk(final FaweChunk<?> chunk) {
this.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(final FaweChunk<?> fc, final boolean fixAll);
}

View File

@ -0,0 +1,228 @@
package com.boydti.fawe.forge.v1_8;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.object.ChunkLoc;
import com.boydti.fawe.object.FaweChunk;
import com.sk89q.worldedit.world.biome.BaseBiome;
import java.util.Arrays;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.world.Chunk;
public class SpongeChunk_1_8 extends FaweChunk<Chunk> {
public char[][] ids;
public short[] count;
public short[] air;
public short[] relight;
public int[][] biomes;
public Chunk chunk;
public SpongeChunk_1_8(ChunkLoc chunk) {
super(chunk);
this.ids = new char[16][];
this.count = new short[16];
this.air = new short[16];
this.relight = new short[16];
}
@Override
public Chunk getChunk() {
if (this.chunk == null) {
ChunkLoc cl = getChunkLoc();
this.chunk = Sponge.getServer().getWorld(cl.world).get().getChunk(cl.x, 0, cl.z).get();
}
return this.chunk;
}
/**
* Get the number of block changes in a specified section.
* @param i
* @return
*/
public int getCount(int i) {
return this.count[i];
}
public int getAir(int i) {
return this.air[i];
}
public void setCount(int i, short value) {
this.count[i] = value;
}
/**
* Get the number of block changes in a specified section.
* @param i
* @return
*/
public int getRelight(int i) {
return this.relight[i];
}
public int getTotalCount() {
int total = 0;
for (int i = 0; i < 16; i++) {
total += this.count[i];
}
return total;
}
public int getTotalRelight() {
if (getTotalCount() == 0) {
Arrays.fill(this.count, (short) 1);
Arrays.fill(this.relight, Short.MAX_VALUE);
return Short.MAX_VALUE;
}
int total = 0;
for (int i = 0; i < 16; i++) {
total += this.relight[i];
}
return total;
}
/**
* Get the raw data for a section.
* @param i
* @return
*/
public char[] getIdArray(int i) {
return this.ids[i];
}
@Override
public void setBlock(int x, int y, int z, int id, byte data) {
int i = FaweCache.CACHE_I[y][x][z];
int j = FaweCache.CACHE_J[y][x][z];
char[] vs = this.ids[i];
if (vs == null) {
vs = this.ids[i] = new char[4096];
this.count[i]++;
} else if (vs[j] == 0) {
this.count[i]++;
}
switch (id) {
case 0:
this.air[i]++;
vs[j] = (char) 1;
return;
case 10:
case 11:
case 39:
case 40:
case 51:
case 74:
case 89:
case 122:
case 124:
case 138:
case 169:
this.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 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 76:
case 62:
this.relight[i]++;
case 54:
case 146:
case 61:
case 65:
case 68:
case 50:
if (data < 2) {
data = 2;
}
default:
vs[j] = (char) ((id << 4) + data);
return;
}
}
@Override
public void setBiome(int x, int z, BaseBiome biome) {
if (this.biomes == null) {
this.biomes = new int[16][];
}
int[] index = this.biomes[x];
if (index == null) {
index = this.biomes[x] = new int[16];
}
index[z] = biome.getId();
}
@Override
public FaweChunk clone() {
SpongeChunk_1_8 toReturn = new SpongeChunk_1_8(getChunkLoc());
toReturn.air = this.air.clone();
toReturn.count = this.count.clone();
toReturn.relight = this.relight.clone();
toReturn.ids = new char[this.ids.length][];
for (int i = 0; i < this.ids.length; i++) {
char[] matrix = this.ids[i];
if (matrix != null) {
toReturn.ids[i] = new char[matrix.length];
System.arraycopy(matrix, 0, toReturn.ids[i], 0, matrix.length);
}
}
return toReturn;
}
}

View File

@ -0,0 +1,304 @@
package com.boydti.fawe.forge.v1_8;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.forge.SpongeUtil;
import com.boydti.fawe.forge.v0.SpongeQueue_0;
import com.boydti.fawe.object.ChunkLoc;
import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.object.PseudoRandom;
import com.boydti.fawe.util.TaskManager;
import com.flowpowered.math.vector.Vector3i;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import net.minecraft.block.Block;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.network.NetHandlerPlayServer;
import net.minecraft.network.play.server.S21PacketChunkData;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.BlockPos;
import net.minecraft.util.ClassInheritanceMultiMap;
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.entity.living.player.Player;
import org.spongepowered.api.world.Chunk;
import org.spongepowered.api.world.Location;
import org.spongepowered.api.world.World;
public class SpongeQueue_1_8 extends SpongeQueue_0 {
@Override
public Collection<FaweChunk<Chunk>> sendChunk(Collection<FaweChunk<Chunk>> fcs) {
if (fcs.isEmpty()) {
return fcs;
}
for (FaweChunk<Chunk> chunk : fcs) {
sendChunk(chunk);
}
fcs.clear();
return fcs;
}
public void sendChunk(FaweChunk<Chunk> fc) {
fixLighting(fc, Settings.FIX_ALL_LIGHTING);
Chunk chunk = fc.getChunk();
if (!chunk.isLoaded()) {
return;
}
World world = chunk.getWorld();
Vector3i pos = chunk.getBlockMin();
int cx = pos.getX() >> 4;
int cz = pos.getZ() >> 4;
for (Player player : Sponge.getServer().getOnlinePlayers()) {
if (!player.getWorld().equals(world)) {
continue;
}
int view = player.getViewDistance();
EntityPlayerMP nmsPlayer = (EntityPlayerMP) player;
Location<World> loc = player.getLocation();
int px = loc.getBlockX() >> 4;
int pz = loc.getBlockZ() >> 4;
int dx = Math.abs(cx - (loc.getBlockX() >> 4));
int dz = Math.abs(cz - (loc.getBlockZ() >> 4));
if ((dx > view) || (dz > view)) {
continue;
}
NetHandlerPlayServer con = nmsPlayer.playerNetServerHandler;
net.minecraft.world.chunk.Chunk nmsChunk = (net.minecraft.world.chunk.Chunk) chunk;
con.sendPacket(new S21PacketChunkData(nmsChunk, false, 65535));
// Try sending true, 0 first
// Try bulk chunk packet
}
}
@Override
public boolean setComponents(FaweChunk<Chunk> fc) {
SpongeChunk_1_8 fs = (SpongeChunk_1_8) fc;
Chunk spongeChunk = fc.getChunk();
net.minecraft.world.World nmsWorld = (net.minecraft.world.World) spongeChunk.getWorld();
ChunkLoc wrapper = fc.getChunkLoc();
spongeChunk.loadChunk(true);
try {
boolean flag = !nmsWorld.provider.getHasNoSky();
// Sections
net.minecraft.world.chunk.Chunk nmsChunk = (net.minecraft.world.chunk.Chunk) spongeChunk;
ExtendedBlockStorage[] sections = nmsChunk.getBlockStorageArray();
Map<BlockPos, TileEntity> tiles = nmsChunk.getTileEntityMap();
ClassInheritanceMultiMap<Entity>[] entities = nmsChunk.getEntityLists();
// Trim tiles
Set<Entry<BlockPos, TileEntity>> entryset = tiles.entrySet();
Iterator<Entry<BlockPos, TileEntity>> iterator = entryset.iterator();
while (iterator.hasNext()) {
Entry<BlockPos, TileEntity> tile = iterator.next();
BlockPos pos = tile.getKey();
int lx = pos.getX() & 15;
int ly = pos.getY();
int lz = pos.getZ() & 15;
int j = FaweCache.CACHE_I[ly][lx][lz];
int k = FaweCache.CACHE_J[ly][lx][lz];
char[] array = fs.getIdArray(j);
if (array == null) {
continue;
}
if (array[k] != 0) {
iterator.remove();
}
}
// Trim entities
for (int i = 0; i < 16; i++) {
if ((entities[i] != null) && (fs.getCount(i) >= 4096)) {
entities[i] = new ClassInheritanceMultiMap<>(Entity.class);
}
}
// Efficiently merge sections
for (int j = 0; j < sections.length; j++) {
if (fs.getCount(j) == 0) {
continue;
}
char[] newArray = fs.getIdArray(j);
if (newArray == null) {
continue;
}
ExtendedBlockStorage section = sections[j];
if ((section == null) || (fs.getCount(j) >= 4096)) {
section = new ExtendedBlockStorage(j << 4, flag);
section.setData(newArray);
sections[j] = section;
continue;
}
char[] currentArray = section.getData();
boolean fill = true;
for (int k = 0; k < newArray.length; k++) {
char n = newArray[k];
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);
}
}
// Clear
} catch (Throwable e) {
e.printStackTrace();
}
int[][] biomes = fs.biomes;
if (biomes != null) {
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;
}
spongeChunk.setBiome(x, z, SpongeUtil.getBiome(biome));
}
}
}
TaskManager.IMP.later(new Runnable() {
@Override
public void run() {
sendChunk(fs);
}
}, 1);
return true;
}
/**
* This should be overridden by any specialized queues.
* @param wrap
*/
@Override
public SpongeChunk_1_8 getChunk(ChunkLoc wrap) {
return new SpongeChunk_1_8(wrap);
}
@Override
public boolean fixLighting(FaweChunk<?> pc, boolean fixAll) {
try {
SpongeChunk_1_8 bc = (SpongeChunk_1_8) pc;
Chunk spongeChunk = bc.getChunk();
net.minecraft.world.chunk.Chunk nmsChunk = (net.minecraft.world.chunk.Chunk) spongeChunk;
if (!spongeChunk.isLoaded()) {
if (!spongeChunk.loadChunk(false)) {
return false;
}
} else {
spongeChunk.unloadChunk();
spongeChunk.loadChunk(false);
}
nmsChunk.generateSkylightMap();
if (bc.getTotalRelight() == 0 && !fixAll) {
return true;
}
ExtendedBlockStorage[] sections = nmsChunk.getBlockStorageArray();
net.minecraft.world.World nmsWorld = nmsChunk.getWorld();
ChunkLoc loc = pc.getChunkLoc();
int X = loc.x << 4;
int Z = loc.z << 4;
for (int j = 0; j < sections.length; j++) {
ExtendedBlockStorage 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;
}
char[] array = section.getData();
int l = PseudoRandom.random.random(2);
for (int k = 0; k < array.length; k++) {
int i = array[k];
if (i < 16) {
continue;
}
short id = (short) (i >> 4);
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:
int x = FaweCache.CACHE_X[j][k];
int y = FaweCache.CACHE_Y[j][k];
int z = FaweCache.CACHE_Z[j][k];
if (isSurrounded(sections, x, y, z)) {
continue;
}
BlockPos pos = new BlockPos(X + x, y, Z + z);
nmsWorld.checkLight(pos);
}
}
}
return true;
} catch (Throwable e) {
e.printStackTrace();
}
return false;
}
public boolean isSurrounded(ExtendedBlockStorage[] 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) {
return i != 0 && Block.getBlockById(i).isOpaqueCube();
}
public int getId(ExtendedBlockStorage[] 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];
ExtendedBlockStorage section = sections[i];
if (section == null) {
return 0;
}
char[] array = section.getData();
int j = FaweCache.CACHE_J[y][x][z];
return array[j] >> 4;
}
}

View File

@ -8,7 +8,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<artifactId>FastAsyncWorldEdit</artifactId>
<version>3.3.4</version>
<version>3.3.5</version>
<name>FastAsyncWorldEdit</name>
<packaging>jar</packaging>
<build>