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:
dordsor21
2021-07-01 21:16:25 +01:00
committed by GitHub
parent b0c0689887
commit aa3ae63682
798 changed files with 5101 additions and 16727 deletions

View File

@ -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);
}
}
}

View File

@ -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.");
}
}
}

View File

@ -0,0 +1,7 @@
package com.fastasyncworldedit.bukkit.adapter;
public interface BukkitGetBlocks {
void send(int mask, boolean lighting);
}

View File

@ -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();
}
}
}
}

View File

@ -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;
}
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}
}

View File

@ -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);
}
}

View File

@ -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));
}
}

View File

@ -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();
}
}
}

View File

@ -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;
}
}
}

View File

@ -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);
}
}
}
}

View File

@ -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);
}
}
}
}

View File

@ -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__");
}
}

View File

@ -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);
}
}
}
}
}

View File

@ -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);
}
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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");
}
}

View File

@ -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));
}
}

View File

@ -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));
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
// }
}

View File

@ -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()));
}
}
}

View File

@ -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());
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}
}
*/

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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()));
}
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}