mirror of
https://github.com/plexusorg/Plex-FAWE.git
synced 2025-07-01 10:56:42 +00:00
Feature/1.17 (#1120)
* start v6 * Update classes to v6 method signatures * change rootVersion to signify p2v6 compat * Use 16 as toolchain version but target 11 for build output * add minimessage as api * Require v6 and don't attempt to "setup" hook from FAWE * Address comments * *address /all/ comments * FAWE classes should only act as a delegate * Uppercase logger * Settings for v6-hook have moved to P2-v6, remove unneeded if statements * Rename classes to Delegate * add whenDone task to setCuboids * Remove bad spaces * Fix plot swap * Initial work on 1.17 support * Remove data versions from the Bukkit adapters (#1507) * Remove data versions from the Bukkit adapters * Don't allow saving schematics without an adapter in place on Bukkit. * Removed confusing line (cherry picked from commit 2056218b4a8644836b1d127105dfa289e9cdbc1c) * More progress * Fix chunk sending * Repackage from com.boydti to com.fastasyncworldedit.<module> (#1119) * Preliminary work on repackaging * Rename build artifacts matching our pattern * Finish up repackaging * Fix a few field accesses and old imports * Dirty fix for chunks container ChunkSections outside of 0-15 * Correctly read from NibbleArrays for lighting * Fix getSections and BlockMaterial for 1.17 * Fix writing blocks to the world. - The issue isn't the presence of a "-1" chunk, it's the constructor for ChunkSection requiring the layer (0 to 15) rather than the y chord * Fix more field accesses * More work towards 1.17 * Update Upstream a57f66f Fix watchdog, add negative y support. (1782) * Add azalea tree to `/tool tree` * Don't define toolchain twice * Repackage GriefDefender * Relocate under new namespace * Bye bye ecma left overs * Add 1.17 to issue templates and instructions * Move to adventure-nbt (#918) * Initial work for adventure-nbt * Some more FAWE specific stuff * Fix erroneous deprecation check * Workflow change * Continued merging all adventure NBT related changes * Continued merging all adventure NBT related changes * Made a constructor public again This needs to be public for BlockTransformExtent.java * Finished converting all NBT data to adventure. * Make this compile * Fix conflicts Co-authored-by: Matt <4009945+MattBDev@users.noreply.github.com> * Update adapters to 1.17 * Change build prefix to 1.17 * Move more nms classes to adapters * Move left over nms classes * Move Spigot 1.17 class * Remove unneeded adapter loader code The loader will find the appropriate class now itself * Update adapters * Update adapters * Lazy fix tests * Update adapters * Update Upstream 43da91a Remove method reflection for getMinHeight in BukkitWorld. (1796) * Relocate adventure-nbt under proper namespace * Add LazyCompoundTag as a non-version-specific class to be used by adapters * Better integration between old NBT and Adventure NBT - begin fixing the issues seen recently * Correctly NBT conversion method * LazyCompoundTags should actually be overriding and correctly returning a CompoundBinaryTag. * Update worldedit-adapters Fixes #1141 * Remove unnecessary massive lag machine * Refactor apply to applyBlock in subclasses * applyBlock should be overriden by all subclasses. Default apply to applyBlock * Closes #1130 Closes #1132 * Squashed commit of the following: commit a9bfa1a07c77083c844a0c3ba62f4bd94bed107c Author: NotMyFault <mc.cache@web.de> Date: Sun Jun 27 21:53:21 2021 +0200 [ci skip] Update gradle wrapper validation commit aa7471f95317d28a16f62e4b200de8d0fea2fa95 Author: Matthew Miller <mnmiller1@me.com> Date: Sat Oct 10 15:49:13 2020 +1000 Add ^x,y,z relative offset support to the offset parser (#1545) * Add ^x,y,z relative offset support to the offset parser * Wrap in a try-catch (cherry picked from commit 28bdf7ff9254bbc85bb4f5f792b303943a3930a8) * Add `fawe.error.schematic.not.found` translation key * Update Upstream 728a152 Skip notify if chunk section doesn't exist (1794) * Fixed #1157 * Add a null check to prevent NPE in nbt code * Update adapters * Update Upstream fbb047a Optimize legacy schematic loading (1808) * Hurr durr I don't want to update Java * Update Upstream 0790e6e Fix CLI Mess (1811) * Fixes #1160 * Expose minimessage transitively thru PlotSquared Touches #32 * [ci skip] Remove unneeded maven repository * Steal tab completion from PlotSquared for P2 related commands * Don't error on startup when building locally Co-Authored-By: goldfishapp <8278196+goldfishapp@users.noreply.github.com> * [ci skip] Update gh actions to Java 16 * Update textures to grab 1.17 jar Co-authored-by: NotMyFault <mc.cache@web.de> Co-authored-by: SirYwell <hannesgreule@outlook.de> Co-authored-by: Matthew Miller <mnmiller1@me.com> Co-authored-by: Matt <4009945+MattBDev@users.noreply.github.com> Co-authored-by: goldfishapp <8278196+goldfishapp@users.noreply.github.com>
This commit is contained in:
@ -0,0 +1,36 @@
|
||||
package com.fastasyncworldedit.bukkit;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.permissions.PermissionAttachment;
|
||||
|
||||
public class BukkitPermissionAttachmentManager {
|
||||
|
||||
private final WorldEditPlugin plugin;
|
||||
private final Map<Player, PermissionAttachment> attachments = new ConcurrentHashMap<>();
|
||||
|
||||
public BukkitPermissionAttachmentManager(WorldEditPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public PermissionAttachment getOrAddAttachment(@Nullable final Player p) {
|
||||
if (p == null) {
|
||||
return null;
|
||||
}
|
||||
return attachments.computeIfAbsent(p, k -> k.addAttachment(plugin));
|
||||
}
|
||||
|
||||
public void removeAttachment(@Nullable final Player p) {
|
||||
if (p == null) {
|
||||
return;
|
||||
}
|
||||
PermissionAttachment attach = attachments.remove(p);
|
||||
if (attach != null) {
|
||||
p.removeAttachment(attach);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,304 @@
|
||||
package com.fastasyncworldedit.bukkit;
|
||||
|
||||
import com.fastasyncworldedit.core.FAWEPlatformAdapterImpl;
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.fastasyncworldedit.core.IFawe;
|
||||
import com.fastasyncworldedit.core.beta.implementation.preloader.AsyncPreloader;
|
||||
import com.fastasyncworldedit.core.beta.implementation.preloader.Preloader;
|
||||
import com.fastasyncworldedit.core.beta.implementation.queue.QueueHandler;
|
||||
import com.fastasyncworldedit.bukkit.adapter.BukkitQueueHandler;
|
||||
import com.fastasyncworldedit.bukkit.adapter.NMSAdapter;
|
||||
import com.fastasyncworldedit.bukkit.listener.BrushListener;
|
||||
import com.fastasyncworldedit.bukkit.listener.ChunkListener9;
|
||||
import com.fastasyncworldedit.bukkit.listener.RenderListener;
|
||||
import com.fastasyncworldedit.bukkit.regions.GriefPreventionFeature;
|
||||
import com.fastasyncworldedit.bukkit.regions.GriefDefenderFeature;
|
||||
import com.fastasyncworldedit.bukkit.regions.ResidenceFeature;
|
||||
import com.fastasyncworldedit.bukkit.regions.TownyFeature;
|
||||
import com.fastasyncworldedit.bukkit.regions.Worldguard;
|
||||
import com.fastasyncworldedit.bukkit.util.BukkitTaskManager;
|
||||
import com.fastasyncworldedit.bukkit.util.ItemUtil;
|
||||
import com.fastasyncworldedit.bukkit.util.MinecraftVersion;
|
||||
import com.fastasyncworldedit.bukkit.util.image.BukkitImageViewer;
|
||||
import com.fastasyncworldedit.core.configuration.Settings;
|
||||
import com.fastasyncworldedit.core.regions.FaweMaskManager;
|
||||
import com.fastasyncworldedit.core.util.ThirdPartyManager;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.fastasyncworldedit.core.util.WEManager;
|
||||
import com.fastasyncworldedit.core.util.image.ImageViewer;
|
||||
import com.plotsquared.core.PlotSquared;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.BukkitPlayer;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.bukkit.event.world.WorldLoadEvent;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class FaweBukkit implements IFawe, Listener {
|
||||
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
|
||||
private final Plugin plugin;
|
||||
private ItemUtil itemUtil;
|
||||
|
||||
private boolean listeningImages;
|
||||
private final boolean chunksStretched;
|
||||
private final FAWEPlatformAdapterImpl platformAdapter;
|
||||
|
||||
public FaweBukkit(Plugin plugin) {
|
||||
this.plugin = plugin;
|
||||
try {
|
||||
Settings.IMP.TICK_LIMITER.ENABLED = !Bukkit.hasWhitelist();
|
||||
Fawe.set(this);
|
||||
Fawe.setupInjector();
|
||||
try {
|
||||
new BrushListener(plugin);
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Brush Listener Failed", e);
|
||||
}
|
||||
if (PaperLib.isPaper() && Settings.IMP.EXPERIMENTAL.DYNAMIC_CHUNK_RENDERING > 1) {
|
||||
new RenderListener(plugin);
|
||||
}
|
||||
} catch (final Throwable e) {
|
||||
e.printStackTrace();
|
||||
Bukkit.getServer().shutdown();
|
||||
}
|
||||
|
||||
chunksStretched = new MinecraftVersion().isEqualOrHigher(MinecraftVersion.NETHER);
|
||||
|
||||
platformAdapter = new NMSAdapter();
|
||||
|
||||
//PlotSquared support is limited to Spigot/Paper as of 02/20/2020
|
||||
TaskManager.IMP.later(this::setupPlotSquared, 0);
|
||||
|
||||
// Registered delayed Event Listeners
|
||||
TaskManager.IMP.task(() -> {
|
||||
// Fix for ProtocolSupport
|
||||
Settings.IMP.PROTOCOL_SUPPORT_FIX =
|
||||
Bukkit.getPluginManager().isPluginEnabled("ProtocolSupport");
|
||||
|
||||
// This class
|
||||
Bukkit.getPluginManager().registerEvents(FaweBukkit.this, FaweBukkit.this.plugin);
|
||||
|
||||
// The tick limiter
|
||||
new ChunkListener9();
|
||||
});
|
||||
}
|
||||
|
||||
@Override public QueueHandler getQueueHandler() {
|
||||
return new BukkitQueueHandler();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized ImageViewer getImageViewer(com.sk89q.worldedit.entity.Player player) {
|
||||
try {
|
||||
listeningImages = true;
|
||||
PluginManager manager = Bukkit.getPluginManager();
|
||||
|
||||
if (manager.getPlugin("PacketListenerApi") == null) {
|
||||
File output = new File(plugin.getDataFolder().getParentFile(),
|
||||
"PacketListenerAPI_v3.7.6-SNAPSHOT.jar");
|
||||
byte[] jarData = ThirdPartyManager.PacketListenerAPI.download();
|
||||
try (FileOutputStream fos = new FileOutputStream(output)) {
|
||||
fos.write(jarData);
|
||||
}
|
||||
}
|
||||
if (manager.getPlugin("MapManager") == null) {
|
||||
File output = new File(plugin.getDataFolder().getParentFile(),
|
||||
"MapManager_v1.7.8-SNAPSHOT.jar");
|
||||
byte[] jarData = ThirdPartyManager.MapManager.download();
|
||||
try (FileOutputStream fos = new FileOutputStream(output)) {
|
||||
fos.write(jarData);
|
||||
}
|
||||
}
|
||||
return new BukkitImageViewer(BukkitAdapter.adapt(player));
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override public File getDirectory() {
|
||||
return plugin.getDataFolder();
|
||||
}
|
||||
|
||||
|
||||
public ItemUtil getItemUtil() {
|
||||
ItemUtil tmp = itemUtil;
|
||||
if (tmp == null) {
|
||||
try {
|
||||
this.itemUtil = tmp = new ItemUtil();
|
||||
} catch (Throwable e) {
|
||||
Settings.IMP.EXPERIMENTAL.PERSISTENT_BRUSHES = false;
|
||||
LOGGER.error("Persistent Brushes Failed", e);
|
||||
}
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
@Override public String getDebugInfo() {
|
||||
StringBuilder msg = new StringBuilder();
|
||||
Plugin[] plugins = Bukkit.getServer().getPluginManager().getPlugins();
|
||||
msg.append("Server Version: ").append(Bukkit.getVersion()).append("\n");
|
||||
msg.append("Plugins (").append(plugins.length).append("): \n");
|
||||
for (Plugin p : plugins) {
|
||||
msg.append(" - ").append(p.getName()).append(":").append("\n")
|
||||
.append(" • Version: ").append(p.getDescription().getVersion()).append("\n")
|
||||
.append(" • Enabled: ").append(p.isEnabled()).append("\n")
|
||||
.append(" • Main: ").append(p.getDescription().getMain()).append("\n")
|
||||
.append(" • Authors: ").append(p.getDescription().getAuthors()).append("\n")
|
||||
.append(" • Load Before: ").append(p.getDescription().getLoadBefore()).append("\n")
|
||||
.append(" • Dependencies: ").append(p.getDescription().getDepend()).append("\n")
|
||||
.append(" • Soft Dependencies: ").append(p.getDescription().getSoftDepend()).append("\n")
|
||||
.append(" • Provides: ").append(p.getDescription().getProvides()).append("\n");
|
||||
}
|
||||
return msg.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* The task manager handles sync/async tasks.
|
||||
*/
|
||||
@Override public TaskManager getTaskManager() {
|
||||
return new BukkitTaskManager(plugin);
|
||||
}
|
||||
|
||||
public Plugin getPlugin() {
|
||||
return plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* A mask manager handles region restrictions e.g., PlotSquared plots / WorldGuard regions
|
||||
*/
|
||||
@Override public Collection<FaweMaskManager> getMaskManagers() {
|
||||
final Plugin worldguardPlugin =
|
||||
Bukkit.getServer().getPluginManager().getPlugin("WorldGuard");
|
||||
final ArrayList<FaweMaskManager> managers = new ArrayList<>();
|
||||
if (worldguardPlugin != null && worldguardPlugin.isEnabled()) {
|
||||
try {
|
||||
managers.add(new Worldguard(worldguardPlugin));
|
||||
LOGGER.info("Attempting to use plugin 'WorldGuard'");
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
final Plugin townyPlugin = Bukkit.getServer().getPluginManager().getPlugin("Towny");
|
||||
if (townyPlugin != null && townyPlugin.isEnabled()) {
|
||||
try {
|
||||
managers.add(new TownyFeature(townyPlugin));
|
||||
LOGGER.info("Attempting to use plugin 'Towny'");
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
final Plugin residencePlugin = Bukkit.getServer().getPluginManager().getPlugin("Residence");
|
||||
if (residencePlugin != null && residencePlugin.isEnabled()) {
|
||||
try {
|
||||
managers.add(new ResidenceFeature(residencePlugin, this));
|
||||
LOGGER.info("Attempting to use plugin 'Residence'");
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
final Plugin griefpreventionPlugin =
|
||||
Bukkit.getServer().getPluginManager().getPlugin("GriefPrevention");
|
||||
if (griefpreventionPlugin != null && griefpreventionPlugin.isEnabled()) {
|
||||
try {
|
||||
managers.add(new GriefPreventionFeature(griefpreventionPlugin));
|
||||
LOGGER.info("Attempting to use plugin 'GriefPrevention'");
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
final Plugin griefdefenderPlugin =
|
||||
Bukkit.getServer().getPluginManager().getPlugin("GriefDefender");
|
||||
if (griefdefenderPlugin != null && griefdefenderPlugin.isEnabled()) {
|
||||
try {
|
||||
managers.add(new GriefDefenderFeature(griefdefenderPlugin));
|
||||
LOGGER.info("Attempting to use plugin 'GriefDefender'");
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
return managers;
|
||||
}
|
||||
|
||||
private volatile boolean keepUnloaded;
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onWorldLoad(WorldLoadEvent event) {
|
||||
if (keepUnloaded) {
|
||||
org.bukkit.World world = event.getWorld();
|
||||
world.setKeepSpawnInMemory(false);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized <T> T createWorldUnloaded(Supplier<T> task) {
|
||||
keepUnloaded = true;
|
||||
try {
|
||||
return task.get();
|
||||
} finally {
|
||||
keepUnloaded = false;
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
BukkitPlayer wePlayer = BukkitAdapter.adapt(player);
|
||||
wePlayer.unregister();
|
||||
}
|
||||
|
||||
@Override public String getPlatform() {
|
||||
return "Bukkit";
|
||||
}
|
||||
|
||||
@Override public UUID getUUID(String name) {
|
||||
return Bukkit.getOfflinePlayer(name).getUniqueId();
|
||||
}
|
||||
|
||||
@Override public String getName(UUID uuid) {
|
||||
return Bukkit.getOfflinePlayer(uuid).getName();
|
||||
}
|
||||
|
||||
@Override public Preloader getPreloader() {
|
||||
if (PaperLib.isPaper()) {
|
||||
return new AsyncPreloader();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override public boolean isChunksStretched() {
|
||||
return chunksStretched;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FAWEPlatformAdapterImpl getPlatformAdapter() {
|
||||
return platformAdapter;
|
||||
}
|
||||
|
||||
private void setupPlotSquared() {
|
||||
Plugin plotSquared = this.plugin.getServer().getPluginManager().getPlugin("PlotSquared");
|
||||
if (plotSquared == null) {
|
||||
return;
|
||||
}
|
||||
if (plotSquared.getClass().getPackage().toString().contains("intellectualsites")) {
|
||||
WEManager.IMP.managers.add(new com.fastasyncworldedit.bukkit.regions.plotsquaredv4.PlotSquaredFeature());
|
||||
LOGGER.info("Plugin 'PlotSquared' found. Using it now.");
|
||||
} else if (PlotSquared.get().getVersion().version[0] == 6){
|
||||
WEManager.IMP.managers.add(new com.fastasyncworldedit.bukkit.regions.plotsquared.PlotSquaredFeature());
|
||||
LOGGER.info("Plugin 'PlotSquared' found. Using it now.");
|
||||
} else {
|
||||
LOGGER.error("Incompatible version of PlotSquared found. Please use PlotSquared v6.");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package com.fastasyncworldedit.bukkit.adapter;
|
||||
|
||||
public interface BukkitGetBlocks {
|
||||
|
||||
void send(int mask, boolean lighting);
|
||||
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
package com.fastasyncworldedit.bukkit.adapter;
|
||||
|
||||
import co.aikar.timings.Timings;
|
||||
import com.fastasyncworldedit.core.beta.implementation.queue.QueueHandler;
|
||||
import com.fastasyncworldedit.bukkit.listener.ChunkListener;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.spigotmc.AsyncCatcher;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class BukkitQueueHandler extends QueueHandler {
|
||||
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
|
||||
private volatile boolean timingsEnabled;
|
||||
private static boolean alertTimingsChange = true;
|
||||
|
||||
private static Method methodCheck;
|
||||
static {
|
||||
try {
|
||||
methodCheck = Class.forName("co.aikar.timings.TimingsManager").getDeclaredMethod("recheckEnabled");
|
||||
methodCheck.setAccessible(true);
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startSet(boolean parallel) {
|
||||
ChunkListener.physicsFreeze = true;
|
||||
if (parallel) {
|
||||
try {
|
||||
AsyncCatcher.enabled = false;
|
||||
timingsEnabled = Timings.isTimingsEnabled();
|
||||
if (timingsEnabled) {
|
||||
if (alertTimingsChange) {
|
||||
alertTimingsChange = false;
|
||||
LOGGER.debug("Having `parallel-threads` > 1 interferes with the timings.");
|
||||
}
|
||||
Timings.setTimingsEnabled(false);
|
||||
methodCheck.invoke(null);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endSet(boolean parallel) {
|
||||
ChunkListener.physicsFreeze = false;
|
||||
if (parallel) {
|
||||
try {
|
||||
AsyncCatcher.enabled = true;
|
||||
if (timingsEnabled) {
|
||||
Timings.setTimingsEnabled(true);
|
||||
methodCheck.invoke(null);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,101 @@
|
||||
package com.fastasyncworldedit.bukkit.adapter;
|
||||
|
||||
import com.sk89q.worldedit.registry.state.Property;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
import com.sk89q.worldedit.world.item.ItemType;
|
||||
import com.sk89q.worldedit.world.item.ItemTypes;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public abstract class CachedBukkitAdapter implements IBukkitAdapter {
|
||||
private int[] itemTypes;
|
||||
private int[] blockTypes;
|
||||
|
||||
private boolean init() {
|
||||
if (itemTypes == null) {
|
||||
Material[] materials = Material.values();
|
||||
itemTypes = new int[materials.length];
|
||||
blockTypes = new int[materials.length];
|
||||
for (int i = 0; i < materials.length; i++) {
|
||||
Material material = materials[i];
|
||||
if (material.isLegacy()) {
|
||||
continue;
|
||||
}
|
||||
NamespacedKey key = material.getKey();
|
||||
String id = key.getNamespace() + ":" + key.getKey();
|
||||
if (material.isBlock()) {
|
||||
blockTypes[i] = BlockTypes.get(id).getInternalId();
|
||||
}
|
||||
if (material.isItem()) {
|
||||
itemTypes[i] = ItemTypes.get(id).getInternalId();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a Material to a ItemType.
|
||||
*
|
||||
* @param material The material
|
||||
* @return The itemtype
|
||||
*/
|
||||
@Override
|
||||
public ItemType asItemType(Material material) {
|
||||
try {
|
||||
return ItemTypes.get(itemTypes[material.ordinal()]);
|
||||
} catch (NullPointerException e) {
|
||||
if (init()) {
|
||||
return asItemType(material);
|
||||
}
|
||||
return ItemTypes.get(itemTypes[material.ordinal()]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockType asBlockType(Material material) {
|
||||
try {
|
||||
return BlockTypesCache.values[blockTypes[material.ordinal()]];
|
||||
} catch (NullPointerException e) {
|
||||
if (init()) {
|
||||
return asBlockType(material);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a WorldEdit BlockStateHolder from a Bukkit BlockData.
|
||||
*
|
||||
* @param blockData The Bukkit BlockData
|
||||
* @return The WorldEdit BlockState
|
||||
*/
|
||||
@Override
|
||||
public BlockState adapt(BlockData blockData) {
|
||||
try {
|
||||
checkNotNull(blockData);
|
||||
Material material = blockData.getMaterial();
|
||||
BlockType type = BlockTypes.getFromStateId(blockTypes[material.ordinal()]);
|
||||
List<? extends Property> propList = type.getProperties();
|
||||
if (propList.size() == 0) {
|
||||
return type.getDefaultState();
|
||||
}
|
||||
String properties = blockData.getAsString();
|
||||
return BlockState.get(type, properties, type.getDefaultState());
|
||||
} catch (NullPointerException e) {
|
||||
if (init()) {
|
||||
return adapt(blockData);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
package com.fastasyncworldedit.bukkit.adapter;
|
||||
|
||||
import com.destroystokyo.paper.util.ReentrantLockWithGetOwner;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class DelegateLock extends ReentrantLockWithGetOwner {
|
||||
private final ReentrantLock parent;
|
||||
private volatile boolean modified;
|
||||
private final AtomicInteger count;
|
||||
|
||||
public DelegateLock(@NotNull ReentrantLock parent) {
|
||||
this.parent = parent;
|
||||
this.count = null;
|
||||
}
|
||||
|
||||
public boolean isModified() {
|
||||
return modified;
|
||||
}
|
||||
|
||||
public void setModified(boolean modified) {
|
||||
this.modified = modified;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void lock() {
|
||||
modified = true;
|
||||
parent.lock();
|
||||
if (count != null) {
|
||||
count.incrementAndGet();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void lockInterruptibly() throws InterruptedException {
|
||||
parent.lockInterruptibly();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean tryLock() {
|
||||
return parent.tryLock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
|
||||
return parent.tryLock(timeout, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlock() {
|
||||
modified = true;
|
||||
parent.unlock();
|
||||
if (count != null) {
|
||||
if (count.getAndDecrement() <= 0) {
|
||||
count.incrementAndGet();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Lock getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Condition newCondition() {
|
||||
return parent.newCondition();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized int getHoldCount() {
|
||||
return parent.getHoldCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isHeldByCurrentThread() {
|
||||
return parent.isHeldByCurrentThread();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isLocked() {
|
||||
return parent.isLocked();
|
||||
}
|
||||
|
||||
public void untilFree() {
|
||||
ReentrantLock rl = parent;
|
||||
if (rl.isLocked()) {
|
||||
rl.lock();
|
||||
rl.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean hasWaiters(Condition condition) {
|
||||
return parent.hasWaiters(condition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized int getWaitQueueLength(Condition condition) {
|
||||
return parent.getWaitQueueLength(condition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized String toString() {
|
||||
return parent.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package com.fastasyncworldedit.bukkit.adapter;
|
||||
|
||||
import java.util.concurrent.Semaphore;
|
||||
|
||||
public class DelegateSemaphore extends Semaphore {
|
||||
private final Semaphore delegate;
|
||||
|
||||
public DelegateSemaphore(int permits, Semaphore delegate) {
|
||||
super(permits);
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
// this is bad
|
||||
@Override
|
||||
public synchronized boolean tryAcquire() {
|
||||
try {
|
||||
this.delegate.acquire();
|
||||
return true;
|
||||
} catch (InterruptedException e) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void acquire() throws InterruptedException {
|
||||
this.delegate.acquire();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void release() {
|
||||
this.delegate.release();
|
||||
}
|
||||
}
|
@ -0,0 +1,354 @@
|
||||
package com.fastasyncworldedit.bukkit.adapter;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.sk89q.worldedit.NotABlockException;
|
||||
import com.sk89q.worldedit.blocks.BaseItemStack;
|
||||
import com.sk89q.worldedit.bukkit.BukkitEntity;
|
||||
import com.sk89q.worldedit.bukkit.BukkitItemStack;
|
||||
import com.sk89q.worldedit.bukkit.BukkitPlayer;
|
||||
import com.sk89q.worldedit.bukkit.BukkitWorld;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.entity.Entity;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.math.Vector3;
|
||||
import com.sk89q.worldedit.util.Location;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.biome.BiomeTypes;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import com.sk89q.worldedit.world.entity.EntityType;
|
||||
import com.sk89q.worldedit.world.entity.EntityTypes;
|
||||
import com.sk89q.worldedit.world.gamemode.GameMode;
|
||||
import com.sk89q.worldedit.world.gamemode.GameModes;
|
||||
import com.sk89q.worldedit.world.item.ItemType;
|
||||
import java.util.Locale;
|
||||
|
||||
import com.sk89q.worldedit.world.item.ItemTypes;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public interface IBukkitAdapter {
|
||||
|
||||
/**
|
||||
* Convert any WorldEdit world into an equivalent wrapped Bukkit world.
|
||||
*
|
||||
* <p>If a matching world cannot be found, a {@link RuntimeException}
|
||||
* will be thrown.</p>
|
||||
*
|
||||
* @param world the world
|
||||
* @return a wrapped Bukkit world
|
||||
*/
|
||||
default BukkitWorld asBukkitWorld(World world) {
|
||||
if (world instanceof BukkitWorld) {
|
||||
return (BukkitWorld) world;
|
||||
} else {
|
||||
BukkitWorld bukkitWorld = WorldEditPlugin.getInstance().getInternalPlatform().matchWorld(world);
|
||||
if (bukkitWorld == null) {
|
||||
throw new RuntimeException("World '" + world.getName() + "' has no matching version in Bukkit");
|
||||
}
|
||||
return bukkitWorld;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Bukkit world from a WorldEdit world.
|
||||
*
|
||||
* @param world the WorldEdit world
|
||||
* @return a Bukkit world
|
||||
*/
|
||||
default org.bukkit.World adapt(World world) {
|
||||
checkNotNull(world);
|
||||
if (world instanceof BukkitWorld) {
|
||||
return ((BukkitWorld) world).getWorld();
|
||||
} else {
|
||||
org.bukkit.World match = Bukkit.getServer().getWorld(world.getName());
|
||||
if (match != null) {
|
||||
return match;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Can't find a Bukkit world for " + world);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Bukkit location from a WorldEdit position with a Bukkit world.
|
||||
*
|
||||
* @param world the Bukkit world
|
||||
* @param position the WorldEdit position
|
||||
* @return a Bukkit location
|
||||
*/
|
||||
default org.bukkit.Location adapt(org.bukkit.World world, Vector3 position) {
|
||||
checkNotNull(world);
|
||||
checkNotNull(position);
|
||||
return new org.bukkit.Location(
|
||||
world,
|
||||
position.getX(), position.getY(), position.getZ());
|
||||
}
|
||||
|
||||
default org.bukkit.Location adapt(org.bukkit.World world, BlockVector3 position) {
|
||||
return adapt(world, position.toVector3());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Bukkit location from a WorldEdit location with a Bukkit world.
|
||||
*
|
||||
* @param world the Bukkit world
|
||||
* @param location the WorldEdit location
|
||||
* @return a Bukkit location
|
||||
*/
|
||||
default org.bukkit.Location adapt(org.bukkit.World world, Location location) {
|
||||
checkNotNull(world);
|
||||
checkNotNull(location);
|
||||
return new org.bukkit.Location(
|
||||
world,
|
||||
location.getX(), location.getY(), location.getZ(),
|
||||
location.getYaw(),
|
||||
location.getPitch());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a WorldEdit Vector from a Bukkit location.
|
||||
*
|
||||
* @param location The Bukkit location
|
||||
* @return a WorldEdit vector
|
||||
*/
|
||||
default Vector3 asVector(org.bukkit.Location location) {
|
||||
checkNotNull(location);
|
||||
return Vector3.at(location.getX(), location.getY(), location.getZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a WorldEdit BlockVector from a Bukkit location.
|
||||
*
|
||||
* @param location The Bukkit location
|
||||
* @return a WorldEdit vector
|
||||
*/
|
||||
default BlockVector3 asBlockVector(org.bukkit.Location location) {
|
||||
checkNotNull(location);
|
||||
return BlockVector3.at(location.getX(), location.getY(), location.getZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a WorldEdit entity from a Bukkit entity.
|
||||
*
|
||||
* @param entity the Bukkit entity
|
||||
* @return a WorldEdit entity
|
||||
*/
|
||||
default Entity adapt(org.bukkit.entity.Entity entity) {
|
||||
checkNotNull(entity);
|
||||
return new BukkitEntity(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Bukkit Material form a WorldEdit ItemType
|
||||
*
|
||||
* @param itemType The WorldEdit ItemType
|
||||
* @return The Bukkit Material
|
||||
*/
|
||||
default Material adapt(ItemType itemType) {
|
||||
checkNotNull(itemType);
|
||||
if (!itemType.getId().startsWith("minecraft:")) {
|
||||
throw new IllegalArgumentException("Bukkit only supports Minecraft items");
|
||||
}
|
||||
return Material.getMaterial(itemType.getId().substring(10).toUpperCase(Locale.ROOT));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Bukkit Material form a WorldEdit BlockType
|
||||
*
|
||||
* @param blockType The WorldEdit BlockType
|
||||
* @return The Bukkit Material
|
||||
*/
|
||||
default Material adapt(BlockType blockType) {
|
||||
checkNotNull(blockType);
|
||||
if (!blockType.getId().startsWith("minecraft:")) {
|
||||
throw new IllegalArgumentException("Bukkit only supports Minecraft blocks");
|
||||
}
|
||||
String id = blockType.getId().substring(10).toUpperCase(Locale.ROOT);
|
||||
return Material.getMaterial(id);
|
||||
}
|
||||
|
||||
default org.bukkit.entity.EntityType adapt(EntityType entityType) {
|
||||
if (!entityType.getId().startsWith("minecraft:")) {
|
||||
throw new IllegalArgumentException("Bukkit only supports vanilla entities");
|
||||
}
|
||||
return org.bukkit.entity.EntityType.fromName(entityType.getId().substring(10).toLowerCase(Locale.ROOT));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a Material to a BlockType
|
||||
*
|
||||
* @param material The material
|
||||
* @return The blocktype
|
||||
*/
|
||||
default BlockType asBlockType(Material material) {
|
||||
checkNotNull(material);
|
||||
if (!material.isBlock()) {
|
||||
throw new IllegalArgumentException(material.getKey().toString() + " is not a block!") {
|
||||
@Override
|
||||
public synchronized Throwable fillInStackTrace() {
|
||||
return this;
|
||||
}
|
||||
};
|
||||
}
|
||||
return BlockTypes.get(material.getKey().toString());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Converts a Material to a ItemType
|
||||
*
|
||||
* @param material The material
|
||||
* @return The itemtype
|
||||
*/
|
||||
default ItemType asItemType(Material material) {
|
||||
return ItemTypes.get(material.getKey().toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a WorldEdit BlockStateHolder from a Bukkit BlockData
|
||||
*
|
||||
* @param blockData The Bukkit BlockData
|
||||
* @return The WorldEdit BlockState
|
||||
*/
|
||||
default BlockState adapt(BlockData blockData) {
|
||||
String id = blockData.getAsString();
|
||||
return BlockState.get(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Bukkit BlockData from a WorldEdit BlockStateHolder
|
||||
*
|
||||
* @param block The WorldEdit BlockStateHolder
|
||||
* @return The Bukkit BlockData
|
||||
*/
|
||||
default <B extends BlockStateHolder<B>> BlockData adapt(B block) {
|
||||
return Bukkit.createBlockData(block.getAsString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a WorldEdit BaseItemStack from a Bukkit ItemStack
|
||||
*
|
||||
* @param itemStack The Bukkit ItemStack
|
||||
* @return The WorldEdit BaseItemStack
|
||||
*/
|
||||
default BaseItemStack adapt(ItemStack itemStack) {
|
||||
checkNotNull(itemStack);
|
||||
return new BukkitItemStack(itemStack);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Bukkit ItemStack from a WorldEdit BaseItemStack
|
||||
*
|
||||
* @param item The WorldEdit BaseItemStack
|
||||
* @return The Bukkit ItemStack
|
||||
*/
|
||||
default ItemStack adapt(BaseItemStack item) {
|
||||
checkNotNull(item);
|
||||
if (item instanceof BukkitItemStack) {
|
||||
return ((BukkitItemStack) item).getBukkitItemStack();
|
||||
}
|
||||
return new ItemStack(adapt(item.getType()), item.getAmount());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a WorldEdit Player from a Bukkit Player.
|
||||
*
|
||||
* @param player The Bukkit player
|
||||
* @return The WorldEdit player
|
||||
*/
|
||||
default BukkitPlayer adapt(Player player) {
|
||||
return WorldEditPlugin.getInstance().wrapPlayer(player);
|
||||
}
|
||||
/**
|
||||
* Create a Bukkit Player from a WorldEdit Player.
|
||||
*
|
||||
* @param player The WorldEdit player
|
||||
* @return The Bukkit player
|
||||
*/
|
||||
default Player adapt(com.sk89q.worldedit.entity.Player player) {
|
||||
return ((BukkitPlayer) player).getPlayer();
|
||||
}
|
||||
|
||||
default Biome adapt(BiomeType biomeType) {
|
||||
if (!biomeType.getId().startsWith("minecraft:")) {
|
||||
throw new IllegalArgumentException("Bukkit only supports vanilla biomes");
|
||||
}
|
||||
try {
|
||||
return Biome.valueOf(biomeType.getId().substring(10).toUpperCase(Locale.ROOT));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
default BiomeType adapt(Biome biome) {
|
||||
return BiomeTypes.get(biome.name().toLowerCase(Locale.ROOT));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks equality between a WorldEdit BlockType and a Bukkit Material
|
||||
*
|
||||
* @param blockType The WorldEdit BlockType
|
||||
* @param type The Bukkit Material
|
||||
* @return If they are equal
|
||||
*/
|
||||
default boolean equals(BlockType blockType, Material type) {
|
||||
return blockType == asItemType(type).getBlockType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a WorldEdit world from a Bukkit world.
|
||||
*
|
||||
* @param world the Bukkit world
|
||||
* @return a WorldEdit world
|
||||
*/
|
||||
default World adapt(org.bukkit.World world) {
|
||||
checkNotNull(world);
|
||||
return new BukkitWorld(world);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a WorldEdit GameMode from a Bukkit one.
|
||||
*
|
||||
* @param gameMode Bukkit GameMode
|
||||
* @return WorldEdit GameMode
|
||||
*/
|
||||
default GameMode adapt(org.bukkit.GameMode gameMode) {
|
||||
checkNotNull(gameMode);
|
||||
return GameModes.get(gameMode.name().toLowerCase(Locale.ROOT));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a WorldEdit EntityType from a Bukkit one.
|
||||
*
|
||||
* @param entityType Bukkit EntityType
|
||||
* @return WorldEdit EntityType
|
||||
*/
|
||||
default EntityType adapt(org.bukkit.entity.EntityType entityType) {
|
||||
return EntityTypes.get(entityType.getName().toLowerCase(Locale.ROOT));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a WorldEdit BlockStateHolder from a Bukkit ItemStack
|
||||
*
|
||||
* @param itemStack The Bukkit ItemStack
|
||||
* @return The WorldEdit BlockState
|
||||
*/
|
||||
default BlockState asBlockState(ItemStack itemStack) {
|
||||
checkNotNull(itemStack);
|
||||
if (itemStack.getType().isBlock()) {
|
||||
return adapt(itemStack.getType().createBlockData());
|
||||
} else {
|
||||
throw new NotABlockException();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,266 @@
|
||||
package com.fastasyncworldedit.bukkit.adapter;
|
||||
|
||||
import com.fastasyncworldedit.core.beta.implementation.packet.ChunkPacket;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.blocks.BaseItem;
|
||||
import com.sk89q.worldedit.blocks.BaseItemStack;
|
||||
import com.sk89q.worldedit.bukkit.BukkitPlayer;
|
||||
import com.sk89q.worldedit.bukkit.BukkitWorld;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.math.Vector3;
|
||||
import com.sk89q.worldedit.registry.state.Property;
|
||||
import com.sk89q.worldedit.util.Direction;
|
||||
import com.sk89q.worldedit.world.DataFixer;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.gamemode.GameMode;
|
||||
import com.sk89q.worldedit.world.item.ItemType;
|
||||
import com.sk89q.worldedit.world.registry.BlockMaterial;
|
||||
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.WorldCreator;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Map;
|
||||
import java.util.OptionalInt;
|
||||
|
||||
public interface IDelegateBukkitImplAdapter<T> extends BukkitImplAdapter<T> {
|
||||
BukkitImplAdapter<T> getParent();
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
default DataFixer getDataFixer() {
|
||||
return getParent().getDataFixer();
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean supportsWatchdog() {
|
||||
return getParent().supportsWatchdog();
|
||||
}
|
||||
|
||||
@Override
|
||||
default void tickWatchdog() {
|
||||
getParent().tickWatchdog();
|
||||
}
|
||||
|
||||
@Override
|
||||
default BaseBlock getBlock(Location location) {
|
||||
return getParent().getBlock(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
default BaseEntity getEntity(Entity entity) {
|
||||
return getParent().getEntity(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
default Entity createEntity(Location location, BaseEntity state) {
|
||||
return getParent().createEntity(location, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
default Map<String, ? extends Property<?>> getProperties(BlockType blockType) {
|
||||
return getParent().getProperties(blockType);
|
||||
}
|
||||
|
||||
@Override
|
||||
default void sendFakeNBT(Player player, BlockVector3 pos, CompoundBinaryTag nbtData) {
|
||||
getParent().sendFakeNBT(player, pos, nbtData);
|
||||
}
|
||||
|
||||
@Override
|
||||
default void sendFakeOP(Player player) {
|
||||
getParent().sendFakeOP(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean simulateItemUse(World world, BlockVector3 position, BaseItem item, Direction face) {
|
||||
return getParent().simulateItemUse(world, position, item, face);
|
||||
}
|
||||
|
||||
@Override
|
||||
default ItemStack adapt(BaseItemStack item) {
|
||||
return getParent().adapt(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
default BaseItemStack adapt(ItemStack itemStack) {
|
||||
return getParent().adapt(itemStack);
|
||||
}
|
||||
|
||||
@Override
|
||||
default OptionalInt getInternalBlockStateId(BlockData data) {
|
||||
return getParent().getInternalBlockStateId(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
default OptionalInt getInternalBlockStateId(BlockState state) {
|
||||
return getParent().getInternalBlockStateId(state);
|
||||
}
|
||||
|
||||
@Override
|
||||
default BlockMaterial getMaterial(BlockType blockType) {
|
||||
return getParent().getMaterial(blockType);
|
||||
}
|
||||
|
||||
@Override
|
||||
default BlockMaterial getMaterial(BlockState blockState) {
|
||||
return getParent().getMaterial(blockState);
|
||||
}
|
||||
|
||||
default Tag toNative(T foreign) {
|
||||
return getParent().toNative(foreign);
|
||||
}
|
||||
|
||||
@Override
|
||||
default T fromNative(Tag foreign) {
|
||||
return getParent().fromNative(foreign);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
default World createWorld(WorldCreator creator) {
|
||||
return getParent().createWorld(creator);
|
||||
}
|
||||
|
||||
@Override
|
||||
default void sendFakeChunk(World world, Player player, ChunkPacket packet) {
|
||||
getParent().sendFakeChunk(world, player, packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
default BukkitWorld asBukkitWorld(com.sk89q.worldedit.world.World world) {
|
||||
return getParent().asBukkitWorld(world);
|
||||
}
|
||||
|
||||
@Override
|
||||
default World adapt(com.sk89q.worldedit.world.World world) {
|
||||
return getParent().adapt(world);
|
||||
}
|
||||
|
||||
@Override
|
||||
default Location adapt(World world, Vector3 position) {
|
||||
return getParent().adapt(world, position);
|
||||
}
|
||||
|
||||
@Override
|
||||
default Location adapt(World world, BlockVector3 position) {
|
||||
return getParent().adapt(world, position);
|
||||
}
|
||||
|
||||
@Override
|
||||
default Location adapt(World world, com.sk89q.worldedit.util.Location location) {
|
||||
return getParent().adapt(world, location);
|
||||
}
|
||||
|
||||
@Override
|
||||
default Vector3 asVector(Location location) {
|
||||
return getParent().asVector(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
default BlockVector3 asBlockVector(Location location) {
|
||||
return getParent().asBlockVector(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
default com.sk89q.worldedit.entity.Entity adapt(Entity entity) {
|
||||
return getParent().adapt(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
default Material adapt(ItemType itemType) {
|
||||
return getParent().adapt(itemType);
|
||||
}
|
||||
|
||||
@Override
|
||||
default Material adapt(BlockType blockType) {
|
||||
return getParent().adapt(blockType);
|
||||
}
|
||||
|
||||
@Override
|
||||
default EntityType adapt(com.sk89q.worldedit.world.entity.EntityType entityType) {
|
||||
return getParent().adapt(entityType);
|
||||
}
|
||||
|
||||
@Override
|
||||
default BlockType asBlockType(Material material) {
|
||||
return getParent().asBlockType(material);
|
||||
}
|
||||
|
||||
@Override
|
||||
default ItemType asItemType(Material material) {
|
||||
return getParent().asItemType(material);
|
||||
}
|
||||
|
||||
@Override
|
||||
default BlockState adapt(BlockData blockData) {
|
||||
return getParent().adapt(blockData);
|
||||
}
|
||||
|
||||
@Override
|
||||
default <B extends BlockStateHolder<B>> BlockData adapt(B block) {
|
||||
return getParent().adapt(block);
|
||||
}
|
||||
|
||||
@Override
|
||||
default BukkitPlayer adapt(Player player) {
|
||||
return getParent().adapt(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
default Player adapt(com.sk89q.worldedit.entity.Player player) {
|
||||
return getParent().adapt(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
default Biome adapt(BiomeType biomeType) {
|
||||
return getParent().adapt(biomeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
default BiomeType adapt(Biome biome) {
|
||||
return getParent().adapt(biome);
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean equals(BlockType blockType, Material type) {
|
||||
return getParent().equals(blockType, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
default com.sk89q.worldedit.world.World adapt(World world) {
|
||||
return getParent().adapt(world);
|
||||
}
|
||||
|
||||
@Override
|
||||
default GameMode adapt(org.bukkit.GameMode gameMode) {
|
||||
return getParent().adapt(gameMode);
|
||||
}
|
||||
|
||||
@Override
|
||||
default com.sk89q.worldedit.world.entity.EntityType adapt(EntityType entityType) {
|
||||
return getParent().adapt(entityType);
|
||||
}
|
||||
|
||||
@Override
|
||||
default BlockState asBlockState(ItemStack itemStack) {
|
||||
return getParent().asBlockState(itemStack);
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
package com.fastasyncworldedit.bukkit.adapter;
|
||||
|
||||
import com.fastasyncworldedit.core.beta.implementation.packet.ChunkPacket;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class MapChunkUtil<T> {
|
||||
protected Field fieldX;
|
||||
protected Field fieldZ;
|
||||
protected Field fieldHeightMap;
|
||||
protected Field fieldBitMask;
|
||||
protected Field fieldChunkData;
|
||||
protected Field fieldBlockEntities;
|
||||
protected Field fieldFull;
|
||||
|
||||
protected abstract T createPacket();
|
||||
|
||||
public T create(BukkitImplAdapter adapter, ChunkPacket packet) {
|
||||
try {
|
||||
T nmsPacket;
|
||||
int bitMask = packet.getChunk().getBitMask();
|
||||
nmsPacket = createPacket();
|
||||
fieldX.setInt(nmsPacket, packet.getChunkX());
|
||||
fieldZ.setInt(nmsPacket, packet.getChunkZ());
|
||||
fieldBitMask.set(nmsPacket, packet.getChunk().getBitMask());
|
||||
|
||||
if (fieldHeightMap != null) {
|
||||
Object heightMap = adapter.fromNative(packet.getHeightMap());
|
||||
fieldHeightMap.set(nmsPacket, heightMap);
|
||||
}
|
||||
|
||||
fieldChunkData.set(nmsPacket, packet.getSectionBytes());
|
||||
|
||||
Map<BlockVector3, CompoundTag> tiles = packet.getChunk().getTiles();
|
||||
ArrayList<Object> nmsTiles = new ArrayList<>(tiles.size());
|
||||
for (Map.Entry<BlockVector3, CompoundTag> entry : tiles.entrySet()) {
|
||||
Object nmsTag = adapter.fromNative(entry.getValue());
|
||||
nmsTiles.add(nmsTag);
|
||||
}
|
||||
fieldBlockEntities.set(nmsPacket, nmsTiles);
|
||||
fieldFull.set(nmsPacket, packet.isFull());
|
||||
return nmsPacket;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,195 @@
|
||||
package com.fastasyncworldedit.bukkit.adapter;
|
||||
|
||||
import com.fastasyncworldedit.core.FAWEPlatformAdapterImpl;
|
||||
import com.fastasyncworldedit.core.beta.IChunkGet;
|
||||
import com.fastasyncworldedit.core.configuration.Settings;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.block.BlockID;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class NMSAdapter implements FAWEPlatformAdapterImpl {
|
||||
public static int createPalette(int[] blockToPalette, int[] paletteToBlock, int[] blocksCopy,
|
||||
int[] num_palette_buffer, char[] set, Map<BlockVector3, Integer> ticking_blocks, boolean fastmode) {
|
||||
int air = 0;
|
||||
int num_palette = 0;
|
||||
char lastOrdinal = BlockID.__RESERVED__;
|
||||
boolean lastticking = false;
|
||||
boolean tick_placed = Settings.IMP.EXPERIMENTAL.ALLOW_TICK_PLACED;
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
char ordinal = set[i];
|
||||
switch (ordinal) {
|
||||
case BlockID.__RESERVED__:
|
||||
ordinal = BlockID.AIR;
|
||||
case BlockID.AIR:
|
||||
case BlockID.CAVE_AIR:
|
||||
case BlockID.VOID_AIR:
|
||||
air++;
|
||||
break;
|
||||
default:
|
||||
if (!fastmode && !tick_placed) {
|
||||
boolean ticking;
|
||||
if (ordinal != lastOrdinal) {
|
||||
ticking = BlockTypesCache.ticking[ordinal];
|
||||
lastOrdinal = ordinal;
|
||||
lastticking = ticking;
|
||||
} else {
|
||||
ticking = lastticking;
|
||||
}
|
||||
if (ticking) {
|
||||
BlockState state = BlockState.getFromOrdinal(ordinal);
|
||||
ticking_blocks
|
||||
.put(BlockVector3.at(i & 15, (i >> 8) & 15, (i >> 4) & 15),
|
||||
WorldEditPlugin.getInstance().getBukkitImplAdapter()
|
||||
.getInternalBlockStateId(state).orElse(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
int palette = blockToPalette[ordinal];
|
||||
if (palette == Integer.MAX_VALUE) {
|
||||
blockToPalette[ordinal] = palette = num_palette;
|
||||
paletteToBlock[num_palette] = ordinal;
|
||||
num_palette++;
|
||||
}
|
||||
blocksCopy[i] = palette;
|
||||
}
|
||||
num_palette_buffer[0] = num_palette;
|
||||
return air;
|
||||
}
|
||||
|
||||
public static int createPalette(int layer, int[] blockToPalette, int[] paletteToBlock,
|
||||
int[] blocksCopy, int[] num_palette_buffer, Function<Integer, char[]> get, char[] set,
|
||||
Map<BlockVector3, Integer> ticking_blocks, boolean fastmode) {
|
||||
int air = 0;
|
||||
int num_palette = 0;
|
||||
char[] getArr = null;
|
||||
char lastOrdinal = BlockID.__RESERVED__;
|
||||
boolean lastticking = false;
|
||||
boolean tick_placed = Settings.IMP.EXPERIMENTAL.ALLOW_TICK_PLACED;
|
||||
boolean tick_existing = Settings.IMP.EXPERIMENTAL.ALLOW_TICK_EXISTING;
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
char ordinal = set[i];
|
||||
switch (ordinal) {
|
||||
case BlockID.__RESERVED__: {
|
||||
if (getArr == null) {
|
||||
getArr = get.apply(layer);
|
||||
}
|
||||
ordinal = getArr[i];
|
||||
switch (ordinal) {
|
||||
case BlockID.__RESERVED__:
|
||||
ordinal = BlockID.AIR;
|
||||
case BlockID.AIR:
|
||||
case BlockID.CAVE_AIR:
|
||||
case BlockID.VOID_AIR:
|
||||
air++;
|
||||
break;
|
||||
default:
|
||||
if (!fastmode && !tick_placed && tick_existing) {
|
||||
boolean ticking;
|
||||
if (ordinal != lastOrdinal) {
|
||||
ticking = BlockTypesCache.ticking[ordinal];
|
||||
lastOrdinal = ordinal;
|
||||
lastticking = ticking;
|
||||
} else {
|
||||
ticking = lastticking;
|
||||
}
|
||||
if (ticking) {
|
||||
BlockState state = BlockState.getFromOrdinal(ordinal);
|
||||
ticking_blocks
|
||||
.put(BlockVector3.at(i & 15, (i >> 8) & 15, (i >> 4) & 15),
|
||||
WorldEditPlugin.getInstance().getBukkitImplAdapter()
|
||||
.getInternalBlockStateId(state).orElse(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
set[i] = ordinal;
|
||||
break;
|
||||
}
|
||||
case BlockID.AIR:
|
||||
case BlockID.CAVE_AIR:
|
||||
case BlockID.VOID_AIR:
|
||||
air++;
|
||||
break;
|
||||
}
|
||||
if (!fastmode && tick_placed) {
|
||||
boolean ticking;
|
||||
if (ordinal != lastOrdinal) {
|
||||
ticking = BlockTypesCache.ticking[ordinal];
|
||||
lastOrdinal = ordinal;
|
||||
lastticking = ticking;
|
||||
} else {
|
||||
ticking = lastticking;
|
||||
}
|
||||
if (ticking) {
|
||||
BlockState state = BlockState.getFromOrdinal(ordinal);
|
||||
ticking_blocks.put(BlockVector3.at(i & 15, (i >> 8) & 15, (i >> 4) & 15),
|
||||
WorldEditPlugin.getInstance().getBukkitImplAdapter()
|
||||
.getInternalBlockStateId(state).orElse(0));
|
||||
}
|
||||
}
|
||||
int palette = blockToPalette[ordinal];
|
||||
if (palette == Integer.MAX_VALUE) {
|
||||
blockToPalette[ordinal] = palette = num_palette;
|
||||
paletteToBlock[num_palette] = ordinal;
|
||||
num_palette++;
|
||||
}
|
||||
blocksCopy[i] = palette;
|
||||
}
|
||||
//Keeping this here for reference.
|
||||
//if (setblocks != 4096) {
|
||||
// char[] getArr = get.apply(layer);
|
||||
// for (i = setblocks; i < 4096; i++) {
|
||||
// char ordinal = set[i];
|
||||
// switch (ordinal) {
|
||||
// case BlockID.__RESERVED__:
|
||||
// ordinal = getArr[i];
|
||||
// switch (ordinal) {
|
||||
// case BlockID.__RESERVED__:
|
||||
// ordinal = BlockID.AIR;
|
||||
// case BlockID.AIR:
|
||||
// case BlockID.CAVE_AIR:
|
||||
// case BlockID.VOID_AIR:
|
||||
// air++;
|
||||
// break;
|
||||
// default:
|
||||
// BlockState state = BlockState.getFromOrdinal(ordinal);
|
||||
// if (state.getMaterial().isTicksRandomly()) {
|
||||
// ticking_blocks
|
||||
// .put(BlockVector3.at(i & 15, (i >> 8) & 15, (i >> 4) & 15),
|
||||
// WorldEditPlugin.getInstance().getBukkitImplAdapter()
|
||||
// .getInternalBlockStateId(state).orElse(0));
|
||||
// }
|
||||
// set[i] = ordinal;
|
||||
// }
|
||||
// break;
|
||||
// case BlockID.AIR:
|
||||
// case BlockID.CAVE_AIR:
|
||||
// case BlockID.VOID_AIR:
|
||||
// air++;
|
||||
// }
|
||||
// int palette = blockToPalette[ordinal];
|
||||
// if (palette == Integer.MAX_VALUE) {
|
||||
// blockToPalette[ordinal] = palette = num_palette;
|
||||
// paletteToBlock[num_palette] = ordinal;
|
||||
// num_palette++;
|
||||
// }
|
||||
// blocksCopy[i] = palette;
|
||||
// }
|
||||
//}
|
||||
|
||||
num_palette_buffer[0] = num_palette;
|
||||
return air;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendChunk(IChunkGet chunk, int mask, boolean lighting) {
|
||||
if (!(chunk instanceof BukkitGetBlocks)) {
|
||||
throw new IllegalArgumentException("(IChunkGet) chunk not of type BukkitGetBlocks");
|
||||
}
|
||||
((BukkitGetBlocks) chunk).send(mask, lighting);
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package com.fastasyncworldedit.bukkit.adapter;
|
||||
|
||||
import com.fastasyncworldedit.core.beta.IQueueChunk;
|
||||
import com.fastasyncworldedit.core.beta.IQueueExtent;
|
||||
import com.fastasyncworldedit.core.beta.implementation.lighting.NMSRelighter;
|
||||
import com.fastasyncworldedit.core.beta.implementation.lighting.Relighter;
|
||||
import com.fastasyncworldedit.core.beta.implementation.lighting.RelighterFactory;
|
||||
import com.fastasyncworldedit.core.configuration.Settings;
|
||||
import com.fastasyncworldedit.core.object.RelightMode;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class NMSRelighterFactory implements RelighterFactory {
|
||||
@Override
|
||||
public @NotNull Relighter createRelighter(RelightMode relightMode, World world, IQueueExtent<IQueueChunk> queue) {
|
||||
return new NMSRelighter(queue,
|
||||
relightMode != null ? relightMode : RelightMode.valueOf(Settings.IMP.LIGHTING.MODE));
|
||||
}
|
||||
}
|
@ -0,0 +1,551 @@
|
||||
package com.fastasyncworldedit.bukkit.adapter;
|
||||
|
||||
import com.fastasyncworldedit.core.beta.IChunkCache;
|
||||
import com.fastasyncworldedit.core.beta.IChunkGet;
|
||||
import com.fastasyncworldedit.core.beta.implementation.queue.SingleThreadQueueExtent;
|
||||
import com.fastasyncworldedit.core.configuration.Settings;
|
||||
import com.fastasyncworldedit.core.util.MathMan;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.world.RegenOptions;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bukkit.generator.BlockPopulator;
|
||||
|
||||
/**
|
||||
* Represents an abstract regeneration handler.
|
||||
* @param <IChunkAccess> the type of the {@Code IChunkAccess} of the current Minecraft implementation
|
||||
* @param <ProtoChunk> the type of the {@Code ProtoChunk} of the current Minecraft implementation
|
||||
* @param <Chunk> the type of the {@Code Chunk} of the current Minecraft implementation
|
||||
* @param <ChunkStatus> the type of the {@Code ChunkStatusWrapper} wrapping the {@Code ChunkStatus} enum
|
||||
*/
|
||||
public abstract class Regenerator<IChunkAccess, ProtoChunk extends IChunkAccess, Chunk extends IChunkAccess, ChunkStatus extends Regenerator.ChunkStatusWrapper<IChunkAccess>> {
|
||||
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
|
||||
protected final org.bukkit.World originalBukkitWorld;
|
||||
protected final Region region;
|
||||
protected final Extent target;
|
||||
protected final RegenOptions options;
|
||||
|
||||
//runtime
|
||||
protected final Map<ChunkStatus, Concurrency> chunkStati = new LinkedHashMap<>();
|
||||
protected boolean generateConcurrent = true;
|
||||
protected long seed;
|
||||
|
||||
private final Long2ObjectLinkedOpenHashMap<ProtoChunk> protoChunks = new Long2ObjectLinkedOpenHashMap<>();
|
||||
private final Long2ObjectOpenHashMap<Chunk> chunks = new Long2ObjectOpenHashMap<>();
|
||||
private ExecutorService executor;
|
||||
private SingleThreadQueueExtent source;
|
||||
|
||||
/**
|
||||
* Initializes an abstract regeneration handler.
|
||||
* @param originalBukkitWorld the Bukkit world containing all the information on how to regenerate the {code Region}
|
||||
* @param region the selection to regenerate
|
||||
* @param target the target {@code Extent} to paste the regenerated blocks into
|
||||
* @param options the options to used while regenerating and pasting into the target {@code Extent}
|
||||
*/
|
||||
public Regenerator(org.bukkit.World originalBukkitWorld, Region region, Extent target, RegenOptions options) {
|
||||
this.originalBukkitWorld = originalBukkitWorld;
|
||||
this.region = region;
|
||||
this.target = target;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Regenerates the selected {@code Region}.
|
||||
* @return whether or not the regeneration process was successful
|
||||
* @throws Exception when something goes terribly wrong
|
||||
*/
|
||||
public boolean regenerate() throws Exception {
|
||||
if (!prepare()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!initNewWorld()) {
|
||||
cleanup0();
|
||||
return false;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
cleanup0();
|
||||
throw e;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!generate()) {
|
||||
cleanup0();
|
||||
return false;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
cleanup0();
|
||||
throw e;
|
||||
}
|
||||
|
||||
try {
|
||||
copyToWorld();
|
||||
} catch (Exception e) {
|
||||
cleanup0();
|
||||
throw e;
|
||||
}
|
||||
|
||||
cleanup0();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@code ProtoChunk} at the given chunk coordinates.
|
||||
* @param x the chunk x coordinate
|
||||
* @param z the chunk z coordinate
|
||||
* @return the {@code ProtoChunk} at the given chunk coordinates or null if it is not part of the regeneration process or has not been initialized yet.
|
||||
*/
|
||||
protected ProtoChunk getProtoChunkAt(int x, int z) {
|
||||
return protoChunks.get(MathMan.pairInt(x, z));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@code Chunk} at the given chunk coordinates.
|
||||
* @param x the chunk x coordinate
|
||||
* @param z the chunk z coordinate
|
||||
* @return the {@code Chunk} at the given chunk coordinates or null if it is not part of the regeneration process or has not been converted yet.
|
||||
*/
|
||||
protected Chunk getChunkAt(int x, int z) {
|
||||
return chunks.get(MathMan.pairInt(x, z));
|
||||
}
|
||||
|
||||
private boolean generate() throws Exception {
|
||||
if (generateConcurrent) {
|
||||
//Using concurrent chunk generation
|
||||
executor = Executors.newFixedThreadPool(Settings.IMP.QUEUE.PARALLEL_THREADS);
|
||||
} // else using sequential chunk generation, concurrent not supported
|
||||
|
||||
//TODO: can we get that required radius down without affecting chunk generation (e.g. strucures, features, ...)?
|
||||
//for now it is working well and fast, if we are bored in the future we could do the research (a lot of it) to reduce the border radius
|
||||
|
||||
//generate chunk coords lists with a certain radius
|
||||
Int2ObjectOpenHashMap<List<Long>> chunkCoordsForRadius = new Int2ObjectOpenHashMap<>();
|
||||
chunkStati.keySet().stream().map(ChunkStatusWrapper::requiredNeigborChunkRadius0).distinct().forEach(radius -> {
|
||||
if (radius == -1) //ignore ChunkStatus.EMPTY
|
||||
return;
|
||||
int border = 16 - radius; //9 = 8 + 1, 8: max border radius used in chunk stages, 1: need 1 extra chunk for chunk features to generate at the border of the region
|
||||
chunkCoordsForRadius.put(radius, getChunkCoordsRegen(region, border));
|
||||
});
|
||||
|
||||
//create chunks
|
||||
for (Long xz : chunkCoordsForRadius.get(0)) {
|
||||
ProtoChunk chunk = createProtoChunk(MathMan.unpairIntX(xz), MathMan.unpairIntY(xz));
|
||||
protoChunks.put(xz, chunk);
|
||||
}
|
||||
|
||||
//generate lists for RegionLimitedWorldAccess, need to be square with odd length (e.g. 17x17), 17 = 1 middle chunk + 8 border chunks * 2
|
||||
Int2ObjectOpenHashMap<Long2ObjectOpenHashMap<List<IChunkAccess>>> worldlimits = new Int2ObjectOpenHashMap<>();
|
||||
chunkStati.keySet().stream().map(ChunkStatusWrapper::requiredNeigborChunkRadius0).distinct().forEach(radius -> {
|
||||
if (radius == -1) //ignore ChunkStatus.EMPTY
|
||||
return;
|
||||
Long2ObjectOpenHashMap<List<IChunkAccess>> map = new Long2ObjectOpenHashMap<>();
|
||||
for (Long xz : chunkCoordsForRadius.get(radius)) {
|
||||
int x = MathMan.unpairIntX(xz);
|
||||
int z = MathMan.unpairIntY(xz);
|
||||
List<IChunkAccess> l = new ArrayList<>((radius + 1 + radius) * (radius + 1 + radius));
|
||||
for (int zz = z - radius; zz <= z + radius; zz++) { //order is important, first z then x
|
||||
for (int xx = x - radius; xx <= x + radius; xx++) {
|
||||
l.add(protoChunks.get(MathMan.pairInt(xx, zz)));
|
||||
}
|
||||
}
|
||||
map.put(xz, l);
|
||||
}
|
||||
worldlimits.put(radius, map);
|
||||
});
|
||||
|
||||
//run generation tasks exluding FULL chunk status
|
||||
for (Map.Entry<ChunkStatus, Concurrency> entry : chunkStati.entrySet()) {
|
||||
ChunkStatus chunkStatus = entry.getKey();
|
||||
int radius = chunkStatus.requiredNeigborChunkRadius0();
|
||||
|
||||
List<Long> coords = chunkCoordsForRadius.get(radius);
|
||||
if (this.generateConcurrent && entry.getValue() == Concurrency.RADIUS) {
|
||||
SequentialTasks<ConcurrentTasks<SequentialTasks<Long>>> tasks = getChunkStatusTaskRows(coords, radius);
|
||||
for (ConcurrentTasks<SequentialTasks<Long>> para : tasks) {
|
||||
List scheduled = new ArrayList<>(tasks.size());
|
||||
for (SequentialTasks<Long> row : para) {
|
||||
scheduled.add((Callable) () -> {
|
||||
for (Long xz : row) {
|
||||
chunkStatus.processChunkSave(xz, worldlimits.get(radius).get(xz));
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
try {
|
||||
List<Future> futures = executor.invokeAll(scheduled);
|
||||
for (Future future : futures) {
|
||||
future.get();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
} else if (this.generateConcurrent && entry.getValue() == Concurrency.FULL) {
|
||||
// every chunk can be processed individually
|
||||
List scheduled = new ArrayList(coords.size());
|
||||
for (long xz : coords) {
|
||||
scheduled.add((Callable) () -> {
|
||||
chunkStatus.processChunkSave(xz, worldlimits.get(radius).get(xz));
|
||||
return null;
|
||||
});
|
||||
}
|
||||
try {
|
||||
List<Future> futures = executor.invokeAll(scheduled);
|
||||
for (Future future : futures) {
|
||||
future.get();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else { // Concurrency.NONE or generateConcurrent == false
|
||||
// run sequential
|
||||
for (long xz : coords) {
|
||||
chunkStatus.processChunkSave(xz, worldlimits.get(radius).get(xz));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//convert to proper chunks
|
||||
for (Long xz : chunkCoordsForRadius.get(0)) {
|
||||
ProtoChunk proto = protoChunks.get(xz);
|
||||
chunks.put(xz, createChunk(proto));
|
||||
}
|
||||
|
||||
//final chunkstatus
|
||||
ChunkStatus FULL = getFullChunkStatus();
|
||||
for (Long xz : chunkCoordsForRadius.get(0)) { //FULL.requiredNeighbourChunkRadius() == 0!
|
||||
Chunk chunk = chunks.get(xz);
|
||||
FULL.processChunkSave(xz, Arrays.asList(chunk));
|
||||
}
|
||||
|
||||
//populate
|
||||
List<BlockPopulator> populators = getBlockPopulators();
|
||||
for (Long xz : chunkCoordsForRadius.get(0)) {
|
||||
int x = MathMan.unpairIntX(xz);
|
||||
int z = MathMan.unpairIntY(xz);
|
||||
|
||||
//prepare chunk seed
|
||||
Random random = getChunkRandom(seed, x, z);
|
||||
|
||||
//actually populate
|
||||
Chunk c = chunks.get(xz);
|
||||
populators.forEach(pop -> {
|
||||
populate(c, random, pop);
|
||||
});
|
||||
}
|
||||
|
||||
source = new SingleThreadQueueExtent();
|
||||
source.init(null, initSourceQueueCache(), null);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void copyToWorld() {
|
||||
//Setting Blocks
|
||||
long start = System.currentTimeMillis();
|
||||
boolean genbiomes = options.shouldRegenBiomes();
|
||||
boolean hasBiome = options.hasBiomeType();
|
||||
BiomeType biome = options.getBiomeType();
|
||||
for (BlockVector3 vec : region) {
|
||||
target.setBlock(vec, source.getBlock(vec));
|
||||
if (hasBiome) {
|
||||
target.setBiome(vec, biome);
|
||||
} else if (genbiomes) {
|
||||
target.setBiome(vec, source.getBiome(vec));
|
||||
}
|
||||
// realExtent.setSkyLight(vec, extent.getSkyLight(vec));
|
||||
// realExtent.setBlockLight(vec, extent.getBrightness(vec));
|
||||
}
|
||||
}
|
||||
|
||||
private void cleanup0() {
|
||||
if (executor != null) {
|
||||
executor.shutdownNow();
|
||||
}
|
||||
cleanup();
|
||||
}
|
||||
|
||||
//functions to be implemented by sub class
|
||||
/**
|
||||
* <p>Implement the preparation process in here. DO NOT instanciate any variable here that require the cleanup function. This function is for gathering further information before initializing a new
|
||||
* world.</p>
|
||||
*
|
||||
* <p>Fields required to be initialized: chunkStati, seed</p>
|
||||
* <p>For chunkStati also see {code ChunkStatusWrapper}.</p>
|
||||
*
|
||||
* @return whether or not the preparation process was successful
|
||||
*/
|
||||
protected abstract boolean prepare();
|
||||
|
||||
/**
|
||||
* Implement the creation of the seperate world in here.
|
||||
*
|
||||
* Fields required to be initialized: generateConcurrent
|
||||
*
|
||||
* @return true if everything went fine, otherwise false. When false is returned the Regenerator halts the regeneration process and calls the cleanup function.
|
||||
* @throws java.lang.Exception When the implementation of this method throws and exception the Regenerator halts the regeneration process and calls the cleanup function.
|
||||
*/
|
||||
protected abstract boolean initNewWorld() throws Exception;
|
||||
|
||||
/**
|
||||
* Implement the cleanup of all the mess that is created during the regeneration process (initNewWorld() and generate()).This function must not throw any exceptions.
|
||||
*/
|
||||
protected abstract void cleanup();
|
||||
|
||||
//functions to implement by sub class - regenate related
|
||||
/**
|
||||
* Implement the initialization of a {@code ProtoChunk} here.
|
||||
*
|
||||
* @param x the x coorinate of the {@code ProtoChunk} to create
|
||||
* @param z the z coorinate of the {@code ProtoChunk} to create
|
||||
* @return an initialized {@code ProtoChunk}
|
||||
*/
|
||||
protected abstract ProtoChunk createProtoChunk(int x, int z);
|
||||
|
||||
/**
|
||||
* Implement the convertion of a {@code ProtoChunk} to a {@code Chunk} here.
|
||||
*
|
||||
* @param protoChunk the {@code ProtoChunk} to be converted to a {@code Chunk}
|
||||
* @return the converted {@code Chunk}
|
||||
*/
|
||||
protected abstract Chunk createChunk(ProtoChunk protoChunk);
|
||||
|
||||
/**
|
||||
* Return the {@code ChunkStatus.FULL} here.
|
||||
* ChunkStatus.FULL is the last step of vanilla chunk generation.
|
||||
*
|
||||
* @return {@code ChunkStatus.FULL}
|
||||
*/
|
||||
protected abstract ChunkStatus getFullChunkStatus();
|
||||
|
||||
/**
|
||||
* Return a list of {@code BlockPopulator} used to populate the original world here.
|
||||
*
|
||||
* @return {@code ChunkStatus.FULL}
|
||||
*/
|
||||
protected abstract List<BlockPopulator> getBlockPopulators();
|
||||
|
||||
/**
|
||||
* Implement the population of the {@code Chunk} with the given chunk random and {@code BlockPopulator} here.
|
||||
*
|
||||
* @param chunk the {@code Chunk} to populate
|
||||
* @param random the chunk random to use for population
|
||||
* @param pop the {@code BlockPopulator} to use
|
||||
*/
|
||||
protected abstract void populate(Chunk chunk, Random random, BlockPopulator pop);
|
||||
|
||||
/**
|
||||
* Implement the initialization an {@code IChunkCache<IChunkGet>} here. Use will need the {@code getChunkAt} function
|
||||
* @return an initialized {@code IChunkCache<IChunkGet>}
|
||||
*/
|
||||
protected abstract IChunkCache<IChunkGet> initSourceQueueCache();
|
||||
|
||||
//algorithms
|
||||
private List<Long> getChunkCoordsRegen(Region region, int border) { //needs to be square num of chunks
|
||||
BlockVector3 oldMin = region.getMinimumPoint();
|
||||
BlockVector3 newMin = BlockVector3.at((oldMin.getX() >> 4 << 4) - border * 16, oldMin.getY(), (oldMin.getZ() >> 4 << 4) - border * 16);
|
||||
BlockVector3 oldMax = region.getMaximumPoint();
|
||||
BlockVector3 newMax = BlockVector3.at((oldMax.getX() >> 4 << 4) + (border + 1) * 16 - 1, oldMax.getY(), (oldMax.getZ() >> 4 << 4) + (border + 1) * 16 - 1);
|
||||
Region adjustedRegion = new CuboidRegion(newMin, newMax);
|
||||
return adjustedRegion.getChunks().stream()
|
||||
.map(c -> BlockVector2.at(c.getX(), c.getZ()))
|
||||
.sorted(Comparator.<BlockVector2>comparingInt(c -> c.getZ()).thenComparingInt(c -> c.getX())) //needed for RegionLimitedWorldAccess
|
||||
.map(c -> MathMan.pairInt(c.getX(), c.getZ()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a list of chunkcoord rows that may be executed concurrently
|
||||
*
|
||||
* @param allcoords the coords that should be sorted into rows, must be sorted by z and x
|
||||
* @param requiredNeighborChunkRadius the radius of neighbor chunks that may not be written to conccurently (ChunkStatus.requiredNeighborRadius)
|
||||
* @return a list of chunkcoords rows that may be executed concurrently
|
||||
*/
|
||||
private SequentialTasks<ConcurrentTasks<SequentialTasks<Long>>> getChunkStatusTaskRows(List<Long> allcoords, int requiredNeighborChunkRadius) {
|
||||
int requiredneighbors = Math.max(0, requiredNeighborChunkRadius);
|
||||
|
||||
int minx = allcoords.isEmpty() ? 0 : MathMan.unpairIntX(allcoords.get(0));
|
||||
int maxx = allcoords.isEmpty() ? 0 : MathMan.unpairIntX(allcoords.get(allcoords.size() - 1));
|
||||
int minz = allcoords.isEmpty() ? 0 : MathMan.unpairIntY(allcoords.get(0));
|
||||
int maxz = allcoords.isEmpty() ? 0 : MathMan.unpairIntY(allcoords.get(allcoords.size() - 1));
|
||||
SequentialTasks<ConcurrentTasks<SequentialTasks<Long>>> tasks;
|
||||
if (maxz - minz > maxx - minx) {
|
||||
int numlists = Math.min(requiredneighbors * 2 + 1, maxx - minx + 1);
|
||||
|
||||
Int2ObjectOpenHashMap<SequentialTasks<Long>> byx = new Int2ObjectOpenHashMap();
|
||||
int expectedListLength = (allcoords.size() + 1) / (maxx - minx);
|
||||
|
||||
//init lists
|
||||
for (int i = minx; i <= maxx; i++) {
|
||||
byx.put(i, new SequentialTasks(expectedListLength));
|
||||
}
|
||||
|
||||
//sort into lists by x coord
|
||||
for (Long xz : allcoords) {
|
||||
byx.get(MathMan.unpairIntX(xz)).add(xz);
|
||||
}
|
||||
|
||||
//create parallel tasks
|
||||
tasks = new SequentialTasks(numlists);
|
||||
for (int offset = 0; offset < numlists; offset++) {
|
||||
ConcurrentTasks<SequentialTasks<Long>> para = new ConcurrentTasks((maxz - minz + 1) / numlists + 1);
|
||||
for (int i = 0; minx + i * numlists + offset <= maxx; i++)
|
||||
para.add(byx.get(minx + i * numlists + offset));
|
||||
tasks.add(para);
|
||||
}
|
||||
} else {
|
||||
int numlists = Math.min(requiredneighbors * 2 + 1, maxz - minz + 1);
|
||||
|
||||
Int2ObjectOpenHashMap<SequentialTasks<Long>> byz = new Int2ObjectOpenHashMap();
|
||||
int expectedListLength = (allcoords.size() + 1) / (maxz - minz);
|
||||
|
||||
//init lists
|
||||
for (int i = minz; i <= maxz; i++) {
|
||||
byz.put(i, new SequentialTasks(expectedListLength));
|
||||
}
|
||||
|
||||
//sort into lists by x coord
|
||||
for (Long xz : allcoords) {
|
||||
byz.get(MathMan.unpairIntY(xz)).add(xz);
|
||||
}
|
||||
|
||||
//create parallel tasks
|
||||
tasks = new SequentialTasks(numlists);
|
||||
for (int offset = 0; offset < numlists; offset++) {
|
||||
ConcurrentTasks<SequentialTasks<Long>> para = new ConcurrentTasks((maxx - minx + 1) / numlists + 1);
|
||||
for (int i = 0; minz + i * numlists + offset <= maxz; i++)
|
||||
para.add(byz.get(minz + i * numlists + offset));
|
||||
tasks.add(para);
|
||||
}
|
||||
}
|
||||
|
||||
return tasks;
|
||||
}
|
||||
|
||||
private static Random getChunkRandom(long worldseed, int x, int z) {
|
||||
Random random = new Random();
|
||||
random.setSeed(worldseed);
|
||||
long xRand = random.nextLong() / 2L * 2L + 1L;
|
||||
long zRand = random.nextLong() / 2L * 2L + 1L;
|
||||
random.setSeed((long) x * xRand + (long) z * zRand ^ worldseed);
|
||||
return random;
|
||||
}
|
||||
|
||||
//classes
|
||||
/**
|
||||
* This class is used to wrap the ChunkStatus of the current Minecraft implementation and as the implementation to execute a chunk generation step.
|
||||
* @param <IChunkAccess> the IChunkAccess class of the current Minecraft implementation
|
||||
*/
|
||||
public static abstract class ChunkStatusWrapper<IChunkAccess> {
|
||||
|
||||
/**
|
||||
* Return the required neighbor chunk radius the wrapped {@code ChunkStatus} requires.
|
||||
*
|
||||
* @return the radius of required neighbor chunks
|
||||
*/
|
||||
public abstract int requiredNeigborChunkRadius();
|
||||
|
||||
int requiredNeigborChunkRadius0() {
|
||||
return Math.max(0, requiredNeigborChunkRadius());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the wrapped {@code ChunkStatus}.
|
||||
*
|
||||
* @return the radius of required neighbor chunks
|
||||
*/
|
||||
public abstract String name();
|
||||
|
||||
/**
|
||||
* Return the name of the wrapped {@code ChunkStatus}.
|
||||
*
|
||||
* @param xz represents the chunk coordinates of the chunk to process as denoted by {@code MathMan}
|
||||
* @param accessibleChunks a list of chunks that will be used during the execution of the wrapped {@code ChunkStatus}.
|
||||
* This list is order in the correct order required by the {@code ChunkStatus}, unless Mojang suddenly decides to do things differently.
|
||||
*/
|
||||
public abstract void processChunk(Long xz, List<IChunkAccess> accessibleChunks);
|
||||
|
||||
void processChunkSave(Long xz, List<IChunkAccess> accessibleChunks) {
|
||||
try {
|
||||
processChunk(xz, accessibleChunks);
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Error while running " + name() + " on chunk " + MathMan.unpairIntX(xz) + "/" + MathMan.unpairIntY(xz), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum Concurrency {
|
||||
FULL,
|
||||
RADIUS,
|
||||
NONE
|
||||
}
|
||||
|
||||
public static class SequentialTasks<T> extends Tasks<T> {
|
||||
|
||||
public SequentialTasks(int expectedsize) {
|
||||
super(expectedsize);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ConcurrentTasks<T> extends Tasks<T> {
|
||||
|
||||
public ConcurrentTasks(int expectedsize) {
|
||||
super(expectedsize);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Tasks<T> implements Iterable<T> {
|
||||
|
||||
private final List<T> tasks;
|
||||
|
||||
public Tasks(int expectedsize) {
|
||||
tasks = new ArrayList(expectedsize);
|
||||
}
|
||||
|
||||
public void add(T task) {
|
||||
tasks.add(task);
|
||||
}
|
||||
|
||||
public List<T> list() {
|
||||
return tasks;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return tasks.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<T> iterator() {
|
||||
return tasks.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return tasks.toString();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package com.fastasyncworldedit.bukkit.adapter;
|
||||
|
||||
import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class SimpleBukkitAdapter extends CachedBukkitAdapter {
|
||||
private BlockData[][] blockDataCache;
|
||||
|
||||
private boolean init() {
|
||||
if (blockDataCache != null) {
|
||||
return false;
|
||||
}
|
||||
this.blockDataCache = new BlockData[BlockTypes.size()][];
|
||||
blockDataCache[0] = new BlockData[] {Material.AIR.createBlockData()};
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Bukkit BlockData from a WorldEdit BlockStateHolder
|
||||
*
|
||||
* @param block The WorldEdit BlockStateHolder
|
||||
* @return The Bukkit BlockData
|
||||
*/
|
||||
@Override
|
||||
public <B extends BlockStateHolder<B>> BlockData adapt(B block) {
|
||||
try {
|
||||
checkNotNull(block);
|
||||
int typeId = block.getInternalBlockTypeId();
|
||||
BlockData[] dataCache = blockDataCache[typeId];
|
||||
if (dataCache == null) {
|
||||
BlockType type = BlockTypes.get(typeId);
|
||||
blockDataCache[typeId] = dataCache = new BlockData[type.getMaxStateId() + 1];
|
||||
}
|
||||
int propId = block.getInternalPropertiesId();
|
||||
BlockData blockData = dataCache[propId];
|
||||
if (blockData == null) {
|
||||
dataCache[propId] = blockData = Bukkit.createBlockData(block.getAsString());
|
||||
}
|
||||
return blockData;
|
||||
} catch (NullPointerException e) {
|
||||
if (init()) {
|
||||
return adapt(block);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package com.fastasyncworldedit.bukkit.filter;
|
||||
|
||||
import com.fastasyncworldedit.core.regions.general.CuboidRegionFilter;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
||||
import com.griefdefender.api.claim.Claim;
|
||||
import com.griefdefender.api.GriefDefender;
|
||||
import com.flowpowered.math.vector.Vector3i;
|
||||
import org.bukkit.World;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Collection;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class GriefDefenderFilter extends CuboidRegionFilter {
|
||||
private final Collection<Claim> claims;
|
||||
private final World world;
|
||||
|
||||
public GriefDefenderFilter(World world) {
|
||||
checkNotNull(world);
|
||||
this.claims = TaskManager.IMP.sync(
|
||||
(Supplier<Collection<Claim>>) () -> new ArrayDeque<>(GriefDefender.getCore().getAllClaims()));
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void calculateRegions() {
|
||||
for (Claim claim : claims) {
|
||||
Vector3i bot = claim.getGreaterBoundaryCorner();
|
||||
if (world.getUID().equals(claim.getWorldUniqueId())) {
|
||||
Vector3i top = claim.getGreaterBoundaryCorner();
|
||||
BlockVector2 pos1 = BlockVector2.at(bot.getX(), bot.getZ());
|
||||
BlockVector2 pos2 = BlockVector2.at(top.getX(), top.getZ());
|
||||
add(pos1, pos2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package com.fastasyncworldedit.bukkit.filter;
|
||||
|
||||
import com.fastasyncworldedit.core.regions.general.CuboidRegionFilter;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
||||
import me.ryanhamshire.GriefPrevention.Claim;
|
||||
import me.ryanhamshire.GriefPrevention.GriefPrevention;
|
||||
import org.bukkit.World;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Collection;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class GriefPreventionFilter extends CuboidRegionFilter {
|
||||
private final Collection<Claim> claims;
|
||||
private final World world;
|
||||
|
||||
public GriefPreventionFilter(World world) {
|
||||
checkNotNull(world);
|
||||
this.claims = TaskManager.IMP.sync(
|
||||
(Supplier<Collection<Claim>>) () -> new ArrayDeque<>(GriefPrevention.instance.dataStore.getClaims()));
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void calculateRegions() {
|
||||
for (Claim claim : claims) {
|
||||
org.bukkit.Location bot = claim.getGreaterBoundaryCorner();
|
||||
if (world.equals(bot.getWorld())) {
|
||||
org.bukkit.Location top = claim.getGreaterBoundaryCorner();
|
||||
BlockVector2 pos1 = BlockVector2.at(bot.getBlockX(), bot.getBlockZ());
|
||||
BlockVector2 pos2 = BlockVector2.at(top.getBlockX(), top.getBlockZ());
|
||||
add(pos1, pos2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
package com.fastasyncworldedit.bukkit.filter;
|
||||
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.fastasyncworldedit.core.regions.general.CuboidRegionFilter;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldguard.WorldGuard;
|
||||
import com.sk89q.worldguard.protection.ApplicableRegionSet;
|
||||
import com.sk89q.worldguard.protection.managers.RegionManager;
|
||||
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
|
||||
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bukkit.World;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class WorldGuardFilter extends CuboidRegionFilter {
|
||||
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
|
||||
private final World world;
|
||||
private boolean large;
|
||||
private RegionManager manager;
|
||||
|
||||
public WorldGuardFilter(World world) {
|
||||
checkNotNull(world);
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void calculateRegions() {
|
||||
Fawe.get().getQueueHandler().sync(() -> {
|
||||
WorldGuardFilter.this.manager = WorldGuard.getInstance().getPlatform().getRegionContainer().get(
|
||||
BukkitAdapter.adapt(world));
|
||||
for (ProtectedRegion region : manager.getRegions().values()) {
|
||||
BlockVector3 min = region.getMinimumPoint();
|
||||
BlockVector3 max = region.getMaximumPoint();
|
||||
if (max.getBlockX() - min.getBlockX() > 1024 || max.getBlockZ() - min.getBlockZ() > 1024) {
|
||||
LOGGER.debug("Large or complex region shapes cannot be optimized. Filtering will be slower");
|
||||
large = true;
|
||||
break;
|
||||
}
|
||||
add(min.toBlockVector2(), max.toBlockVector2());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsChunk(int chunkX, int chunkZ) {
|
||||
if (!large) {
|
||||
return super.containsChunk(chunkX, chunkZ);
|
||||
}
|
||||
BlockVector3 pos1 = BlockVector3.at(chunkX << 4, 0, chunkZ << 4);
|
||||
BlockVector3 pos2 = BlockVector3.at(pos1.getBlockX() + 15, 255, pos1.getBlockZ() + 15);
|
||||
ProtectedCuboidRegion chunkRegion = new ProtectedCuboidRegion("unimportant", pos1, pos2);
|
||||
ApplicableRegionSet set = manager.getApplicableRegions(chunkRegion);
|
||||
return set.size() > 0 && !set.getRegions().iterator().next().getId().equals("__global__");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsRegion(int mcaX, int mcaZ) {
|
||||
if (!large) {
|
||||
return super.containsRegion(mcaX, mcaZ);
|
||||
}
|
||||
BlockVector3 pos1 = BlockVector3.at(mcaX << 9, 0, mcaZ << 9);
|
||||
BlockVector3 pos2 = BlockVector3.at(pos1.getBlockX() + 511, 255, pos1.getBlockZ() + 511);
|
||||
ProtectedCuboidRegion regionRegion = new ProtectedCuboidRegion("unimportant", pos1, pos2);
|
||||
ApplicableRegionSet set = manager.getApplicableRegions(regionRegion);
|
||||
return set.size() > 0 && !set.getRegions().iterator().next().getId().equals("__global__");
|
||||
}
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
package com.fastasyncworldedit.bukkit.listener;
|
||||
|
||||
import com.fastasyncworldedit.core.object.brush.MovableTool;
|
||||
import com.fastasyncworldedit.core.object.brush.ResettableTool;
|
||||
import com.fastasyncworldedit.core.object.brush.scroll.ScrollTool;
|
||||
import com.sk89q.worldedit.LocalSession;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.BukkitPlayer;
|
||||
import com.sk89q.worldedit.command.tool.Tool;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.event.player.PlayerItemHeldEvent;
|
||||
import org.bukkit.event.player.PlayerMoveEvent;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
public class BrushListener implements Listener {
|
||||
public BrushListener(Plugin plugin) {
|
||||
Bukkit.getPluginManager().registerEvents(this, plugin);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onPlayerItemHoldEvent(final PlayerItemHeldEvent event) {
|
||||
final Player bukkitPlayer = event.getPlayer();
|
||||
if (bukkitPlayer.isSneaking()) {
|
||||
return;
|
||||
}
|
||||
BukkitPlayer player = BukkitAdapter.adapt(bukkitPlayer);
|
||||
LocalSession session = player.getSession();
|
||||
Tool tool = session.getTool(player);
|
||||
if (tool instanceof ScrollTool) {
|
||||
final int slot = event.getNewSlot();
|
||||
final int oldSlot = event.getPreviousSlot();
|
||||
final int ri;
|
||||
if ((((slot - oldSlot) <= 4) && ((slot - oldSlot) > 0)) || ((slot - oldSlot) < -4)) {
|
||||
ri = 1;
|
||||
} else {
|
||||
ri = -1;
|
||||
}
|
||||
ScrollTool scrollable = (ScrollTool) tool;
|
||||
if (scrollable.increment(player, ri)) {
|
||||
bukkitPlayer.getInventory().setHeldItemSlot(oldSlot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onPlayerMove(PlayerMoveEvent event) {
|
||||
Location from = event.getFrom();
|
||||
Location to = event.getTo();
|
||||
if ((from.getYaw() != to.getYaw() && from.getPitch() != to.getPitch()) || from.getBlockX() != to.getBlockX() || from.getBlockZ() != to.getBlockZ() || from.getBlockY() != to.getBlockY()) {
|
||||
Player bukkitPlayer = event.getPlayer();
|
||||
com.sk89q.worldedit.entity.Player player = BukkitAdapter.adapt(bukkitPlayer);
|
||||
LocalSession session = player.getSession();
|
||||
Tool tool = session.getTool(player);
|
||||
if (tool != null) {
|
||||
if (tool instanceof MovableTool) {
|
||||
((MovableTool) tool).move(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onPlayerInteract(final PlayerInteractEvent event) {
|
||||
Player bukkitPlayer = event.getPlayer();
|
||||
if (bukkitPlayer.isSneaking()) {
|
||||
if (event.getAction() == Action.PHYSICAL) {
|
||||
return;
|
||||
}
|
||||
com.sk89q.worldedit.entity.Player player = BukkitAdapter.adapt(bukkitPlayer);
|
||||
LocalSession session = player.getSession();
|
||||
Tool tool = session.getTool(player);
|
||||
if (tool instanceof ResettableTool) {
|
||||
if (((ResettableTool) tool).reset()) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,417 @@
|
||||
package com.fastasyncworldedit.bukkit.listener;
|
||||
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.fastasyncworldedit.bukkit.FaweBukkit;
|
||||
import com.fastasyncworldedit.core.configuration.Settings;
|
||||
import com.fastasyncworldedit.core.util.FaweTimer;
|
||||
import com.fastasyncworldedit.core.util.MathMan;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.BlockBurnEvent;
|
||||
import org.bukkit.event.block.BlockCanBuildEvent;
|
||||
import org.bukkit.event.block.BlockDamageEvent;
|
||||
import org.bukkit.event.block.BlockDispenseEvent;
|
||||
import org.bukkit.event.block.BlockExpEvent;
|
||||
import org.bukkit.event.block.BlockExplodeEvent;
|
||||
import org.bukkit.event.block.BlockFadeEvent;
|
||||
import org.bukkit.event.block.BlockFromToEvent;
|
||||
import org.bukkit.event.block.BlockGrowEvent;
|
||||
import org.bukkit.event.block.BlockIgniteEvent;
|
||||
import org.bukkit.event.block.BlockPhysicsEvent;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
import org.bukkit.event.block.BlockRedstoneEvent;
|
||||
import org.bukkit.event.block.LeavesDecayEvent;
|
||||
import org.bukkit.event.block.NotePlayEvent;
|
||||
import org.bukkit.event.block.SignChangeEvent;
|
||||
import org.bukkit.event.entity.EntityChangeBlockEvent;
|
||||
import org.bukkit.event.entity.ItemSpawnEvent;
|
||||
import org.bukkit.event.inventory.FurnaceBurnEvent;
|
||||
import org.bukkit.event.inventory.FurnaceSmeltEvent;
|
||||
import org.bukkit.event.world.ChunkLoadEvent;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
public abstract class ChunkListener implements Listener {
|
||||
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
protected int rateLimit = 0;
|
||||
protected Location lastCancelPos;
|
||||
private int[] badLimit = new int[]{Settings.IMP.TICK_LIMITER.PHYSICS_MS,
|
||||
Settings.IMP.TICK_LIMITER.FALLING, Settings.IMP.TICK_LIMITER.ITEMS};
|
||||
|
||||
public ChunkListener() {
|
||||
if (Settings.IMP.TICK_LIMITER.ENABLED) {
|
||||
PluginManager plm = Bukkit.getPluginManager();
|
||||
Plugin plugin = Fawe.<FaweBukkit>imp().getPlugin();
|
||||
plm.registerEvents(this, plugin);
|
||||
TaskManager.IMP.repeat(() -> {
|
||||
Location tmpLoc = lastCancelPos;
|
||||
if (tmpLoc != null) {
|
||||
LOGGER.debug("[FAWE Tick Limiter] Detected and cancelled physics lag source at "
|
||||
+ tmpLoc);
|
||||
}
|
||||
rateLimit--;
|
||||
physicsFreeze = false;
|
||||
itemFreeze = false;
|
||||
lastZ = Integer.MIN_VALUE;
|
||||
physSkip = 0;
|
||||
physCancelPair = Long.MIN_VALUE;
|
||||
physCancel = false;
|
||||
lastCancelPos = null;
|
||||
|
||||
counter.clear();
|
||||
for (Long2ObjectMap.Entry<Boolean> entry : badChunks.long2ObjectEntrySet()) {
|
||||
long key = entry.getLongKey();
|
||||
int x = MathMan.unpairIntX(key);
|
||||
int z = MathMan.unpairIntY(key);
|
||||
counter.put(key, badLimit);
|
||||
}
|
||||
badChunks.clear();
|
||||
}, Settings.IMP.TICK_LIMITER.INTERVAL);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract int getDepth(Exception ex);
|
||||
|
||||
protected abstract StackTraceElement getElement(Exception ex, int index);
|
||||
|
||||
public static boolean physicsFreeze = false;
|
||||
public static boolean itemFreeze = false;
|
||||
|
||||
protected final Long2ObjectOpenHashMap<Boolean> badChunks = new Long2ObjectOpenHashMap<>();
|
||||
private Long2ObjectOpenHashMap<int[]> counter = new Long2ObjectOpenHashMap<>();
|
||||
private int lastX = Integer.MIN_VALUE;
|
||||
private int lastZ = Integer.MIN_VALUE;
|
||||
private int[] lastCount;
|
||||
|
||||
public int[] getCount(int cx, int cz) {
|
||||
if (lastX == cx && lastZ == cz) {
|
||||
return lastCount;
|
||||
}
|
||||
lastX = cx;
|
||||
lastZ = cz;
|
||||
long pair = MathMan.pairInt(cx, cz);
|
||||
int[] tmp = lastCount = counter.get(pair);
|
||||
if (tmp == null) {
|
||||
lastCount = tmp = new int[3];
|
||||
counter.put(pair, tmp);
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
public void cleanup(Chunk chunk) {
|
||||
for (Entity entity : chunk.getEntities()) {
|
||||
if (entity.getType() == EntityType.DROPPED_ITEM) {
|
||||
entity.remove();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected int physSkip;
|
||||
protected boolean physCancel;
|
||||
protected long physCancelPair;
|
||||
|
||||
protected long physStart;
|
||||
protected long physTick;
|
||||
|
||||
public final void reset() {
|
||||
physSkip = 0;
|
||||
physStart = System.currentTimeMillis();
|
||||
physCancel = false;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void event(BlockExplodeEvent event) {
|
||||
reset();
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void event(BlockBurnEvent event) {
|
||||
reset();
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void event(BlockCanBuildEvent event) {
|
||||
reset();
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void event(BlockDamageEvent event) {
|
||||
reset();
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void event(BlockDispenseEvent event) {
|
||||
reset();
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void event(BlockExpEvent event) {
|
||||
reset();
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void event(BlockFadeEvent event) {
|
||||
reset();
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void event(BlockFromToEvent event) {
|
||||
reset();
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void event(BlockGrowEvent event) {
|
||||
reset();
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void event(BlockIgniteEvent event) {
|
||||
reset();
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void event(BlockPlaceEvent event) {
|
||||
reset();
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void event(FurnaceBurnEvent event) {
|
||||
reset();
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void event(FurnaceSmeltEvent event) {
|
||||
reset();
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void event(LeavesDecayEvent event) {
|
||||
reset();
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void event(NotePlayEvent event) {
|
||||
reset();
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void event(SignChangeEvent event) {
|
||||
reset();
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void event(BlockRedstoneEvent event) {
|
||||
reset();
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onPhysics(BlockPhysicsEvent event) {
|
||||
if (physicsFreeze) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
if (physCancel) {
|
||||
Block block = event.getBlock();
|
||||
long pair = MathMan.pairInt(block.getX() >> 4, block.getZ() >> 4);
|
||||
if (physCancelPair == pair) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
if (badChunks.containsKey(pair)) {
|
||||
physCancelPair = pair;
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if ((++physSkip & 1023) != 0) {
|
||||
return;
|
||||
}
|
||||
FaweTimer timer = Fawe.get().getTimer();
|
||||
if (timer.getTick() != physTick) {
|
||||
physTick = timer.getTick();
|
||||
physStart = System.currentTimeMillis();
|
||||
return;
|
||||
} else if (System.currentTimeMillis() - physStart
|
||||
< Settings.IMP.TICK_LIMITER.PHYSICS_MS) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
Exception e = new Exception();
|
||||
int depth = getDepth(e);
|
||||
if (depth >= 256) {
|
||||
if (containsSetAir(e, event)) {
|
||||
Block block = event.getBlock();
|
||||
int cx = block.getX() >> 4;
|
||||
int cz = block.getZ() >> 4;
|
||||
physCancelPair = MathMan.pairInt(cx, cz);
|
||||
if (rateLimit <= 0) {
|
||||
rateLimit = 20;
|
||||
lastCancelPos = block.getLocation();
|
||||
}
|
||||
cancelNearby(cx, cz);
|
||||
event.setCancelled(true);
|
||||
physCancel = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
physSkip = 1;
|
||||
physCancel = false;
|
||||
}
|
||||
|
||||
protected boolean containsSetAir(Exception e, BlockPhysicsEvent event) {
|
||||
for (int frame = 25; frame < 35; frame++) {
|
||||
StackTraceElement elem = getElement(e, frame);
|
||||
if (elem != null) {
|
||||
String methodName = elem.getMethodName();
|
||||
// setAir | setTypeAndData (hacky, but this needs to be efficient)
|
||||
if (methodName.charAt(0) == 's' && methodName.length() == 6
|
||||
|| methodName.length() == 14) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void cancelNearby(int cx, int cz) {
|
||||
cancel(cx, cz);
|
||||
cancel(cx + 1, cz);
|
||||
cancel(cx - 1, cz);
|
||||
cancel(cx, cz + 1);
|
||||
cancel(cx, cz - 1);
|
||||
cancel(cx - 1, cz - 1);
|
||||
cancel(cx - 1, cz + 1);
|
||||
cancel(cx + 1, cz - 1);
|
||||
cancel(cx + 1, cz + 1);
|
||||
}
|
||||
|
||||
private void cancel(int cx, int cz) {
|
||||
long key = MathMan.pairInt(cx, cz);
|
||||
badChunks.put(key, (Boolean) true);
|
||||
counter.put(key, badLimit);
|
||||
int[] count = getCount(cx, cz);
|
||||
count[0] = Integer.MAX_VALUE;
|
||||
count[1] = Integer.MAX_VALUE;
|
||||
count[2] = Integer.MAX_VALUE;
|
||||
|
||||
}
|
||||
|
||||
// Falling
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onBlockChange(EntityChangeBlockEvent event) {
|
||||
if (physicsFreeze) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
Block block = event.getBlock();
|
||||
int x = block.getX();
|
||||
int z = block.getZ();
|
||||
int cx = x >> 4;
|
||||
int cz = z >> 4;
|
||||
int[] count = getCount(cx, cz);
|
||||
if (count[1] >= Settings.IMP.TICK_LIMITER.FALLING) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
if (event.getEntityType() == EntityType.FALLING_BLOCK) {
|
||||
if (++count[1] >= Settings.IMP.TICK_LIMITER.FALLING) {
|
||||
|
||||
// Only cancel falling blocks when it's lagging
|
||||
if (Fawe.get().getTimer().getTPS() < 18) {
|
||||
cancelNearby(cx, cz);
|
||||
if (rateLimit <= 0) {
|
||||
rateLimit = 20;
|
||||
lastCancelPos = block.getLocation();
|
||||
}
|
||||
event.setCancelled(true);
|
||||
} else {
|
||||
count[1] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent firework from loading chunks.
|
||||
*/
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onChunkLoad(ChunkLoadEvent event) {
|
||||
if (!Settings.IMP.TICK_LIMITER.FIREWORKS_LOAD_CHUNKS) {
|
||||
Chunk chunk = event.getChunk();
|
||||
Entity[] entities = chunk.getEntities();
|
||||
World world = chunk.getWorld();
|
||||
|
||||
Exception e = new Exception();
|
||||
int start = 14;
|
||||
int end = 22;
|
||||
int depth = Math.min(end, getDepth(e));
|
||||
|
||||
for (int frame = start; frame < depth; frame++) {
|
||||
StackTraceElement elem = getElement(e, frame);
|
||||
if (elem == null) {
|
||||
return;
|
||||
}
|
||||
String className = elem.getClassName();
|
||||
int len = className.length();
|
||||
if (len > 15 && className.charAt(len - 15) == 'E' && className
|
||||
.endsWith("EntityFireworks")) {
|
||||
for (Entity ent : world.getEntities()) {
|
||||
if (ent.getType() == EntityType.FIREWORK) {
|
||||
Vector velocity = ent.getVelocity();
|
||||
double vertical = Math.abs(velocity.getY());
|
||||
if (Math.abs(velocity.getX()) > vertical
|
||||
|| Math.abs(velocity.getZ()) > vertical) {
|
||||
LOGGER.warn(
|
||||
"[FAWE `tick-limiter`] Detected and cancelled rogue FireWork at "
|
||||
+ ent.getLocation());
|
||||
ent.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onItemSpawn(ItemSpawnEvent event) {
|
||||
if (physicsFreeze) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
Location loc = event.getLocation();
|
||||
int cx = loc.getBlockX() >> 4;
|
||||
int cz = loc.getBlockZ() >> 4;
|
||||
int[] count = getCount(cx, cz);
|
||||
if (count[2] >= Settings.IMP.TICK_LIMITER.ITEMS) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
if (++count[2] >= Settings.IMP.TICK_LIMITER.ITEMS) {
|
||||
cleanup(loc.getChunk());
|
||||
cancelNearby(cx, cz);
|
||||
if (rateLimit <= 0) {
|
||||
rateLimit = 20;
|
||||
LOGGER.warn(
|
||||
"[FAWE `tick-limiter`] Detected and cancelled item lag source at " + loc);
|
||||
}
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
package com.fastasyncworldedit.bukkit.listener;
|
||||
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.fastasyncworldedit.core.configuration.Settings;
|
||||
import com.fastasyncworldedit.core.util.FaweTimer;
|
||||
import com.fastasyncworldedit.core.util.MathMan;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.block.BlockPhysicsEvent;
|
||||
|
||||
public class ChunkListener9 extends ChunkListener {
|
||||
|
||||
private Exception exception;
|
||||
private StackTraceElement[] elements;
|
||||
|
||||
public ChunkListener9() {
|
||||
super();
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
@Override
|
||||
public void onPhysics(BlockPhysicsEvent event) {
|
||||
if (physicsFreeze) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
if (physCancel) {
|
||||
Block block = event.getBlock();
|
||||
long pair = MathMan.pairInt(block.getX() >> 4, block.getZ() >> 4);
|
||||
if (physCancelPair == pair) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
if (badChunks.containsKey(pair)) {
|
||||
physCancelPair = pair;
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
if (System.currentTimeMillis() - physStart > Settings.IMP.TICK_LIMITER.PHYSICS_MS) {
|
||||
physCancelPair = pair;
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
FaweTimer timer = Fawe.get().getTimer();
|
||||
if (timer.getTick() != physTick) {
|
||||
physTick = timer.getTick();
|
||||
physStart = System.currentTimeMillis();
|
||||
physSkip = 0;
|
||||
physCancel = false;
|
||||
return;
|
||||
}
|
||||
if ((++physSkip & 1023) == 0) {
|
||||
if (System.currentTimeMillis() - physStart > Settings.IMP.TICK_LIMITER.PHYSICS_MS) {
|
||||
Block block = event.getBlock();
|
||||
int cx = block.getX() >> 4;
|
||||
int cz = block.getZ() >> 4;
|
||||
physCancelPair = MathMan.pairInt(cx, cz);
|
||||
if (rateLimit <= 0) {
|
||||
rateLimit = 20;
|
||||
lastCancelPos = block.getLocation();
|
||||
}
|
||||
cancelNearby(cx, cz);
|
||||
event.setCancelled(true);
|
||||
physCancel = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private StackTraceElement[] getElements(Exception ex) {
|
||||
if (elements == null || ex != exception) {
|
||||
exception = ex;
|
||||
elements = ex.getStackTrace();
|
||||
}
|
||||
return elements;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getDepth(Exception ex) {
|
||||
return getElements(ex).length;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected StackTraceElement getElement(Exception ex, int i) {
|
||||
StackTraceElement[] elems = getElements(ex);
|
||||
return elems.length > i ? elems[i] : null;
|
||||
}
|
||||
}
|
@ -0,0 +1,139 @@
|
||||
package com.fastasyncworldedit.bukkit.listener;
|
||||
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.fastasyncworldedit.core.configuration.Settings;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerMoveEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class RenderListener implements Listener {
|
||||
|
||||
private final Map<UUID, int[]> views = new ConcurrentHashMap<>();
|
||||
private Iterator<Map.Entry<UUID, int[]>> entrySet;
|
||||
private int OFFSET = 6;
|
||||
|
||||
public RenderListener(Plugin plugin) {
|
||||
Bukkit.getPluginManager().registerEvents(this, plugin);
|
||||
TaskManager.IMP.repeat(new Runnable() {
|
||||
private long last = 0;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (views.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
int tps32 = (int) (Math.round(Fawe.get().getTimer().getTPS()) * 32);
|
||||
long diff = now - last;
|
||||
last = now;
|
||||
if (diff > 75) {
|
||||
OFFSET = diff > 100 ? 0 : 4;
|
||||
return;
|
||||
}
|
||||
int timeOut;
|
||||
if (diff < 55 && tps32 > 608) {
|
||||
OFFSET = 8;
|
||||
timeOut = 2;
|
||||
} else {
|
||||
OFFSET = 1 + (tps32 / 102400);
|
||||
timeOut = 162 - (tps32 / 2560);
|
||||
}
|
||||
if (entrySet == null || !entrySet.hasNext()) {
|
||||
entrySet = views.entrySet().iterator();
|
||||
}
|
||||
int nowTick = (int) (Fawe.get().getTimer().getTick());
|
||||
while (entrySet.hasNext()) {
|
||||
Map.Entry<UUID, int[]> entry = entrySet.next();
|
||||
Player player = Bukkit.getPlayer(entry.getKey());
|
||||
if (player != null) {
|
||||
int[] value = entry.getValue();
|
||||
if (nowTick - value[1] >= timeOut) {
|
||||
value[1] = nowTick + 1;
|
||||
setViewDistance(player, Math.max(4, value[0] + 1));
|
||||
long spent = System.currentTimeMillis() - now;
|
||||
if (spent > 5) {
|
||||
if (spent > 10) {
|
||||
value[1] = nowTick + 20;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 1);
|
||||
}
|
||||
|
||||
private void setViewDistance(Player player, int value) {
|
||||
UUID uuid = player.getUniqueId();
|
||||
if (value == Settings.IMP.EXPERIMENTAL.DYNAMIC_CHUNK_RENDERING) {
|
||||
views.remove(uuid);
|
||||
} else {
|
||||
int[] val = views.get(uuid);
|
||||
if (val == null) {
|
||||
val = new int[] {value, (int) Fawe.get().getTimer().getTick()};
|
||||
UUID uid = player.getUniqueId();
|
||||
views.put(uid, val);
|
||||
} else {
|
||||
if (value <= val[0]) {
|
||||
val[1] = (int) Fawe.get().getTimer().getTick();
|
||||
}
|
||||
if (val[0] == value) {
|
||||
return;
|
||||
} else {
|
||||
val[0] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
player.setViewDistance(value);
|
||||
}
|
||||
|
||||
private int getViewDistance(Player player) {
|
||||
int[] value = views.get(player.getUniqueId());
|
||||
return value == null ? Settings.IMP.EXPERIMENTAL.DYNAMIC_CHUNK_RENDERING : value[0];
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onPlayerTeleport(PlayerTeleportEvent event) {
|
||||
setViewDistance(event.getPlayer(), 1);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onPlayerMove(PlayerMoveEvent event) {
|
||||
Location from = event.getFrom();
|
||||
Location to = event.getTo();
|
||||
if (from.getBlockX() >> OFFSET != to.getBlockX() >> OFFSET || from.getBlockZ() >> OFFSET != to.getBlockZ() >> OFFSET) {
|
||||
Player player = event.getPlayer();
|
||||
int currentView = getViewDistance(player);
|
||||
setViewDistance(player, Math.max(currentView - 1, 1));
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
|
||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
setViewDistance(player, 1);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onPlayerLeave(PlayerQuitEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
UUID uid = player.getUniqueId();
|
||||
views.remove(uid);
|
||||
}
|
||||
}
|
@ -0,0 +1,205 @@
|
||||
package com.fastasyncworldedit.bukkit.preloader;
|
||||
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.generator.ChunkGenerator;
|
||||
import org.bukkit.plugin.PluginBase;
|
||||
import org.bukkit.plugin.PluginDescriptionFile;
|
||||
import org.bukkit.plugin.PluginLoader;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class PluginPreloader extends PluginBase {
|
||||
private World world;
|
||||
private Set<BlockVector2> loaded;
|
||||
private int index;
|
||||
private AtomicBoolean invalidator;
|
||||
private final Object invalidatorLock;
|
||||
|
||||
public PluginPreloader() {
|
||||
invalidator = new AtomicBoolean();
|
||||
invalidatorLock = new Object();
|
||||
}
|
||||
|
||||
public AtomicBoolean invalidate() {
|
||||
synchronized (invalidatorLock) {
|
||||
invalidator.set(false);
|
||||
return invalidator = new AtomicBoolean(true);
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void unload() {
|
||||
World oldWorld = world;
|
||||
if (oldWorld != null) {
|
||||
Set<BlockVector2> toUnload = loaded;
|
||||
if (loaded != null && index > 0) {
|
||||
Iterator<BlockVector2> iter = toUnload.iterator();
|
||||
Fawe.get().getQueueHandler().sync(() -> {
|
||||
for (int i = 0; i < index && iter.hasNext(); i++) {
|
||||
BlockVector2 chunk = iter.next();
|
||||
world.removePluginChunkTicket(chunk.getX(), chunk.getZ(), this);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
this.world = null;
|
||||
this.loaded = null;
|
||||
this.index = 0;
|
||||
}
|
||||
|
||||
public void update(Region region) {
|
||||
AtomicBoolean invalidator = invalidate();
|
||||
synchronized (this) {
|
||||
com.sk89q.worldedit.world.World weWorld = region.getWorld();
|
||||
if (weWorld == null) {
|
||||
return;
|
||||
}
|
||||
unload();
|
||||
index = 0;
|
||||
world = BukkitAdapter.adapt(weWorld);
|
||||
loaded = region.getChunks();
|
||||
Iterator<BlockVector2> iter = loaded.iterator();
|
||||
|
||||
if (!invalidator.get()) {
|
||||
return;
|
||||
}
|
||||
Fawe.get().getQueueHandler().syncWhenFree(() -> {
|
||||
for (; iter.hasNext() && invalidator.get();index++) {
|
||||
BlockVector2 chunk = iter.next();
|
||||
if (!world.isChunkLoaded(chunk.getX(), chunk.getZ())) {
|
||||
world.addPluginChunkTicket(chunk.getX(), chunk.getZ(), this);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
invalidate();
|
||||
unload();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public File getDataFolder() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public PluginDescriptionFile getDescription() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public FileConfiguration getConfig() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public InputStream getResource(@NotNull String filename) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveConfig() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveDefaultConfig() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveResource(@NotNull String resourcePath, boolean replace) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reloadConfig() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public PluginLoader getPluginLoader() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Server getServer() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNaggable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNaggable(boolean canNag) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public ChunkGenerator getDefaultWorldGenerator(@NotNull String worldName, @Nullable String id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Logger getLogger() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) {
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package com.fastasyncworldedit.bukkit.regions;
|
||||
|
||||
import com.fastasyncworldedit.core.regions.FaweMaskManager;
|
||||
import org.bukkit.permissions.Permissible;
|
||||
|
||||
public abstract class BukkitMaskManager extends FaweMaskManager {
|
||||
|
||||
public BukkitMaskManager(final String plugin) {
|
||||
super(plugin);
|
||||
}
|
||||
|
||||
public boolean hasMemberPermission(Permissible player) {
|
||||
return player.hasPermission("fawe." + getKey() + ".member");
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package com.fastasyncworldedit.bukkit.regions;
|
||||
|
||||
import com.fastasyncworldedit.bukkit.filter.GriefDefenderFilter;
|
||||
import com.fastasyncworldedit.core.regions.FaweMask;
|
||||
import com.fastasyncworldedit.core.regions.general.RegionFilter;
|
||||
import com.flowpowered.math.vector.Vector3i;
|
||||
import com.griefdefender.api.GriefDefender;
|
||||
import com.griefdefender.api.claim.Claim;
|
||||
import com.griefdefender.api.claim.TrustTypes;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
public class GriefDefenderFeature extends BukkitMaskManager implements Listener {
|
||||
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
|
||||
public GriefDefenderFeature(final Plugin GriefDefenderPlugin) {
|
||||
super(GriefDefenderPlugin.getName());
|
||||
LOGGER.info("Plugin 'GriefDefender' found. Using it now.");
|
||||
}
|
||||
|
||||
public boolean isAllowed(Player player, Claim claim, MaskType type) {
|
||||
return GriefDefender.getCore().isEnabled(player.getWorld().getUID()) && !claim.isWilderness() && (claim.getOwnerName().equalsIgnoreCase(player.getName()) || claim.getOwnerUniqueId().equals(player.getUniqueId()) ||
|
||||
type == MaskType.MEMBER && claim.getUserTrusts(TrustTypes.BUILDER).contains(player.getUniqueId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public FaweMask getMask(final com.sk89q.worldedit.entity.Player wePlayer, MaskType type) {
|
||||
final Player player = BukkitAdapter.adapt(wePlayer);
|
||||
final Location loc = player.getLocation();
|
||||
final Vector3i vector = Vector3i.from(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
|
||||
final Claim claim = GriefDefender.getCore().getClaimManager(loc.getWorld().getUID()).getClaimAt(vector);
|
||||
if (!claim.isWilderness()) {
|
||||
if (isAllowed(player, claim, type)) {
|
||||
claim.getGreaterBoundaryCorner().getX();
|
||||
final BlockVector3 pos1 = BlockVector3.at(claim.getLesserBoundaryCorner().getX(), claim.getLesserBoundaryCorner().getY(), claim.getLesserBoundaryCorner().getZ());
|
||||
final BlockVector3 pos2 = BlockVector3.at(claim.getGreaterBoundaryCorner().getX(), claim.getGreaterBoundaryCorner().getY(), claim.getGreaterBoundaryCorner().getZ());
|
||||
return new FaweMask(new CuboidRegion(pos1, pos2)) {
|
||||
|
||||
@Override
|
||||
public boolean isValid(com.sk89q.worldedit.entity.Player wePlayer, MaskType type) {
|
||||
return isAllowed(player, claim, type);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegionFilter getFilter(String world) {
|
||||
return new GriefDefenderFilter(Bukkit.getWorld(world));
|
||||
}
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
package com.fastasyncworldedit.bukkit.regions;
|
||||
|
||||
import com.fastasyncworldedit.bukkit.filter.GriefPreventionFilter;
|
||||
import com.fastasyncworldedit.core.regions.FaweMask;
|
||||
import com.fastasyncworldedit.core.regions.general.RegionFilter;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import me.ryanhamshire.GriefPrevention.Claim;
|
||||
import me.ryanhamshire.GriefPrevention.GriefPrevention;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
public class GriefPreventionFeature extends BukkitMaskManager implements Listener {
|
||||
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
|
||||
public GriefPreventionFeature(final Plugin griefpreventionPlugin) {
|
||||
super(griefpreventionPlugin.getName());
|
||||
LOGGER.debug("Plugin 'GriefPrevention' found. Using it now.");
|
||||
}
|
||||
|
||||
public boolean isAllowed(Player player, Claim claim, MaskType type) {
|
||||
return claim != null && (claim.getOwnerName().equalsIgnoreCase(player.getName()) || claim.getOwnerName().equals(player.getUniqueId()) ||
|
||||
type == MaskType.MEMBER && claim.allowBuild(player, Material.AIR) == null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FaweMask getMask(final com.sk89q.worldedit.entity.Player wePlayer, MaskType type) {
|
||||
final Player player = BukkitAdapter.adapt(wePlayer);
|
||||
final Claim claim = GriefPrevention.instance.dataStore.getClaimAt(player.getLocation(), true, null);
|
||||
if (claim != null) {
|
||||
if (isAllowed(player, claim, type)) {
|
||||
claim.getGreaterBoundaryCorner().getBlockX();
|
||||
final BlockVector3 pos1 = BlockVector3.at(claim.getLesserBoundaryCorner().getBlockX(), 0, claim.getLesserBoundaryCorner().getBlockZ());
|
||||
final BlockVector3 pos2 = BlockVector3.at(claim.getGreaterBoundaryCorner().getBlockX(), 256, claim.getGreaterBoundaryCorner().getBlockZ());
|
||||
return new FaweMask(new CuboidRegion(pos1, pos2)) {
|
||||
|
||||
@Override
|
||||
public boolean isValid(com.sk89q.worldedit.entity.Player wePlayer, MaskType type) {
|
||||
return isAllowed(player, claim, type);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegionFilter getFilter(String world) {
|
||||
return new GriefPreventionFilter(Bukkit.getWorld(world));
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
package com.fastasyncworldedit.bukkit.regions;
|
||||
|
||||
import com.bekvon.bukkit.residence.Residence;
|
||||
import com.bekvon.bukkit.residence.protection.ClaimedResidence;
|
||||
import com.bekvon.bukkit.residence.protection.CuboidArea;
|
||||
import com.fastasyncworldedit.bukkit.FaweBukkit;
|
||||
import com.fastasyncworldedit.core.regions.FaweMask;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
public class ResidenceFeature extends BukkitMaskManager implements Listener {
|
||||
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
|
||||
private FaweBukkit plugin;
|
||||
private Plugin residence;
|
||||
|
||||
public ResidenceFeature(final Plugin residencePlugin, final FaweBukkit p3) {
|
||||
super(residencePlugin.getName());
|
||||
this.residence = residencePlugin;
|
||||
this.plugin = p3;
|
||||
LOGGER.debug("Plugin 'Residence' found. Using it now.");
|
||||
}
|
||||
|
||||
public boolean isAllowed(Player player, ClaimedResidence residence, MaskType type) {
|
||||
return residence != null && (residence.getOwner().equals(player.getName()) || residence.getOwner().equals(player.getUniqueId().toString()) || type == MaskType.MEMBER && residence.getPermissions().playerHas(player, "build", false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public FaweMask getMask(final com.sk89q.worldedit.entity.Player wePlayer, final MaskType type) {
|
||||
final Player player = BukkitAdapter.adapt(wePlayer);
|
||||
final Location location = player.getLocation();
|
||||
ClaimedResidence residence = Residence.getInstance().getResidenceManager().getByLoc(location);
|
||||
if (residence != null) {
|
||||
boolean isAllowed;
|
||||
while (!(isAllowed = isAllowed(player, residence, type)) && residence != null) {
|
||||
residence = residence.getSubzoneByLoc(location);
|
||||
}
|
||||
if (isAllowed) {
|
||||
final CuboidArea area = residence.getAreaArray()[0];
|
||||
final Location pos1 = area.getLowLoc();
|
||||
final Location pos2 = area.getHighLoc();
|
||||
final ClaimedResidence finalResidence = residence;
|
||||
return new FaweMask(new CuboidRegion(BukkitAdapter.asBlockVector(pos1), BukkitAdapter.asBlockVector(pos2))) {
|
||||
@Override
|
||||
public boolean isValid(com.sk89q.worldedit.entity.Player player, MaskType type) {
|
||||
return isAllowed(BukkitAdapter.adapt(player), finalResidence, type);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,101 @@
|
||||
package com.fastasyncworldedit.bukkit.regions;
|
||||
|
||||
import com.fastasyncworldedit.core.regions.FaweMask;
|
||||
import com.palmergames.bukkit.towny.Towny;
|
||||
import com.palmergames.bukkit.towny.exceptions.NotRegisteredException;
|
||||
import com.palmergames.bukkit.towny.object.PlayerCache;
|
||||
import com.palmergames.bukkit.towny.object.Resident;
|
||||
import com.palmergames.bukkit.towny.object.Town;
|
||||
import com.palmergames.bukkit.towny.object.TownBlock;
|
||||
import com.palmergames.bukkit.towny.object.TownyUniverse;
|
||||
import com.palmergames.bukkit.towny.object.WorldCoord;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
public class TownyFeature extends BukkitMaskManager implements Listener {
|
||||
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
|
||||
private final Plugin towny;
|
||||
|
||||
public TownyFeature(Plugin townyPlugin) {
|
||||
super(townyPlugin.getName());
|
||||
this.towny = townyPlugin;
|
||||
LOGGER.debug("Plugin 'Towny' found. Using it now.");
|
||||
}
|
||||
|
||||
public boolean isAllowed(Player player, TownBlock block) {
|
||||
if (block == null) {
|
||||
return false;
|
||||
}
|
||||
Resident resident;
|
||||
try {
|
||||
resident = TownyUniverse.getDataSource().getResident(player.getName());
|
||||
try {
|
||||
if (block.getResident().equals(resident)) {
|
||||
return true;
|
||||
}
|
||||
} catch (NotRegisteredException ignored) {
|
||||
}
|
||||
Town town = block.getTown();
|
||||
if (town.isMayor(resident)) {
|
||||
return true;
|
||||
}
|
||||
if (!town.hasResident(resident)) {
|
||||
return false;
|
||||
}
|
||||
if (player.hasPermission("fawe.towny.*")) {
|
||||
return true;
|
||||
}
|
||||
for (String rank : resident.getTownRanks()) {
|
||||
if (player.hasPermission("fawe.towny." + rank)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (NotRegisteredException ignored) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FaweMask getMask(final com.sk89q.worldedit.entity.Player wePlayer, MaskType type) {
|
||||
final Player player = BukkitAdapter.adapt(wePlayer);
|
||||
final Location location = player.getLocation();
|
||||
try {
|
||||
final PlayerCache cache = ((Towny) this.towny).getCache(player);
|
||||
final WorldCoord mycoord = cache.getLastTownBlock();
|
||||
if (mycoord == null) {
|
||||
return null;
|
||||
}
|
||||
final TownBlock myplot = mycoord.getTownBlock();
|
||||
if (myplot == null) {
|
||||
return null;
|
||||
}
|
||||
boolean isMember = isAllowed(player, myplot);
|
||||
if (isMember) {
|
||||
final Chunk chunk = location.getChunk();
|
||||
final BlockVector3 pos1 = BlockVector3
|
||||
.at(chunk.getX() * 16, 0, chunk.getZ() * 16);
|
||||
final BlockVector3 pos2 = BlockVector3.at(
|
||||
chunk.getX() * 16 + 15, 156, chunk.getZ() * 16
|
||||
+ 15);
|
||||
return new FaweMask(new CuboidRegion(pos1, pos2)) {
|
||||
@Override
|
||||
public boolean isValid(com.sk89q.worldedit.entity.Player player, MaskType type) {
|
||||
return isAllowed(BukkitAdapter.adapt(player), myplot);
|
||||
}
|
||||
};
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,195 @@
|
||||
package com.fastasyncworldedit.bukkit.regions;
|
||||
|
||||
import com.fastasyncworldedit.bukkit.filter.WorldGuardFilter;
|
||||
import com.fastasyncworldedit.core.object.RegionWrapper;
|
||||
import com.fastasyncworldedit.core.regions.FaweMask;
|
||||
import com.fastasyncworldedit.core.regions.general.RegionFilter;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.AbstractRegion;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.regions.Polygonal2DRegion;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldguard.LocalPlayer;
|
||||
import com.sk89q.worldguard.WorldGuard;
|
||||
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
|
||||
import com.sk89q.worldguard.protection.ApplicableRegionSet;
|
||||
import com.sk89q.worldguard.protection.flags.Flags;
|
||||
import com.sk89q.worldguard.protection.managers.RegionManager;
|
||||
import com.sk89q.worldguard.protection.regions.GlobalProtectedRegion;
|
||||
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
|
||||
import com.sk89q.worldguard.protection.regions.ProtectedPolygonalRegion;
|
||||
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
|
||||
import com.sk89q.worldguard.protection.regions.RegionContainer;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import java.util.Locale;
|
||||
|
||||
public class Worldguard extends BukkitMaskManager implements Listener {
|
||||
private final WorldGuardPlugin worldguard;
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
|
||||
private WorldGuardPlugin getWorldGuard() {
|
||||
final Plugin plugin = Bukkit.getPluginManager().getPlugin("WorldGuard");
|
||||
|
||||
// WorldGuard may not be loaded
|
||||
if (!(plugin instanceof WorldGuardPlugin)) {
|
||||
return null; // Maybe you want throw an exception instead
|
||||
}
|
||||
|
||||
return (WorldGuardPlugin) plugin;
|
||||
}
|
||||
|
||||
public Worldguard(Plugin p2) {
|
||||
super(p2.getName());
|
||||
this.worldguard = this.getWorldGuard();
|
||||
LOGGER.debug("Plugin 'WorldGuard' found. Using it now.");
|
||||
|
||||
}
|
||||
|
||||
public ProtectedRegion getRegion(LocalPlayer player, Location location) {
|
||||
RegionContainer container = WorldGuard.getInstance().getPlatform().getRegionContainer();
|
||||
if (container == null) {
|
||||
LOGGER.info("Region capability is not enabled for WorldGuard.");
|
||||
return null;
|
||||
}
|
||||
RegionManager manager = container.get(BukkitAdapter.adapt(location.getWorld()));
|
||||
if (manager == null) {
|
||||
LOGGER.info("Region capability is not enabled for that world.");
|
||||
return null;
|
||||
}
|
||||
final ProtectedRegion global = manager.getRegion("__global__");
|
||||
if (global != null && isAllowed(player, global)) {
|
||||
return global;
|
||||
}
|
||||
final ApplicableRegionSet regions = manager.getApplicableRegions(BlockVector3.at(location.getX(), location.getY(), location.getZ()));
|
||||
//Merge WorldGuardFlag
|
||||
if (player.hasPermission("fawe.worldguardflag") && !regions.testState(player, Flags.BUILD, Flags.BLOCK_PLACE, Flags.BLOCK_BREAK)) {
|
||||
return null;
|
||||
}
|
||||
for (ProtectedRegion region : regions) {
|
||||
if (isAllowed(player, region)) {
|
||||
return region;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isAllowed(LocalPlayer localplayer, ProtectedRegion region) {
|
||||
//Check if player is the owner of the region, the region's ID contains the player's name (why?), or if the region's owners contains "*".
|
||||
if (region.isOwner(localplayer) || region.isOwner(localplayer.getName())) {
|
||||
return true;
|
||||
} else if (region.getId().toLowerCase(Locale.ROOT).equals(localplayer.getName().toLowerCase(Locale.ROOT))) {
|
||||
return true;
|
||||
} else if (region.getId().toLowerCase(Locale.ROOT).contains(localplayer.getName().toLowerCase(Locale.ROOT) + "//")) {
|
||||
return true;
|
||||
} else if (region.isOwner("*")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//Check if the player has the FAWE permission for editing in WG regions as member, then checking member status.
|
||||
if (localplayer.hasPermission("fawe.worldguard.member")) {
|
||||
if (region.isMember(localplayer) || region.isMember(localplayer.getName())) {
|
||||
return true;
|
||||
} else {
|
||||
return region.isMember("*");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FaweMask getMask(com.sk89q.worldedit.entity.Player wePlayer, MaskType type) {
|
||||
final Player player = BukkitAdapter.adapt(wePlayer);
|
||||
final LocalPlayer localplayer = this.worldguard.wrapPlayer(player);
|
||||
final Location location = player.getLocation();
|
||||
final ProtectedRegion myregion = this.getRegion(localplayer, location);
|
||||
if (myregion != null) {
|
||||
final BlockVector3 pos1;
|
||||
final BlockVector3 pos2;
|
||||
if (myregion.getId().equals("__global__")) {
|
||||
pos1 = BlockVector3.at(Integer.MIN_VALUE, 0, Integer.MIN_VALUE);
|
||||
pos2 = BlockVector3.at(Integer.MAX_VALUE, 255, Integer.MAX_VALUE);
|
||||
} else {
|
||||
if (myregion instanceof ProtectedCuboidRegion) {
|
||||
pos1 = BlockVector3.at(myregion.getMinimumPoint().getBlockX(), myregion.getMinimumPoint().getBlockY(), myregion.getMinimumPoint().getBlockZ());
|
||||
pos2 = BlockVector3.at(myregion.getMaximumPoint().getBlockX(), myregion.getMaximumPoint().getBlockY(), myregion.getMaximumPoint().getBlockZ());
|
||||
} else {
|
||||
return new FaweMask(adapt(myregion)) {
|
||||
@Override
|
||||
public boolean isValid(com.sk89q.worldedit.entity.Player player, MaskType type) {
|
||||
return isAllowed(worldguard.wrapPlayer(BukkitAdapter.adapt(player)), myregion);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
return new FaweMask(new CuboidRegion(pos1, pos2)) {
|
||||
@Override
|
||||
public boolean isValid(com.sk89q.worldedit.entity.Player player, MaskType type) {
|
||||
return isAllowed(worldguard.wrapPlayer(BukkitAdapter.adapt(player)), myregion);
|
||||
}
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegionFilter getFilter(String world) {
|
||||
return new WorldGuardFilter(Bukkit.getWorld(world));
|
||||
}
|
||||
|
||||
private static class AdaptedRegion extends AbstractRegion {
|
||||
private final ProtectedRegion region;
|
||||
|
||||
public AdaptedRegion(ProtectedRegion region) {
|
||||
super(null);
|
||||
this.region = region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockVector3 getMinimumPoint() {
|
||||
return region.getMinimumPoint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockVector3 getMaximumPoint() {
|
||||
return region.getMaximumPoint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void expand(BlockVector3... changes) {
|
||||
throw new UnsupportedOperationException("Region is immutable");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contract(BlockVector3... changes) {
|
||||
throw new UnsupportedOperationException("Region is immutable");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(BlockVector3 position) {
|
||||
return region.contains(position);
|
||||
}
|
||||
}
|
||||
|
||||
private static Region adapt(ProtectedRegion region) {
|
||||
if (region instanceof ProtectedCuboidRegion) {
|
||||
return new CuboidRegion(region.getMinimumPoint(), region.getMaximumPoint());
|
||||
}
|
||||
if (region instanceof GlobalProtectedRegion) {
|
||||
return RegionWrapper.GLOBAL();
|
||||
}
|
||||
if (region instanceof ProtectedPolygonalRegion) {
|
||||
ProtectedPolygonalRegion casted = (ProtectedPolygonalRegion) region;
|
||||
BlockVector3 max = region.getMaximumPoint();
|
||||
BlockVector3 min = region.getMinimumPoint();
|
||||
return new Polygonal2DRegion(null, casted.getPoints(), min.getBlockY(), max.getBlockY());
|
||||
}
|
||||
return new AdaptedRegion(region);
|
||||
}
|
||||
}
|
@ -0,0 +1,253 @@
|
||||
package com.fastasyncworldedit.bukkit.regions.plotsquared;
|
||||
|
||||
import com.fastasyncworldedit.core.FaweAPI;
|
||||
import com.fastasyncworldedit.core.object.RelightMode;
|
||||
import com.fastasyncworldedit.core.util.EditSessionBuilder;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.plotsquared.core.configuration.Settings;
|
||||
import com.plotsquared.core.generator.HybridPlotManager;
|
||||
import com.plotsquared.core.generator.HybridPlotWorld;
|
||||
import com.plotsquared.core.location.Location;
|
||||
import com.plotsquared.core.plot.Plot;
|
||||
import com.plotsquared.core.plot.PlotArea;
|
||||
import com.plotsquared.core.plot.PlotAreaTerrainType;
|
||||
import com.plotsquared.core.plot.PlotAreaType;
|
||||
import com.plotsquared.core.plot.PlotManager;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.MaxChangedBlocksException;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats;
|
||||
import com.sk89q.worldedit.function.FlatRegionFunction;
|
||||
import com.sk89q.worldedit.function.biome.BiomeReplace;
|
||||
import com.sk89q.worldedit.function.operation.ForwardExtentCopy;
|
||||
import com.sk89q.worldedit.function.operation.Operations;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
import com.sk89q.worldedit.function.visitor.FlatRegionVisitor;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.bukkit.Bukkit.getWorld;
|
||||
|
||||
public class FaweDelegateRegionManager {
|
||||
|
||||
public boolean setCuboids(final @NonNull PlotArea area,
|
||||
final @NonNull Set<CuboidRegion> regions,
|
||||
final @NonNull Pattern blocks,
|
||||
int minY,
|
||||
int maxY,
|
||||
Runnable whenDone) {
|
||||
TaskManager.IMP.async(() -> {
|
||||
synchronized (FaweDelegateRegionManager.class) {
|
||||
World world = BukkitAdapter.adapt(getWorld(area.getWorldName()));
|
||||
EditSession session =
|
||||
new EditSessionBuilder(world).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull()
|
||||
.autoQueue(false).build();
|
||||
for (CuboidRegion region : regions) {
|
||||
region.setPos1(region.getPos1().withY(minY));
|
||||
region.setPos2(region.getPos2().withY(maxY));
|
||||
session.setBlocks((Region) region, blocks);
|
||||
}
|
||||
try {
|
||||
session.flushQueue();
|
||||
for (CuboidRegion region : regions) {
|
||||
FaweAPI.fixLighting(world, region, null,
|
||||
RelightMode.valueOf(com.fastasyncworldedit.core.configuration.Settings.IMP.LIGHTING.MODE));
|
||||
}
|
||||
} catch (MaxChangedBlocksException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
TaskManager.IMP.task(whenDone);
|
||||
}
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean notifyClear(PlotManager manager) {
|
||||
final HybridPlotWorld hpw = ((HybridPlotManager) manager).getHybridPlotWorld();
|
||||
return hpw.getType() != PlotAreaType.AUGMENTED || hpw.getTerrain() == PlotAreaTerrainType.NONE;
|
||||
}
|
||||
|
||||
public boolean handleClear(@NotNull Plot plot,
|
||||
@Nullable Runnable whenDone,
|
||||
@NotNull PlotManager manager) {
|
||||
TaskManager.IMP.async(() -> {
|
||||
synchronized (FaweDelegateRegionManager.class) {
|
||||
final HybridPlotWorld hybridPlotWorld = ((HybridPlotManager) manager).getHybridPlotWorld();
|
||||
World world = BukkitAdapter.adapt(getWorld(hybridPlotWorld.getWorldName()));
|
||||
EditSession editSession = new EditSessionBuilder(world).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build();
|
||||
|
||||
if (!hybridPlotWorld.PLOT_SCHEMATIC || !Settings.Schematics.PASTE_ON_TOP) {
|
||||
final BlockType bedrock;
|
||||
final BlockType air = BlockTypes.AIR;
|
||||
if (hybridPlotWorld.PLOT_BEDROCK) {
|
||||
bedrock = BlockTypes.BEDROCK;
|
||||
} else {
|
||||
bedrock = air;
|
||||
}
|
||||
|
||||
final Pattern filling = hybridPlotWorld.MAIN_BLOCK.toPattern();
|
||||
final Pattern plotfloor = hybridPlotWorld.TOP_BLOCK.toPattern();
|
||||
final BiomeType biome = hybridPlotWorld.getPlotBiome();
|
||||
|
||||
BlockVector3 pos1 = plot.getBottomAbs().getBlockVector3().withY(0);
|
||||
BlockVector3 pos2 = pos1.add(BlockVector3.at(hybridPlotWorld.PLOT_WIDTH - 1, 255, hybridPlotWorld.PLOT_WIDTH - 1));
|
||||
|
||||
Region bedrockRegion = new CuboidRegion(pos1, pos2.withY(0));
|
||||
Region fillingRegion = new CuboidRegion(pos1.withY(1), pos2.withY(hybridPlotWorld.PLOT_HEIGHT - 1));
|
||||
Region floorRegion = new CuboidRegion(pos1.withY(hybridPlotWorld.PLOT_HEIGHT), pos2.withY(hybridPlotWorld.PLOT_HEIGHT));
|
||||
Region airRegion = new CuboidRegion(pos1.withY(hybridPlotWorld.PLOT_HEIGHT + 1), pos2.withY(manager.getWorldHeight()));
|
||||
|
||||
editSession.setBlocks(bedrockRegion, bedrock);
|
||||
editSession.setBlocks(fillingRegion, filling);
|
||||
editSession.setBlocks(floorRegion, plotfloor);
|
||||
editSession.setBlocks(airRegion, air);
|
||||
editSession.flushQueue();
|
||||
}
|
||||
|
||||
if (hybridPlotWorld.PLOT_SCHEMATIC) {
|
||||
// We cannot reuse the editsession
|
||||
EditSession scheditsession = !Settings.Schematics.PASTE_ON_TOP ? editSession :
|
||||
new EditSessionBuilder(world).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build();
|
||||
File schematicFile = new File(hybridPlotWorld.getRoot(), "plot.schem");
|
||||
if (!schematicFile.exists()) {
|
||||
schematicFile = new File(hybridPlotWorld.getRoot(), "plot.schematic");
|
||||
}
|
||||
BlockVector3 to = plot.getBottomAbs().getBlockVector3().withY(Settings.Schematics.PASTE_ON_TOP ? hybridPlotWorld.SCHEM_Y : 1);
|
||||
try {
|
||||
Clipboard clip = ClipboardFormats.findByFile(schematicFile).getReader(new FileInputStream(schematicFile)).read();
|
||||
clip.paste(scheditsession, to, true, true, true);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
// Be verbose in editsession flushing
|
||||
scheditsession.flushQueue();
|
||||
}
|
||||
|
||||
// Be verbose in editsession flushing
|
||||
editSession.flushQueue();
|
||||
FaweAPI.fixLighting(world, new CuboidRegion(plot.getBottomAbs().getBlockVector3(), plot.getTopAbs().getBlockVector3()), null,
|
||||
RelightMode.valueOf(com.fastasyncworldedit.core.configuration.Settings.IMP.LIGHTING.MODE));
|
||||
TaskManager.IMP.task(whenDone);
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
public void swap(Location pos1,
|
||||
Location pos2,
|
||||
Location swapPos,
|
||||
final Runnable whenDone) {
|
||||
TaskManager.IMP.async(() -> {
|
||||
synchronized (FaweDelegateRegionManager.class) {
|
||||
//todo because of the following code this should proably be in the Bukkit module
|
||||
World pos1World = BukkitAdapter.adapt(getWorld(pos1.getWorldName()));
|
||||
World pos3World = BukkitAdapter.adapt(getWorld(swapPos.getWorldName()));
|
||||
WorldEdit.getInstance().getEditSessionFactory().getEditSession(pos1World, -1);
|
||||
EditSession sessionA = new EditSessionBuilder(pos1World).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build();
|
||||
EditSession sessionB = new EditSessionBuilder(pos3World).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build();
|
||||
CuboidRegion regionA = new CuboidRegion(pos1.getBlockVector3(), pos2.getBlockVector3());
|
||||
CuboidRegion regionB = new CuboidRegion(swapPos.getBlockVector3(), swapPos.getBlockVector3().add(pos2.getBlockVector3()).subtract(pos1.getBlockVector3()));
|
||||
regionA.setWorld(pos1World);
|
||||
regionB.setWorld(pos3World);
|
||||
Clipboard clipA = Clipboard.create(regionA, UUID.randomUUID());
|
||||
Clipboard clipB = Clipboard.create(regionB, UUID.randomUUID());
|
||||
ForwardExtentCopy copyA = new ForwardExtentCopy(sessionA, regionA, clipA, clipA.getMinimumPoint());
|
||||
ForwardExtentCopy copyB = new ForwardExtentCopy(sessionB, regionB, clipB, clipB.getMinimumPoint());
|
||||
try {
|
||||
Operations.completeLegacy(copyA);
|
||||
Operations.completeLegacy(copyB);
|
||||
clipA.paste(sessionB, swapPos.getBlockVector3(), true);
|
||||
clipB.paste(sessionA, pos1.getBlockVector3(), true);
|
||||
sessionA.flushQueue();
|
||||
sessionB.flushQueue();
|
||||
} catch (MaxChangedBlocksException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
FaweAPI.fixLighting(pos1World, new CuboidRegion(pos1.getBlockVector3(), pos2.getBlockVector3()), null,
|
||||
RelightMode.valueOf(com.fastasyncworldedit.core.configuration.Settings.IMP.LIGHTING.MODE));
|
||||
FaweAPI.fixLighting(pos1World, new CuboidRegion(swapPos.getBlockVector3(),
|
||||
BlockVector3.at(swapPos.getX() + pos2.getX() - pos1.getX(), 0, swapPos.getZ() + pos2.getZ() - pos1.getZ())), null,
|
||||
RelightMode.valueOf(com.fastasyncworldedit.core.configuration.Settings.IMP.LIGHTING.MODE));
|
||||
TaskManager.IMP.task(whenDone);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void setBiome(CuboidRegion region, int extendBiome, BiomeType biome, String world, Runnable whenDone) {
|
||||
region.expand(BlockVector3.at(extendBiome, 0, extendBiome));
|
||||
region.expand(BlockVector3.at(-extendBiome, 0, -extendBiome));
|
||||
TaskManager.IMP.async(() -> {
|
||||
synchronized (FaweDelegateRegionManager.class) {
|
||||
EditSession editSession = new EditSessionBuilder(BukkitAdapter.adapt(getWorld(world))).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build();
|
||||
FlatRegionFunction replace = new BiomeReplace(editSession, biome);
|
||||
FlatRegionVisitor visitor = new FlatRegionVisitor(region, replace);
|
||||
try {
|
||||
Operations.completeLegacy(visitor);
|
||||
editSession.flushQueue();
|
||||
} catch (MaxChangedBlocksException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
TaskManager.IMP.task(whenDone);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public boolean copyRegion(final @NonNull Location pos1,
|
||||
final @NonNull Location pos2,
|
||||
final @NonNull Location pos3,
|
||||
final @NonNull Runnable whenDone) {
|
||||
TaskManager.IMP.async(() -> {
|
||||
synchronized (FaweDelegateRegionManager.class) {
|
||||
World pos1World = BukkitAdapter.adapt(getWorld(pos1.getWorldName()));
|
||||
World pos3World = BukkitAdapter.adapt(getWorld(pos3.getWorldName()));
|
||||
EditSession from = new EditSessionBuilder(pos1World).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build();
|
||||
EditSession to = new EditSessionBuilder(pos3World).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build();
|
||||
CuboidRegion region = new CuboidRegion(BlockVector3.at(pos1.getX(), pos1.getY(), pos1.getZ()), BlockVector3.at(pos2.getX(), pos2.getY(), pos2.getZ()));
|
||||
ForwardExtentCopy copy = new ForwardExtentCopy(from, region, to, BlockVector3.at(pos3.getX(), pos3.getY(), pos3.getZ()));
|
||||
try {
|
||||
Operations.completeLegacy(copy);
|
||||
to.flushQueue();
|
||||
FaweAPI.fixLighting(pos1World,
|
||||
new CuboidRegion(pos3.getBlockVector3(), pos3.getBlockVector3().add(pos2.getBlockVector3().subtract(pos1.getBlockVector3()))),
|
||||
null, RelightMode.valueOf(com.fastasyncworldedit.core.configuration.Settings.IMP.LIGHTING.MODE));
|
||||
} catch (MaxChangedBlocksException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
TaskManager.IMP.task(whenDone);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean regenerateRegion(final Location pos1, final Location pos2, boolean ignore, final Runnable whenDone) {
|
||||
TaskManager.IMP.async(() -> {
|
||||
synchronized (FaweDelegateRegionManager.class) {
|
||||
World pos1World = BukkitAdapter.adapt(getWorld(pos1.getWorldName()));
|
||||
try (EditSession editSession = new EditSessionBuilder(pos1World).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build()) {
|
||||
CuboidRegion region = new CuboidRegion(BlockVector3.at(pos1.getX(), pos1.getY(), pos1.getZ()), BlockVector3.at(pos2.getX(), pos2.getY(), pos2.getZ()));
|
||||
editSession.regenerate(region);
|
||||
editSession.flushQueue();
|
||||
}
|
||||
TaskManager.IMP.task(whenDone);
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,229 @@
|
||||
package com.fastasyncworldedit.bukkit.regions.plotsquared;
|
||||
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.fastasyncworldedit.core.FaweAPI;
|
||||
import com.fastasyncworldedit.core.FaweCache;
|
||||
import com.fastasyncworldedit.core.object.io.PGZIPOutputStream;
|
||||
import com.fastasyncworldedit.core.util.EditSessionBuilder;
|
||||
import com.fastasyncworldedit.core.util.IOUtil;
|
||||
import com.plotsquared.core.PlotSquared;
|
||||
import com.plotsquared.core.generator.ClassicPlotWorld;
|
||||
import com.plotsquared.core.plot.Plot;
|
||||
import com.plotsquared.core.plot.PlotArea;
|
||||
import com.plotsquared.core.plot.schematic.Schematic;
|
||||
import com.plotsquared.core.util.FileUtils;
|
||||
import com.plotsquared.core.util.SchematicHandler;
|
||||
import com.plotsquared.core.util.task.RunnableVal;
|
||||
import com.plotsquared.core.util.task.TaskManager;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.CompressedCompoundTag;
|
||||
import com.sk89q.jnbt.NBTInputStream;
|
||||
import com.sk89q.jnbt.NBTOutputStream;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.jnbt.fawe.CompressedSchematicTag;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.BuiltInClipboardFormat;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.FastSchematicReader;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.FastSchematicWriter;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.MCEditSchematicReader;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.SpongeSchematicReader;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import net.jpountz.lz4.LZ4BlockInputStream;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.EOFException;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URL;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
public class FaweDelegateSchematicHandler {
|
||||
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
|
||||
private static final AtomicBoolean exportingAll = new AtomicBoolean();
|
||||
|
||||
public void paste(final Schematic schematic,
|
||||
final Plot plot,
|
||||
final int xOffset,
|
||||
final int yOffset,
|
||||
final int zOffset,
|
||||
final boolean autoHeight,
|
||||
final RunnableVal<Boolean> whenDone) {
|
||||
Runnable r = () -> {
|
||||
if (whenDone != null) {
|
||||
whenDone.value = false;
|
||||
}
|
||||
if (schematic == null) {
|
||||
TaskManager.runTask(whenDone);
|
||||
return;
|
||||
}
|
||||
BlockVector3 dimension = schematic.getClipboard().getDimensions();
|
||||
final int WIDTH = dimension.getX();
|
||||
final int LENGTH = dimension.getZ();
|
||||
final int HEIGHT = dimension.getY();
|
||||
// Validate dimensions
|
||||
CuboidRegion region = plot.getLargestRegion();
|
||||
if (((region.getMaximumPoint().getX() - region.getMinimumPoint().getX() + xOffset + 1) < WIDTH) || (
|
||||
(region.getMaximumPoint().getZ() - region.getMinimumPoint().getZ() + zOffset + 1) < LENGTH) || (HEIGHT
|
||||
> 256)) {
|
||||
TaskManager.runTask(whenDone);
|
||||
return;
|
||||
}
|
||||
// Calculate the optimal height to paste the schematic at
|
||||
final int y_offset_actual;
|
||||
if (autoHeight) {
|
||||
if (HEIGHT >= 256) {
|
||||
y_offset_actual = yOffset;
|
||||
} else {
|
||||
PlotArea pw = plot.getArea();
|
||||
if (pw instanceof ClassicPlotWorld) {
|
||||
y_offset_actual = yOffset + ((ClassicPlotWorld) pw).PLOT_HEIGHT;
|
||||
} else {
|
||||
y_offset_actual = yOffset + 1 + PlotSquared.platform().worldUtil()
|
||||
.getHighestBlockSynchronous(plot.getWorldName(), region.getMinimumPoint().getX() + 1,
|
||||
region.getMinimumPoint().getZ() + 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
y_offset_actual = yOffset;
|
||||
}
|
||||
|
||||
final BlockVector3 to = BlockVector3
|
||||
.at(region.getMinimumPoint().getX() + xOffset, y_offset_actual, region.getMinimumPoint().getZ() + zOffset);
|
||||
|
||||
try (EditSession editSession = new EditSessionBuilder(FaweAPI.getWorld(plot.getWorldName())).checkMemory(false)
|
||||
.fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build()) {
|
||||
final Clipboard clipboard = schematic.getClipboard();
|
||||
clipboard.paste(editSession, to, true, false, true);
|
||||
if (whenDone != null) {
|
||||
whenDone.value = true;
|
||||
TaskManager.runTask(whenDone);
|
||||
}
|
||||
}
|
||||
};
|
||||
if (Fawe.isMainThread()) {
|
||||
com.fastasyncworldedit.core.util.TaskManager.IMP.async(r);
|
||||
} else {
|
||||
r.run();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean save(CompoundTag tag, String path) {
|
||||
if (tag == null) {
|
||||
LOGGER.warn("Cannot save empty tag");
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
File tmp = FileUtils.getFile(PlotSquared.platform().getDirectory(), path);
|
||||
tmp.getParentFile().mkdirs();
|
||||
if (tag instanceof CompressedCompoundTag) {
|
||||
CompressedCompoundTag cTag = (CompressedCompoundTag) tag;
|
||||
if (cTag instanceof CompressedSchematicTag) {
|
||||
Clipboard clipboard = (Clipboard) cTag.getSource();
|
||||
try (OutputStream stream = new FileOutputStream(tmp);
|
||||
NBTOutputStream output = new NBTOutputStream(
|
||||
new BufferedOutputStream(new PGZIPOutputStream(stream)))) {
|
||||
new FastSchematicWriter(output).write(clipboard);
|
||||
}
|
||||
} else {
|
||||
try (OutputStream stream = new FileOutputStream(tmp);
|
||||
BufferedOutputStream output = new BufferedOutputStream(new PGZIPOutputStream(stream))) {
|
||||
LZ4BlockInputStream is = cTag.adapt(cTag.getSource());
|
||||
IOUtil.copy(is, output);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try (OutputStream stream = new FileOutputStream(tmp);
|
||||
NBTOutputStream output = new NBTOutputStream(new PGZIPOutputStream(stream))) {
|
||||
Map<String, Tag> map = tag.getValue();
|
||||
output.writeNamedTag("Schematic", map.getOrDefault("Schematic", tag));
|
||||
}
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void upload(final CompoundTag tag, final UUID uuid, final String file, final RunnableVal<URL> whenDone) {
|
||||
if (tag == null) {
|
||||
LOGGER.warn("Cannot save empty tag");
|
||||
com.plotsquared.core.util.task.TaskManager.runTask(whenDone);
|
||||
return;
|
||||
}
|
||||
final CompoundTag weTag = (CompoundTag) FaweCache.IMP.asTag(tag);
|
||||
SchematicHandler.upload(uuid, file, "schem", new RunnableVal<>() {
|
||||
@Override
|
||||
public void run(OutputStream output) {
|
||||
if (weTag instanceof CompressedSchematicTag) {
|
||||
Clipboard clipboard = ((CompressedSchematicTag) weTag).getSource();
|
||||
BuiltInClipboardFormat.SPONGE_SCHEMATIC.write(output, clipboard);
|
||||
}
|
||||
try {
|
||||
try (PGZIPOutputStream gzip = new PGZIPOutputStream(output)) {
|
||||
try (NBTOutputStream nos = new NBTOutputStream(gzip)) {
|
||||
Map<String, Tag> map = weTag.getValue();
|
||||
nos.writeNamedTag("Schematic", map.getOrDefault("Schematic", weTag));
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}, whenDone);
|
||||
}
|
||||
|
||||
public Schematic getSchematic(@NotNull InputStream is) {
|
||||
try {
|
||||
FastSchematicReader schematicReader = new FastSchematicReader(
|
||||
new NBTInputStream(new BufferedInputStream(new GZIPInputStream(new BufferedInputStream(is)))));
|
||||
Clipboard clip = schematicReader.read();
|
||||
return new Schematic(clip);
|
||||
} catch (IOException e) {
|
||||
if (e instanceof EOFException) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
SpongeSchematicReader schematicReader =
|
||||
new SpongeSchematicReader(new NBTInputStream(new GZIPInputStream(is)));
|
||||
Clipboard clip = schematicReader.read();
|
||||
return new Schematic(clip);
|
||||
} catch (IOException e2) {
|
||||
if (e2 instanceof EOFException) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
MCEditSchematicReader schematicReader =
|
||||
new MCEditSchematicReader(new NBTInputStream(new GZIPInputStream(is)));
|
||||
Clipboard clip = schematicReader.read();
|
||||
return new Schematic(clip);
|
||||
} catch (IOException e3) {
|
||||
e.printStackTrace();
|
||||
LOGGER.warn(
|
||||
is + " | " + is.getClass().getCanonicalName() + " is not in GZIP format : " + e
|
||||
.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,205 @@
|
||||
package com.fastasyncworldedit.bukkit.regions.plotsquared;
|
||||
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.fastasyncworldedit.core.FaweCache;
|
||||
import com.fastasyncworldedit.core.beta.IQueueChunk;
|
||||
import com.fastasyncworldedit.core.beta.IQueueExtent;
|
||||
import com.plotsquared.core.queue.LightingMode;
|
||||
import com.plotsquared.core.queue.QueueCoordinator;
|
||||
import com.plotsquared.core.queue.subscriber.ProgressSubscriber;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.entity.Entity;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.math.MutableBlockVector3;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class FaweQueueCoordinator extends QueueCoordinator {
|
||||
|
||||
public final IQueueExtent<IQueueChunk> instance;
|
||||
private final World world;
|
||||
private BlockVector3 mutable = new MutableBlockVector3();
|
||||
private boolean setbiome = false;
|
||||
|
||||
public FaweQueueCoordinator(World world) {
|
||||
super(world);
|
||||
this.world = world;
|
||||
instance = Fawe.get().getQueueHandler().getQueue(world);
|
||||
Fawe.get().getQueueHandler().unCache();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return instance.isEmpty() ? 0 : 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setModified(long l) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(final int x, final int y, final int z, final BlockState id) {
|
||||
return instance.setBlock(x, y, z, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(int x, int y, int z, Pattern pattern) {
|
||||
mutable.setComponents(x, y, z);
|
||||
return pattern.apply(instance, mutable, mutable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(final int x, final int y, final int z, final BaseBlock id) {
|
||||
return instance.setBlock(x, y, z, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getBlock(int x, int y, int z) {
|
||||
return instance.getBlock(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBiome(int x, int z, BiomeType biomeType) {
|
||||
setbiome = true;
|
||||
return instance.setBiome(x, 0, z, biomeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBiome(int x, int y, int z, @NotNull BiomeType biome) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSettingBiomes() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setEntity(@NotNull Entity entity) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<BlockVector2> getReadChunks() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addReadChunks(@NotNull Set<BlockVector2> readChunks) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addReadChunk(@NotNull BlockVector2 chunk) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUnloadAfter() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUnloadAfter(boolean unloadAfter) {
|
||||
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public CuboidRegion getRegenRegion() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRegenRegion(@NotNull CuboidRegion regenRegion) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean enqueue() {
|
||||
boolean val = super.enqueue();
|
||||
instance.enableQueue();
|
||||
return val;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Runnable getCompleteTask() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCompleteTask(@Nullable Runnable whenDone) {
|
||||
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Consumer<BlockVector2> getChunkConsumer() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChunkConsumer(@NotNull Consumer<BlockVector2> consumer) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addProgressSubscriber(@NotNull ProgressSubscriber progressSubscriber) {
|
||||
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public LightingMode getLightingMode() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLightingMode(@Nullable LightingMode mode) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void regenChunk(int x, int z) {
|
||||
instance.regenerateChunk(x, z, null, null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public World getWorld() {
|
||||
return world;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setTile(int x, int y, int z, CompoundTag tag) {
|
||||
instance.setTile(x, y, z, (com.sk89q.jnbt.CompoundTag) FaweCache.IMP.asTag(tag));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSettingTiles() {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package com.fastasyncworldedit.bukkit.regions.plotsquared;
|
||||
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.plotsquared.core.PlotSquared;
|
||||
import com.plotsquared.core.command.CommandCategory;
|
||||
import com.plotsquared.core.command.CommandDeclaration;
|
||||
import com.plotsquared.core.command.RequiredType;
|
||||
import com.plotsquared.core.command.SubCommand;
|
||||
import com.plotsquared.core.configuration.caption.StaticCaption;
|
||||
import com.plotsquared.core.configuration.caption.Templates;
|
||||
import com.plotsquared.core.configuration.caption.TranslatableCaption;
|
||||
import com.plotsquared.core.player.PlotPlayer;
|
||||
|
||||
@CommandDeclaration(command = "trimchunks",
|
||||
permission = "plots.admin",
|
||||
description = "Delete unmodified portions of your plotworld",
|
||||
requiredType = RequiredType.PLAYER,
|
||||
category = CommandCategory.ADMINISTRATION)
|
||||
public class FaweTrim extends SubCommand {
|
||||
|
||||
private boolean ran = false;
|
||||
|
||||
@Override
|
||||
public boolean onCommand(final PlotPlayer plotPlayer, final String[] strings) {
|
||||
if (ran) {
|
||||
plotPlayer.sendMessage(TranslatableCaption.of("error.task_in_process"));
|
||||
return false;
|
||||
}
|
||||
if (strings.length != 2) {
|
||||
plotPlayer.sendMessage(StaticCaption
|
||||
.of("First make a backup of your world called <world-copy> then stand in the middle of an empty plot"));
|
||||
plotPlayer.sendMessage(StaticCaption.of("use /plot trimall <world> <boolean-delete-unowned>"));
|
||||
return false;
|
||||
}
|
||||
if (!PlotSquared.platform().worldUtil().isWorld(strings[0])) {
|
||||
plotPlayer.sendMessage(TranslatableCaption.of("errors.not_valid_plot_world"), Templates.of("value", strings[0]));
|
||||
return false;
|
||||
}
|
||||
ran = true;
|
||||
TaskManager.IMP.async(() -> {
|
||||
try {
|
||||
// TODO NOT IMPLEMENTED
|
||||
//PlotTrim trim = new PlotTrim(plotPlayer, plotPlayer.getPlotAreaAbs(), strings[0], Boolean.parseBoolean(strings[1]));
|
||||
//Location loc = plotPlayer.getLocation();
|
||||
//trim.setChunk(loc.getX() >> 4, loc.getZ() >> 4);
|
||||
//trim.run();
|
||||
//plotPlayer.sendMessage("Done!");
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
ran = false;
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,342 @@
|
||||
package com.fastasyncworldedit.bukkit.regions.plotsquared;
|
||||
|
||||
|
||||
import com.plotsquared.core.command.CommandCategory;
|
||||
import com.plotsquared.core.command.CommandDeclaration;
|
||||
import com.plotsquared.core.command.RequiredType;
|
||||
|
||||
@CommandDeclaration(
|
||||
command = "moveto512",
|
||||
permission = "plots.moveto512",
|
||||
category = CommandCategory.DEBUG,
|
||||
requiredType = RequiredType.CONSOLE,
|
||||
description = "Move plots to a 512 sized region",
|
||||
usage = "/plots moveto512 [world]"
|
||||
)
|
||||
// TODO FIXME
|
||||
public class MoveTo512 /*extends Command*/ {
|
||||
|
||||
// public MoveTo512() {
|
||||
// super(MainCommand.getInstance(), true);
|
||||
// }
|
||||
//
|
||||
// private MCAChunk emptyPlot(MCAChunk chunk, HybridPlotWorld hpw) {
|
||||
// int maxLayer = (hpw.PLOT_HEIGHT) >> 4;
|
||||
// for (int i = maxLayer + 1; i < chunk.ids.length; i++) {
|
||||
// chunk.ids[i] = null;
|
||||
// chunk.data[i] = null;
|
||||
// }
|
||||
// for (int layer = 0; layer <= maxLayer; layer++) {
|
||||
// byte[] ids = chunk.ids[layer];
|
||||
// if (ids == null) {
|
||||
// ids = chunk.ids[layer] = new byte[4096];
|
||||
// chunk.data[layer] = new byte[2048];
|
||||
// chunk.skyLight[layer] = new byte[2048];
|
||||
// chunk.blockLight[layer] = new byte[2048];
|
||||
// } else {
|
||||
// Arrays.fill(ids, (byte) 0);
|
||||
// Arrays.fill(chunk.data[layer], (byte) 0);
|
||||
// Arrays.fill(chunk.skyLight[layer], (byte) 0);
|
||||
// Arrays.fill(chunk.blockLight[layer], (byte) 0);
|
||||
// }
|
||||
// if (layer == maxLayer) {
|
||||
// int yMax = hpw.PLOT_HEIGHT & 15;
|
||||
// for (int y = yMax + 1; y < 15; y++) {
|
||||
// Arrays.fill(chunk.skyLight[layer], y << 7, (y << 7) + 128, (byte) 255);
|
||||
// }
|
||||
// if (layer == 0) {
|
||||
// Arrays.fill(ids, 0, 256, (byte) 7);
|
||||
// for (int y = 1; y < yMax; y++) {
|
||||
// int y8 = y << 8;
|
||||
// Arrays.fill(ids, y8, y8 + 256, (byte) 3);
|
||||
// }
|
||||
// } else {
|
||||
// for (int y = 0; y < yMax; y++) {
|
||||
// int y8 = y << 8;
|
||||
// Arrays.fill(ids, y8, y8 + 256, (byte) 3);
|
||||
// }
|
||||
// }
|
||||
// int yMax15 = yMax & 15;
|
||||
// int yMax158 = yMax15 << 8;
|
||||
// Arrays.fill(ids, yMax158, yMax158 + 256, (byte) 2);
|
||||
// if (yMax != 15) {
|
||||
// Arrays.fill(ids, yMax158 + 256, 4096, (byte) 0);
|
||||
// }
|
||||
// } else if (layer == 0) {
|
||||
// Arrays.fill(ids, 256, 4096, (byte) 3);
|
||||
// Arrays.fill(ids, 0, 256, (byte) 7);
|
||||
// } else {
|
||||
// Arrays.fill(ids, (byte) 3);
|
||||
// }
|
||||
// }
|
||||
// return chunk;
|
||||
// }
|
||||
//
|
||||
// private MCAChunk emptyRoad(MCAChunk chunk, HybridPlotWorld hpw) {
|
||||
// int maxLayer = (hpw.ROAD_HEIGHT) >> 4;
|
||||
// for (int i = maxLayer + 1; i < chunk.ids.length; i++) {
|
||||
// chunk.ids[i] = null;
|
||||
// chunk.data[i] = null;
|
||||
// }
|
||||
// for (int layer = 0; layer <= maxLayer; layer++) {
|
||||
// byte[] ids = chunk.ids[layer];
|
||||
// if (ids == null) {
|
||||
// ids = chunk.ids[layer] = new byte[4096];
|
||||
// chunk.data[layer] = new byte[2048];
|
||||
// chunk.skyLight[layer] = new byte[2048];
|
||||
// chunk.blockLight[layer] = new byte[2048];
|
||||
// } else {
|
||||
// Arrays.fill(ids, (byte) 0);
|
||||
// Arrays.fill(chunk.data[layer], (byte) 0);
|
||||
// Arrays.fill(chunk.skyLight[layer], (byte) 0);
|
||||
// Arrays.fill(chunk.blockLight[layer], (byte) 0);
|
||||
// }
|
||||
// if (layer == maxLayer) {
|
||||
// int yMax = hpw.ROAD_HEIGHT & 15;
|
||||
// for (int y = yMax + 1; y < 15; y++) {
|
||||
// Arrays.fill(chunk.skyLight[layer], y << 7, (y << 7) + 128, (byte) 255);
|
||||
// }
|
||||
// if (layer == 0) {
|
||||
// Arrays.fill(ids, 0, 256, (byte) 7);
|
||||
// for (int y = 1; y <= yMax; y++) {
|
||||
// int y8 = y << 8;
|
||||
// Arrays.fill(ids, y8, y8 + 256, (byte) hpw.ROAD_BLOCK.id);
|
||||
// }
|
||||
// } else {
|
||||
// for (int y = 0; y <= yMax; y++) {
|
||||
// int y8 = y << 8;
|
||||
// Arrays.fill(ids, y8, y8 + 256, (byte) hpw.ROAD_BLOCK.id);
|
||||
// }
|
||||
// }
|
||||
// if (yMax != 15) {
|
||||
// int yMax15 = yMax & 15;
|
||||
// int yMax158 = yMax15 << 8;
|
||||
// Arrays.fill(ids, yMax158 + 256, 4096, (byte) 0);
|
||||
// }
|
||||
// } else if (layer == 0) {
|
||||
// Arrays.fill(ids, 256, 4096, (byte) hpw.ROAD_BLOCK.id);
|
||||
// Arrays.fill(ids, 0, 256, (byte) 7);
|
||||
// } else {
|
||||
// Arrays.fill(ids, (byte) hpw.ROAD_BLOCK.id);
|
||||
// }
|
||||
// }
|
||||
// return chunk;
|
||||
// }
|
||||
|
||||
// @Override
|
||||
// public void execute(PlotPlayer player, String[] args, RunnableVal3<Command, Runnable, Runnable> confirm, RunnableVal2<Command, CommandResult> whenDone) throws CommandException {
|
||||
// checkTrue(args.length == 1, Captions.COMMAND_SYNTAX, getUsage());
|
||||
// PlotArea area = player.getPlotAreaAbs();
|
||||
// check(area, Captions.COMMAND_SYNTAX, getUsage());
|
||||
// checkTrue(area instanceof HybridPlotWorld, Captions.NOT_VALID_HYBRID_PLOT_WORLD);
|
||||
//
|
||||
// WorldUtil.IMP.saveWorld(area.worldname);
|
||||
//
|
||||
// IQueueExtent defaultQueue = SetQueue.IMP.getNewQueue(area.worldname, true, false);
|
||||
// MCAQueue queueFrom = new MCAQueue(area.worldname, defaultQueue.getSaveFolder(), defaultQueue.hasSky());
|
||||
//
|
||||
// String world = args[0];
|
||||
// File folder = new File(PS.imp().getWorldContainer(), world + File.separator + "region");
|
||||
// checkTrue(!folder.exists(), Captions.SETUP_WORLD_TAKEN, world);
|
||||
//
|
||||
// HybridPlotWorld hpw = (HybridPlotWorld) area;
|
||||
// int minRoad = 7;
|
||||
// int pLen = Math.min(hpw.PLOT_WIDTH, 512 - minRoad);
|
||||
// int roadWidth = 512 - pLen;
|
||||
// int roadPosLower;
|
||||
// if ((roadWidth & 1) == 0) {
|
||||
// roadPosLower = (short) (Math.floor(roadWidth / 2) - 1);
|
||||
// } else {
|
||||
// roadPosLower = (short) Math.floor(roadWidth / 2);
|
||||
// }
|
||||
// int roadPosUpper = 512 - roadWidth + roadPosLower + 1;
|
||||
//
|
||||
// final ThreadLocal<boolean[]> roadCache = new ThreadLocal<boolean[]>() {
|
||||
// @Override
|
||||
// protected boolean[] initialValue() {
|
||||
// return new boolean[64];
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// MCAChunk reference = new MCAChunk(null, 0, 0);
|
||||
// {
|
||||
// reference.fillCuboid(0, 15, 0, 0, 0, 15, 7, (byte) 0);
|
||||
// reference.fillCuboid(0, 15, 1, hpw.PLOT_HEIGHT - 1, 0, 15, 3, (byte) 0);
|
||||
// reference.fillCuboid(0, 15, hpw.PLOT_HEIGHT, hpw.PLOT_HEIGHT, 0, 15, 2, (byte) 0);
|
||||
// }
|
||||
//
|
||||
// Map<PlotId, Plot> rawPlots = area.getPlotsRaw();
|
||||
// ArrayList<Plot> plots = new ArrayList(rawPlots.values());
|
||||
// int size = plots.size();
|
||||
//
|
||||
// PlotId nextId = new PlotId(0, 0);
|
||||
//
|
||||
// long start = System.currentTimeMillis();
|
||||
//
|
||||
// int percent = 0;
|
||||
// for (Plot plot : plots) {
|
||||
// Fawe.debug(((percent += 100) / size) + "% complete!");
|
||||
//
|
||||
// Location bot = plot.getBottomAbs();
|
||||
// Location top = plot.getTopAbs();
|
||||
//
|
||||
// int oX = roadPosLower - bot.getX() + 1;
|
||||
// int oZ = roadPosLower - bot.getZ() + 1;
|
||||
//
|
||||
// { // Move
|
||||
// PlotId id = plot.getId();
|
||||
// Fawe.debug("Moving " + plot.getId() + " to " + nextId);
|
||||
// id.x = nextId.x;
|
||||
// id.y = nextId.y;
|
||||
// id.recalculateHash();
|
||||
// }
|
||||
//
|
||||
// MCAWriter writer = new MCAWriter(512, 512, folder) {
|
||||
//
|
||||
// @Override
|
||||
// public boolean shouldWrite(int chunkX, int chunkZ) {
|
||||
// int bx = chunkX << 4;
|
||||
// int bz = chunkZ << 4;
|
||||
// int tx = bx + 15;
|
||||
// int tz = bz + 15;
|
||||
// return !(tx < roadPosLower || tz < roadPosLower || bx > roadPosUpper || bz > roadPosUpper);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public MCAChunk write(MCAChunk newChunk, int bx, int tx, int bz, int tz) {
|
||||
// Arrays.fill(newChunk.biomes, (byte) 4);
|
||||
// if (!newChunk.tiles.isEmpty()) newChunk.tiles.clear();
|
||||
// if (tx < roadPosLower || tz < roadPosLower || bx > roadPosUpper || bz > roadPosUpper) {
|
||||
// return emptyRoad(newChunk, hpw);
|
||||
// } else {
|
||||
// boolean partRoad = (bx <= roadPosLower || bz <= roadPosLower || tx >= roadPosUpper || tz >= roadPosUpper);
|
||||
//
|
||||
// boolean changed = false;
|
||||
// emptyPlot(newChunk, hpw);
|
||||
//
|
||||
// int obx = bx - oX;
|
||||
// int obz = bz - oZ;
|
||||
// int otx = tx - oX;
|
||||
// int otz = tz - oZ;
|
||||
// int otherBCX = (obx) >> 4;
|
||||
// int otherBCZ = (obz) >> 4;
|
||||
// int otherTCX = (otx) >> 4;
|
||||
// int otherTCZ = (otz) >> 4;
|
||||
// int cx = newChunk.getX();
|
||||
// int cz = newChunk.getZ();
|
||||
// int cbx = (cx << 4) - oX;
|
||||
// int cbz = (cz << 4) - oZ;
|
||||
//
|
||||
// for (int otherCZ = otherBCZ; otherCZ <= otherTCZ; otherCZ++) {
|
||||
// for (int otherCX = otherBCX; otherCX <= otherTCX; otherCX++) {
|
||||
// FaweChunk chunk;
|
||||
// synchronized (queueFrom) {
|
||||
// chunk = queueFrom.getFaweChunk(otherCX, otherCZ);
|
||||
// }
|
||||
// if (!(chunk instanceof NullFaweChunk)) {
|
||||
// changed = true;
|
||||
// MCAChunk other = (MCAChunk) chunk;
|
||||
// int ocbx = otherCX << 4;
|
||||
// int ocbz = otherCZ << 4;
|
||||
// int octx = ocbx + 15;
|
||||
// int octz = ocbz + 15;
|
||||
// int offsetY = 0;
|
||||
// int minX = obx > ocbx ? (obx - ocbx) & 15 : 0;
|
||||
// int maxX = otx < octx ? (otx - ocbx) : 15;
|
||||
// int minZ = obz > ocbz ? (obz - ocbz) & 15 : 0;
|
||||
// int maxZ = otz < octz ? (otz - ocbz) : 15;
|
||||
// int offsetX = ocbx - cbx;
|
||||
// int offsetZ = ocbz - cbz;
|
||||
// newChunk.copyFrom(other, minX, maxX, 0, 255, minZ, maxZ, offsetX, offsetY, offsetZ);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// if (!changed || reference.idsEqual(newChunk, false)) {
|
||||
// return null;
|
||||
// }
|
||||
// if (partRoad) {
|
||||
// boolean[] rwp = roadCache.get();
|
||||
// for (short i = 0; i < 16; i++) {
|
||||
// int vx = bx + i;
|
||||
// int vz = bz + i;
|
||||
// rwp[i] = vx < roadPosLower || vx > roadPosUpper;
|
||||
// rwp[i + 32] = vx == roadPosLower || vx == roadPosUpper;
|
||||
// rwp[i + 16] = vz < roadPosLower || vz > roadPosUpper;
|
||||
// rwp[i + 48] = vz == roadPosLower || vz == roadPosUpper;
|
||||
// }
|
||||
// for (int z = 0; z < 16; z++) {
|
||||
// final boolean rwpz16 = rwp[z + 16];
|
||||
// final boolean rwpz48 = rwp[z + 48];
|
||||
// for (int x = 0; x < 16; x++) {
|
||||
// if (rwpz16 || rwp[x]) {
|
||||
// for (int y = 1; y <= hpw.ROAD_HEIGHT; y++) {
|
||||
// newChunk.setBlock(x, y, z, hpw.ROAD_BLOCK.id, hpw.ROAD_BLOCK.data);
|
||||
// }
|
||||
// for (int y = hpw.ROAD_HEIGHT + 1; y < 256; y++) {
|
||||
// newChunk.setBlock(x, y, z, 0, 0);
|
||||
// }
|
||||
// } else if (rwpz48 || rwp[x + 32]) {
|
||||
// for (int y = 1; y <= hpw.WALL_HEIGHT; y++) {
|
||||
// newChunk.setBlock(x, y, z, hpw.WALL_FILLING.id, hpw.WALL_FILLING.data);
|
||||
// }
|
||||
// for (int y = hpw.WALL_HEIGHT + 2; y < 256; y++) {
|
||||
// newChunk.setBlock(x, y, z, 0, 0);
|
||||
// }
|
||||
// newChunk.setBlock(x, hpw.WALL_HEIGHT + 1, z, hpw.CLAIMED_WALL_BLOCK.id, hpw.CLAIMED_WALL_BLOCK.data);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return newChunk;
|
||||
// }
|
||||
// };
|
||||
// writer.setMCAOffset(nextId.x - 1, nextId.y - 1);
|
||||
// try {
|
||||
// writer.generate();
|
||||
// System.gc();
|
||||
// } catch (IOException e) {
|
||||
// e.printStackTrace();
|
||||
// return;
|
||||
// }
|
||||
// queueFrom.clear();
|
||||
// nextId = nextId.getNextId(1);
|
||||
// }
|
||||
// Fawe.debug("Anvil copy completed in " + ((System.currentTimeMillis() - start) / 1000d) + "s");
|
||||
// Fawe.debug("Updating database, please wait...");
|
||||
// rawPlots.clear();
|
||||
// for (Plot plot : plots) {
|
||||
// rawPlots.put(plot.getId(), plot);
|
||||
// DBFunc.movePlot(plot, plot);
|
||||
// }
|
||||
// SQLManager db = (SQLManager) DBFunc.dbManager;
|
||||
// db.addNotifyTask(new Runnable() {
|
||||
// @Override
|
||||
// public void run() {
|
||||
// Fawe.debug("Instructions");
|
||||
// Fawe.debug(" - Stop the server");
|
||||
// Fawe.debug(" - Rename the folder for the new world to the current world");
|
||||
// Fawe.debug(" - Change the plot size to " + pLen);
|
||||
// Fawe.debug(" - Change the road size to " + roadWidth);
|
||||
// Fawe.debug(" - Start the server");
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// ConfigurationSection section = PS.get().worlds.getConfigurationSection("worlds." + world);
|
||||
// if (section == null) section = PS.get().worlds.createSection("worlds." + world);
|
||||
// area.saveConfiguration(section);
|
||||
// section.set("plot.size", pLen);
|
||||
// section.set("road.width", roadWidth);
|
||||
// try {
|
||||
// PS.get().worlds.save(PS.get().worldsFile);
|
||||
// } catch (IOException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
//
|
||||
// final SetupObject object = new SetupObject();
|
||||
// object.world = world;
|
||||
// object.plotManager = PS.imp().getPluginName();
|
||||
// object.setupGenerator = PS.imp().getPluginName();
|
||||
// String created = SetupUtils.manager.setupWorld(object);
|
||||
// }
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package com.fastasyncworldedit.bukkit.regions.plotsquared;
|
||||
|
||||
import com.fastasyncworldedit.core.regions.general.CuboidRegionFilter;
|
||||
import com.plotsquared.core.location.Location;
|
||||
import com.plotsquared.core.plot.Plot;
|
||||
import com.plotsquared.core.plot.PlotArea;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class PlotRegionFilter extends CuboidRegionFilter {
|
||||
private final PlotArea area;
|
||||
|
||||
public PlotRegionFilter(PlotArea area) {
|
||||
checkNotNull(area);
|
||||
this.area = area;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void calculateRegions() {
|
||||
ArrayList<Plot> plots = new ArrayList<>(area.getPlots());
|
||||
for (Plot plot : plots) {
|
||||
Location bottom = plot.getCorners()[0];
|
||||
Location top = plot.getCorners()[1];
|
||||
add(BlockVector2.at(bottom.getX(), bottom.getZ()), BlockVector2.at(top.getX(), top.getZ()));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
package com.fastasyncworldedit.bukkit.regions.plotsquared;
|
||||
|
||||
import com.fastasyncworldedit.core.util.EditSessionBuilder;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.plotsquared.core.command.Command;
|
||||
import com.plotsquared.core.command.CommandCategory;
|
||||
import com.plotsquared.core.command.CommandDeclaration;
|
||||
import com.plotsquared.core.command.MainCommand;
|
||||
import com.plotsquared.core.command.RequiredType;
|
||||
import com.plotsquared.core.configuration.caption.Templates;
|
||||
import com.plotsquared.core.configuration.caption.TranslatableCaption;
|
||||
import com.plotsquared.core.player.PlotPlayer;
|
||||
import com.plotsquared.core.plot.Plot;
|
||||
import com.plotsquared.core.util.Permissions;
|
||||
import com.plotsquared.core.util.StringMan;
|
||||
import com.plotsquared.core.util.task.RunnableVal2;
|
||||
import com.plotsquared.core.util.task.RunnableVal3;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.command.util.SuggestionHelper;
|
||||
import com.sk89q.worldedit.extension.platform.Capability;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.biome.BiomeTypes;
|
||||
import com.sk89q.worldedit.world.biome.Biomes;
|
||||
import com.sk89q.worldedit.world.registry.BiomeRegistry;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@CommandDeclaration(command = "generatebiome",
|
||||
permission = "plots.generatebiome",
|
||||
category = CommandCategory.APPEARANCE,
|
||||
requiredType = RequiredType.PLAYER,
|
||||
description = "Generate a biome in your plot",
|
||||
aliases = {"bg", "gb"},
|
||||
usage = "/plots generatebiome <biome>")
|
||||
public class PlotSetBiome extends Command {
|
||||
public PlotSetBiome() {
|
||||
super(MainCommand.getInstance(), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> execute(final PlotPlayer<?> player,
|
||||
String[] args,
|
||||
RunnableVal3<Command, Runnable, Runnable> confirm,
|
||||
RunnableVal2<Command, CommandResult> whenDone) throws CommandException {
|
||||
final Plot plot = check(player.getCurrentPlot(), TranslatableCaption.of("errors.not_in_plot"));
|
||||
checkTrue(plot.isOwner(player.getUUID()) || Permissions.hasPermission(player, "plots.admin.command.generatebiome"),
|
||||
TranslatableCaption.of("permission.no_plot_perms"));
|
||||
if (plot.getRunning() != 0) {
|
||||
player.sendMessage(TranslatableCaption.of("errors.wait_for_timer"));
|
||||
return null;
|
||||
}
|
||||
checkTrue(args.length == 1, TranslatableCaption.of("commandconfig.command_syntax"),
|
||||
Templates.of("value", getUsage()));
|
||||
final Set<CuboidRegion> regions = plot.getRegions();
|
||||
BiomeRegistry biomeRegistry =
|
||||
WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS).getRegistries()
|
||||
.getBiomeRegistry();
|
||||
Collection<BiomeType> knownBiomes = BiomeTypes.values();
|
||||
final BiomeType biome = Biomes.findBiomeByName(knownBiomes, args[0], biomeRegistry);
|
||||
if (biome == null) {
|
||||
String biomes = StringMan.join(BiomeType.REGISTRY.values(),
|
||||
TranslatableCaption.of("blocklist.block_list_separator").getComponent(player));
|
||||
player.sendMessage(TranslatableCaption.of("biome.need_biome"));
|
||||
player.sendMessage(TranslatableCaption.of("commandconfig.subcommand_set_options_header"),
|
||||
Templates.of("values", biomes));
|
||||
return CompletableFuture.completedFuture(false);
|
||||
}
|
||||
confirm.run(this, () -> {
|
||||
if (plot.getRunning() != 0) {
|
||||
player.sendMessage(TranslatableCaption.of("errors.wait_for_timer"));
|
||||
return;
|
||||
}
|
||||
plot.addRunning();
|
||||
TaskManager.IMP.async(() -> {
|
||||
EditSession session =
|
||||
new EditSessionBuilder(BukkitAdapter.adapt(Bukkit.getWorld(plot.getArea().getWorldName())))
|
||||
.autoQueue(false).checkMemory(false).allowedRegionsEverywhere()
|
||||
.player(BukkitAdapter.adapt(Bukkit.getPlayer(player.getUUID()))).limitUnlimited().build();
|
||||
long seed = ThreadLocalRandom.current().nextLong();
|
||||
for (CuboidRegion region : regions) {
|
||||
session.regenerate(region, biome, seed);
|
||||
}
|
||||
session.flushQueue();
|
||||
plot.removeRunning();
|
||||
});
|
||||
}, null);
|
||||
|
||||
return CompletableFuture.completedFuture(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Command> tab(final PlotPlayer<?> player, final String[] args, final boolean space) {
|
||||
return SuggestionHelper.getNamespacedRegistrySuggestions(BiomeType.REGISTRY, args[0])
|
||||
.map(value -> value.toLowerCase(Locale.ENGLISH).replace("minecraft:", ""))
|
||||
.filter(value -> value.startsWith(args[0].toLowerCase(Locale.ENGLISH)))
|
||||
.map(value -> new Command(null, false, value, "", RequiredType.PLAYER, null) {
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
}
|
@ -0,0 +1,143 @@
|
||||
package com.fastasyncworldedit.bukkit.regions.plotsquared;
|
||||
|
||||
import com.fastasyncworldedit.core.FaweAPI;
|
||||
import com.fastasyncworldedit.core.regions.FaweMask;
|
||||
import com.fastasyncworldedit.core.regions.FaweMaskManager;
|
||||
import com.fastasyncworldedit.core.regions.general.RegionFilter;
|
||||
import com.github.intellectualsites.plotsquared.plot.util.UUIDHandler;
|
||||
import com.plotsquared.core.PlotSquared;
|
||||
import com.plotsquared.core.command.MainCommand;
|
||||
import com.plotsquared.core.configuration.Settings;
|
||||
import com.plotsquared.core.database.DBFunc;
|
||||
import com.plotsquared.core.player.PlotPlayer;
|
||||
import com.plotsquared.core.plot.Plot;
|
||||
import com.plotsquared.core.plot.PlotArea;
|
||||
import com.plotsquared.core.plot.flag.implementations.DoneFlag;
|
||||
import com.plotsquared.core.plot.flag.implementations.NoWorldeditFlag;
|
||||
import com.plotsquared.core.util.WEManager;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.regions.RegionIntersection;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class PlotSquaredFeature extends FaweMaskManager {
|
||||
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
|
||||
public PlotSquaredFeature() {
|
||||
super("PlotSquared");
|
||||
LOGGER.debug("Optimizing PlotSquared");
|
||||
if (Settings.FAWE_Components.FAWE_HOOK) {
|
||||
Settings.Enabled_Components.WORLDEDIT_RESTRICTIONS = false;
|
||||
if (Settings.PLATFORM.toLowerCase(Locale.ROOT).startsWith("bukkit")) {
|
||||
new FaweTrim();
|
||||
}
|
||||
if (MainCommand.getInstance().getCommand("generatebiome") == null) {
|
||||
new PlotSetBiome();
|
||||
}
|
||||
}
|
||||
// TODO: revisit this later on
|
||||
/*
|
||||
try {
|
||||
if (Settings.Enabled_Components.WORLDS) {
|
||||
new ReplaceAll();
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
log.debug("You need to update PlotSquared to access the CFI and REPLACEALL commands");
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
public static String getName(UUID uuid) {
|
||||
return UUIDHandler.getName(uuid);
|
||||
}
|
||||
|
||||
public boolean isAllowed(Player player, Plot plot, MaskType type) {
|
||||
if (plot == null) {
|
||||
return false;
|
||||
}
|
||||
UUID uid = player.getUniqueId();
|
||||
return !plot.getFlag(NoWorldeditFlag.class) && (plot.isOwner(uid) || type == MaskType.MEMBER && (
|
||||
plot.getTrusted().contains(uid) || plot.getTrusted().contains(DBFunc.EVERYONE)
|
||||
|| (plot.getMembers().contains(uid) || plot.getMembers().contains(DBFunc.EVERYONE)) && player
|
||||
.hasPermission("fawe.plotsquared.member")) || player.hasPermission("fawe.plotsquared.admin"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public FaweMask getMask(Player player, MaskType type) {
|
||||
final PlotPlayer<org.bukkit.entity.Player> pp = PlotPlayer.from(BukkitAdapter.adapt(player));
|
||||
if (pp == null) {
|
||||
return null;
|
||||
}
|
||||
final Set<CuboidRegion> regions;
|
||||
Plot plot = pp.getCurrentPlot();
|
||||
if (isAllowed(player, plot, type)) {
|
||||
regions = plot.getRegions();
|
||||
} else {
|
||||
plot = null;
|
||||
regions = WEManager.getMask(pp);
|
||||
if (regions.size() == 1) {
|
||||
CuboidRegion region = regions.iterator().next();
|
||||
if (region.getMinimumPoint().getX() == Integer.MIN_VALUE
|
||||
&& region.getMaximumPoint().getX() == Integer.MAX_VALUE) {
|
||||
regions.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (regions.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
PlotArea area = pp.getApplicablePlotArea();
|
||||
final Plot finalPlot = plot;
|
||||
if (Settings.Done.RESTRICT_BUILDING && DoneFlag.isDone(finalPlot) || regions.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Region maskedRegion;
|
||||
if (regions.size() == 1) {
|
||||
int min = area != null ? area.getMinBuildHeight() : 0;
|
||||
int max = area != null ? Math.min(255, area.getMaxBuildHeight()) : 255;
|
||||
|
||||
final CuboidRegion region = regions.iterator().next();
|
||||
final BlockVector3 pos1 = BlockVector3.at(region.getMinimumX(), min, region.getMinimumZ());
|
||||
final BlockVector3 pos2 = BlockVector3.at(region.getMaximumX(), max, region.getMaximumZ());
|
||||
maskedRegion = new CuboidRegion(pos1, pos2);
|
||||
} else {
|
||||
World world = FaweAPI.getWorld(area.getWorldName());
|
||||
List<Region> weRegions = regions.stream().map(
|
||||
r -> new CuboidRegion(world, BlockVector3.at(r.getMinimumX(), r.getMinimumY(), r.getMinimumZ()),
|
||||
BlockVector3.at(r.getMaximumX(), r.getMaximumY(), r.getMaximumZ()))).collect(Collectors.toList());
|
||||
maskedRegion = new RegionIntersection(world, weRegions);
|
||||
}
|
||||
|
||||
return new FaweMask(maskedRegion) {
|
||||
@Override
|
||||
public boolean isValid(Player player, MaskType type) {
|
||||
if (Settings.Done.RESTRICT_BUILDING && DoneFlag.isDone(finalPlot)) {
|
||||
return false;
|
||||
}
|
||||
return isAllowed(player, finalPlot, type);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegionFilter getFilter(String world) {
|
||||
PlotArea area = PlotSquared.get().getPlotAreaManager().getPlotArea(world, null);
|
||||
if (area != null) {
|
||||
return new PlotRegionFilter(area);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
/*
|
||||
package com.boydti.fawe.regions.general.plot;
|
||||
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.object.RunnableVal;
|
||||
import com.boydti.fawe.util.StringMan;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.boydti.fawe.wrappers.FakePlayer;
|
||||
import com.github.intellectualsites.plotsquared.commands.Command;
|
||||
import com.github.intellectualsites.plotsquared.commands.CommandDeclaration;
|
||||
import com.github.intellectualsites.plotsquared.plot.commands.CommandCategory;
|
||||
import com.github.intellectualsites.plotsquared.plot.commands.MainCommand;
|
||||
import com.github.intellectualsites.plotsquared.plot.commands.RequiredType;
|
||||
import com.github.intellectualsites.plotsquared.plot.config.Captions;
|
||||
import com.github.intellectualsites.plotsquared.plot.object.Plot;
|
||||
import com.github.intellectualsites.plotsquared.plot.object.PlotArea;
|
||||
import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer;
|
||||
import com.github.intellectualsites.plotsquared.plot.object.RunnableVal2;
|
||||
import com.github.intellectualsites.plotsquared.plot.object.RunnableVal3;
|
||||
import com.github.intellectualsites.plotsquared.plot.object.worlds.SinglePlotArea;
|
||||
import com.github.intellectualsites.plotsquared.plot.util.SetupUtils;
|
||||
import com.sk89q.worldedit.event.platform.CommandEvent;
|
||||
import com.sk89q.worldedit.extension.platform.PlatformCommandManager;
|
||||
|
||||
@CommandDeclaration(
|
||||
command = "replaceall",
|
||||
permission = "plots.replaceall",
|
||||
category = CommandCategory.APPEARANCE,
|
||||
requiredType = RequiredType.NONE,
|
||||
description = "Replace all block in the plot",
|
||||
usage = "/plots replaceall <from> <to>"
|
||||
)
|
||||
public class ReplaceAll extends Command {
|
||||
public ReplaceAll() {
|
||||
super(MainCommand.getInstance(), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(final PlotPlayer player, String[] args, RunnableVal3<Command, Runnable, Runnable> confirm, RunnableVal2<Command, CommandResult> whenDone) throws CommandException {
|
||||
checkTrue(args.length >= 1, Captions.COMMAND_SYNTAX, getUsage());
|
||||
final Plot plot = check(player.getCurrentPlot(), Captions.NOT_IN_PLOT);
|
||||
checkTrue(plot.isOwner(player.getUUID()), Captions.NOW_OWNER);
|
||||
checkTrue(plot.getRunning() == 0, Captions.WAIT_FOR_TIMER);
|
||||
final PlotArea area = plot.getArea();
|
||||
if (area instanceof SinglePlotArea) {
|
||||
plot.addRunning();
|
||||
FawePlayer<Object> fp = FawePlayer.wrap(player.getName());
|
||||
Captions.TASK_START.send(player);
|
||||
TaskManager.IMP.async(() -> fp.runAction(() -> {
|
||||
String worldName = plot.getWorldName();
|
||||
TaskManager.IMP.sync(new RunnableVal<Object>() {
|
||||
@Override
|
||||
public void run(Object value) {
|
||||
SetupUtils.manager.unload(worldName, true);
|
||||
}
|
||||
});
|
||||
FakePlayer actor = FakePlayer.getConsole();
|
||||
String cmd = "/replaceallpattern " + worldName + " " + StringMan.join(args, " ");
|
||||
CommandEvent event = new CommandEvent(actor, cmd);
|
||||
PlatformCommandManager.getInstance().handleCommandOnCurrentThread(event);
|
||||
TaskManager.IMP.sync(new RunnableVal<Object>() {
|
||||
@Override
|
||||
public void run(Object value) {
|
||||
plot.teleportPlayer(player);
|
||||
}
|
||||
});
|
||||
plot.removeRunning();
|
||||
}, true, false));
|
||||
} else {
|
||||
player.sendMessage("Must have the `worlds` component enabled in the PlotSquared config.yml");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
@ -0,0 +1,126 @@
|
||||
package com.fastasyncworldedit.bukkit.regions.plotsquaredv4;
|
||||
|
||||
import com.fastasyncworldedit.core.configuration.Settings;
|
||||
import com.fastasyncworldedit.core.util.EditSessionBuilder;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.github.intellectualsites.plotsquared.plot.object.Location;
|
||||
import com.github.intellectualsites.plotsquared.plot.object.Plot;
|
||||
import com.github.intellectualsites.plotsquared.plot.util.ChunkManager;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.MaxChangedBlocksException;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.function.operation.ForwardExtentCopy;
|
||||
import com.sk89q.worldedit.function.operation.Operations;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import static org.bukkit.Bukkit.getWorld;
|
||||
|
||||
public class FaweChunkManager extends ChunkManager {
|
||||
|
||||
private ChunkManager parent;
|
||||
|
||||
public FaweChunkManager(ChunkManager parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] countEntities(Plot plot) {
|
||||
return parent.countEntities(plot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture loadChunk(String world, BlockVector2 loc, boolean force) {
|
||||
return parent.loadChunk(world, loc, force);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unloadChunk(String world, BlockVector2 loc, boolean save) {
|
||||
parent.unloadChunk(world, loc, save);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearAllEntities(Location pos1, Location pos2) {
|
||||
parent.clearAllEntities(pos1, pos2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void swap(final Location pos1, final Location pos2, final Location pos3, final Location pos4, final Runnable whenDone) {
|
||||
if (!Settings.IMP.PLOTSQUARED_INTEGRATION.COPY_AND_SWAP) {
|
||||
parent.swap(pos1, pos2, pos3, pos4, whenDone);
|
||||
}
|
||||
TaskManager.IMP.async(() -> {
|
||||
synchronized (FaweChunkManager.class) {
|
||||
//todo because of the following code this should proably be in the Bukkit module
|
||||
World pos1World = BukkitAdapter.adapt(getWorld(pos1.getWorld()));
|
||||
World pos3World = BukkitAdapter.adapt(getWorld(pos3.getWorld()));
|
||||
WorldEdit.getInstance().getEditSessionFactory().getEditSession(
|
||||
pos1World,-1);
|
||||
EditSession sessionA = new EditSessionBuilder(pos1World).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build();
|
||||
EditSession sessionB = new EditSessionBuilder(pos3World).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build();
|
||||
CuboidRegion regionA = new CuboidRegion(BlockVector3.at(pos1.getX(), pos1.getY(), pos1.getZ()), BlockVector3.at(pos2.getX(), pos2.getY(), pos2.getZ()));
|
||||
CuboidRegion regionB = new CuboidRegion(BlockVector3.at(pos3.getX(), pos3.getY(), pos3.getZ()), BlockVector3.at(pos4.getX(), pos4.getY(), pos4.getZ()));
|
||||
ForwardExtentCopy copyA = new ForwardExtentCopy(sessionA, regionA, sessionB, regionB.getMinimumPoint());
|
||||
ForwardExtentCopy copyB = new ForwardExtentCopy(sessionB, regionB, sessionA, regionA.getMinimumPoint());
|
||||
try {
|
||||
Operations.completeLegacy(copyA);
|
||||
Operations.completeLegacy(copyB);
|
||||
sessionA.flushQueue();
|
||||
sessionB.flushQueue();
|
||||
} catch (MaxChangedBlocksException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
TaskManager.IMP.task(whenDone);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean copyRegion(final Location pos1, final Location pos2, final Location pos3, final Runnable whenDone) {
|
||||
if (!Settings.IMP.PLOTSQUARED_INTEGRATION.COPY_AND_SWAP) {
|
||||
return parent.copyRegion(pos1, pos2, pos3, whenDone);
|
||||
}
|
||||
TaskManager.IMP.async(() -> {
|
||||
synchronized (FaweChunkManager.class) {
|
||||
World pos1World = BukkitAdapter.adapt(getWorld(pos1.getWorld()));
|
||||
World pos3World = BukkitAdapter.adapt(getWorld(pos3.getWorld()));
|
||||
EditSession from = new EditSessionBuilder(pos1World).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build();
|
||||
EditSession to = new EditSessionBuilder(pos3World).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build();
|
||||
CuboidRegion region = new CuboidRegion(BlockVector3.at(pos1.getX(), pos1.getY(), pos1.getZ()), BlockVector3.at(pos2.getX(), pos2.getY(), pos2.getZ()));
|
||||
ForwardExtentCopy copy = new ForwardExtentCopy(from, region, to, BlockVector3.at(pos3.getX(), pos3.getY(), pos3.getZ()));
|
||||
try {
|
||||
Operations.completeLegacy(copy);
|
||||
to.flushQueue();
|
||||
} catch (MaxChangedBlocksException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
TaskManager.IMP.task(whenDone);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean regenerateRegion(final Location pos1, final Location pos2, boolean ignore, final Runnable whenDone) {
|
||||
TaskManager.IMP.async(() -> {
|
||||
synchronized (FaweChunkManager.class) {
|
||||
World pos1World = BukkitAdapter.adapt(getWorld(pos1.getWorld()));
|
||||
try (EditSession editSession = new EditSessionBuilder(pos1World).checkMemory(false)
|
||||
.fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build()) {
|
||||
CuboidRegion region = new CuboidRegion(
|
||||
BlockVector3.at(pos1.getX(), pos1.getY(), pos1.getZ()),
|
||||
BlockVector3.at(pos2.getX(), pos2.getY(), pos2.getZ()));
|
||||
editSession.regenerate(region);
|
||||
editSession.flushQueue();
|
||||
}
|
||||
TaskManager.IMP.task(whenDone);
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,130 @@
|
||||
package com.fastasyncworldedit.bukkit.regions.plotsquaredv4;
|
||||
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.fastasyncworldedit.core.FaweAPI;
|
||||
import com.fastasyncworldedit.core.FaweCache;
|
||||
import com.fastasyncworldedit.core.beta.IQueueChunk;
|
||||
import com.fastasyncworldedit.core.beta.IQueueExtent;
|
||||
import com.github.intellectualsites.plotsquared.plot.util.block.LocalBlockQueue;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.math.MutableBlockVector3;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
|
||||
// TODO FIXME
|
||||
public class FaweLocalBlockQueue extends LocalBlockQueue {
|
||||
|
||||
public final IQueueExtent<IQueueChunk> instance;
|
||||
private final World world;
|
||||
private BlockVector3 mutable = new MutableBlockVector3();
|
||||
|
||||
public FaweLocalBlockQueue(String worldName) {
|
||||
super(worldName);
|
||||
this.world = FaweAPI.getWorld(worldName);
|
||||
instance = Fawe.get().getQueueHandler().getQueue(world);
|
||||
Fawe.get().getQueueHandler().unCache();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean next() {
|
||||
if (!instance.isEmpty()) {
|
||||
instance.flush();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startSet(boolean parallel) {
|
||||
Fawe.get().getQueueHandler().startSet(parallel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endSet(boolean parallel) {
|
||||
Fawe.get().getQueueHandler().endSet(parallel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return instance.isEmpty() ? 0 : 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void optimize() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setModified(long l) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getModified() {
|
||||
return instance.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(final int x, final int y, final int z, final BlockState id) {
|
||||
return instance.setBlock(x, y, z, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(int x, int y, int z, Pattern pattern) {
|
||||
mutable.setComponents(x, y, z);
|
||||
return pattern.apply(instance, mutable, mutable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(final int x, final int y, final int z, final BaseBlock id) {
|
||||
return instance.setBlock(x, y, z, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getBlock(int x, int y, int z) {
|
||||
return instance.getBlock(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBiome(int x, int z, BiomeType biomeType) {
|
||||
return instance.setBiome(x, 0, z, biomeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWorld() {
|
||||
return world.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
instance.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean enqueue() {
|
||||
boolean val = super.enqueue();
|
||||
instance.enableQueue();
|
||||
return val;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refreshChunk(int x, int z) {
|
||||
world.refreshChunk(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fixChunkLighting(int x, int z) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void regenChunk(int x, int z) {
|
||||
instance.regenerateChunk(x, z, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setTile(int x, int y, int z, CompoundTag tag) {
|
||||
instance.setTile(x, y, z, (com.sk89q.jnbt.CompoundTag) FaweCache.IMP.asTag(tag));
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,141 @@
|
||||
package com.fastasyncworldedit.bukkit.regions.plotsquaredv4;
|
||||
|
||||
import com.fastasyncworldedit.core.FaweAPI;
|
||||
import com.fastasyncworldedit.core.FaweCache;
|
||||
import com.fastasyncworldedit.core.object.clipboard.ReadOnlyClipboard;
|
||||
import com.fastasyncworldedit.core.object.io.PGZIPOutputStream;
|
||||
import com.fastasyncworldedit.core.util.EditSessionBuilder;
|
||||
import com.fastasyncworldedit.core.util.IOUtil;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.github.intellectualsites.plotsquared.plot.PlotSquared;
|
||||
import com.github.intellectualsites.plotsquared.plot.object.Location;
|
||||
import com.github.intellectualsites.plotsquared.plot.object.RunnableVal;
|
||||
import com.github.intellectualsites.plotsquared.plot.util.MainUtil;
|
||||
import com.github.intellectualsites.plotsquared.plot.util.SchematicHandler;
|
||||
import com.github.intellectualsites.plotsquared.plot.util.block.LocalBlockQueue;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.CompressedCompoundTag;
|
||||
import com.sk89q.jnbt.fawe.CompressedSchematicTag;
|
||||
import com.sk89q.jnbt.NBTOutputStream;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.BuiltInClipboardFormat;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.FastSchematicWriter;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import net.jpountz.lz4.LZ4BlockInputStream;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URL;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.bukkit.Bukkit.getWorld;
|
||||
|
||||
public class FaweSchematicHandler extends SchematicHandler {
|
||||
@Override
|
||||
public boolean restoreTile(LocalBlockQueue queue, CompoundTag compoundTag, int x, int y, int z) {
|
||||
if (queue instanceof FaweLocalBlockQueue) {
|
||||
queue.setTile(x, y, z, compoundTag);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getCompoundTag(final String world, final Set<CuboidRegion> regions, final RunnableVal<CompoundTag> whenDone) {
|
||||
TaskManager.IMP.async(() -> {
|
||||
Location[] corners = MainUtil.getCorners(world, regions);
|
||||
Location pos1 = corners[0];
|
||||
Location pos2 = corners[1];
|
||||
World adaptedWorld = BukkitAdapter.adapt(getWorld(world));
|
||||
final CuboidRegion region = new CuboidRegion(BlockVector3.at(pos1.getX(), pos1.getY(), pos1.getZ()), BlockVector3.at(pos2.getX(), pos2.getY(), pos2.getZ()));
|
||||
final EditSession editSession = new EditSessionBuilder(adaptedWorld).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build();
|
||||
|
||||
ReadOnlyClipboard clipboard = ReadOnlyClipboard.of(editSession, region, false, true);
|
||||
|
||||
Clipboard holder = new BlockArrayClipboard(region, clipboard);
|
||||
|
||||
CompressedSchematicTag tag = new CompressedSchematicTag(holder);
|
||||
whenDone.run(tag);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean save(CompoundTag tag, String path) {
|
||||
if (tag == null) {
|
||||
PlotSquared.debug("&cCannot save empty tag");
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
File tmp = MainUtil.getFile(PlotSquared.get().IMP.getDirectory(), path);
|
||||
tmp.getParentFile().mkdirs();
|
||||
if (tag instanceof CompressedCompoundTag) {
|
||||
CompressedCompoundTag cTag = (CompressedCompoundTag) tag;
|
||||
if (cTag instanceof CompressedSchematicTag) {
|
||||
Clipboard clipboard = (Clipboard) cTag.getSource();
|
||||
try (OutputStream stream = new FileOutputStream(tmp); NBTOutputStream output = new NBTOutputStream(new BufferedOutputStream(new PGZIPOutputStream(stream)))) {
|
||||
new FastSchematicWriter(output).write(clipboard);
|
||||
}
|
||||
} else {
|
||||
try (OutputStream stream = new FileOutputStream(tmp); BufferedOutputStream output = new BufferedOutputStream(new PGZIPOutputStream(stream))) {
|
||||
LZ4BlockInputStream is = cTag.adapt(cTag.getSource());
|
||||
IOUtil.copy(is, stream);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try (OutputStream stream = new FileOutputStream(tmp); NBTOutputStream output = new NBTOutputStream(new PGZIPOutputStream(stream))) {
|
||||
Map<String, Tag> map = tag.getValue();
|
||||
output.writeNamedTag("Schematic", map.getOrDefault("Schematic", tag));
|
||||
}
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void upload(final CompoundTag tag, final UUID uuid, final String file, final RunnableVal<URL> whenDone) {
|
||||
if (tag == null) {
|
||||
PlotSquared.debug("&cCannot save empty tag");
|
||||
com.github.intellectualsites.plotsquared.plot.util.TaskManager.runTask(whenDone);
|
||||
return;
|
||||
}
|
||||
CompoundTag weTag = (CompoundTag) FaweCache.IMP.asTag(tag);
|
||||
if (weTag instanceof CompressedSchematicTag) {
|
||||
Clipboard clipboard = ((CompressedSchematicTag) weTag).getSource();
|
||||
URL url = FaweAPI.upload(clipboard, BuiltInClipboardFormat.SPONGE_SCHEMATIC);
|
||||
whenDone.run(url);
|
||||
return;
|
||||
}
|
||||
MainUtil.upload(uuid, file, "schem", new RunnableVal<OutputStream>() {
|
||||
@Override
|
||||
public void run(OutputStream output) {
|
||||
try {
|
||||
try (PGZIPOutputStream gzip = new PGZIPOutputStream(output)) {
|
||||
try (NBTOutputStream nos = new NBTOutputStream(gzip)) {
|
||||
Map<String, Tag> map = weTag.getValue();
|
||||
nos.writeNamedTag("Schematic", map.getOrDefault("Schematic", weTag));
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}, whenDone);
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
package com.fastasyncworldedit.bukkit.regions.plotsquaredv4;
|
||||
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.github.intellectualsites.plotsquared.commands.CommandDeclaration;
|
||||
import com.github.intellectualsites.plotsquared.plot.commands.CommandCategory;
|
||||
import com.github.intellectualsites.plotsquared.plot.commands.RequiredType;
|
||||
import com.github.intellectualsites.plotsquared.plot.commands.SubCommand;
|
||||
import com.github.intellectualsites.plotsquared.plot.config.Captions;
|
||||
import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer;
|
||||
import com.github.intellectualsites.plotsquared.plot.util.WorldUtil;
|
||||
|
||||
@CommandDeclaration(
|
||||
command = "trimchunks",
|
||||
permission = "plots.admin",
|
||||
description = "Delete unmodified portions of your plotworld",
|
||||
requiredType = RequiredType.PLAYER,
|
||||
category = CommandCategory.ADMINISTRATION)
|
||||
public class FaweTrim extends SubCommand {
|
||||
|
||||
private boolean ran = false;
|
||||
|
||||
@Override
|
||||
public boolean onCommand(final PlotPlayer plotPlayer, final String[] strings) {
|
||||
if (ran) {
|
||||
plotPlayer.sendMessage("Already running!");
|
||||
return false;
|
||||
}
|
||||
if (strings.length != 2) {
|
||||
plotPlayer.sendMessage("First make a backup of your world called <world-copy> then stand in the middle of an empty plot");
|
||||
plotPlayer.sendMessage("use /plot trimall <world> <boolean-delete-unowned>");
|
||||
return false;
|
||||
}
|
||||
if (!WorldUtil.IMP.isWorld(strings[0])) {
|
||||
Captions.NOT_VALID_PLOT_WORLD.send(plotPlayer, strings[0]);
|
||||
return false;
|
||||
}
|
||||
ran = true;
|
||||
TaskManager.IMP.async(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
// TODO NOT IMPLEMENTED
|
||||
// PlotTrim trim = new PlotTrim(plotPlayer, plotPlayer.getPlotAreaAbs(), strings[0], Boolean.parseBoolean(strings[1]));
|
||||
// Location loc = plotPlayer.getLocation();
|
||||
// trim.setChunk(loc.getX() >> 4, loc.getZ() >> 4);
|
||||
// trim.run();
|
||||
// plotPlayer.sendMessage("Done!");
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
ran = false;
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package com.fastasyncworldedit.bukkit.regions.plotsquaredv4;
|
||||
|
||||
import com.fastasyncworldedit.core.regions.general.CuboidRegionFilter;
|
||||
import com.github.intellectualsites.plotsquared.plot.object.Location;
|
||||
import com.github.intellectualsites.plotsquared.plot.object.Plot;
|
||||
import com.github.intellectualsites.plotsquared.plot.object.PlotArea;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class PlotRegionFilter extends CuboidRegionFilter {
|
||||
private final PlotArea area;
|
||||
|
||||
public PlotRegionFilter(PlotArea area) {
|
||||
checkNotNull(area);
|
||||
this.area = area;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void calculateRegions() {
|
||||
ArrayList<Plot> plots = new ArrayList<>(area.getPlots());
|
||||
for (Plot plot : plots) {
|
||||
Location bottom = plot.getCorners()[0];
|
||||
Location top = plot.getCorners()[1];
|
||||
add(BlockVector2.at(bottom.getX(), bottom.getZ()), BlockVector2.at(top.getX(), top.getZ()));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
package com.fastasyncworldedit.bukkit.regions.plotsquaredv4;
|
||||
|
||||
import com.fastasyncworldedit.core.util.EditSessionBuilder;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.github.intellectualsites.plotsquared.commands.Command;
|
||||
import com.github.intellectualsites.plotsquared.commands.CommandDeclaration;
|
||||
import com.github.intellectualsites.plotsquared.plot.commands.CommandCategory;
|
||||
import com.github.intellectualsites.plotsquared.plot.commands.MainCommand;
|
||||
import com.github.intellectualsites.plotsquared.plot.commands.RequiredType;
|
||||
import com.github.intellectualsites.plotsquared.plot.config.Captions;
|
||||
import com.github.intellectualsites.plotsquared.plot.object.Plot;
|
||||
import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer;
|
||||
import com.github.intellectualsites.plotsquared.plot.object.RunnableVal2;
|
||||
import com.github.intellectualsites.plotsquared.plot.object.RunnableVal3;
|
||||
import com.github.intellectualsites.plotsquared.plot.util.MainUtil;
|
||||
import com.github.intellectualsites.plotsquared.plot.util.Permissions;
|
||||
import com.github.intellectualsites.plotsquared.plot.util.StringMan;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.extension.platform.Capability;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.biome.BiomeTypes;
|
||||
import com.sk89q.worldedit.world.biome.Biomes;
|
||||
import com.sk89q.worldedit.world.registry.BiomeRegistry;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
@CommandDeclaration(
|
||||
command = "generatebiome",
|
||||
permission = "plots.generatebiome",
|
||||
category = CommandCategory.APPEARANCE,
|
||||
requiredType = RequiredType.NONE,
|
||||
description = "Generate a biome in your plot",
|
||||
aliases = {"bg", "gb"},
|
||||
usage = "/plots generatebiome <biome>"
|
||||
)
|
||||
public class PlotSetBiome extends Command {
|
||||
public PlotSetBiome() {
|
||||
super(MainCommand.getInstance(), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> execute(final PlotPlayer player, String[] args, RunnableVal3<Command, Runnable, Runnable> confirm, RunnableVal2<Command, CommandResult> whenDone) throws CommandException {
|
||||
final Plot plot = check(player.getCurrentPlot(), Captions.NOT_IN_PLOT);
|
||||
checkTrue(plot.isOwner(player.getUUID()) || Permissions
|
||||
.hasPermission(player, "plots.admin.command.generatebiome"), Captions.NO_PLOT_PERMS);
|
||||
if (plot.getRunning() != 0) {
|
||||
Captions.WAIT_FOR_TIMER.send(player);
|
||||
return null;
|
||||
}
|
||||
checkTrue(args.length == 1, Captions.COMMAND_SYNTAX, getUsage());
|
||||
final Set<CuboidRegion> regions = plot.getRegions();
|
||||
BiomeRegistry biomeRegistry = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS).getRegistries().getBiomeRegistry();
|
||||
Collection<BiomeType> knownBiomes = BiomeTypes.values();
|
||||
final BiomeType biome = Biomes.findBiomeByName(knownBiomes, args[0], biomeRegistry);
|
||||
if (biome == null) {
|
||||
String biomes = StringMan
|
||||
.join(BiomeType.REGISTRY.values(), Captions.BLOCK_LIST_SEPARATOR.getTranslated());
|
||||
Captions.NEED_BIOME.send(player);
|
||||
MainUtil.sendMessage(player, Captions.SUBCOMMAND_SET_OPTIONS_HEADER.toString() + biomes);
|
||||
return CompletableFuture.completedFuture(false);
|
||||
}
|
||||
confirm.run(this, () -> {
|
||||
if (plot.getRunning() != 0) {
|
||||
Captions.WAIT_FOR_TIMER.send(player);
|
||||
return;
|
||||
}
|
||||
plot.addRunning();
|
||||
TaskManager.IMP.async(() -> {
|
||||
EditSession session = new EditSessionBuilder(BukkitAdapter.adapt(Bukkit.getWorld(plot.getArea().worldname)))
|
||||
.autoQueue(false)
|
||||
.checkMemory(false)
|
||||
.allowedRegionsEverywhere()
|
||||
.player(BukkitAdapter.adapt(Bukkit.getPlayer(player.getUUID())))
|
||||
.limitUnlimited()
|
||||
.build();
|
||||
long seed = ThreadLocalRandom.current().nextLong();
|
||||
for (CuboidRegion region : regions) {
|
||||
session.regenerate(region, biome, seed);
|
||||
}
|
||||
session.flushQueue();
|
||||
plot.removeRunning();
|
||||
});
|
||||
}, null);
|
||||
|
||||
return CompletableFuture.completedFuture(true);
|
||||
}
|
||||
}
|
@ -0,0 +1,175 @@
|
||||
package com.fastasyncworldedit.bukkit.regions.plotsquaredv4;
|
||||
|
||||
import com.fastasyncworldedit.core.FaweAPI;
|
||||
import com.fastasyncworldedit.core.object.RegionWrapper;
|
||||
import com.fastasyncworldedit.core.regions.FaweMask;
|
||||
import com.fastasyncworldedit.core.regions.FaweMaskManager;
|
||||
import com.fastasyncworldedit.core.regions.general.RegionFilter;
|
||||
import com.github.intellectualsites.plotsquared.plot.PlotSquared;
|
||||
import com.github.intellectualsites.plotsquared.plot.commands.MainCommand;
|
||||
import com.github.intellectualsites.plotsquared.plot.config.Settings;
|
||||
import com.github.intellectualsites.plotsquared.plot.database.DBFunc;
|
||||
import com.github.intellectualsites.plotsquared.plot.flag.Flags;
|
||||
import com.github.intellectualsites.plotsquared.plot.listener.WEManager;
|
||||
import com.github.intellectualsites.plotsquared.plot.object.Plot;
|
||||
import com.github.intellectualsites.plotsquared.plot.object.PlotArea;
|
||||
import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer;
|
||||
import com.github.intellectualsites.plotsquared.plot.util.ChunkManager;
|
||||
import com.github.intellectualsites.plotsquared.plot.util.SchematicHandler;
|
||||
import com.github.intellectualsites.plotsquared.plot.util.UUIDHandler;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.regions.RegionIntersection;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class PlotSquaredFeature extends FaweMaskManager {
|
||||
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
|
||||
public PlotSquaredFeature() {
|
||||
super("PlotSquared");
|
||||
LOGGER.debug("Optimizing PlotSquared");
|
||||
if (com.fastasyncworldedit.core.configuration.Settings.IMP.ENABLED_COMPONENTS.PLOTSQUARED_v4_HOOK) {
|
||||
Settings.Enabled_Components.WORLDEDIT_RESTRICTIONS = false;
|
||||
try {
|
||||
setupBlockQueue();
|
||||
setupSchematicHandler();
|
||||
setupChunkManager();
|
||||
} catch (Throwable ignored) {
|
||||
LOGGER.debug("Please update PlotSquared: https://www.spigotmc.org/resources/77506/");
|
||||
}
|
||||
if (Settings.PLATFORM.toLowerCase(Locale.ROOT).startsWith("bukkit")) {
|
||||
new FaweTrim();
|
||||
}
|
||||
if (MainCommand.getInstance().getCommand("generatebiome") == null) {
|
||||
new PlotSetBiome();
|
||||
}
|
||||
}
|
||||
// TODO: revisit this later on
|
||||
/*
|
||||
try {
|
||||
if (Settings.Enabled_Components.WORLDS) {
|
||||
new ReplaceAll();
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
log.debug("You need to update PlotSquared to access the CFI and REPLACEALL commands");
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
public static String getName(UUID uuid) {
|
||||
return UUIDHandler.getName(uuid);
|
||||
}
|
||||
|
||||
private void setupBlockQueue() throws RuntimeException {
|
||||
// If it's going to fail, throw an error now rather than later
|
||||
//QueueProvider provider = QueueProvider.of(FaweLocalBlockQueue.class, null);
|
||||
//GlobalBlockQueue.IMP.setProvider(provider);
|
||||
//HybridPlotManager.REGENERATIVE_CLEAR = false;
|
||||
//log.debug(" - QueueProvider: " + FaweLocalBlockQueue.class);
|
||||
//log.debug(" - HybridPlotManager.REGENERATIVE_CLEAR: " + HybridPlotManager.REGENERATIVE_CLEAR);
|
||||
}
|
||||
|
||||
private void setupChunkManager() throws RuntimeException {
|
||||
ChunkManager.manager = new FaweChunkManager(ChunkManager.manager);
|
||||
LOGGER.debug(" - ChunkManager: " + ChunkManager.manager);
|
||||
}
|
||||
|
||||
private void setupSchematicHandler() throws RuntimeException {
|
||||
SchematicHandler.manager = new FaweSchematicHandler();
|
||||
LOGGER.debug(" - SchematicHandler: " + SchematicHandler.manager);
|
||||
}
|
||||
|
||||
public boolean isAllowed(Player player, Plot plot, MaskType type) {
|
||||
if (plot == null) {
|
||||
return false;
|
||||
}
|
||||
UUID uid = player.getUniqueId();
|
||||
return !Flags.NO_WORLDEDIT.isTrue(plot) && (plot.isOwner(uid)
|
||||
|| type == MaskType.MEMBER && (plot.getTrusted().contains(uid) || plot.getTrusted()
|
||||
.contains(DBFunc.EVERYONE)
|
||||
|| (plot.getMembers().contains(uid) || plot.getMembers().contains(DBFunc.EVERYONE))
|
||||
&& player.hasPermission("fawe.plotsquared.member")) || player
|
||||
.hasPermission("fawe.plotsquared.admin"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public FaweMask getMask(Player player, MaskType type) {
|
||||
final PlotPlayer pp = PlotPlayer.wrap(player.getUniqueId());
|
||||
if (pp == null) {
|
||||
return null;
|
||||
}
|
||||
final Set<CuboidRegion> regions;
|
||||
Plot plot = pp.getCurrentPlot();
|
||||
if (isAllowed(player, plot, type)) {
|
||||
regions = plot.getRegions();
|
||||
} else {
|
||||
plot = null;
|
||||
regions = WEManager.getMask(pp);
|
||||
if (regions.size() == 1) {
|
||||
CuboidRegion region = regions.iterator().next();
|
||||
if (region.getMinimumPoint().getX() == Integer.MIN_VALUE && region.getMaximumPoint().getX() == Integer.MAX_VALUE) {
|
||||
regions.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (regions.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
PlotArea area = pp.getApplicablePlotArea();
|
||||
int min = area != null ? area.MIN_BUILD_HEIGHT : 0;
|
||||
int max = area != null ? Math.min(255, area.MAX_BUILD_HEIGHT) : 255;
|
||||
final HashSet<RegionWrapper> faweRegions = new HashSet<>();
|
||||
for (CuboidRegion current : regions) {
|
||||
faweRegions.add(new RegionWrapper(current.getMinimumX(), current.getMaximumX(), min, max, current.getMinimumZ(), current.getMaximumZ()));
|
||||
}
|
||||
final CuboidRegion region = regions.iterator().next();
|
||||
final BlockVector3 pos1 = BlockVector3.at(region.getMinimumX(), min, region.getMinimumZ());
|
||||
final BlockVector3 pos2 = BlockVector3.at(region.getMaximumX(), max, region.getMaximumZ());
|
||||
final Plot finalPlot = plot;
|
||||
if (Settings.Done.RESTRICT_BUILDING && Flags.DONE.isSet(finalPlot) || regions.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Region maskedRegion;
|
||||
if (regions.size() == 1) {
|
||||
maskedRegion = new CuboidRegion(pos1, pos2);
|
||||
} else {
|
||||
World world = FaweAPI.getWorld(area.worldname);
|
||||
List<Region> weRegions = regions.stream()
|
||||
.map(r -> new CuboidRegion(world, BlockVector3.at(r.getMinimumX(), r.getMinimumY(), r.getMinimumZ()), BlockVector3.at(r.getMaximumX(), r.getMaximumY(), r.getMaximumZ())))
|
||||
.collect(Collectors.toList());
|
||||
maskedRegion = new RegionIntersection(world, weRegions);
|
||||
}
|
||||
|
||||
return new FaweMask(maskedRegion) {
|
||||
@Override
|
||||
public boolean isValid(Player player, MaskType type) {
|
||||
if (Settings.Done.RESTRICT_BUILDING && Flags.DONE.isSet(finalPlot)) {
|
||||
return false;
|
||||
}
|
||||
return isAllowed(player, finalPlot, type);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegionFilter getFilter(String world) {
|
||||
PlotArea area = PlotSquared.get().getPlotArea(world, null);
|
||||
if (area != null) {
|
||||
return new PlotRegionFilter(area);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
package com.fastasyncworldedit.bukkit.util;
|
||||
|
||||
import com.fastasyncworldedit.core.util.ReflectionUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Server;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class BukkitReflectionUtils {
|
||||
/**
|
||||
* Prefix of Bukkit classes.
|
||||
*/
|
||||
private static volatile String preClassB = null;
|
||||
/**
|
||||
* Prefix of Minecraft classes.
|
||||
*/
|
||||
private static volatile String preClassM = null;
|
||||
|
||||
/**
|
||||
* Check server version and class names.
|
||||
*/
|
||||
public static void init() {
|
||||
final Server server = Bukkit.getServer();
|
||||
final Class<?> bukkitServerClass = server.getClass();
|
||||
String[] pas = bukkitServerClass.getName().split("\\.");
|
||||
if (pas.length == 5) {
|
||||
final String verB = pas[3];
|
||||
preClassB = "org.bukkit.craftbukkit." + verB;
|
||||
}
|
||||
try {
|
||||
final Method getHandle = bukkitServerClass.getDeclaredMethod("getHandle");
|
||||
final Object handle = getHandle.invoke(server);
|
||||
final Class<?> handleServerClass = handle.getClass();
|
||||
pas = handleServerClass.getName().split("\\.");
|
||||
if (pas.length == 5) {
|
||||
final String verM = pas[3];
|
||||
preClassM = "net.minecraft.server." + verM;
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static Class<?> getNmsClass(final String name) {
|
||||
final String className = "net.minecraft.server." + getVersion() + "." + name;
|
||||
return ReflectionUtils.getClass(className);
|
||||
}
|
||||
|
||||
public static Class<?> getCbClass(final String name) {
|
||||
final String className = "org.bukkit.craftbukkit." + getVersion() + "." + name;
|
||||
return ReflectionUtils.getClass(className);
|
||||
}
|
||||
|
||||
public static String getVersion() {
|
||||
final String packageName = Bukkit.getServer().getClass().getPackage().getName();
|
||||
return packageName.substring(packageName.lastIndexOf('.') + 1);
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package com.fastasyncworldedit.bukkit.util;
|
||||
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import org.apache.commons.lang.mutable.MutableInt;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class BukkitTaskManager extends TaskManager {
|
||||
|
||||
private final Plugin plugin;
|
||||
|
||||
public BukkitTaskManager(final Plugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int repeat(@NotNull final Runnable runnable, final int interval) {
|
||||
return this.plugin.getServer().getScheduler().scheduleSyncRepeatingTask(this.plugin, runnable, interval, interval);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int repeatAsync(@NotNull final Runnable runnable, final int interval) {
|
||||
return this.plugin.getServer().getScheduler().scheduleAsyncRepeatingTask(this.plugin, runnable, interval, interval);
|
||||
}
|
||||
|
||||
public MutableInt index = new MutableInt(0);
|
||||
|
||||
@Override
|
||||
public void async(@NotNull final Runnable runnable) {
|
||||
this.plugin.getServer().getScheduler().runTaskAsynchronously(this.plugin, runnable).getTaskId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void task(@NotNull final Runnable runnable) {
|
||||
this.plugin.getServer().getScheduler().runTask(this.plugin, runnable).getTaskId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void later(@NotNull final Runnable runnable, final int delay) {
|
||||
this.plugin.getServer().getScheduler().runTaskLater(this.plugin, runnable, delay).getTaskId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void laterAsync(@NotNull final Runnable runnable, final int delay) {
|
||||
this.plugin.getServer().getScheduler().runTaskLaterAsynchronously(this.plugin, runnable, delay);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel(final int task) {
|
||||
if (task != -1) {
|
||||
Bukkit.getScheduler().cancelTask(task);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,116 @@
|
||||
package com.fastasyncworldedit.bukkit.util;
|
||||
|
||||
import com.fastasyncworldedit.core.util.ReflectionUtils;
|
||||
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import static com.google.gson.internal.$Gson$Preconditions.checkNotNull;
|
||||
|
||||
public class ItemUtil {
|
||||
|
||||
private final Method methodAsNMSCopy;
|
||||
private final Method methodGetTag;
|
||||
private final Method methodHasTag;
|
||||
private final Method methodSetTag;
|
||||
private final Method methodAsBukkitCopy;
|
||||
private final Field fieldHandle;
|
||||
private final BukkitImplAdapter adapter;
|
||||
|
||||
private SoftReference<Int2ObjectOpenHashMap<WeakReference<Tag>>> hashToNMSTag = new SoftReference<>(new Int2ObjectOpenHashMap<>());
|
||||
|
||||
public ItemUtil() throws Exception {
|
||||
this.adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
checkNotNull(adapter);
|
||||
Class<?> classCraftItemStack = BukkitReflectionUtils.getCbClass("inventory.CraftItemStack");
|
||||
Class<?> classNMSItem = BukkitReflectionUtils.getNmsClass("ItemStack");
|
||||
this.methodAsNMSCopy = ReflectionUtils.setAccessible(classCraftItemStack.getDeclaredMethod("asNMSCopy", ItemStack.class));
|
||||
this.methodHasTag = ReflectionUtils.setAccessible(classNMSItem.getDeclaredMethod("hasTag"));
|
||||
this.methodGetTag = ReflectionUtils.setAccessible(classNMSItem.getDeclaredMethod("getTag"));
|
||||
this.fieldHandle = ReflectionUtils.setAccessible(classCraftItemStack.getDeclaredField("handle"));
|
||||
Class<?> classNBTTagCompound = BukkitReflectionUtils.getNmsClass("NBTTagCompound");
|
||||
this.methodSetTag = ReflectionUtils.setAccessible(classNMSItem.getDeclaredMethod("setTag", classNBTTagCompound));
|
||||
this.methodAsBukkitCopy = ReflectionUtils.setAccessible(classCraftItemStack.getDeclaredMethod("asBukkitCopy", classNMSItem));
|
||||
}
|
||||
|
||||
public Object getNMSItem(ItemStack item) {
|
||||
try {
|
||||
Object nmsItem = fieldHandle.get(item);
|
||||
if (nmsItem == null) {
|
||||
nmsItem = methodAsNMSCopy.invoke(null, item);
|
||||
}
|
||||
return nmsItem;
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public CompoundTag getNBT(ItemStack item) {
|
||||
try {
|
||||
if (!item.hasItemMeta()) {
|
||||
return null;
|
||||
}
|
||||
Object nmsItem = fieldHandle.get(item);
|
||||
if (nmsItem == null) {
|
||||
nmsItem = methodAsNMSCopy.invoke(null, item);
|
||||
}
|
||||
if (methodHasTag.invoke(nmsItem).equals(true)) {
|
||||
Object nmsTag = methodGetTag.invoke(nmsItem);
|
||||
if (nmsTag == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Int2ObjectOpenHashMap<WeakReference<Tag>> map = hashToNMSTag.get();
|
||||
if (map == null) {
|
||||
map = new Int2ObjectOpenHashMap<>();
|
||||
hashToNMSTag = new SoftReference<>(new Int2ObjectOpenHashMap<>(map));
|
||||
}
|
||||
WeakReference<Tag> nativeTagRef = map.get(nmsTag.hashCode());
|
||||
if (nativeTagRef != null) {
|
||||
Tag nativeTag = nativeTagRef.get();
|
||||
if (nativeTag != null) {
|
||||
return (CompoundTag) nativeTag;
|
||||
}
|
||||
}
|
||||
Tag nativeTag = adapter.toNative(nmsTag);
|
||||
map.put(nmsTag.hashCode(), new WeakReference<>(nativeTag));
|
||||
return null;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public ItemStack setNBT(ItemStack item, CompoundTag tag) {
|
||||
try {
|
||||
Object nmsItem = fieldHandle.get(item);
|
||||
boolean copy = false;
|
||||
if (nmsItem == null) {
|
||||
copy = true;
|
||||
nmsItem = methodAsNMSCopy.invoke(null, item);
|
||||
}
|
||||
Object nmsTag = adapter.fromNative(tag);
|
||||
methodSetTag.invoke(nmsItem, nmsTag);
|
||||
if (copy) {
|
||||
return (ItemStack) methodAsBukkitCopy.invoke(null, nmsItem);
|
||||
}
|
||||
return item;
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,143 @@
|
||||
package com.fastasyncworldedit.bukkit.util;
|
||||
|
||||
import com.google.common.collect.ComparisonChain;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Utility class for retrieving and comparing minecraft server versions.
|
||||
*/
|
||||
public class MinecraftVersion implements Comparable<MinecraftVersion> {
|
||||
|
||||
public static final MinecraftVersion NETHER = new MinecraftVersion(1, 16);
|
||||
|
||||
private final int major;
|
||||
private final int minor;
|
||||
private final int release;
|
||||
|
||||
/**
|
||||
* Construct a new version with major, minor and release version.
|
||||
*
|
||||
* @param major Major part of the version, only {@code 1} would make sense.
|
||||
* @param minor Minor part, full updates, e.g. Nether & Caves & Cliffs
|
||||
* @param release Release, changes for the server software during a minor update.
|
||||
*/
|
||||
public MinecraftVersion(int major, int minor, int release) {
|
||||
this.major = major;
|
||||
this.minor = minor;
|
||||
this.release = release;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new version with major and minor version.
|
||||
* The release version is set to 0, therefore ignored.
|
||||
*
|
||||
* @see MinecraftVersion#MinecraftVersion(int, int, int)
|
||||
*/
|
||||
public MinecraftVersion(int major, int minor) {
|
||||
this(major, minor, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new version with major, minor and release based on the server version.
|
||||
*/
|
||||
public MinecraftVersion() {
|
||||
// Array consists of three version parts, eg. ['v1', '16', 'R3']
|
||||
String[] versionParts = getPackageVersion().split("_");
|
||||
|
||||
if (versionParts.length != 3) {
|
||||
throw new IllegalStateException("Failed to determine minecraft version!");
|
||||
}
|
||||
|
||||
this.major = Integer.parseInt(versionParts[0].substring(1));
|
||||
this.minor = Integer.parseInt(versionParts[1]);
|
||||
this.release = Integer.parseInt(versionParts[2].substring(1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param other The other version to compare against.
|
||||
* @return {@code true} if this version is equal to the other version.
|
||||
*/
|
||||
public boolean isEqual(MinecraftVersion other) {
|
||||
return compareTo(other) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param other The other version to compare against.
|
||||
* @return {@code true} if this version is higher or equal compared to the other version.
|
||||
*/
|
||||
public boolean isEqualOrHigher(MinecraftVersion other) {
|
||||
return compareTo(other) >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param other The other version to compare against.
|
||||
* @return {@code true} if this version is lower or equal compared to the other version.
|
||||
*/
|
||||
public boolean isEqualOrLower(MinecraftVersion other) {
|
||||
return compareTo(other) <= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param other The other version to compare against.
|
||||
* @return {@code true} if this version is higher than the other version.
|
||||
*/
|
||||
public boolean isHigher(MinecraftVersion other) {
|
||||
return compareTo(other) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param other The other version to compare against.
|
||||
* @return {@code true} if this version is lower than to the other version.
|
||||
*/
|
||||
public boolean isLower(MinecraftVersion other) {
|
||||
return compareTo(other) < 0;
|
||||
}
|
||||
|
||||
public int getMajor() {
|
||||
return major;
|
||||
}
|
||||
|
||||
public int getMinor() {
|
||||
return minor;
|
||||
}
|
||||
|
||||
public int getRelease() {
|
||||
return release;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(@NotNull MinecraftVersion other) {
|
||||
if (other.equals(this)) {
|
||||
return 0;
|
||||
}
|
||||
return ComparisonChain.start()
|
||||
.compare(getMajor(), other.getMajor())
|
||||
.compare(getMinor(), other.getMinor())
|
||||
.compare(getRelease(), other.getRelease()).result();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
MinecraftVersion that = (MinecraftVersion) o;
|
||||
|
||||
if (getMajor() != that.getMajor()) return false;
|
||||
if (getMinor() != that.getMinor()) return false;
|
||||
return getRelease() == that.getRelease();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the server version based on the package path, e.g. {@code org.bukkit.craftbukkit.v1_16_R3},
|
||||
* where v1_16_R3 is the resolved version.
|
||||
*
|
||||
* @return The package version.
|
||||
*/
|
||||
private static String getPackageVersion() {
|
||||
String fullPackagePath = Bukkit.getServer().getClass().getPackage().getName();
|
||||
return fullPackagePath.substring(fullPackagePath.lastIndexOf('.') + 1);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package com.fastasyncworldedit.bukkit.util;
|
||||
|
||||
import net.milkbowl.vault.permission.Permission;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.RegisteredServiceProvider;
|
||||
|
||||
public class VaultUtil {
|
||||
public final Permission permission;
|
||||
|
||||
public VaultUtil() {
|
||||
final RegisteredServiceProvider<Permission> permissionProvider =
|
||||
Bukkit.getServer().getServicesManager().getRegistration(Permission.class);
|
||||
if (permissionProvider != null) {
|
||||
this.permission = permissionProvider.getProvider();
|
||||
} else {
|
||||
this.permission = null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,202 @@
|
||||
package com.fastasyncworldedit.bukkit.util.image;
|
||||
|
||||
import com.fastasyncworldedit.core.util.image.Drawable;
|
||||
import com.fastasyncworldedit.core.util.image.ImageUtil;
|
||||
import com.fastasyncworldedit.core.util.image.ImageViewer;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Rotation;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.ItemFrame;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.PlayerInventory;
|
||||
import org.inventivetalent.mapmanager.MapManagerPlugin;
|
||||
import org.inventivetalent.mapmanager.controller.MapController;
|
||||
import org.inventivetalent.mapmanager.controller.MultiMapController;
|
||||
import org.inventivetalent.mapmanager.manager.MapManager;
|
||||
import org.inventivetalent.mapmanager.wrapper.MapWrapper;
|
||||
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class BukkitImageViewer implements ImageViewer {
|
||||
private final MapManager mapManager;
|
||||
private final Player player;
|
||||
private BufferedImage last;
|
||||
private ItemFrame[][] frames;
|
||||
private boolean reverse;
|
||||
|
||||
public BukkitImageViewer(Player player) {
|
||||
mapManager = ((MapManagerPlugin) Bukkit.getPluginManager().getPlugin("MapManager")).getMapManager();
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
public void selectFrame(ItemFrame start) {
|
||||
Location pos1 = start.getLocation().clone();
|
||||
Location pos2 = start.getLocation().clone();
|
||||
|
||||
BlockFace facing = start.getFacing();
|
||||
int planeX = facing.getModX() == 0 ? 1 : 0;
|
||||
int planeY = facing.getModY() == 0 ? 1 : 0;
|
||||
int planeZ = facing.getModZ() == 0 ? 1 : 0;
|
||||
|
||||
ItemFrame[][] res = find(pos1, pos2, facing);
|
||||
Location tmp;
|
||||
while (true) {
|
||||
if (res != null) {
|
||||
frames = res;
|
||||
}
|
||||
tmp = pos1.clone().subtract(planeX, planeY, planeZ);
|
||||
if ((res = find(tmp, pos2, facing)) != null) {
|
||||
pos1 = tmp;
|
||||
continue;
|
||||
}
|
||||
tmp = pos2.clone().add(planeX, planeY, planeZ);
|
||||
if ((res = find(pos1, tmp, facing)) != null) {
|
||||
pos2 = tmp;
|
||||
continue;
|
||||
}
|
||||
tmp = pos1.clone().subtract(planeX, 0, planeZ);
|
||||
if ((res = find(tmp, pos2, facing)) != null) {
|
||||
pos1 = tmp;
|
||||
continue;
|
||||
}
|
||||
tmp = pos2.clone().add(planeX, 0, planeZ);
|
||||
if ((res = find(pos1, tmp, facing)) != null) {
|
||||
pos2 = tmp;
|
||||
continue;
|
||||
}
|
||||
tmp = pos1.clone().subtract(0, 1, 0);
|
||||
if ((res = find(tmp, pos2, facing)) != null) {
|
||||
pos1 = tmp;
|
||||
continue;
|
||||
}
|
||||
tmp = pos2.clone().add(0, 1, 0);
|
||||
if ((res = find(pos1, tmp, facing)) != null) {
|
||||
pos2 = tmp;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public ItemFrame[][] getItemFrames() {
|
||||
return frames;
|
||||
}
|
||||
|
||||
private ItemFrame[][] find(Location pos1, Location pos2, BlockFace facing) {
|
||||
try {
|
||||
Location distance = pos2.clone().subtract(pos1).add(1, 1, 1);
|
||||
int width = Math.max(distance.getBlockX(), distance.getBlockZ());
|
||||
ItemFrame[][] frames = new ItemFrame[width][distance.getBlockY()];
|
||||
|
||||
World world = pos1.getWorld();
|
||||
|
||||
this.reverse = facing == BlockFace.NORTH || facing == BlockFace.EAST;
|
||||
int v = 0;
|
||||
for (double y = pos1.getY(); y <= pos2.getY(); y++, v++) {
|
||||
int h = 0;
|
||||
for (double z = pos1.getZ(); z <= pos2.getZ(); z++) {
|
||||
for (double x = pos1.getX(); x <= pos2.getX(); x++, h++) {
|
||||
Location pos = new Location(world, x, y, z);
|
||||
Collection<Entity> entities = world.getNearbyEntities(pos, 0.1, 0.1, 0.1);
|
||||
boolean contains = false;
|
||||
for (Entity ent : entities) {
|
||||
if (ent instanceof ItemFrame && ent.getFacing() == facing) {
|
||||
ItemFrame itemFrame = (ItemFrame) ent;
|
||||
itemFrame.setRotation(Rotation.NONE);
|
||||
contains = true;
|
||||
frames[reverse ? width - 1 - h : h][v] = (ItemFrame) ent;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!contains) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return frames;
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void view(Drawable drawable) {
|
||||
view(null, drawable);
|
||||
}
|
||||
|
||||
private void view(@Nullable BufferedImage image, @Nullable Drawable drawable) {
|
||||
if (image == null && drawable == null) {
|
||||
throw new IllegalArgumentException("An image or drawable must be provided. Both cannot be null");
|
||||
}
|
||||
boolean initializing = last == null;
|
||||
|
||||
if (this.frames != null) {
|
||||
if (image == null && drawable != null) {
|
||||
image = drawable.draw();
|
||||
}
|
||||
last = image;
|
||||
int width = frames.length;
|
||||
int height = frames[0].length;
|
||||
BufferedImage scaled = ImageUtil.getScaledInstance(image, 128 * width, 128 * height, RenderingHints.VALUE_INTERPOLATION_BILINEAR, false);
|
||||
MapWrapper mapWrapper = mapManager.wrapMultiImage(scaled, width, height);
|
||||
MultiMapController controller = (MultiMapController) mapWrapper.getController();
|
||||
controller.addViewer(player);
|
||||
controller.sendContent(player);
|
||||
controller.showInFrames(player, frames, true);
|
||||
} else {
|
||||
int slot = getMapSlot(player);
|
||||
if (slot == -1) {
|
||||
if (initializing) {
|
||||
player.getInventory().setItemInMainHand(new ItemStack(Material.MAP));
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else if (player.getInventory().getHeldItemSlot() != slot) {
|
||||
player.getInventory().setHeldItemSlot(slot);
|
||||
}
|
||||
if (image == null && drawable != null) {
|
||||
image = drawable.draw();
|
||||
}
|
||||
last = image;
|
||||
BufferedImage scaled = ImageUtil.getScaledInstance(image, 128, 128, RenderingHints.VALUE_INTERPOLATION_BILINEAR, false);
|
||||
MapWrapper mapWrapper = mapManager.wrapImage(scaled);
|
||||
MapController controller = mapWrapper.getController();
|
||||
controller.addViewer(player);
|
||||
controller.sendContent(player);
|
||||
controller.showInHand(player, true);
|
||||
}
|
||||
}
|
||||
|
||||
private int getMapSlot(Player player) {
|
||||
PlayerInventory inventory = player.getInventory();
|
||||
for (int i = 0; i < 9; i++) {
|
||||
ItemStack item = inventory.getItem(i);
|
||||
if (item != null && item.getType() == Material.MAP) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public void refresh() {
|
||||
if (last != null) {
|
||||
view(last, null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
last = null;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user