Mirror von
https://github.com/IntellectualSites/FastAsyncWorldEdit.git
synchronisiert 2024-11-03 01:50:07 +01:00
Merge branch 'commanding' of https://github.com/IntellectualSites/FastAsyncWorldEdit-1.13 into commanding
Dieser Commit ist enthalten in:
Commit
f04cae1686
@ -89,7 +89,7 @@ subprojects {
|
||||
ivy {
|
||||
url 'https://ci.athion.net/job'
|
||||
layout 'pattern', {
|
||||
artifact '/[organisation]/[module]/artifact/[revision].[ext]'
|
||||
artifact '/[organisation]/[revision]/artifact/[module].[ext]'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -27,10 +27,9 @@ dependencies {
|
||||
compile "it.unimi.dsi:fastutil:8.2.1"
|
||||
testCompile 'org.mockito:mockito-core:1.9.0-rc1'
|
||||
implementation('org.apache.logging.log4j:log4j-slf4j-impl:2.8.1'){transitive = false}
|
||||
implementation 'com.destroystokyo.paper:paper-api:1.14.4-R0.1-SNAPSHOT'
|
||||
implementation('io.papermc:paperlib:1.0.2')
|
||||
compileOnly 'org.spigotmc:spigot:1.13.2-R0.1-SNAPSHOT'
|
||||
compileOnly 'BuildTools:lastSuccessfulBuild:spigot-1.14.4@jar'
|
||||
compile 'com.destroystokyo.paper:paper-api:1.14.4-R0.1-SNAPSHOT'
|
||||
implementation('io.papermc:paperlib:1.0.2'){transitive = false}
|
||||
compileOnly 'BuildTools:spigot-1.14.4:lastSuccessfulBuild@jar'
|
||||
implementation('com.sk89q.worldguard:worldguard-core:7.0.0-20190215.210421-39'){transitive = false}
|
||||
implementation('com.sk89q.worldguard:worldguard-legacy:7.0.0-20190215.210421-39'){transitive = false}
|
||||
implementation('com.massivecraft:factions:2.8.0'){transitive = false}
|
||||
@ -48,9 +47,20 @@ dependencies {
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
relocate("it.unimi.dsi.fastutil", "com.sk89q.worldedit.bukkit.fastutil") {
|
||||
include("it.unimi.dsi:fastutil")
|
||||
dependencies {
|
||||
relocate "org.slf4j", "com.sk89q.worldedit.slf4j"
|
||||
relocate "org.apache.logging.slf4j", "com.sk89q.worldedit.log4jbridge"
|
||||
include(dependency(':worldedit-core'))
|
||||
include(dependency(':worldedit-libs:core'))
|
||||
include(dependency(':worldedit-libs:bukkit'))
|
||||
include(dependency('org.slf4j:slf4j-api'))
|
||||
include(dependency("org.apache.logging.log4j:log4j-slf4j-impl"))
|
||||
relocate("it.unimi.dsi.fastutil", "com.sk89q.worldedit.bukkit.fastutil") {
|
||||
include("it.unimi.dsi:fastutil")
|
||||
}
|
||||
}
|
||||
archiveName = "${parent.name}-${project.name.replaceAll("worldedit-", "")}-${parent.version}.jar"
|
||||
destinationDir = file '../target'
|
||||
}
|
||||
|
||||
processResources {
|
||||
@ -103,5 +113,6 @@ task copyFiles {
|
||||
}
|
||||
}
|
||||
}
|
||||
build.dependsOn(shadowJar)
|
||||
build.finalizedBy(copyFiles)
|
||||
copyFiles.dependsOn(createPom)
|
||||
|
@ -13,16 +13,11 @@ import com.boydti.fawe.bukkit.util.BukkitTaskMan;
|
||||
import com.boydti.fawe.bukkit.util.ItemUtil;
|
||||
import com.boydti.fawe.bukkit.util.VaultUtil;
|
||||
import com.boydti.fawe.bukkit.util.image.BukkitImageViewer;
|
||||
import com.boydti.fawe.bukkit.v0.BukkitQueue_0;
|
||||
import com.boydti.fawe.bukkit.v0.BukkitQueue_All;
|
||||
import com.boydti.fawe.bukkit.v0.ChunkListener_8;
|
||||
import com.boydti.fawe.bukkit.v0.ChunkListener_9;
|
||||
import com.boydti.fawe.bukkit.v1_13.BukkitQueue_1_13;
|
||||
import com.boydti.fawe.bukkit.v1_14.BukkitQueue_1_14;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.FaweCommand;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.object.FaweQueue;
|
||||
import com.boydti.fawe.regions.FaweMaskManager;
|
||||
import com.boydti.fawe.util.Jars;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
@ -40,9 +35,11 @@ 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 org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
@ -52,6 +49,9 @@ import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class FaweBukkit implements IFawe, Listener {
|
||||
|
||||
@ -279,102 +279,6 @@ public class FaweBukkit implements IFawe, Listener {
|
||||
return new BukkitTaskMan(plugin);
|
||||
}
|
||||
|
||||
private boolean hasNMS = true;
|
||||
private boolean playerChunk = false;
|
||||
|
||||
@Override
|
||||
public FaweQueue getNewQueue(String world, boolean fast) {
|
||||
if (playerChunk != (playerChunk = true)) {
|
||||
try {
|
||||
Field fieldDirtyCount = BukkitReflectionUtils.getRefClass("{nms}.PlayerChunk").getField("dirtyCount").getRealField();
|
||||
fieldDirtyCount.setAccessible(true);
|
||||
int mod = fieldDirtyCount.getModifiers();
|
||||
if ((mod & Modifier.VOLATILE) == 0) {
|
||||
Field modifiersField = Field.class.getDeclaredField("modifiers");
|
||||
modifiersField.setAccessible(true);
|
||||
modifiersField.setInt(fieldDirtyCount, mod + Modifier.VOLATILE);
|
||||
}
|
||||
} catch (Throwable ignore) {}
|
||||
}
|
||||
try {
|
||||
return getQueue(world);
|
||||
} catch (Throwable throwable) {
|
||||
// Disable incompatible settings
|
||||
Settings.IMP.QUEUE.PARALLEL_THREADS = 1; // BukkitAPI placer is too slow to parallel thread at the chunk level
|
||||
Settings.IMP.HISTORY.COMBINE_STAGES = false; // Performing a chunk copy (if possible) wouldn't be faster using the BukkitAPI
|
||||
if (hasNMS) {
|
||||
|
||||
debug("====== NO NMS BLOCK PLACER FOUND ======");
|
||||
debug("FAWE couldn't find a fast block placer");
|
||||
debug("Bukkit version: " + Bukkit.getVersion());
|
||||
debug("NMS label: " + plugin.getClass().getSimpleName().split("_")[1]);
|
||||
debug("Fallback placer: " + BukkitQueue_All.class);
|
||||
debug("=======================================");
|
||||
debug("Download the version of FAWE for your platform");
|
||||
debug(" - http://ci.athion.net/job/FastAsyncWorldEdit/lastSuccessfulBuild/artifact/target");
|
||||
debug("=======================================");
|
||||
throwable.printStackTrace();
|
||||
debug("=======================================");
|
||||
TaskManager.IMP.laterAsync(
|
||||
() -> MainUtil.sendAdmin("&cNo NMS placer found, see console!"), 1);
|
||||
hasNMS = false;
|
||||
}
|
||||
return new BukkitQueue_All(world);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The FaweQueue is a core part of block placement<br>
|
||||
* - The queue returned here is used in the SetQueue class (SetQueue handles the implementation specific queue)<br>
|
||||
* - Block changes are grouped by chunk (as it's more efficient for lighting/packet sending)<br>
|
||||
* - The FaweQueue returned here will provide the wrapper around the chunk object (FaweChunk)<br>
|
||||
* - When a block change is requested, the SetQueue will first check if the chunk exists in the queue, or it will create and add it<br>
|
||||
*/
|
||||
@Override
|
||||
public FaweQueue getNewQueue(World world, boolean fast) {
|
||||
if (fast) {
|
||||
if (playerChunk != (playerChunk = true)) {
|
||||
try {
|
||||
Field fieldDirtyCount = BukkitReflectionUtils.getRefClass("{nms}.PlayerChunk").getField("dirtyCount").getRealField();
|
||||
fieldDirtyCount.setAccessible(true);
|
||||
int mod = fieldDirtyCount.getModifiers();
|
||||
if ((mod & Modifier.VOLATILE) == 0) {
|
||||
Field modifiersField = Field.class.getDeclaredField("modifiers");
|
||||
modifiersField.setAccessible(true);
|
||||
modifiersField.setInt(fieldDirtyCount, mod + Modifier.VOLATILE);
|
||||
}
|
||||
} catch (Throwable ignore) {
|
||||
}
|
||||
}
|
||||
Throwable error;
|
||||
try {
|
||||
return getQueue(world);
|
||||
} catch (Throwable throwable) {
|
||||
error = throwable;
|
||||
}
|
||||
// Disable incompatible settings
|
||||
Settings.IMP.QUEUE.PARALLEL_THREADS = 1; // BukkitAPI placer is too slow to parallel thread at the chunk level
|
||||
Settings.IMP.HISTORY.COMBINE_STAGES = false; // Performing a chunk copy (if possible) wouldn't be faster using the BukkitAPI
|
||||
if (hasNMS) {
|
||||
debug("====== NO NMS BLOCK PLACER FOUND ======");
|
||||
debug("FAWE couldn't find a fast block placer");
|
||||
debug("Bukkit version: " + Bukkit.getVersion());
|
||||
debug("NMS label: " + plugin.getClass().getSimpleName());
|
||||
debug("Fallback placer: " + BukkitQueue_All.class);
|
||||
debug("=======================================");
|
||||
debug("Download the version of FAWE for your platform");
|
||||
debug(" - http://ci.athion.net/job/FastAsyncWorldEdit/lastSuccessfulBuild/artifact/target");
|
||||
debug("=======================================");
|
||||
error.printStackTrace();
|
||||
debug("=======================================");
|
||||
TaskManager.IMP.laterAsync(
|
||||
() -> MainUtil.sendAdmin("&cNo NMS placer found, see console!"), 1);
|
||||
hasNMS = false;
|
||||
}
|
||||
}
|
||||
return new BukkitQueue_All(world);
|
||||
}
|
||||
|
||||
public Plugin getPlugin() {
|
||||
return plugin;
|
||||
}
|
||||
@ -479,6 +383,25 @@ public class FaweBukkit implements IFawe, Listener {
|
||||
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();
|
||||
@ -520,51 +443,4 @@ public class FaweBukkit implements IFawe, Listener {
|
||||
return null;
|
||||
// return ((BlocksHubBukkit) blocksHubPlugin).getApi();
|
||||
}
|
||||
|
||||
private Version version = null;
|
||||
|
||||
public Version getVersion() {
|
||||
Version tmp = this.version;
|
||||
if (tmp == null) {
|
||||
tmp = Version.NONE;
|
||||
for (Version v : Version.values()) {
|
||||
try {
|
||||
BukkitQueue_0.checkVersion(v.name());
|
||||
this.version = tmp = v;
|
||||
break;
|
||||
} catch (IllegalStateException ignored) {}
|
||||
}
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
public enum Version {
|
||||
v1_14_R1,
|
||||
v1_13_R2,
|
||||
NONE,
|
||||
}
|
||||
|
||||
private FaweQueue getQueue(World world) {
|
||||
switch (getVersion()) {
|
||||
case v1_13_R2:
|
||||
return new BukkitQueue_1_13(world);
|
||||
case v1_14_R1:
|
||||
return new BukkitQueue_1_14(world);
|
||||
default:
|
||||
case NONE:
|
||||
return new BukkitQueue_All(world);
|
||||
}
|
||||
}
|
||||
|
||||
private FaweQueue getQueue(String world) {
|
||||
switch (getVersion()) {
|
||||
case v1_13_R2:
|
||||
return new BukkitQueue_1_13(world);
|
||||
case v1_14_R1:
|
||||
return new BukkitQueue_1_14(world);
|
||||
default:
|
||||
case NONE:
|
||||
return new BukkitQueue_All(world);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,150 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.v1_13_1;
|
||||
|
||||
import com.sk89q.worldedit.world.registry.BlockMaterial;
|
||||
import net.minecraft.server.v1_13_R2.Block;
|
||||
import net.minecraft.server.v1_13_R2.EnumPistonReaction;
|
||||
import net.minecraft.server.v1_13_R2.IBlockData;
|
||||
import net.minecraft.server.v1_13_R2.ITileEntity;
|
||||
import net.minecraft.server.v1_13_R2.Material;
|
||||
import org.bukkit.craftbukkit.v1_13_R2.block.data.CraftBlockData;
|
||||
|
||||
public class BlockMaterial_1_13 implements BlockMaterial {
|
||||
private final Block block;
|
||||
private final IBlockData defaultState;
|
||||
private final Material material;
|
||||
private final boolean isTranslucent;
|
||||
private final CraftBlockData craftBlockData;
|
||||
|
||||
public BlockMaterial_1_13(Block block) {
|
||||
this(block, block.getBlockData());
|
||||
}
|
||||
|
||||
public BlockMaterial_1_13(Block block, IBlockData defaultState) {
|
||||
this.block = block;
|
||||
this.defaultState = defaultState;
|
||||
this.material = defaultState.getMaterial();
|
||||
this.craftBlockData = CraftBlockData.fromData(defaultState);
|
||||
this.isTranslucent = block.f(defaultState); //isSolid
|
||||
}
|
||||
|
||||
public Block getBlock() {
|
||||
return block;
|
||||
}
|
||||
|
||||
public IBlockData getState() {
|
||||
return defaultState;
|
||||
}
|
||||
|
||||
public CraftBlockData getCraftBlockData() {
|
||||
return craftBlockData;
|
||||
}
|
||||
|
||||
public Material getMaterial() {
|
||||
return material;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAir() {
|
||||
return defaultState.isAir();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFullCube() {
|
||||
return defaultState.g();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpaque() {
|
||||
return material.f();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPowerSource() {
|
||||
return defaultState.isPowerSource();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLiquid() {
|
||||
return material.isLiquid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSolid() {
|
||||
return material.isBuildable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getHardness() {
|
||||
return block.strength;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getResistance() {
|
||||
return block.getDurability();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getSlipperiness() {
|
||||
return block.n();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLightValue() {
|
||||
return defaultState.e();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLightOpacity() {
|
||||
return isTranslucent() ? 15 : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFragileWhenPushed() {
|
||||
return material.getPushReaction() == EnumPistonReaction.DESTROY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUnpushable() {
|
||||
return material.getPushReaction() == EnumPistonReaction.BLOCK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTicksRandomly() {
|
||||
return block.isTicking(defaultState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMovementBlocker() {
|
||||
return material.isSolid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBurnable() {
|
||||
return material.isBurnable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isToolRequired() {
|
||||
return !material.isAlwaysDestroyable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReplacedDuringPlacement() {
|
||||
return material.isReplaceable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTranslucent() {
|
||||
return isTranslucent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasContainer() {
|
||||
return block instanceof ITileEntity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMapColor() {
|
||||
return material.i().rgb;
|
||||
}
|
||||
}
|
@ -1,579 +0,0 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.boydti.fawe.bukkit.adapter.v1_13_1;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.jnbt.*;
|
||||
import com.sk89q.worldedit.blocks.TileEntityBlock;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.CachedBukkitAdapter;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.entity.LazyBaseEntity;
|
||||
import com.sk89q.worldedit.internal.Constants;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.registry.state.BooleanProperty;
|
||||
import com.sk89q.worldedit.registry.state.DirectionalProperty;
|
||||
import com.sk89q.worldedit.registry.state.EnumProperty;
|
||||
import com.sk89q.worldedit.registry.state.IntegerProperty;
|
||||
import com.sk89q.worldedit.registry.state.Property;
|
||||
import com.sk89q.worldedit.util.Direction;
|
||||
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.block.BlockTypes;
|
||||
import com.sk89q.worldedit.world.entity.EntityType;
|
||||
import com.sk89q.worldedit.world.registry.BlockMaterial;
|
||||
import net.minecraft.server.v1_13_R2.*;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.craftbukkit.v1_13_R2.CraftChunk;
|
||||
import org.bukkit.craftbukkit.v1_13_R2.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_13_R2.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_13_R2.block.data.CraftBlockData;
|
||||
import org.bukkit.craftbukkit.v1_13_R2.entity.CraftEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public final class Spigot_v1_13_R2 extends CachedBukkitAdapter implements BukkitImplAdapter<NBTBase>{
|
||||
|
||||
private final Logger logger = Logger.getLogger(getClass().getCanonicalName());
|
||||
|
||||
private final Field nbtListTagListField;
|
||||
private final Method nbtCreateTagMethod;
|
||||
|
||||
static {
|
||||
// A simple test
|
||||
if (!Bukkit.getServer().getClass().getName().endsWith("DummyServer")) CraftServer.class.cast(Bukkit.getServer());
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Code that may break between versions of Minecraft
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
public Spigot_v1_13_R2() throws NoSuchFieldException, NoSuchMethodException {
|
||||
// A simple test
|
||||
CraftServer.class.cast(Bukkit.getServer());
|
||||
|
||||
// The list of tags on an NBTTagList
|
||||
nbtListTagListField = NBTTagList.class.getDeclaredField("list");
|
||||
nbtListTagListField.setAccessible(true);
|
||||
|
||||
// The method to create an NBTBase tag given its type ID
|
||||
nbtCreateTagMethod = NBTBase.class.getDeclaredMethod("createTag", byte.class);
|
||||
nbtCreateTagMethod.setAccessible(true);
|
||||
}
|
||||
|
||||
public char[] idbToStateOrdinal;
|
||||
|
||||
private synchronized boolean init() {
|
||||
if (idbToStateOrdinal != null) return false;
|
||||
idbToStateOrdinal = new char[Block.REGISTRY_ID.a()]; // size
|
||||
for (int i = 0; i < idbToStateOrdinal.length; i++) {
|
||||
BlockState state = BlockTypes.states[i];
|
||||
BlockMaterial_1_13 material = (BlockMaterial_1_13) state.getMaterial();
|
||||
int id = Block.REGISTRY_ID.getId(material.getState());
|
||||
idbToStateOrdinal[id] = state.getOrdinalChar();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the given NBT data into the given tile entity.
|
||||
*
|
||||
* @param tileEntity the tile entity
|
||||
* @param tag the tag
|
||||
*/
|
||||
private static void readTagIntoTileEntity(NBTTagCompound tag, TileEntity tileEntity) {
|
||||
try {
|
||||
tileEntity.load(tag);
|
||||
} catch (Throwable e) {
|
||||
Fawe.debug("Invalid tag " + tag + " | " + tileEntity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the tile entity's NBT data to the given tag.
|
||||
*
|
||||
* @param tileEntity the tile entity
|
||||
* @param tag the tag
|
||||
*/
|
||||
private static void readTileEntityIntoTag(TileEntity tileEntity, NBTTagCompound tag) {
|
||||
tileEntity.save(tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ID string of the given entity.
|
||||
*
|
||||
* @param entity the entity
|
||||
* @return the entity ID or null if one is not known
|
||||
*/
|
||||
@Nullable
|
||||
private static String getEntityId(Entity entity) {
|
||||
MinecraftKey minecraftkey = EntityTypes.getName(entity.getBukkitEntity().getHandle().P());
|
||||
|
||||
return minecraftkey == null ? null : minecraftkey.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an entity using the given entity ID.
|
||||
*
|
||||
* @param id the entity ID
|
||||
* @param world the world
|
||||
* @return an entity or null
|
||||
*/
|
||||
@Nullable
|
||||
private static Entity createEntityFromId(String id, World world) {
|
||||
return EntityTypes.a(world, new MinecraftKey(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the given NBT data into the given entity.
|
||||
*
|
||||
* @param entity the entity
|
||||
* @param tag the tag
|
||||
*/
|
||||
private static void readTagIntoEntity(NBTTagCompound tag, Entity entity) {
|
||||
entity.f(tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the entity's NBT data to the given tag.
|
||||
*
|
||||
* @param entity the entity
|
||||
* @param tag the tag
|
||||
*/
|
||||
private static void readEntityIntoTag(Entity entity, NBTTagCompound tag) {
|
||||
entity.save(tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockMaterial getMaterial(BlockType blockType) {
|
||||
return new BlockMaterial_1_13(getBlock(blockType));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockMaterial getMaterial(BlockState state) {
|
||||
IBlockData bs = ((CraftBlockData) Bukkit.createBlockData(state.getAsString())).getState();
|
||||
return new BlockMaterial_1_13(bs.getBlock(), bs);
|
||||
}
|
||||
|
||||
public Block getBlock(BlockType blockType) {
|
||||
return IRegistry.BLOCK.getOrDefault(new MinecraftKey(blockType.getNamespace(), blockType.getResource()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getBlock(Location location) {
|
||||
checkNotNull(location);
|
||||
|
||||
CraftWorld craftWorld = ((CraftWorld) location.getWorld());
|
||||
int x = location.getBlockX();
|
||||
int y = location.getBlockY();
|
||||
int z = location.getBlockZ();
|
||||
|
||||
org.bukkit.block.Block bukkitBlock = location.getBlock();
|
||||
BlockState state = BukkitAdapter.adapt(bukkitBlock.getBlockData());
|
||||
if (state.getBlockType().getMaterial().hasContainer()) {
|
||||
//Read the NBT data
|
||||
TileEntity te = craftWorld.getHandle().getTileEntity(new BlockPosition(x, y, z));
|
||||
if (te != null) {
|
||||
NBTTagCompound tag = new NBTTagCompound();
|
||||
readTileEntityIntoTag(te, tag); // Load data
|
||||
return state.toBaseBlock((CompoundTag) toNative(tag));
|
||||
}
|
||||
}
|
||||
|
||||
return state.toBaseBlock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChunkInUse(org.bukkit.Chunk chunk) {
|
||||
CraftChunk craftChunk = (CraftChunk) chunk;
|
||||
PlayerChunkMap chunkMap = ((WorldServer) craftChunk.getHandle().getWorld()).getPlayerChunkMap();
|
||||
return chunkMap.isChunkInUse(chunk.getX(), chunk.getZ());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(org.bukkit.Chunk chunk, int x, int y, int z, BlockStateHolder state, boolean update) {
|
||||
CraftChunk craftChunk = (CraftChunk) chunk;
|
||||
Chunk nmsChunk = craftChunk.getHandle();
|
||||
World nmsWorld = nmsChunk.getWorld();
|
||||
|
||||
IBlockData blockData = ((BlockMaterial_1_13) state.getMaterial()).getState();
|
||||
ChunkSection[] sections = nmsChunk.getSections();
|
||||
int y4 = y >> 4;
|
||||
ChunkSection section = sections[y4];
|
||||
|
||||
IBlockData existing;
|
||||
if (section == null) {
|
||||
existing = ((BlockMaterial_1_13) BlockTypes.AIR.getDefaultState().getMaterial()).getState();
|
||||
} else {
|
||||
existing = section.getType(x & 15, y & 15, z & 15);
|
||||
}
|
||||
|
||||
BlockPosition pos = new BlockPosition(x, y, z);
|
||||
|
||||
nmsChunk.d(pos); // Force delete the old tile entity
|
||||
|
||||
CompoundTag nativeTag = state instanceof BaseBlock ? state.getNbtData() : null;
|
||||
if (nativeTag != null || existing instanceof TileEntityBlock) {
|
||||
nmsWorld.setTypeAndData(pos, blockData, 0);
|
||||
// remove tile
|
||||
if (nativeTag != null) {
|
||||
// We will assume that the tile entity was created for us,
|
||||
// though we do not do this on the Forge version
|
||||
TileEntity tileEntity = nmsWorld.getTileEntity(pos);
|
||||
if (tileEntity != null) {
|
||||
NBTTagCompound tag = (NBTTagCompound) fromNative(nativeTag);
|
||||
tag.set("x", new NBTTagInt(x));
|
||||
tag.set("y", new NBTTagInt(y));
|
||||
tag.set("z", new NBTTagInt(z));
|
||||
readTagIntoTileEntity(tag, tileEntity); // Load data
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (existing == blockData) return true;
|
||||
if (section == null) {
|
||||
if (blockData.isAir()) return true;
|
||||
sections[y4] = section = new ChunkSection(y4 << 4, nmsWorld.worldProvider.g());
|
||||
}
|
||||
if (existing.e() != blockData.e() || existing.getMaterial().f() != blockData.getMaterial().f()) {
|
||||
nmsChunk.setType(pos = new BlockPosition(x, y, z), blockData, false);
|
||||
} else {
|
||||
section.setType(x & 15, y & 15, z & 15, blockData);
|
||||
}
|
||||
}
|
||||
if (update) {
|
||||
nmsWorld.getMinecraftWorld().notify(pos, existing, blockData, 0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseEntity getEntity(org.bukkit.entity.Entity entity) {
|
||||
checkNotNull(entity);
|
||||
|
||||
CraftEntity craftEntity = ((CraftEntity) entity);
|
||||
Entity mcEntity = craftEntity.getHandle();
|
||||
|
||||
String id = getEntityId(mcEntity);
|
||||
|
||||
if (id != null) {
|
||||
EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id);
|
||||
Supplier<CompoundTag> saveTag = new Supplier<CompoundTag>() {
|
||||
@Override
|
||||
public CompoundTag get() {
|
||||
NBTTagCompound tag = new NBTTagCompound();
|
||||
readEntityIntoTag(mcEntity, tag);
|
||||
return (CompoundTag) toNative(tag);
|
||||
}
|
||||
};
|
||||
return new LazyBaseEntity(type, saveTag);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public org.bukkit.entity.Entity createEntity(Location location, BaseEntity state) {
|
||||
checkNotNull(location);
|
||||
checkNotNull(state);
|
||||
if (state.getType() == com.sk89q.worldedit.world.entity.EntityTypes.PLAYER) return null;
|
||||
CraftWorld craftWorld = ((CraftWorld) location.getWorld());
|
||||
WorldServer worldServer = craftWorld.getHandle();
|
||||
|
||||
Entity createdEntity = createEntityFromId(state.getType().getId(), craftWorld.getHandle());
|
||||
|
||||
if (createdEntity != null) {
|
||||
CompoundTag nativeTag = state.getNbtData();
|
||||
if (nativeTag != null) {
|
||||
NBTTagCompound tag = (NBTTagCompound) fromNative(nativeTag);
|
||||
for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) {
|
||||
tag.remove(name);
|
||||
}
|
||||
readTagIntoEntity(tag, createdEntity);
|
||||
}
|
||||
|
||||
createdEntity.setLocation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
|
||||
|
||||
worldServer.addEntity(createdEntity, SpawnReason.CUSTOM);
|
||||
return createdEntity.getBukkitEntity();
|
||||
} else {
|
||||
Fawe.debug("Invalid entity " + state.getType().getId());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Map<String, ? extends Property<?>> getProperties(BlockType blockType) {
|
||||
Block block;
|
||||
try {
|
||||
block = IRegistry.BLOCK.getOrDefault(new MinecraftKey(blockType.getNamespace(), blockType.getResource()));
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
if (block == null) {
|
||||
logger.warning("Failed to find properties for " + blockType.getId());
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
Map<String, Property<?>> properties = Maps.newLinkedHashMap();
|
||||
BlockStateList<Block, IBlockData> blockStateList = block.getStates();
|
||||
for (IBlockState state : blockStateList.d()) {
|
||||
Property property;
|
||||
if (state instanceof BlockStateBoolean) {
|
||||
property = new BooleanProperty(state.a(), ImmutableList.copyOf(state.d()));
|
||||
} else if (state instanceof BlockStateDirection) {
|
||||
property = new DirectionalProperty(state.a(),
|
||||
(List<Direction>) state.d().stream().map(e -> Direction.valueOf(((INamable) e).getName().toUpperCase(Locale.ROOT))).collect(Collectors.toList()));
|
||||
} else if (state instanceof BlockStateEnum) {
|
||||
property = new EnumProperty(state.a(),
|
||||
(List<String>) state.d().stream().map(e -> ((INamable) e).getName()).collect(Collectors.toList()));
|
||||
} else if (state instanceof BlockStateInteger) {
|
||||
property = new IntegerProperty(state.a(), ImmutableList.copyOf(state.d()));
|
||||
} else {
|
||||
throw new IllegalArgumentException("WorldEdit needs an update to support " + state.getClass().getSimpleName());
|
||||
}
|
||||
|
||||
properties.put(property.getName(), property);
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts from a non-native NMS NBT structure to a native WorldEdit NBT
|
||||
* structure.
|
||||
*
|
||||
* @param foreign non-native NMS NBT structure
|
||||
* @return native WorldEdit NBT structure
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Tag toNative(NBTBase foreign) {
|
||||
if (foreign == null) {
|
||||
return null;
|
||||
}
|
||||
if (foreign instanceof NBTTagCompound) {
|
||||
Map<String, Tag> values = new HashMap<>();
|
||||
Set<String> foreignKeys = ((NBTTagCompound) foreign).getKeys(); // map.keySet
|
||||
|
||||
for (String str : foreignKeys) {
|
||||
NBTBase base = ((NBTTagCompound) foreign).get(str);
|
||||
values.put(str, toNative(base));
|
||||
}
|
||||
return new CompoundTag(values);
|
||||
} else if (foreign instanceof NBTTagByte) {
|
||||
return new ByteTag(((NBTTagByte) foreign).asByte());
|
||||
} else if (foreign instanceof NBTTagByteArray) {
|
||||
return new ByteArrayTag(((NBTTagByteArray) foreign).c()); // data
|
||||
} else if (foreign instanceof NBTTagDouble) {
|
||||
return new DoubleTag(((NBTTagDouble) foreign).asDouble()); // getDouble
|
||||
} else if (foreign instanceof NBTTagFloat) {
|
||||
return new FloatTag(((NBTTagFloat) foreign).asFloat());
|
||||
} else if (foreign instanceof NBTTagInt) {
|
||||
return new IntTag(((NBTTagInt) foreign).asInt());
|
||||
} else if (foreign instanceof NBTTagIntArray) {
|
||||
return new IntArrayTag(((NBTTagIntArray) foreign).d()); // data
|
||||
} else if (foreign instanceof NBTTagLongArray) {
|
||||
return new LongArrayTag(((NBTTagLongArray) foreign).d()); // data
|
||||
} else if (foreign instanceof NBTTagList) {
|
||||
try {
|
||||
return toNativeList((NBTTagList) foreign);
|
||||
} catch (Throwable e) {
|
||||
logger.log(Level.WARNING, "Failed to convert NBTTagList", e);
|
||||
return new ListTag(ByteTag.class, new ArrayList<ByteTag>());
|
||||
}
|
||||
} else if (foreign instanceof NBTTagLong) {
|
||||
return new LongTag(((NBTTagLong) foreign).asLong());
|
||||
} else if (foreign instanceof NBTTagShort) {
|
||||
return new ShortTag(((NBTTagShort) foreign).asShort());
|
||||
} else if (foreign instanceof NBTTagString) {
|
||||
return new StringTag(foreign.asString());
|
||||
} else if (foreign instanceof NBTTagEnd) {
|
||||
return new EndTag();
|
||||
} else {
|
||||
throw new IllegalArgumentException("Don't know how to make native " + foreign.getClass().getCanonicalName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a foreign NBT list tag into a native WorldEdit one.
|
||||
*
|
||||
* @param foreign the foreign tag
|
||||
* @return the converted tag
|
||||
* @throws NoSuchFieldException on error
|
||||
* @throws SecurityException on error
|
||||
* @throws IllegalArgumentException on error
|
||||
* @throws IllegalAccessException on error
|
||||
*/
|
||||
private ListTag toNativeList(NBTTagList foreign) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
|
||||
List<Tag> values = new ArrayList<>();
|
||||
int type = foreign.d();
|
||||
|
||||
List foreignList;
|
||||
foreignList = (List) nbtListTagListField.get(foreign);
|
||||
for (int i = 0; i < foreign.size(); i++) {
|
||||
NBTBase element = (NBTBase) foreignList.get(i);
|
||||
values.add(toNative(element)); // List elements shouldn't have names
|
||||
}
|
||||
|
||||
Class<? extends Tag> cls = NBTConstants.getClassFromType(type);
|
||||
return new ListTag(cls, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a WorldEdit-native NBT structure to a NMS structure.
|
||||
*
|
||||
* @param foreign structure to convert
|
||||
* @return non-native structure
|
||||
*/
|
||||
@Override
|
||||
public NBTBase fromNative(Tag foreign) {
|
||||
if (foreign == null) {
|
||||
return null;
|
||||
}
|
||||
if (foreign instanceof CompoundTag) {
|
||||
NBTTagCompound tag = new NBTTagCompound();
|
||||
for (Map.Entry<String, Tag> entry : ((CompoundTag) foreign)
|
||||
.getValue().entrySet()) {
|
||||
tag.set(entry.getKey(), fromNative(entry.getValue()));
|
||||
}
|
||||
return tag;
|
||||
} else if (foreign instanceof ByteTag) {
|
||||
return new NBTTagByte(((ByteTag) foreign).getValue());
|
||||
} else if (foreign instanceof ByteArrayTag) {
|
||||
return new NBTTagByteArray(((ByteArrayTag) foreign).getValue());
|
||||
} else if (foreign instanceof DoubleTag) {
|
||||
return new NBTTagDouble(((DoubleTag) foreign).getValue());
|
||||
} else if (foreign instanceof FloatTag) {
|
||||
return new NBTTagFloat(((FloatTag) foreign).getValue());
|
||||
} else if (foreign instanceof IntTag) {
|
||||
return new NBTTagInt(((IntTag) foreign).getValue());
|
||||
} else if (foreign instanceof IntArrayTag) {
|
||||
return new NBTTagIntArray(((IntArrayTag) foreign).getValue());
|
||||
} else if (foreign instanceof LongArrayTag) {
|
||||
return new NBTTagLongArray(((LongArrayTag) foreign).getValue());
|
||||
} else if (foreign instanceof ListTag) {
|
||||
NBTTagList tag = new NBTTagList();
|
||||
ListTag foreignList = (ListTag) foreign;
|
||||
for (Tag t : foreignList.getValue()) {
|
||||
tag.add(fromNative(t));
|
||||
}
|
||||
return tag;
|
||||
} else if (foreign instanceof LongTag) {
|
||||
return new NBTTagLong(((LongTag) foreign).getValue());
|
||||
} else if (foreign instanceof ShortTag) {
|
||||
return new NBTTagShort(((ShortTag) foreign).getValue());
|
||||
} else if (foreign instanceof StringTag) {
|
||||
return new NBTTagString(((StringTag) foreign).getValue());
|
||||
} else if (foreign instanceof EndTag) {
|
||||
try {
|
||||
return (NBTBase) nbtCreateTagMethod.invoke(null, (byte) 0);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("Don't know how to make NMS " + foreign.getClass().getCanonicalName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState adapt(BlockData blockData) {
|
||||
CraftBlockData cbd = ((CraftBlockData) blockData);
|
||||
IBlockData ibd = cbd.getState();
|
||||
return adapt(ibd);
|
||||
}
|
||||
|
||||
public BlockState adapt(IBlockData ibd) {
|
||||
return BlockTypes.states[adaptToInt(ibd)];
|
||||
}
|
||||
|
||||
public int adaptToInt(IBlockData ibd) {
|
||||
try {
|
||||
int id = Block.REGISTRY_ID.getId(ibd);
|
||||
return idbToStateOrdinal[id];
|
||||
} catch (NullPointerException e) {
|
||||
init();
|
||||
return adaptToInt(ibd);
|
||||
}
|
||||
}
|
||||
|
||||
public char adaptToChar(IBlockData ibd) {
|
||||
try {
|
||||
int id = Block.REGISTRY_ID.getId(ibd);
|
||||
return idbToStateOrdinal[id];
|
||||
} catch (NullPointerException e) {
|
||||
init();
|
||||
return adaptToChar(ibd);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockData adapt(BlockStateHolder state) {
|
||||
BlockMaterial_1_13 material = (BlockMaterial_1_13) state.getMaterial();
|
||||
return material.getCraftBlockData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendFakeNBT(Player player, BlockVector3 pos, CompoundTag nbtData) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyAndLightBlock(Location position, BlockState previousType) {
|
||||
this.setBlock(position.getChunk(), position.getBlockX(), position.getBlockY(), position.getBlockZ(), previousType, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(Location location, BlockStateHolder<?> state, boolean notifyAndLight) {
|
||||
return this.setBlock(location.getChunk(), location.getBlockX(), location.getBlockY(), location.getBlockZ(), state, notifyAndLight);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendFakeOP(Player player) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
}
|
@ -1,356 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.beta;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.IQueueExtent;
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.boydti.fawe.beta.implementation.QueueHandler;
|
||||
import com.boydti.fawe.beta.implementation.holder.ChunkHolder;
|
||||
import com.boydti.fawe.util.MemUtil;
|
||||
import com.boydti.fawe.util.ReflectionUtils;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.ListTag;
|
||||
import com.sk89q.jnbt.LongTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.internal.Constants;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import net.minecraft.server.v1_14_R1.BiomeBase;
|
||||
import net.minecraft.server.v1_14_R1.BlockPosition;
|
||||
import net.minecraft.server.v1_14_R1.Chunk;
|
||||
import net.minecraft.server.v1_14_R1.ChunkSection;
|
||||
import net.minecraft.server.v1_14_R1.Entity;
|
||||
import net.minecraft.server.v1_14_R1.EntityTypes;
|
||||
import net.minecraft.server.v1_14_R1.NBTTagCompound;
|
||||
import net.minecraft.server.v1_14_R1.NBTTagInt;
|
||||
import net.minecraft.server.v1_14_R1.TileEntity;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.craftbukkit.v1_14_R1.block.CraftBlock;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
public class BukkitChunkHolder<T extends Future<T>> extends ChunkHolder {
|
||||
@Override
|
||||
public void init(final IQueueExtent extent, final int chunkX, final int chunkZ) {
|
||||
super.init(extent, chunkX, chunkZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkGet get() {
|
||||
BukkitQueue extent = (BukkitQueue) getExtent();
|
||||
return new BukkitGetBlocks(extent.getNmsWorld(), getX(), getZ(), MemUtil.isMemoryFree());
|
||||
}
|
||||
|
||||
private void updateGet(BukkitGetBlocks get, Chunk nmsChunk, ChunkSection[] sections, ChunkSection section, char[] arr, int layer) {
|
||||
synchronized (get) {
|
||||
if (get.nmsChunk != nmsChunk) {
|
||||
get.nmsChunk = nmsChunk;
|
||||
get.sections = sections.clone();
|
||||
get.reset();
|
||||
}
|
||||
if (get.sections == null) {
|
||||
get.sections = sections.clone();
|
||||
}
|
||||
if (get.sections[layer] != section) {
|
||||
get.sections[layer] = section;
|
||||
}
|
||||
get.blocks[layer] = arr;
|
||||
}
|
||||
}
|
||||
|
||||
private void removeEntity(Entity entity) {
|
||||
entity.die();
|
||||
entity.valid = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized T call() {
|
||||
try {
|
||||
int X = getX();
|
||||
int Z = getZ();
|
||||
BukkitQueue extent = (BukkitQueue) getExtent();
|
||||
BukkitGetBlocks get = (BukkitGetBlocks) getOrCreateGet();
|
||||
IChunkSet set = getOrCreateSet();
|
||||
|
||||
Chunk nmsChunk = extent.ensureLoaded(X, Z);
|
||||
|
||||
// Remove existing tiles
|
||||
{
|
||||
Map<BlockPosition, TileEntity> tiles = nmsChunk.getTileEntities();
|
||||
if (!tiles.isEmpty()) {
|
||||
final Iterator<Map.Entry<BlockPosition, TileEntity>> iterator = tiles.entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
final Map.Entry<BlockPosition, TileEntity> entry = iterator.next();
|
||||
final BlockPosition pos = entry.getKey();
|
||||
final int lx = pos.getX() & 15;
|
||||
final int ly = pos.getY();
|
||||
final int lz = pos.getZ() & 15;
|
||||
final int layer = ly >> 4;
|
||||
if (!set.hasSection(layer)) {
|
||||
continue;
|
||||
}
|
||||
if (set.getBlock(lx, ly, lz).getOrdinal() != 0) {
|
||||
TileEntity tile = entry.getValue();
|
||||
tile.n();
|
||||
tile.invalidateBlockCache();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int bitMask = 0;
|
||||
synchronized (nmsChunk) {
|
||||
ChunkSection[] sections = nmsChunk.getSections();
|
||||
World world = extent.getBukkitWorld();
|
||||
boolean hasSky = world.getEnvironment() == World.Environment.NORMAL;
|
||||
|
||||
for (int layer = 0; layer < 16; layer++) {
|
||||
if (!set.hasSection(layer)) continue;
|
||||
|
||||
bitMask |= 1 << layer;
|
||||
|
||||
char[] setArr = set.getArray(layer);
|
||||
ChunkSection newSection;
|
||||
ChunkSection existingSection = sections[layer];
|
||||
if (existingSection == null) {
|
||||
newSection = extent.newChunkSection(layer, setArr);
|
||||
if (BukkitQueue.setSectionAtomic(sections, null, newSection, layer)) {
|
||||
updateGet(get, nmsChunk, sections, newSection, setArr, layer);
|
||||
continue;
|
||||
} else {
|
||||
existingSection = sections[layer];
|
||||
if (existingSection == null) {
|
||||
System.out.println("Skipping invalid null section. chunk:" + X + "," + Z + " layer: " + layer);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
DelegateLock lock = BukkitQueue.applyLock(existingSection);
|
||||
synchronized (get) {
|
||||
synchronized (lock) {
|
||||
lock.untilFree();
|
||||
|
||||
ChunkSection getSection;
|
||||
if (get.nmsChunk != nmsChunk) {
|
||||
get.nmsChunk = nmsChunk;
|
||||
get.sections = null;
|
||||
get.reset();
|
||||
} else {
|
||||
getSection = get.getSections()[layer];
|
||||
if (getSection != existingSection) {
|
||||
get.sections[layer] = existingSection;
|
||||
get.reset();
|
||||
} else if (lock.isModified()) {
|
||||
get.reset(layer);
|
||||
}
|
||||
}
|
||||
char[] getArr = get.load(layer);
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
char value = setArr[i];
|
||||
if (value != 0) {
|
||||
getArr[i] = value;
|
||||
}
|
||||
}
|
||||
newSection = extent.newChunkSection(layer, getArr);
|
||||
if (!BukkitQueue.setSectionAtomic(sections, existingSection, newSection, layer)) {
|
||||
System.out.println("Failed to set chunk section:" + X + "," + Z + " layer: " + layer);
|
||||
continue;
|
||||
} else {
|
||||
updateGet(get, nmsChunk, sections, newSection, setArr, layer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Biomes
|
||||
BiomeType[] biomes = set.getBiomes();
|
||||
if (biomes != null) {
|
||||
// set biomes
|
||||
final BiomeBase[] currentBiomes = nmsChunk.getBiomeIndex();
|
||||
for (int i = 0; i < biomes.length; i++) {
|
||||
final BiomeType biome = biomes[i];
|
||||
if (biome != null) {
|
||||
final Biome craftBiome = BukkitAdapter.adapt(biome);
|
||||
currentBiomes[i] = CraftBlock.biomeToBiomeBase(craftBiome);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Runnable[] syncTasks = null;
|
||||
|
||||
net.minecraft.server.v1_14_R1.World nmsWorld = nmsChunk.getWorld();
|
||||
int bx = X << 4;
|
||||
int bz = Z << 4;
|
||||
|
||||
Set<UUID> entityRemoves = set.getEntityRemoves();
|
||||
if (entityRemoves != null && !entityRemoves.isEmpty()) {
|
||||
if (syncTasks == null) syncTasks = new Runnable[3];
|
||||
|
||||
syncTasks[2] = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final List<Entity>[] entities = nmsChunk.getEntitySlices();
|
||||
|
||||
for (int i = 0; i < entities.length; i++) {
|
||||
final Collection<Entity> ents = entities[i];
|
||||
if (!ents.isEmpty()) {
|
||||
final Iterator<Entity> iter = ents.iterator();
|
||||
while (iter.hasNext()) {
|
||||
final Entity entity = iter.next();
|
||||
if (entityRemoves.contains(entity.getUniqueID())) {
|
||||
iter.remove();
|
||||
removeEntity(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Set<CompoundTag> entities = set.getEntities();
|
||||
if (entities != null && !entities.isEmpty()) {
|
||||
if (syncTasks == null) syncTasks = new Runnable[2];
|
||||
|
||||
syncTasks[1] = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (final CompoundTag nativeTag : entities) {
|
||||
final Map<String, Tag> entityTagMap = ReflectionUtils.getMap(nativeTag.getValue());
|
||||
final StringTag idTag = (StringTag) entityTagMap.get("Id");
|
||||
final ListTag posTag = (ListTag) entityTagMap.get("Pos");
|
||||
final ListTag rotTag = (ListTag) entityTagMap.get("Rotation");
|
||||
if (idTag == null || posTag == null || rotTag == null) {
|
||||
Fawe.debug("Unknown entity tag: " + nativeTag);
|
||||
continue;
|
||||
}
|
||||
final double x = posTag.getDouble(0);
|
||||
final double y = posTag.getDouble(1);
|
||||
final double z = posTag.getDouble(2);
|
||||
final float yaw = rotTag.getFloat(0);
|
||||
final float pitch = rotTag.getFloat(1);
|
||||
final String id = idTag.getValue();
|
||||
|
||||
EntityTypes<?> type = EntityTypes.a(id).orElse(null);
|
||||
if (type != null) {
|
||||
Entity entity = type.a(nmsWorld);
|
||||
if (entity != null) {
|
||||
UUID uuid = entity.getUniqueID();
|
||||
entityTagMap.put("UUIDMost", new LongTag(uuid.getMostSignificantBits()));
|
||||
entityTagMap.put("UUIDLeast", new LongTag(uuid.getLeastSignificantBits()));
|
||||
if (nativeTag != null) {
|
||||
final NBTTagCompound tag = (NBTTagCompound) BukkitQueue_1_14.fromNative(nativeTag);
|
||||
for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) {
|
||||
tag.remove(name);
|
||||
}
|
||||
entity.f(tag);
|
||||
}
|
||||
entity.setLocation(x, y, z, yaw, pitch);
|
||||
nmsWorld.addEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// set tiles
|
||||
Map<Short, CompoundTag> tiles = set.getTiles();
|
||||
if (tiles != null && !tiles.isEmpty()) {
|
||||
if (syncTasks == null) syncTasks = new Runnable[1];
|
||||
|
||||
syncTasks[0] = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (final Map.Entry<Short, CompoundTag> entry : tiles.entrySet()) {
|
||||
final CompoundTag nativeTag = entry.getValue();
|
||||
final short blockHash = entry.getKey();
|
||||
final int x = (blockHash >> 12 & 0xF) + bx;
|
||||
final int y = (blockHash & 0xFF);
|
||||
final int z = (blockHash >> 8 & 0xF) + bz;
|
||||
final BlockPosition pos = new BlockPosition(x, y, z);
|
||||
synchronized (nmsWorld) {
|
||||
TileEntity tileEntity = nmsWorld.getTileEntity(pos);
|
||||
if (tileEntity == null || tileEntity.isRemoved()) {
|
||||
nmsWorld.removeTileEntity(pos);
|
||||
tileEntity = nmsWorld.getTileEntity(pos);
|
||||
}
|
||||
if (tileEntity != null) {
|
||||
final NBTTagCompound tag = (NBTTagCompound) fromNative(nativeTag);
|
||||
tag.set("x", new NBTTagInt(x));
|
||||
tag.set("y", new NBTTagInt(y));
|
||||
tag.set("z", new NBTTagInt(z));
|
||||
tileEntity.load(tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Runnable callback;
|
||||
if (bitMask == 0) {
|
||||
callback = null;
|
||||
} else {
|
||||
int finalMask = bitMask;
|
||||
callback = () -> {
|
||||
// Set Modified
|
||||
nmsChunk.d(true); // Set Modified
|
||||
nmsChunk.mustNotSave = false;
|
||||
nmsChunk.markDirty();
|
||||
// send to player
|
||||
extent.sendChunk(X, Z, finalMask);
|
||||
|
||||
extent.returnToPool(BukkitChunkHolder.this);
|
||||
};
|
||||
}
|
||||
if (syncTasks != null) {
|
||||
QueueHandler queueHandler = Fawe.get().getQueueHandler();
|
||||
Runnable[] finalSyncTasks = syncTasks;
|
||||
|
||||
// Chain the sync tasks and the callback
|
||||
Callable<Future> chain = new Callable<Future>() {
|
||||
@Override
|
||||
public Future call() {
|
||||
// Run the sync tasks
|
||||
for (int i = 1; i < finalSyncTasks.length; i++) {
|
||||
Runnable task = finalSyncTasks[i];
|
||||
if (task != null) {
|
||||
task.run();
|
||||
}
|
||||
}
|
||||
if (callback == null) {
|
||||
extent.returnToPool(BukkitChunkHolder.this);
|
||||
return null;
|
||||
} else {
|
||||
return queueHandler.async(callback, null);
|
||||
}
|
||||
}
|
||||
};
|
||||
return (T) (Future) queueHandler.sync(chain);
|
||||
} else {
|
||||
if (callback == null) {
|
||||
extent.returnToPool(BukkitChunkHolder.this);
|
||||
} else {
|
||||
callback.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,54 +1,76 @@
|
||||
package com.boydti.fawe.bukkit.beta;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.boydti.fawe.beta.implementation.QueueHandler;
|
||||
import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks;
|
||||
import com.boydti.fawe.bukkit.v1_14.BukkitQueue_1_14;
|
||||
import com.boydti.fawe.bukkit.v1_14.adapter.Spigot_v1_14_R1;
|
||||
import com.boydti.fawe.jnbt.anvil.BitArray4096;
|
||||
import com.boydti.fawe.util.MemUtil;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.boydti.fawe.object.collection.BitArray4096;
|
||||
import com.boydti.fawe.util.ReflectionUtils;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.ListTag;
|
||||
import com.sk89q.jnbt.LongTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.internal.Constants;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import net.minecraft.server.v1_14_R1.BiomeBase;
|
||||
import net.minecraft.server.v1_14_R1.BlockPosition;
|
||||
import net.minecraft.server.v1_14_R1.Chunk;
|
||||
import net.minecraft.server.v1_14_R1.ChunkCoordIntPair;
|
||||
import net.minecraft.server.v1_14_R1.ChunkProviderServer;
|
||||
import net.minecraft.server.v1_14_R1.ChunkSection;
|
||||
import net.minecraft.server.v1_14_R1.DataBits;
|
||||
import net.minecraft.server.v1_14_R1.DataPalette;
|
||||
import net.minecraft.server.v1_14_R1.DataPaletteBlock;
|
||||
import net.minecraft.server.v1_14_R1.DataPaletteHash;
|
||||
import net.minecraft.server.v1_14_R1.DataPaletteLinear;
|
||||
import net.minecraft.server.v1_14_R1.Entity;
|
||||
import net.minecraft.server.v1_14_R1.EntityTypes;
|
||||
import net.minecraft.server.v1_14_R1.IBlockData;
|
||||
import net.minecraft.server.v1_14_R1.World;
|
||||
import net.minecraft.server.v1_14_R1.NBTTagCompound;
|
||||
import net.minecraft.server.v1_14_R1.NBTTagInt;
|
||||
import net.minecraft.server.v1_14_R1.TileEntity;
|
||||
import net.minecraft.server.v1_14_R1.WorldServer;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.craftbukkit.v1_14_R1.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_14_R1.block.CraftBlock;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
public class BukkitGetBlocks extends CharGetBlocks {
|
||||
public ChunkSection[] sections;
|
||||
public Chunk nmsChunk;
|
||||
public World nmsWorld;
|
||||
public CraftWorld world;
|
||||
public int X, Z;
|
||||
private boolean forceLoad;
|
||||
|
||||
public BukkitGetBlocks(World nmsWorld, int X, int Z, boolean forceLoad) {
|
||||
this.nmsWorld = nmsWorld;
|
||||
public BukkitGetBlocks(World world, int X, int Z, boolean forceLoad) {
|
||||
this.world = (CraftWorld) world;
|
||||
this.X = X;
|
||||
this.Z = Z;
|
||||
if (forceLoad) {
|
||||
((WorldServer) nmsWorld).setForceLoaded(X, Z, this.forceLoad = true);
|
||||
this.world.getHandle().setForceLoaded(X, Z, this.forceLoad = true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() {
|
||||
if (forceLoad) {
|
||||
((WorldServer) nmsWorld).setForceLoaded(X, Z, forceLoad = false);
|
||||
this.world.getHandle().setForceLoaded(X, Z, forceLoad = false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,14 +91,310 @@ public class BukkitGetBlocks extends CharGetBlocks {
|
||||
return load(layer, null);
|
||||
}
|
||||
|
||||
private void updateGet(BukkitGetBlocks get, Chunk nmsChunk, ChunkSection[] sections, ChunkSection section, char[] arr, int layer) {
|
||||
synchronized (get) {
|
||||
if (this.nmsChunk != nmsChunk) {
|
||||
this.nmsChunk = nmsChunk;
|
||||
this.sections = sections.clone();
|
||||
this.reset();
|
||||
}
|
||||
if (this.sections == null) {
|
||||
this.sections = sections.clone();
|
||||
}
|
||||
if (this.sections[layer] != section) {
|
||||
this.sections[layer] = section;
|
||||
}
|
||||
this.blocks[layer] = arr;
|
||||
}
|
||||
}
|
||||
|
||||
private void removeEntity(Entity entity) {
|
||||
entity.die();
|
||||
entity.valid = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
|
||||
try {
|
||||
WorldServer nmsWorld = world.getHandle();
|
||||
Chunk nmsChunk = BukkitQueue.ensureLoaded(nmsWorld, X, Z);
|
||||
|
||||
// Remove existing tiles
|
||||
|
||||
{
|
||||
Map<BlockPosition, TileEntity> tiles = nmsChunk.getTileEntities();
|
||||
if (!tiles.isEmpty()) {
|
||||
final Iterator<Map.Entry<BlockPosition, TileEntity>> iterator = tiles.entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
final Map.Entry<BlockPosition, TileEntity> entry = iterator.next();
|
||||
final BlockPosition pos = entry.getKey();
|
||||
final int lx = pos.getX() & 15;
|
||||
final int ly = pos.getY();
|
||||
final int lz = pos.getZ() & 15;
|
||||
final int layer = ly >> 4;
|
||||
if (!set.hasSection(layer)) {
|
||||
continue;
|
||||
}
|
||||
if (set.getBlock(lx, ly, lz).getOrdinal() != 0) {
|
||||
TileEntity tile = entry.getValue();
|
||||
tile.n();
|
||||
tile.invalidateBlockCache();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int bitMask = 0;
|
||||
synchronized (nmsChunk) {
|
||||
ChunkSection[] sections = nmsChunk.getSections();
|
||||
|
||||
for (int layer = 0; layer < 16; layer++) {
|
||||
if (!set.hasSection(layer)) continue;
|
||||
|
||||
bitMask |= 1 << layer;
|
||||
|
||||
char[] setArr = set.getArray(layer);
|
||||
ChunkSection newSection;
|
||||
ChunkSection existingSection = sections[layer];
|
||||
if (existingSection == null) {
|
||||
newSection = BukkitQueue.newChunkSection(layer, setArr);
|
||||
if (BukkitQueue.setSectionAtomic(sections, null, newSection, layer)) {
|
||||
updateGet(this, nmsChunk, sections, newSection, setArr, layer);
|
||||
continue;
|
||||
} else {
|
||||
existingSection = sections[layer];
|
||||
if (existingSection == null) {
|
||||
System.out.println("Skipping invalid null section. chunk:" + X + "," + Z + " layer: " + layer);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
DelegateLock lock = BukkitQueue.applyLock(existingSection);
|
||||
synchronized (this) {
|
||||
synchronized (lock) {
|
||||
lock.untilFree();
|
||||
ChunkSection getSection;
|
||||
if (this.nmsChunk != nmsChunk) {
|
||||
this.nmsChunk = nmsChunk;
|
||||
this.sections = null;
|
||||
this.reset();
|
||||
} else {
|
||||
getSection = this.getSections()[layer];
|
||||
if (getSection != existingSection) {
|
||||
this.sections[layer] = existingSection;
|
||||
this.reset();
|
||||
} else if (lock.isModified()) {
|
||||
this.reset(layer);
|
||||
}
|
||||
}
|
||||
char[] getArr = this.load(layer);
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
char value = setArr[i];
|
||||
if (value != 0) {
|
||||
getArr[i] = value;
|
||||
}
|
||||
}
|
||||
newSection = BukkitQueue.newChunkSection(layer, getArr);
|
||||
if (!BukkitQueue.setSectionAtomic(sections, existingSection, newSection, layer)) {
|
||||
System.out.println("Failed to set chunk section:" + X + "," + Z + " layer: " + layer);
|
||||
continue;
|
||||
} else {
|
||||
updateGet(this, nmsChunk, sections, newSection, setArr, layer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Biomes
|
||||
BiomeType[] biomes = set.getBiomes();
|
||||
if (biomes != null) {
|
||||
// set biomes
|
||||
final BiomeBase[] currentBiomes = nmsChunk.getBiomeIndex();
|
||||
for (int i = 0; i < biomes.length; i++) {
|
||||
final BiomeType biome = biomes[i];
|
||||
if (biome != null) {
|
||||
final Biome craftBiome = BukkitAdapter.adapt(biome);
|
||||
currentBiomes[i] = CraftBlock.biomeToBiomeBase(craftBiome);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Runnable[] syncTasks = null;
|
||||
|
||||
int bx = X << 4;
|
||||
int bz = Z << 4;
|
||||
|
||||
Set<UUID> entityRemoves = set.getEntityRemoves();
|
||||
if (entityRemoves != null && !entityRemoves.isEmpty()) {
|
||||
if (syncTasks == null) syncTasks = new Runnable[3];
|
||||
|
||||
syncTasks[2] = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final List<Entity>[] entities = nmsChunk.getEntitySlices();
|
||||
|
||||
for (int i = 0; i < entities.length; i++) {
|
||||
final Collection<Entity> ents = entities[i];
|
||||
if (!ents.isEmpty()) {
|
||||
final Iterator<Entity> iter = ents.iterator();
|
||||
while (iter.hasNext()) {
|
||||
final Entity entity = iter.next();
|
||||
if (entityRemoves.contains(entity.getUniqueID())) {
|
||||
iter.remove();
|
||||
removeEntity(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Set<CompoundTag> entities = set.getEntities();
|
||||
if (entities != null && !entities.isEmpty()) {
|
||||
if (syncTasks == null) syncTasks = new Runnable[2];
|
||||
|
||||
syncTasks[1] = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (final CompoundTag nativeTag : entities) {
|
||||
final Map<String, Tag> entityTagMap = ReflectionUtils.getMap(nativeTag.getValue());
|
||||
final StringTag idTag = (StringTag) entityTagMap.get("Id");
|
||||
final ListTag posTag = (ListTag) entityTagMap.get("Pos");
|
||||
final ListTag rotTag = (ListTag) entityTagMap.get("Rotation");
|
||||
if (idTag == null || posTag == null || rotTag == null) {
|
||||
Fawe.debug("Unknown entity tag: " + nativeTag);
|
||||
continue;
|
||||
}
|
||||
final double x = posTag.getDouble(0);
|
||||
final double y = posTag.getDouble(1);
|
||||
final double z = posTag.getDouble(2);
|
||||
final float yaw = rotTag.getFloat(0);
|
||||
final float pitch = rotTag.getFloat(1);
|
||||
final String id = idTag.getValue();
|
||||
|
||||
EntityTypes<?> type = EntityTypes.a(id).orElse(null);
|
||||
if (type != null) {
|
||||
Entity entity = type.a(nmsWorld);
|
||||
if (entity != null) {
|
||||
UUID uuid = entity.getUniqueID();
|
||||
entityTagMap.put("UUIDMost", new LongTag(uuid.getMostSignificantBits()));
|
||||
entityTagMap.put("UUIDLeast", new LongTag(uuid.getLeastSignificantBits()));
|
||||
if (nativeTag != null) {
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
final NBTTagCompound tag = (NBTTagCompound) adapter.fromNative(nativeTag);
|
||||
for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) {
|
||||
tag.remove(name);
|
||||
}
|
||||
entity.f(tag);
|
||||
}
|
||||
entity.setLocation(x, y, z, yaw, pitch);
|
||||
nmsWorld.addEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// set tiles
|
||||
Map<Short, CompoundTag> tiles = set.getTiles();
|
||||
if (tiles != null && !tiles.isEmpty()) {
|
||||
if (syncTasks == null) syncTasks = new Runnable[1];
|
||||
|
||||
syncTasks[0] = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (final Map.Entry<Short, CompoundTag> entry : tiles.entrySet()) {
|
||||
final CompoundTag nativeTag = entry.getValue();
|
||||
final short blockHash = entry.getKey();
|
||||
final int x = (blockHash >> 12 & 0xF) + bx;
|
||||
final int y = (blockHash & 0xFF);
|
||||
final int z = (blockHash >> 8 & 0xF) + bz;
|
||||
final BlockPosition pos = new BlockPosition(x, y, z);
|
||||
synchronized (nmsWorld) {
|
||||
TileEntity tileEntity = nmsWorld.getTileEntity(pos);
|
||||
if (tileEntity == null || tileEntity.isRemoved()) {
|
||||
nmsWorld.removeTileEntity(pos);
|
||||
tileEntity = nmsWorld.getTileEntity(pos);
|
||||
}
|
||||
if (tileEntity != null) {
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
final NBTTagCompound tag = (NBTTagCompound) adapter.fromNative(nativeTag);
|
||||
tag.set("x", new NBTTagInt(x));
|
||||
tag.set("y", new NBTTagInt(y));
|
||||
tag.set("z", new NBTTagInt(z));
|
||||
tileEntity.load(tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Runnable callback;
|
||||
if (bitMask == 0) {
|
||||
callback = null;
|
||||
} else {
|
||||
int finalMask = bitMask;
|
||||
callback = () -> {
|
||||
// Set Modified
|
||||
nmsChunk.d(true); // Set Modified
|
||||
nmsChunk.mustNotSave = false;
|
||||
nmsChunk.markDirty();
|
||||
// send to player
|
||||
BukkitQueue.sendChunk(nmsWorld, X, Z, finalMask);
|
||||
if (finalizer != null) finalizer.run();
|
||||
};
|
||||
}
|
||||
if (syncTasks != null) {
|
||||
QueueHandler queueHandler = Fawe.get().getQueueHandler();
|
||||
Runnable[] finalSyncTasks = syncTasks;
|
||||
|
||||
// Chain the sync tasks and the callback
|
||||
Callable<Future> chain = new Callable<Future>() {
|
||||
@Override
|
||||
public Future call() {
|
||||
// Run the sync tasks
|
||||
for (int i = 1; i < finalSyncTasks.length; i++) {
|
||||
Runnable task = finalSyncTasks[i];
|
||||
if (task != null) {
|
||||
task.run();
|
||||
}
|
||||
}
|
||||
if (callback == null) {
|
||||
if (finalizer != null) finalizer.run();
|
||||
return null;
|
||||
} else {
|
||||
return queueHandler.async(callback, null);
|
||||
}
|
||||
}
|
||||
};
|
||||
return (T) (Future) queueHandler.sync(chain);
|
||||
} else {
|
||||
if (callback == null) {
|
||||
if (finalizer != null) finalizer.run();
|
||||
} else {
|
||||
callback.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized char[] load(int layer, char[] data) {
|
||||
ChunkSection section = getSections()[layer];
|
||||
// Section is null, return empty array
|
||||
if (section == null) {
|
||||
return FaweCache.EMPTY_CHAR_4096;
|
||||
return FaweCache.IMP.EMPTY_CHAR_4096;
|
||||
}
|
||||
if (data == null || data == FaweCache.EMPTY_CHAR_4096) {
|
||||
if (data == null || data == FaweCache.IMP.EMPTY_CHAR_4096) {
|
||||
data = new char[4096];
|
||||
}
|
||||
DelegateLock lock = BukkitQueue.applyLock(section);
|
||||
@ -88,8 +406,8 @@ public class BukkitGetBlocks extends CharGetBlocks {
|
||||
Spigot_v1_14_R1 adapter = ((Spigot_v1_14_R1) WorldEditPlugin.getInstance().getBukkitImplAdapter());
|
||||
|
||||
final DataPaletteBlock<IBlockData> blocks = section.getBlocks();
|
||||
final DataBits bits = (DataBits) BukkitQueue_1_14.fieldBits.get(blocks);
|
||||
final DataPalette<IBlockData> palette = (DataPalette<IBlockData>) BukkitQueue_1_14.fieldPalette.get(blocks);
|
||||
final DataBits bits = (DataBits) BukkitQueue.fieldBits.get(blocks);
|
||||
final DataPalette<IBlockData> palette = (DataPalette<IBlockData>) BukkitQueue.fieldPalette.get(blocks);
|
||||
|
||||
final int bitsPerEntry = bits.c();
|
||||
final long[] blockStates = bits.a();
|
||||
@ -103,8 +421,8 @@ public class BukkitGetBlocks extends CharGetBlocks {
|
||||
num_palette = ((DataPaletteHash<IBlockData>) palette).b();
|
||||
} else {
|
||||
num_palette = 0;
|
||||
int[] paletteToBlockInts = FaweCache.PALETTE_TO_BLOCK.get();
|
||||
char[] paletteToBlockChars = FaweCache.PALETTE_TO_BLOCK_CHAR.get();
|
||||
int[] paletteToBlockInts = FaweCache.IMP.PALETTE_TO_BLOCK.get();
|
||||
char[] paletteToBlockChars = FaweCache.IMP.PALETTE_TO_BLOCK_CHAR.get();
|
||||
try {
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
char paletteVal = data[i];
|
||||
@ -130,7 +448,7 @@ public class BukkitGetBlocks extends CharGetBlocks {
|
||||
return data;
|
||||
}
|
||||
|
||||
char[] paletteToBlockChars = FaweCache.PALETTE_TO_BLOCK_CHAR.get();
|
||||
char[] paletteToBlockChars = FaweCache.IMP.PALETTE_TO_BLOCK_CHAR.get();
|
||||
try {
|
||||
final int size = num_palette;
|
||||
if (size != 1) {
|
||||
@ -188,7 +506,7 @@ public class BukkitGetBlocks extends CharGetBlocks {
|
||||
synchronized (this) {
|
||||
tmp = nmsChunk;
|
||||
if (tmp == null) {
|
||||
nmsChunk = tmp = BukkitQueue.ensureLoaded(nmsWorld, X, Z);
|
||||
nmsChunk = tmp = BukkitQueue.ensureLoaded(this.world.getHandle(), X, Z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,15 +2,18 @@ package com.boydti.fawe.bukkit.beta;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IChunk;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.boydti.fawe.beta.implementation.SimpleCharQueueExtent;
|
||||
import com.boydti.fawe.beta.implementation.WorldChunkCache;
|
||||
import com.boydti.fawe.beta.implementation.IChunkCache;
|
||||
import com.boydti.fawe.bukkit.v1_14.adapter.BlockMaterial_1_14;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.collection.BitArray4096;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.boydti.fawe.wrappers.WorldWrapper;
|
||||
import com.sk89q.worldedit.bukkit.BukkitWorld;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import com.sk89q.worldedit.world.block.BlockID;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
@ -42,30 +45,19 @@ import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class BukkitQueue extends SimpleCharQueueExtent {
|
||||
|
||||
private org.bukkit.World bukkitWorld;
|
||||
private WorldServer nmsWorld;
|
||||
|
||||
@Override
|
||||
public void enableQueue() {
|
||||
|
||||
public BukkitQueue() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disableQueue() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void init(WorldChunkCache cache) {
|
||||
World world = cache.getWorld();
|
||||
public synchronized void init(Extent extent, IChunkCache<IChunkGet> get, IChunkCache<IChunkSet> set) {
|
||||
World world = WorldWrapper.unwrap(extent);
|
||||
if (world == null) throw new IllegalArgumentException("Get must be a world.");
|
||||
if (world instanceof BukkitWorld) {
|
||||
this.bukkitWorld = ((BukkitWorld) world).getWorld();
|
||||
} else {
|
||||
@ -74,15 +66,7 @@ public class BukkitQueue extends SimpleCharQueueExtent {
|
||||
checkNotNull(this.bukkitWorld);
|
||||
CraftWorld craftWorld = ((CraftWorld) bukkitWorld);
|
||||
this.nmsWorld = craftWorld.getHandle();
|
||||
super.init(cache);
|
||||
}
|
||||
|
||||
public WorldServer getNmsWorld() {
|
||||
return nmsWorld;
|
||||
}
|
||||
|
||||
public org.bukkit.World getBukkitWorld() {
|
||||
return bukkitWorld;
|
||||
super.init(extent, get, set);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -90,22 +74,6 @@ public class BukkitQueue extends SimpleCharQueueExtent {
|
||||
super.reset();
|
||||
}
|
||||
|
||||
// private static final IterableThreadLocal<BukkitFullChunk> FULL_CHUNKS = new IterableThreadLocal<BukkitFullChunk>() {
|
||||
// @Override
|
||||
// public BukkitFullChunk init() {
|
||||
// return new BukkitFullChunk();
|
||||
// }
|
||||
// };
|
||||
|
||||
@Override
|
||||
public IChunk create(boolean isFull) {
|
||||
// if (full) {
|
||||
// //TODO implement
|
||||
// return FULL_CHUNKS.get();
|
||||
// }
|
||||
return new BukkitChunkHolder();
|
||||
}
|
||||
|
||||
/*
|
||||
NMS fields
|
||||
*/
|
||||
@ -235,7 +203,7 @@ public class BukkitQueue extends SimpleCharQueueExtent {
|
||||
return TaskManager.IMP.sync(() -> nmsWorld.getChunkAt(X, Z));
|
||||
}
|
||||
|
||||
private PlayerChunk getPlayerChunk(final int cx, final int cz) {
|
||||
private static PlayerChunk getPlayerChunk(net.minecraft.server.v1_14_R1.WorldServer nmsWorld, final int cx, final int cz) {
|
||||
PlayerChunkMap chunkMap = nmsWorld.getChunkProvider().playerChunkMap;
|
||||
PlayerChunk playerChunk = chunkMap.visibleChunks.get(ChunkCoordIntPair.pair(cx, cz));
|
||||
if (playerChunk == null) {
|
||||
@ -244,9 +212,8 @@ public class BukkitQueue extends SimpleCharQueueExtent {
|
||||
return playerChunk;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendChunk(final int X, final int Z, final int mask) {
|
||||
PlayerChunk playerChunk = getPlayerChunk(X, Z);
|
||||
public static void sendChunk(net.minecraft.server.v1_14_R1.WorldServer nmsWorld, int X, int Z, int mask) {
|
||||
PlayerChunk playerChunk = getPlayerChunk(nmsWorld, X, Z);
|
||||
if (playerChunk == null) {
|
||||
return;
|
||||
}
|
||||
@ -256,7 +223,7 @@ public class BukkitQueue extends SimpleCharQueueExtent {
|
||||
// sections[layer] = new ChunkSection(layer << 4);
|
||||
// }
|
||||
// }
|
||||
if (playerChunk.k()) {
|
||||
if (playerChunk.hasBeenLoaded()) {
|
||||
TaskManager.IMP.sync(new Supplier<Object>() {
|
||||
@Override
|
||||
public Object get() {
|
||||
@ -284,6 +251,11 @@ public class BukkitQueue extends SimpleCharQueueExtent {
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendChunk(final int X, final int Z, final int mask) {
|
||||
sendChunk(nmsWorld, X, Z, mask);
|
||||
}
|
||||
|
||||
/*
|
||||
NMS conversion
|
||||
*/
|
||||
@ -293,10 +265,10 @@ public class BukkitQueue extends SimpleCharQueueExtent {
|
||||
if (blocks == null) {
|
||||
return section;
|
||||
}
|
||||
final int[] blockToPalette = FaweCache.BLOCK_TO_PALETTE.get();
|
||||
final int[] paletteToBlock = FaweCache.PALETTE_TO_BLOCK.get();
|
||||
final long[] blockStates = FaweCache.BLOCK_STATES.get();
|
||||
final int[] blocksCopy = FaweCache.SECTION_BLOCKS.get();
|
||||
final int[] blockToPalette = FaweCache.IMP.BLOCK_TO_PALETTE.get();
|
||||
final int[] paletteToBlock = FaweCache.IMP.PALETTE_TO_BLOCK.get();
|
||||
final long[] blockStates = FaweCache.IMP.BLOCK_STATES.get();
|
||||
final int[] blocksCopy = FaweCache.IMP.SECTION_BLOCKS.get();
|
||||
try {
|
||||
int num_palette = 0;
|
||||
int air = 0;
|
||||
|
@ -1,11 +1,78 @@
|
||||
package com.boydti.fawe.bukkit.beta;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.beta.IQueueExtent;
|
||||
import com.boydti.fawe.beta.implementation.QueueHandler;
|
||||
import com.boydti.fawe.bukkit.v0.ChunkListener;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class BukkitQueueHandler extends QueueHandler {
|
||||
@Override
|
||||
public IQueueExtent create() {
|
||||
return new BukkitQueue();
|
||||
}
|
||||
}
|
||||
|
||||
private volatile boolean timingsEnabled;
|
||||
private static boolean alertTimingsChange = true;
|
||||
|
||||
private static Field fieldTimingsEnabled;
|
||||
private static Field fieldAsyncCatcherEnabled;
|
||||
private static Method methodCheck;
|
||||
static {
|
||||
try {
|
||||
fieldAsyncCatcherEnabled = Class.forName("org.spigotmc.AsyncCatcher").getField("enabled");
|
||||
fieldAsyncCatcherEnabled.setAccessible(true);
|
||||
} catch (Throwable ignore) {}
|
||||
try {
|
||||
fieldTimingsEnabled = Class.forName("co.aikar.timings.Timings").getDeclaredField("timingsEnabled");
|
||||
fieldTimingsEnabled.setAccessible(true);
|
||||
methodCheck = Class.forName("co.aikar.timings.TimingsManager").getDeclaredMethod("recheckEnabled");
|
||||
methodCheck.setAccessible(true);
|
||||
} catch (Throwable ignore){}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startSet(boolean parallel) {
|
||||
ChunkListener.physicsFreeze = true;
|
||||
if (parallel) {
|
||||
try {
|
||||
if (fieldAsyncCatcherEnabled != null) {
|
||||
fieldAsyncCatcherEnabled.set(null, false);
|
||||
}
|
||||
if (fieldTimingsEnabled != null) {
|
||||
timingsEnabled = (boolean) fieldTimingsEnabled.get(null);
|
||||
if (timingsEnabled) {
|
||||
if (alertTimingsChange) {
|
||||
alertTimingsChange = false;
|
||||
Fawe.debug("Having `parallel-threads` > 1 interferes with the timings.");
|
||||
}
|
||||
fieldTimingsEnabled.set(null, false);
|
||||
methodCheck.invoke(null);
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endSet(boolean parallel) {
|
||||
ChunkListener.physicsFreeze = false;
|
||||
if (parallel) {
|
||||
try {
|
||||
if (fieldAsyncCatcherEnabled != null) {
|
||||
fieldAsyncCatcherEnabled.set(null, true);
|
||||
}
|
||||
if (fieldTimingsEnabled != null && timingsEnabled) {
|
||||
fieldTimingsEnabled.set(null, true);
|
||||
methodCheck.invoke(null);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +1,11 @@
|
||||
package com.boydti.fawe.bukkit.listener;
|
||||
|
||||
import com.boydti.fawe.beta.IQueueExtent;
|
||||
import com.boydti.fawe.bukkit.util.image.BukkitImageViewer;
|
||||
import com.boydti.fawe.command.CFICommands;
|
||||
import com.boydti.fawe.object.brush.visualization.cfi.HeightMapMCAGenerator;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.object.brush.BrushSettings;
|
||||
import com.boydti.fawe.object.extent.FastWorldEditExtent;
|
||||
import com.boydti.fawe.util.EditSessionBuilder;
|
||||
import com.boydti.fawe.util.ExtentTraverser;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
@ -16,6 +16,7 @@ import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.command.tool.BrushTool;
|
||||
import com.sk89q.worldedit.command.tool.InvalidToolBindException;
|
||||
import com.sk89q.worldedit.command.tool.brush.Brush;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
@ -286,7 +287,8 @@ public class BukkitImageListener implements Listener {
|
||||
.combineStages(false).autoQueue(false).blockBag(null).limitUnlimited()
|
||||
.build();
|
||||
ExtentTraverser last = new ExtentTraverser(es.getExtent()).last();
|
||||
if (last.get() instanceof FastWorldEditExtent) {
|
||||
Extent extent = last.get();
|
||||
if (extent instanceof IQueueExtent) {
|
||||
last = last.previous();
|
||||
}
|
||||
last.setNext(generator);
|
||||
|
@ -1,12 +1,9 @@
|
||||
package com.boydti.fawe.bukkit.listener;
|
||||
|
||||
import com.boydti.fawe.command.CFICommands;
|
||||
import com.boydti.fawe.object.FaweChunk;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.object.FaweQueue;
|
||||
import com.boydti.fawe.object.RunnableVal3;
|
||||
import com.boydti.fawe.object.brush.visualization.VirtualWorld;
|
||||
import com.boydti.fawe.util.SetQueue;
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.ProtocolLibrary;
|
||||
import com.comphenix.protocol.ProtocolManager;
|
||||
@ -58,98 +55,99 @@ public class CFIPacketListener implements Listener {
|
||||
this.plugin = plugin;
|
||||
this.protocolmanager = ProtocolLibrary.getProtocolManager();
|
||||
|
||||
// Direct digging to the virtual world
|
||||
registerBlockEvent(PacketType.Play.Client.BLOCK_DIG, false, new RunnableVal3<PacketEvent, VirtualWorld, BlockVector3>() {
|
||||
@Override
|
||||
public void run(Builder event, URI gen, String pt) {
|
||||
try {
|
||||
Player plr = event.getPlayer();
|
||||
BlockVector3 realPos = pt.add(gen.getOrigin().toBlockPoint());
|
||||
if (!sendBlockChange(plr, gen, pt, Interaction.HIT)) {
|
||||
gen.setBlock(pt, BlockTypes.AIR.getDefaultState());
|
||||
}
|
||||
} catch (WorldEditException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Direct placing to the virtual world
|
||||
RunnableVal3<PacketEvent, VirtualWorld, BlockVector3> placeTask = new RunnableVal3<PacketEvent, VirtualWorld, BlockVector3>() {
|
||||
@Override
|
||||
public void run(Builder event, URI gen, String pt) {
|
||||
try {
|
||||
Player plr = event.getPlayer();
|
||||
List<EnumWrappers.Hand> hands = event.getPacket().getHands().getValues();
|
||||
|
||||
EnumWrappers.Hand enumHand = hands.isEmpty() ? EnumWrappers.Hand.MAIN_HAND : hands.get(0);
|
||||
PlayerInventory inv = plr.getInventory();
|
||||
ItemStack hand = enumHand == EnumWrappers.Hand.MAIN_HAND ? inv.getItemInMainHand() : inv.getItemInOffHand();
|
||||
if (hand.getType().isBlock()) {
|
||||
Material type = hand.getType();
|
||||
switch (type) {
|
||||
case AIR:
|
||||
case CAVE_AIR:
|
||||
case VOID_AIR:
|
||||
break;
|
||||
default: {
|
||||
BlockStateHolder block = BukkitAdapter.asBlockState(hand);
|
||||
if (block != null) {
|
||||
gen.setBlock(pt, block);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pt = getRelPos(event, gen);
|
||||
sendBlockChange(plr, gen, pt, Interaction.OPEN);
|
||||
} catch (WorldEditException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
};
|
||||
registerBlockEvent(PacketType.Play.Client.BLOCK_PLACE, true, placeTask);
|
||||
registerBlockEvent(PacketType.Play.Client.USE_ITEM, true, placeTask);
|
||||
|
||||
// Cancel block change packets where the real world overlaps with the virtual one
|
||||
registerBlockEvent(PacketType.Play.Server.BLOCK_CHANGE, false, new RunnableVal3<PacketEvent, VirtualWorld, BlockVector3>() {
|
||||
@Override
|
||||
public void run(Builder event, URI gen, String pt) {
|
||||
// Do nothing
|
||||
}
|
||||
});
|
||||
|
||||
// Modify chunk packets where the real world overlaps with the virtual one
|
||||
protocolmanager.addPacketListener(new PacketAdapter(plugin, ListenerPriority.NORMAL, PacketType.Play.Server.MAP_CHUNK) {
|
||||
@Override
|
||||
public void onPacketSending(PacketEvent event) {
|
||||
if (!event.isServerPacket()) return;
|
||||
|
||||
VirtualWorld gen = getGenerator(event);
|
||||
if (gen != null) {
|
||||
BlockVector3 origin = gen.getOrigin().toBlockPoint();
|
||||
PacketContainer packet = event.getPacket();
|
||||
StructureModifier<Integer> ints = packet.getIntegers();
|
||||
int cx = ints.read(0);
|
||||
int cz = ints.read(1);
|
||||
|
||||
int ocx = origin.getBlockX() >> 4;
|
||||
int ocz = origin.getBlockZ() >> 4;
|
||||
|
||||
if (gen.contains(BlockVector3.at((cx - ocx) << 4, 0, (cz - ocz) << 4))) {
|
||||
event.setCancelled(true);
|
||||
|
||||
Player plr = event.getPlayer();
|
||||
|
||||
FaweQueue queue = SetQueue.IMP.getNewQueue(plr.getWorld().getName(), true, false);
|
||||
|
||||
FaweChunk toSend = gen.getSnapshot(cx - ocx, cz - ocz);
|
||||
toSend.setLoc(gen, cx, cz);
|
||||
queue.sendChunkUpdate(toSend, FawePlayer.wrap(plr));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
// TODO NOT IMPLEMENTED
|
||||
// // Direct digging to the virtual world
|
||||
// registerBlockEvent(PacketType.Play.Client.BLOCK_DIG, false, new RunnableVal3<PacketEvent, VirtualWorld, BlockVector3>() {
|
||||
// @Override
|
||||
// public void run(Builder event, URI gen, String pt) {
|
||||
// try {
|
||||
// Player plr = event.getPlayer();
|
||||
// BlockVector3 realPos = pt.add(gen.getOrigin().toBlockPoint());
|
||||
// if (!sendBlockChange(plr, gen, pt, Interaction.HIT)) {
|
||||
// gen.setBlock(pt, BlockTypes.AIR.getDefaultState());
|
||||
// }
|
||||
// } catch (WorldEditException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// // Direct placing to the virtual world
|
||||
// RunnableVal3<PacketEvent, VirtualWorld, BlockVector3> placeTask = new RunnableVal3<PacketEvent, VirtualWorld, BlockVector3>() {
|
||||
// @Override
|
||||
// public void run(Builder event, URI gen, String pt) {
|
||||
// try {
|
||||
// Player plr = event.getPlayer();
|
||||
// List<EnumWrappers.Hand> hands = event.getPacket().getHands().getValues();
|
||||
//
|
||||
// EnumWrappers.Hand enumHand = hands.isEmpty() ? EnumWrappers.Hand.MAIN_HAND : hands.get(0);
|
||||
// PlayerInventory inv = plr.getInventory();
|
||||
// ItemStack hand = enumHand == EnumWrappers.Hand.MAIN_HAND ? inv.getItemInMainHand() : inv.getItemInOffHand();
|
||||
// if (hand.getType().isBlock()) {
|
||||
// Material type = hand.getType();
|
||||
// switch (type) {
|
||||
// case AIR:
|
||||
// case CAVE_AIR:
|
||||
// case VOID_AIR:
|
||||
// break;
|
||||
// default: {
|
||||
// BlockStateHolder block = BukkitAdapter.asBlockState(hand);
|
||||
// if (block != null) {
|
||||
// gen.setBlock(pt, block);
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// pt = getRelPos(event, gen);
|
||||
// sendBlockChange(plr, gen, pt, Interaction.OPEN);
|
||||
// } catch (WorldEditException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
// registerBlockEvent(PacketType.Play.Client.BLOCK_PLACE, true, placeTask);
|
||||
// registerBlockEvent(PacketType.Play.Client.USE_ITEM, true, placeTask);
|
||||
//
|
||||
// // Cancel block change packets where the real world overlaps with the virtual one
|
||||
// registerBlockEvent(PacketType.Play.Server.BLOCK_CHANGE, false, new RunnableVal3<PacketEvent, VirtualWorld, BlockVector3>() {
|
||||
// @Override
|
||||
// public void run(Builder event, URI gen, String pt) {
|
||||
// // Do nothing
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// // Modify chunk packets where the real world overlaps with the virtual one
|
||||
// protocolmanager.addPacketListener(new PacketAdapter(plugin, ListenerPriority.NORMAL, PacketType.Play.Server.MAP_CHUNK) {
|
||||
// @Override
|
||||
// public void onPacketSending(PacketEvent event) {
|
||||
// if (!event.isServerPacket()) return;
|
||||
//
|
||||
// VirtualWorld gen = getGenerator(event);
|
||||
// if (gen != null) {
|
||||
// BlockVector3 origin = gen.getOrigin().toBlockPoint();
|
||||
// PacketContainer packet = event.getPacket();
|
||||
// StructureModifier<Integer> ints = packet.getIntegers();
|
||||
// int cx = ints.read(0);
|
||||
// int cz = ints.read(1);
|
||||
//
|
||||
// int ocx = origin.getBlockX() >> 4;
|
||||
// int ocz = origin.getBlockZ() >> 4;
|
||||
//
|
||||
// if (gen.contains(BlockVector3.at((cx - ocx) << 4, 0, (cz - ocz) << 4))) {
|
||||
// event.setCancelled(true);
|
||||
//
|
||||
// Player plr = event.getPlayer();
|
||||
//
|
||||
// FaweQueue queue = SetQueue.IMP.getNewQueue(plr.getWorld().getName(), true, false);
|
||||
//
|
||||
// FaweChunk toSend = gen.getSnapshot(cx - ocx, cz - ocz);
|
||||
// toSend.setLoc(gen, cx, cz);
|
||||
// queue.sendChunkUpdate(toSend, FawePlayer.wrap(plr));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
// The following few listeners are to ignore block collisions where the virtual and real world overlap
|
||||
|
||||
|
@ -3,16 +3,12 @@ package com.boydti.fawe.bukkit.regions;
|
||||
import com.boydti.fawe.bukkit.wrapper.AsyncBlock;
|
||||
import com.boydti.fawe.bukkit.wrapper.AsyncWorld;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.object.queue.NullFaweQueue;
|
||||
import com.boydti.fawe.regions.FaweMask;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import jdk.nashorn.internal.ir.Block;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventException;
|
||||
@ -21,7 +17,6 @@ import org.bukkit.event.block.BlockBreakEvent;
|
||||
import org.bukkit.plugin.RegisteredListener;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import org.bukkit.util.BlockVector;
|
||||
|
||||
public class FreeBuildRegion extends BukkitMaskManager {
|
||||
private final ArrayList<RegisteredListener> listeners;
|
||||
@ -60,7 +55,7 @@ public class FreeBuildRegion extends BukkitMaskManager {
|
||||
BlockVector3 pos1 = BlockVector3.ZERO;
|
||||
BlockVector3 pos2 = BlockVector3.ZERO;
|
||||
|
||||
AsyncBlock block = new AsyncBlock(asyncWorld, new NullFaweQueue(asyncWorld.getWorldName(), BlockTypes.STONE.getDefaultState()), 0, 0, 0);
|
||||
AsyncBlock block = new AsyncBlock(asyncWorld, 0, 0, 0);
|
||||
BlockBreakEvent event = new BlockBreakEvent(block, BukkitAdapter.adapt(player.toWorldEditPlayer()));
|
||||
|
||||
return new FaweMask(pos1, pos2) {
|
||||
|
@ -1,10 +1,14 @@
|
||||
package com.boydti.fawe.bukkit.util;
|
||||
|
||||
import com.boydti.fawe.bukkit.v0.BukkitQueue_0;
|
||||
import com.boydti.fawe.bukkit.beta.BukkitQueue;
|
||||
import com.boydti.fawe.util.ReflectionUtils;
|
||||
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
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;
|
||||
|
||||
@ -13,6 +17,8 @@ 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;
|
||||
@ -21,10 +27,13 @@ public class ItemUtil {
|
||||
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));
|
||||
@ -68,7 +77,7 @@ public class ItemUtil {
|
||||
Tag nativeTag = nativeTagRef.get();
|
||||
if (nativeTag != null) return (CompoundTag) nativeTag;
|
||||
}
|
||||
Tag nativeTag = BukkitQueue_0.toNative(nmsTag);
|
||||
Tag nativeTag = adapter.toNative(nmsTag);
|
||||
map.put(nmsTag.hashCode(), new WeakReference<>(nativeTag));
|
||||
return null;
|
||||
}
|
||||
@ -86,7 +95,7 @@ public class ItemUtil {
|
||||
copy = true;
|
||||
nmsItem = methodAsNMSCopy.invoke(null, item);
|
||||
}
|
||||
Object nmsTag = BukkitQueue_0.fromNative(tag);
|
||||
Object nmsTag = adapter.fromNative(tag);
|
||||
methodSetTag.invoke(nmsItem, nmsTag);
|
||||
if (copy) return (ItemStack) methodAsBukkitCopy.invoke(null, nmsItem);
|
||||
return item;
|
||||
|
@ -382,7 +382,7 @@
|
||||
// int z = location.getBlockZ();
|
||||
//
|
||||
// org.bukkit.block.Block bukkitBlock = location.getBlock();
|
||||
// BaseBlock block = FaweCache.getBlock(bukkitBlock.getTypeId(), bukkitBlock.getData());
|
||||
// BaseBlock block = FaweCache.IMP.getBlock(bukkitBlock.getTypeId(), bukkitBlock.getData());
|
||||
//
|
||||
// // Read the NBT data
|
||||
// Object nmsWorld = getHandleWorld.invoke(craftWorld);
|
||||
|
@ -51,6 +51,7 @@ import com.sk89q.worldedit.registry.state.EnumProperty;
|
||||
import com.sk89q.worldedit.registry.state.IntegerProperty;
|
||||
import com.sk89q.worldedit.registry.state.Property;
|
||||
import com.sk89q.worldedit.util.Direction;
|
||||
import com.sk89q.worldedit.world.DataFixer;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
@ -104,6 +105,7 @@ import org.bukkit.craftbukkit.v1_14_R1.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_14_R1.block.data.CraftBlockData;
|
||||
import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
|
||||
import org.bukkit.craftbukkit.v1_14_R1.entity.CraftPlayer;
|
||||
import org.bukkit.craftbukkit.v1_14_R1.util.CraftMagicNumbers;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason;
|
||||
import org.slf4j.Logger;
|
||||
@ -250,6 +252,21 @@ public final class Spigot_v1_14_R1 extends CachedBukkitAdapter implements Bukkit
|
||||
// Code that is less likely to break
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public int getDataVersion() {
|
||||
return CraftMagicNumbers.INSTANCE.getDataVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataFixer getDataFixer() {
|
||||
try {
|
||||
Class<?> converter = Class.forName("com.sk89q.worldedit.bukkit.adapter.impl.DataConverters_1_14_R4");
|
||||
return (DataFixer) converter.getDeclaredField("INSTANCE").get(null);
|
||||
} catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public BaseBlock getBlock(Location location) {
|
||||
@ -409,15 +426,15 @@ public final class Spigot_v1_14_R1 extends CachedBukkitAdapter implements Bukkit
|
||||
for (IBlockState state : blockStateList.d()) {
|
||||
Property property;
|
||||
if (state instanceof BlockStateBoolean) {
|
||||
property = new BooleanProperty(state.a(), ImmutableList.copyOf(state.d()));
|
||||
property = new BooleanProperty(state.a(), ImmutableList.copyOf(state.getValues()));
|
||||
} else if (state instanceof BlockStateDirection) {
|
||||
property = new DirectionalProperty(state.a(),
|
||||
(List<Direction>) state.d().stream().map(e -> Direction.valueOf(((INamable) e).getName().toUpperCase())).collect(Collectors.toList()));
|
||||
(List<Direction>) state.getValues().stream().map(e -> Direction.valueOf(((INamable) e).getName().toUpperCase())).collect(Collectors.toList()));
|
||||
} else if (state instanceof BlockStateEnum) {
|
||||
property = new EnumProperty(state.a(),
|
||||
(List<String>) state.d().stream().map(e -> ((INamable) e).getName()).collect(Collectors.toList()));
|
||||
(List<String>) state.getValues().stream().map(e -> ((INamable) e).getName()).collect(Collectors.toList()));
|
||||
} else if (state instanceof BlockStateInteger) {
|
||||
property = new IntegerProperty(state.a(), ImmutableList.copyOf(state.d()));
|
||||
property = new IntegerProperty(state.a(), ImmutableList.copyOf(state.getValues()));
|
||||
} else {
|
||||
throw new IllegalArgumentException("WorldEdit needs an update to support " + state.getClass().getSimpleName());
|
||||
}
|
||||
|
@ -1,13 +1,14 @@
|
||||
package com.boydti.fawe.bukkit.wrapper;
|
||||
|
||||
import com.boydti.fawe.bukkit.wrapper.state.AsyncSign;
|
||||
import com.boydti.fawe.object.FaweQueue;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.destroystokyo.paper.block.BlockSoundGroup;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockID;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import org.bukkit.FluidCollisionMode;
|
||||
@ -34,12 +35,10 @@ public class AsyncBlock implements Block {
|
||||
public int z;
|
||||
public int y;
|
||||
public int x;
|
||||
public final FaweQueue queue;
|
||||
public final AsyncWorld world;
|
||||
|
||||
public AsyncBlock(AsyncWorld world, FaweQueue queue, int x, int y, int z) {
|
||||
public AsyncBlock(AsyncWorld world, int x, int y, int z) {
|
||||
this.world = world;
|
||||
this.queue = queue;
|
||||
this.x = x;
|
||||
this.y = Math.max(0, Math.min(255, y));
|
||||
this.z = z;
|
||||
@ -54,25 +53,24 @@ public class AsyncBlock implements Block {
|
||||
@Override
|
||||
@Deprecated
|
||||
public byte getData() {
|
||||
return (byte) (queue.getCachedCombinedId4Data(x, y, z, BlockTypes.AIR.getInternalId()) & 0xF);
|
||||
return (byte) getPropertyId();
|
||||
}
|
||||
|
||||
public int getPropertyId() {
|
||||
return (queue.getCachedCombinedId4Data(x, y, z, BlockTypes.AIR.getInternalId()) >> BlockTypes.BIT_OFFSET);
|
||||
return world.getBlock(x, y, z).getInternalId() >> BlockTypes.BIT_OFFSET;
|
||||
}
|
||||
|
||||
public int getCombinedId() {
|
||||
return queue.getCachedCombinedId4Data(x, y, z, BlockTypes.AIR.getInternalId());
|
||||
return world.getBlock(x, y, z).getInternalId();
|
||||
}
|
||||
|
||||
public int getTypeId() {
|
||||
int id = (queue.getCachedCombinedId4Data(x, y, z, BlockTypes.AIR.getInternalId()));
|
||||
return BlockTypes.getFromStateId(id).getInternalId();
|
||||
return world.getBlock(x, y, z).getBlockType().getInternalId();
|
||||
}
|
||||
|
||||
@NotNull @Override
|
||||
public AsyncBlock getRelative(int modX, int modY, int modZ) {
|
||||
return new AsyncBlock(world, queue, x + modX, y + modY, z + modZ);
|
||||
return new AsyncBlock(world, x + modX, y + modY, z + modZ);
|
||||
}
|
||||
|
||||
@NotNull @Override
|
||||
@ -92,7 +90,7 @@ public class AsyncBlock implements Block {
|
||||
|
||||
@NotNull @Override
|
||||
public BlockData getBlockData() {
|
||||
return BukkitAdapter.getBlockData(queue.getCachedCombinedId4Data(x, y, z, BlockTypes.AIR.getInternalId()));
|
||||
return BukkitAdapter.adapt(world.getBlock(x, y, z));
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@ -102,7 +100,7 @@ public class AsyncBlock implements Block {
|
||||
|
||||
@Deprecated
|
||||
public boolean setCombinedId(int combinedId) {
|
||||
return queue.setBlock(x, y, z, combinedId);
|
||||
return world.setBlock(x, y, z, BlockState.getFromInternalId(combinedId));
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@ -112,7 +110,7 @@ public class AsyncBlock implements Block {
|
||||
|
||||
@Deprecated
|
||||
public boolean setTypeId(int typeId) {
|
||||
return queue.setBlock(x, y, z, BlockTypes.get(typeId).getDefaultState());
|
||||
return world.setBlock(x, y, z, BlockTypes.get(typeId).getDefaultState());
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@ -122,17 +120,17 @@ public class AsyncBlock implements Block {
|
||||
|
||||
@Override
|
||||
public byte getLightLevel() {
|
||||
return (byte) queue.getLight(x, y, z);
|
||||
return (byte) world.getLight(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getLightFromSky() {
|
||||
return (byte) queue.getSkyLight(x, y, z);
|
||||
return (byte) world.getSkyLight(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getLightFromBlocks() {
|
||||
return (byte) queue.getEmmittedLight(x, y, z);
|
||||
return (byte) world.getBlockLight(x, y, z);
|
||||
}
|
||||
|
||||
@NotNull @Override
|
||||
@ -179,7 +177,7 @@ public class AsyncBlock implements Block {
|
||||
@Override
|
||||
public void setBlockData(@NotNull BlockData blockData) {
|
||||
try {
|
||||
queue.setBlock(x, y, z, BukkitAdapter.adapt(blockData));
|
||||
world.setBlock(x, y, z, BukkitAdapter.adapt(blockData));
|
||||
} catch (WorldEditException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
@ -193,7 +191,7 @@ public class AsyncBlock implements Block {
|
||||
@Override
|
||||
public void setType(@NotNull Material type) {
|
||||
try {
|
||||
queue.setBlock(x, y, z, BukkitAdapter.adapt(type).getDefaultState());
|
||||
world.setBlock(x, y, z, BukkitAdapter.adapt(type).getDefaultState());
|
||||
} catch (WorldEditException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
@ -219,9 +217,8 @@ public class AsyncBlock implements Block {
|
||||
|
||||
@NotNull @Override
|
||||
public AsyncBlockState getState() {
|
||||
int combined = queue.getCombinedId4Data(x, y, z, 0);
|
||||
BlockType type = BlockTypes.getFromStateId(combined);
|
||||
switch (type.getInternalId()) {
|
||||
BaseBlock state = world.getFullBlock(x, y, z);
|
||||
switch (state.getBlockType().getInternalId()) {
|
||||
case BlockID.ACACIA_SIGN:
|
||||
case BlockID.SPRUCE_SIGN:
|
||||
case BlockID.ACACIA_WALL_SIGN:
|
||||
@ -234,9 +231,9 @@ public class AsyncBlock implements Block {
|
||||
case BlockID.JUNGLE_WALL_SIGN:
|
||||
case BlockID.OAK_SIGN:
|
||||
case BlockID.OAK_WALL_SIGN:
|
||||
return new AsyncSign(this, combined);
|
||||
return new AsyncSign(this, state);
|
||||
default:
|
||||
return new AsyncBlockState(this, combined);
|
||||
return new AsyncBlockState(this, state);
|
||||
}
|
||||
}
|
||||
|
||||
@ -248,13 +245,13 @@ public class AsyncBlock implements Block {
|
||||
|
||||
@NotNull @Override
|
||||
public Biome getBiome() {
|
||||
return world.getAdapter().adapt(queue.getBiomeType(x, z));
|
||||
return world.getAdapter().adapt(world.getBiomeType(x, z));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBiome(@NotNull Biome bio) {
|
||||
BiomeType biome = world.getAdapter().adapt(bio);
|
||||
queue.setBiome(x, z, biome);
|
||||
world.setBiome(x, 0, z, biome);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -301,9 +298,7 @@ public class AsyncBlock implements Block {
|
||||
|
||||
@Override
|
||||
public boolean isLiquid() {
|
||||
int combined = queue.getCombinedId4Data(x, y, z, 0);
|
||||
BlockType type = BlockTypes.getFromStateId(combined);
|
||||
return type.getMaterial().isLiquid();
|
||||
return world.getBlock(x, y, z).getMaterial().isLiquid();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -6,6 +6,8 @@ import java.util.List;
|
||||
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Location;
|
||||
@ -20,30 +22,26 @@ import org.bukkit.plugin.Plugin;
|
||||
|
||||
public class AsyncBlockState implements BlockState {
|
||||
|
||||
private int combinedId;
|
||||
private BaseBlock state;
|
||||
private BlockData blockData;
|
||||
private CompoundTag nbt;
|
||||
private final AsyncBlock block;
|
||||
|
||||
public AsyncBlockState(AsyncBlock block) {
|
||||
this(block, block.queue.getCombinedId4Data(block.x, block.y, block.z, 0));
|
||||
this(block, block.world.getFullBlock(block.x, block.y, block.z));
|
||||
}
|
||||
|
||||
public AsyncBlockState(AsyncBlock block, int combined) {
|
||||
this.combinedId = combined;
|
||||
public AsyncBlockState(AsyncBlock block, BaseBlock state) {
|
||||
this.state = state;
|
||||
this.block = block;
|
||||
this.blockData = BukkitAdapter.getBlockData(combined);
|
||||
if (BlockTypes.getFromStateId(combined).getMaterial().hasContainer()) {
|
||||
this.nbt = block.queue.getTileEntity(block.x, block.y, block.z);
|
||||
}
|
||||
this.blockData = BukkitAdapter.adapt(state);
|
||||
}
|
||||
|
||||
public int getTypeId() {
|
||||
return BlockTypes.getFromStateId(combinedId).getInternalId();
|
||||
return state.getBlockType().getInternalId();
|
||||
}
|
||||
|
||||
public int getPropertyId() {
|
||||
return combinedId >> BlockTypes.BIT_OFFSET;
|
||||
return state.getInternalId() >> BlockTypes.BIT_OFFSET;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -68,7 +66,7 @@ public class AsyncBlockState implements BlockState {
|
||||
|
||||
@Override
|
||||
public byte getLightLevel() {
|
||||
return (byte) BlockTypes.getFromStateId(combinedId).getMaterial().getLightValue();
|
||||
return (byte) state.getMaterial().getLightValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -114,7 +112,14 @@ public class AsyncBlockState implements BlockState {
|
||||
@Override
|
||||
public void setBlockData(BlockData blockData) {
|
||||
this.blockData = blockData;
|
||||
this.combinedId = BukkitAdapter.adapt(blockData).getInternalId();
|
||||
CompoundTag nbt = state.getNbtData();
|
||||
BlockType oldType = state.getBlockType();
|
||||
com.sk89q.worldedit.world.block.BlockState newState = BukkitAdapter.adapt(blockData);
|
||||
if (nbt != null && newState.getBlockType() == oldType) {
|
||||
state = newState.toBaseBlock(nbt);
|
||||
} else {
|
||||
state = newState.toBaseBlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -135,33 +140,30 @@ public class AsyncBlockState implements BlockState {
|
||||
@Override
|
||||
public boolean update(boolean force, boolean applyPhysics) {
|
||||
try {
|
||||
boolean result = block.queue.setBlock(block.x, block.y, block.z, BukkitAdapter.adapt(blockData));
|
||||
if (nbt != null) {
|
||||
block.queue.setTile(block.x, block.y, block.z, nbt);
|
||||
}
|
||||
return result;
|
||||
return block.world.setBlock(block.x, block.y, block.z, state);
|
||||
} catch (WorldEditException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public CompoundTag getNbtData() {
|
||||
return nbt;
|
||||
return state.getNbtData();
|
||||
}
|
||||
|
||||
public void setNbtData(CompoundTag nbt) {
|
||||
this.nbt = nbt;
|
||||
state = this.state.toBaseBlock(nbt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getRawData() {
|
||||
return (byte) (combinedId >> BlockTypes.BIT_OFFSET);
|
||||
return (byte) (state.getInternalId() >> BlockTypes.BIT_OFFSET);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRawData(byte data) {
|
||||
this.combinedId = getTypeId() + (data << BlockTypes.BIT_OFFSET);
|
||||
this.blockData = BukkitAdapter.getBlockData(this.combinedId);
|
||||
int combinedId = getTypeId() + (data << BlockTypes.BIT_OFFSET);
|
||||
state = com.sk89q.worldedit.world.block.BlockState.getFromInternalId(combinedId).toBaseBlock(state.getNbtData());
|
||||
this.blockData = BukkitAdapter.adapt(state);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,8 +1,6 @@
|
||||
package com.boydti.fawe.bukkit.wrapper;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.bukkit.v0.BukkitQueue_0;
|
||||
import com.boydti.fawe.object.FaweQueue;
|
||||
import com.boydti.fawe.object.RunnableVal;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
@ -21,11 +19,9 @@ public class AsyncChunk implements Chunk {
|
||||
private final AsyncWorld world;
|
||||
private final int z;
|
||||
private final int x;
|
||||
private final FaweQueue queue;
|
||||
|
||||
public AsyncChunk(World world, FaweQueue queue, int x, int z) {
|
||||
public AsyncChunk(World world, int x, int z) {
|
||||
this.world = world instanceof AsyncWorld ? (AsyncWorld) world : new AsyncWorld(world, true);
|
||||
this.queue = queue;
|
||||
this.x = x;
|
||||
this.z = z;
|
||||
}
|
||||
@ -61,7 +57,7 @@ public class AsyncChunk implements Chunk {
|
||||
|
||||
@Override
|
||||
public AsyncBlock getBlock(int x, int y, int z) {
|
||||
return new AsyncBlock(world, queue, (this.x << 4) + x, y, (this.z << 4) + z);
|
||||
return new AsyncBlock(world, (this.x << 4) + x, y, (this.z << 4) + z);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -87,8 +83,7 @@ public class AsyncChunk implements Chunk {
|
||||
task.run();
|
||||
return task.value;
|
||||
}
|
||||
if (queue instanceof BukkitQueue_0) {
|
||||
BukkitQueue_0 bq = (BukkitQueue_0) queue;
|
||||
if (world.isWorld()) {
|
||||
if (world.isChunkLoaded(x, z)) {
|
||||
if (world.isChunkLoaded(x, z)) {
|
||||
task.run();
|
||||
|
@ -1,32 +1,36 @@
|
||||
package com.boydti.fawe.bukkit.wrapper;
|
||||
|
||||
import com.bekvon.bukkit.residence.commands.material;
|
||||
import com.boydti.fawe.FaweAPI;
|
||||
import com.boydti.fawe.bukkit.v0.BukkitQueue_0;
|
||||
import com.boydti.fawe.object.FaweQueue;
|
||||
import com.boydti.fawe.object.HasFaweQueue;
|
||||
import com.boydti.fawe.object.RunnableVal;
|
||||
import com.boydti.fawe.object.queue.DelegateFaweQueue;
|
||||
import com.boydti.fawe.util.SetQueue;
|
||||
import com.boydti.fawe.util.StringMan;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.sk89q.worldedit.bukkit.BukkitWorld;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.extent.PassthroughExtent;
|
||||
import com.sk89q.worldedit.function.operation.Operation;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import java.io.File;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import org.bukkit.*;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import org.bukkit.BlockChangeDelegate;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.ChunkSnapshot;
|
||||
import org.bukkit.Difficulty;
|
||||
import org.bukkit.Effect;
|
||||
import org.bukkit.FluidCollisionMode;
|
||||
import org.bukkit.GameRule;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.SoundCategory;
|
||||
import org.bukkit.StructureType;
|
||||
import org.bukkit.TreeType;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.WorldBorder;
|
||||
import org.bukkit.WorldCreator;
|
||||
import org.bukkit.WorldType;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
@ -50,6 +54,17 @@ import org.bukkit.util.Consumer;
|
||||
import org.bukkit.util.RayTraceResult;
|
||||
import org.bukkit.util.Vector;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Modify the world from an async thread<br>
|
||||
@ -60,10 +75,9 @@ import org.jetbrains.annotations.NotNull;
|
||||
* @see #wrap(World)
|
||||
* @see #create(WorldCreator)
|
||||
*/
|
||||
public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue {
|
||||
public class AsyncWorld extends PassthroughExtent implements World {
|
||||
|
||||
private World parent;
|
||||
private FaweQueue queue;
|
||||
private BukkitImplAdapter adapter;
|
||||
|
||||
@Override
|
||||
@ -78,7 +92,7 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue
|
||||
*/
|
||||
@Deprecated
|
||||
public AsyncWorld(World parent, boolean autoQueue) {
|
||||
this(parent, FaweAPI.createQueue(parent.getName(), autoQueue));
|
||||
this(parent, FaweAPI.createQueue(new BukkitWorld(parent), autoQueue));
|
||||
}
|
||||
|
||||
public AsyncWorld(String world, boolean autoQueue) {
|
||||
@ -91,19 +105,10 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue
|
||||
* @param queue
|
||||
*/
|
||||
@Deprecated
|
||||
public AsyncWorld(World parent, FaweQueue queue) {
|
||||
super(queue);
|
||||
public AsyncWorld(World parent, Extent extent) {
|
||||
super(extent);
|
||||
this.parent = parent;
|
||||
this.queue = queue;
|
||||
if (queue instanceof BukkitQueue_0) {
|
||||
this.adapter = BukkitQueue_0.getAdapter();
|
||||
} else {
|
||||
try {
|
||||
this.adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
this.adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -118,32 +123,15 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue
|
||||
return new AsyncWorld(world, false);
|
||||
}
|
||||
|
||||
public void changeWorld(World world, FaweQueue queue) {
|
||||
this.parent = world;
|
||||
if (queue != this.queue) {
|
||||
if (this.queue != null) {
|
||||
final FaweQueue oldQueue = this.queue;
|
||||
TaskManager.IMP.async(oldQueue::flush);
|
||||
}
|
||||
this.queue = queue;
|
||||
}
|
||||
setParent(queue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + ":" + queue.toString();
|
||||
return getName();
|
||||
}
|
||||
|
||||
public World getBukkitWorld() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FaweQueue getQueue() {
|
||||
return queue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a world async (untested)
|
||||
* - Only optimized for 1.10
|
||||
@ -151,8 +139,8 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue
|
||||
* @return
|
||||
*/
|
||||
public synchronized static AsyncWorld create(final WorldCreator creator) {
|
||||
BukkitQueue_0 queue = (BukkitQueue_0) SetQueue.IMP.getNewQueue(creator.name(), true, false);
|
||||
World world = queue.createWorld(creator);
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
@Nullable World world = adapter.createWorld(creator);
|
||||
return wrap(world);
|
||||
}
|
||||
|
||||
@ -163,9 +151,7 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue
|
||||
}
|
||||
|
||||
public void flush() {
|
||||
if (queue != null) {
|
||||
queue.flush();
|
||||
}
|
||||
getExtent().commit();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -240,7 +226,7 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue
|
||||
|
||||
@Override
|
||||
public AsyncBlock getBlockAt(final int x, final int y, final int z) {
|
||||
return new AsyncBlock(this, queue, x, y, z);
|
||||
return new AsyncBlock(this, x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -251,9 +237,8 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue
|
||||
@Override
|
||||
public int getHighestBlockYAt(int x, int z) {
|
||||
for (int y = getMaxHeight() - 1; y >= 0; y--) {
|
||||
int stateId = queue.getCachedCombinedId4Data(x, y, z, BlockTypes.AIR.getInternalId());
|
||||
BlockType type = BlockTypes.getFromStateId(stateId);
|
||||
if (!type.getMaterial().isAir()) return y;
|
||||
BlockState state = this.getBlock(x, y, z);
|
||||
if (!state.getMaterial().isAir()) return y;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -276,7 +261,7 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue
|
||||
|
||||
@Override
|
||||
public AsyncChunk getChunkAt(int x, int z) {
|
||||
return new AsyncChunk(this, queue, x, z);
|
||||
return new AsyncChunk(this, x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -422,8 +407,7 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue
|
||||
@Override
|
||||
@Deprecated
|
||||
public boolean refreshChunk(int x, int z) {
|
||||
queue.sendChunk(queue.getFaweChunk(x, z));
|
||||
return true;
|
||||
return parent.refreshChunk(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -825,13 +809,13 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue
|
||||
|
||||
@Override
|
||||
public Biome getBiome(int x, int z) {
|
||||
return adapter.adapt(queue.getBiomeType(x, z));
|
||||
return adapter.adapt(getExtent().getBiomeType(x, z));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBiome(int x, int z, Biome bio) {
|
||||
BiomeType biome = adapter.adapt(bio);
|
||||
queue.setBiome(x, z, biome);
|
||||
getExtent().setBiome(x, 0, z, biome);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -1114,6 +1098,11 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue
|
||||
return parent.locateNearestStructure(arg0, arg1, arg2, arg3);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getViewDistance() {
|
||||
return parent.getViewDistance();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RayTraceResult rayTrace(Location arg0, Vector arg1, double arg2, FluidCollisionMode arg3, boolean arg4,
|
||||
double arg5, Predicate<Entity> arg6) {
|
||||
|
@ -54,7 +54,7 @@ public final class AsyncDataContainer implements PersistentDataContainer {
|
||||
Validate.notNull(key, "The provided key for the custom value was null");
|
||||
Validate.notNull(type, "The provided type for the custom value was null");
|
||||
Validate.notNull(value, "The provided value for the custom value was null");
|
||||
get().put(key.toString(), FaweCache.asTag(type.toPrimitive(value, null)));
|
||||
get().put(key.toString(), FaweCache.IMP.asTag(type.toPrimitive(value, null)));
|
||||
}
|
||||
|
||||
public <T, Z> boolean has(NamespacedKey key, PersistentDataType<T, Z> type) {
|
||||
|
@ -10,6 +10,8 @@ import com.sk89q.worldedit.util.formatting.text.TextComponent;
|
||||
import com.sk89q.worldedit.util.formatting.text.serializer.gson.GsonComponentSerializer;
|
||||
import com.sk89q.worldedit.util.formatting.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import java.util.Map;
|
||||
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import org.bukkit.DyeColor;
|
||||
import org.bukkit.block.Sign;
|
||||
import org.bukkit.persistence.PersistentDataContainer;
|
||||
@ -17,8 +19,8 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class AsyncSign extends AsyncBlockState implements Sign {
|
||||
public AsyncSign(AsyncBlock block, int combined) {
|
||||
super(block, combined);
|
||||
public AsyncSign(AsyncBlock block, BaseBlock state) {
|
||||
super(block, state);
|
||||
}
|
||||
|
||||
private boolean isEditable = false;
|
||||
|
@ -330,10 +330,6 @@ public enum BukkitAdapter {
|
||||
return getAdapter().adapt(block);
|
||||
}
|
||||
|
||||
public static BlockData getBlockData(int combinedId) {
|
||||
return getAdapter().getBlockData(combinedId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a WorldEdit BlockState from a Bukkit ItemStack
|
||||
*
|
||||
|
@ -21,6 +21,10 @@ package com.sk89q.worldedit.bukkit;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.bukkit.beta.BukkitGetBlocks;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
@ -494,9 +498,19 @@ public class BukkitWorld extends AbstractWorld {
|
||||
return BukkitAdapter.adapt(getWorld().getBiome(position.getBlockX(), position.getBlockZ()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBiome(BlockVector2 position, BiomeType biome) {
|
||||
getWorld().setBiome(position.getBlockX(), position.getBlockZ(), BukkitAdapter.adapt(biome));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkGet get(int chunkX, int chunkZ) {
|
||||
return new BukkitGetBlocks(getWorldChecked(), chunkX, chunkZ, Settings.IMP.QUEUE.POOL);
|
||||
}
|
||||
}
|
||||
|
@ -41,18 +41,18 @@ import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import com.sk89q.worldedit.extension.platform.Capability;
|
||||
import com.sk89q.worldedit.extension.platform.Platform;
|
||||
import com.sk89q.worldedit.extent.inventory.BlockBag;
|
||||
import com.sk89q.worldedit.util.command.CommandMapping;
|
||||
import com.sk89q.worldedit.internal.command.CommandUtil;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BlockCategory;
|
||||
import com.sk89q.worldedit.world.entity.EntityType;
|
||||
import com.sk89q.worldedit.world.item.ItemCategory;
|
||||
import com.sk89q.worldedit.world.item.ItemType;
|
||||
import com.sk89q.worldedit.world.registry.LegacyMapper;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Tag;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.command.BlockCommandSender;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
@ -19,6 +19,8 @@
|
||||
|
||||
package com.sk89q.worldedit.bukkit.adapter;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.bukkit.FaweBukkit;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
@ -33,6 +35,8 @@ import com.sk89q.worldedit.world.registry.BlockMaterial;
|
||||
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.WorldCreator;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
@ -149,4 +153,8 @@ public interface BukkitImplAdapter<T> extends IBukkitAdapter {
|
||||
* @param player The player
|
||||
*/
|
||||
void sendFakeOP(Player player);
|
||||
|
||||
default @org.jetbrains.annotations.Nullable World createWorld(WorldCreator creator) {
|
||||
return ((FaweBukkit) Fawe.imp()).createWorldUnloaded(creator::createWorld);
|
||||
}
|
||||
}
|
||||
|
@ -303,10 +303,6 @@ public interface IBukkitAdapter {
|
||||
*/
|
||||
BlockData adapt(BlockStateHolder block);
|
||||
|
||||
default BlockData getBlockData(int combinedId) {
|
||||
return adapt(BlockState.getFromInternalId(combinedId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a WorldEdit BlockStateHolder from a Bukkit ItemStack
|
||||
*
|
||||
|
@ -4,6 +4,7 @@ import com.boydti.fawe.beta.Trimable;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.collection.BitArray4096;
|
||||
import com.boydti.fawe.object.collection.IterableThreadLocal;
|
||||
import com.boydti.fawe.util.IOUtil;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.sk89q.jnbt.ByteArrayTag;
|
||||
import com.sk89q.jnbt.ByteTag;
|
||||
@ -29,92 +30,182 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public final class FaweCache implements Trimable {
|
||||
public final static int BLOCKS_PER_LAYER = 4096;
|
||||
public final static int CHUNK_LAYERS = 16;
|
||||
public final static int WORLD_HEIGHT = CHUNK_LAYERS << 4;
|
||||
public final static int WORLD_MAX_Y = WORLD_HEIGHT - 1;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public enum FaweCache implements Trimable {
|
||||
IMP
|
||||
; // singleton
|
||||
|
||||
public static final char[] EMPTY_CHAR_4096 = new char[4096];
|
||||
public final int BLOCKS_PER_LAYER = 4096;
|
||||
public final int CHUNK_LAYERS = 16;
|
||||
public final int WORLD_HEIGHT = CHUNK_LAYERS << 4;
|
||||
public final int WORLD_MAX_Y = WORLD_HEIGHT - 1;
|
||||
|
||||
public final char[] EMPTY_CHAR_4096 = new char[4096];
|
||||
|
||||
private final IdentityHashMap<Class, IterableThreadLocal> REGISTERED_SINGLETONS = new IdentityHashMap<>();
|
||||
private final IdentityHashMap<Class, Pool> REGISTERED_POOLS = new IdentityHashMap<>();
|
||||
|
||||
public interface Pool<T> {
|
||||
T poll();
|
||||
default boolean offer(T recycle) {
|
||||
return false;
|
||||
}
|
||||
default void clear() {}
|
||||
}
|
||||
|
||||
public class QueuePool<T> extends ConcurrentLinkedQueue<T> implements Pool<T> {
|
||||
private final Supplier<T> supplier;
|
||||
|
||||
public QueuePool(Supplier<T> supplier) {
|
||||
this.supplier = supplier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean offer(T t) {
|
||||
return super.offer(t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T poll() {
|
||||
T result = super.poll();
|
||||
if (result == null) {
|
||||
return supplier.get();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
if (!isEmpty()) super.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Palette buffers / cache
|
||||
*/
|
||||
|
||||
@Override
|
||||
public boolean trim(boolean aggressive) {
|
||||
public synchronized boolean trim(boolean aggressive) {
|
||||
BLOCK_TO_PALETTE.clean();
|
||||
PALETTE_TO_BLOCK.clean();
|
||||
BLOCK_STATES.clean();
|
||||
SECTION_BLOCKS.clean();
|
||||
PALETTE_CACHE.clean();
|
||||
PALETTE_TO_BLOCK_CHAR.clean();
|
||||
INDEX_STORE.clean();
|
||||
|
||||
MUTABLE_VECTOR3.clean();
|
||||
MUTABLE_BLOCKVECTOR3.clean();
|
||||
SECTION_BITS_TO_CHAR.clean();
|
||||
for (Map.Entry<Class, IterableThreadLocal> entry : REGISTERED_SINGLETONS.entrySet()) {
|
||||
entry.getValue().clean();
|
||||
}
|
||||
for (Map.Entry<Class, Pool> entry : REGISTERED_POOLS.entrySet()) {
|
||||
Pool pool = entry.getValue();
|
||||
pool.clear();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static final IterableThreadLocal<int[]> BLOCK_TO_PALETTE = new IterableThreadLocal<int[]>() {
|
||||
@Override
|
||||
public int[] init() {
|
||||
int[] result = new int[BlockTypes.states.length];
|
||||
Arrays.fill(result, Integer.MAX_VALUE);
|
||||
return result;
|
||||
public final <T> Pool<T> getPool(Class<T> clazz) {
|
||||
Pool<T> pool = REGISTERED_POOLS.get(clazz);
|
||||
if (pool == null) {
|
||||
synchronized (this) {
|
||||
pool = REGISTERED_POOLS.get(clazz);
|
||||
if (pool == null) {
|
||||
Fawe.debug("Not registered " + clazz);
|
||||
Supplier<T> supplier = IOUtil.supplier(clazz::newInstance);
|
||||
pool = supplier::get;
|
||||
REGISTERED_POOLS.put(clazz, pool);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
return pool;
|
||||
}
|
||||
|
||||
public static final IterableThreadLocal<char[]> SECTION_BITS_TO_CHAR = new IterableThreadLocal<char[]>() {
|
||||
@Override
|
||||
public char[] init() {
|
||||
char[] result = new char[4096];
|
||||
return result;
|
||||
}
|
||||
};
|
||||
public final <T> T getFromPool(Class<T> clazz) {
|
||||
Pool<T> pool = getPool(clazz);
|
||||
return pool.poll();
|
||||
}
|
||||
|
||||
public static final IterableThreadLocal<int[]> PALETTE_TO_BLOCK = new IterableThreadLocal<int[]>() {
|
||||
@Override
|
||||
public int[] init() {
|
||||
return new int[Character.MAX_VALUE + 1];
|
||||
public final <T> T getSingleton(Class<T> clazz) {
|
||||
IterableThreadLocal<T> cache = REGISTERED_SINGLETONS.get(clazz);
|
||||
if (cache == null) {
|
||||
synchronized (this) {
|
||||
cache = REGISTERED_SINGLETONS.get(clazz);
|
||||
if (cache == null) {
|
||||
Fawe.debug("Not registered " + clazz);
|
||||
cache = new IterableThreadLocal<>(IOUtil.supplier(clazz::newInstance));
|
||||
REGISTERED_SINGLETONS.put(clazz, cache);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
return cache.get();
|
||||
}
|
||||
|
||||
public static final IterableThreadLocal<char[]> PALETTE_TO_BLOCK_CHAR = new IterableThreadLocal<char[]>() {
|
||||
@Override
|
||||
public char[] init() {
|
||||
char[] result = new char[Character.MAX_VALUE + 1];
|
||||
Arrays.fill(result, Character.MAX_VALUE);
|
||||
return result;
|
||||
public synchronized <T> IterableThreadLocal<T> registerSingleton(Class<T> clazz, Supplier<T> cache) {
|
||||
checkNotNull(cache);
|
||||
IterableThreadLocal<T> local = new IterableThreadLocal<>(cache);
|
||||
IterableThreadLocal previous = REGISTERED_SINGLETONS.putIfAbsent(clazz, local);
|
||||
if (previous != null) {
|
||||
throw new IllegalStateException("Previous key");
|
||||
}
|
||||
};
|
||||
return local;
|
||||
}
|
||||
|
||||
public static final IterableThreadLocal<long[]> BLOCK_STATES = new IterableThreadLocal<long[]>() {
|
||||
@Override
|
||||
public long[] init() {
|
||||
return new long[2048];
|
||||
public synchronized <T> Pool<T> registerPool(Class<T> clazz, Supplier<T> cache, boolean buffer) {
|
||||
checkNotNull(cache);
|
||||
Pool<T> pool;
|
||||
if (buffer) {
|
||||
pool = new QueuePool<>(cache);
|
||||
} else {
|
||||
pool = cache::get;
|
||||
}
|
||||
};
|
||||
Pool previous = REGISTERED_POOLS.putIfAbsent(clazz, pool);
|
||||
if (previous != null) {
|
||||
throw new IllegalStateException("Previous key");
|
||||
}
|
||||
return pool;
|
||||
}
|
||||
|
||||
public static final IterableThreadLocal<int[]> SECTION_BLOCKS = new IterableThreadLocal<int[]>() {
|
||||
@Override
|
||||
public int[] init() {
|
||||
return new int[4096];
|
||||
public final IterableThreadLocal<int[]> BLOCK_TO_PALETTE = new IterableThreadLocal<>(() -> {
|
||||
int[] result = new int[BlockTypes.states.length];
|
||||
Arrays.fill(result, Integer.MAX_VALUE);
|
||||
return result;
|
||||
});
|
||||
|
||||
public final IterableThreadLocal<char[]> SECTION_BITS_TO_CHAR = new IterableThreadLocal<>(() -> new char[4096]);
|
||||
|
||||
public final IterableThreadLocal<int[]> PALETTE_TO_BLOCK = new IterableThreadLocal<>(() -> new int[Character.MAX_VALUE + 1]);
|
||||
|
||||
public final IterableThreadLocal<char[]> PALETTE_TO_BLOCK_CHAR = new IterableThreadLocal<>(
|
||||
() -> new char[Character.MAX_VALUE + 1], a -> {
|
||||
Arrays.fill(a, Character.MAX_VALUE);
|
||||
}
|
||||
};
|
||||
);
|
||||
|
||||
public final IterableThreadLocal<long[]> BLOCK_STATES = new IterableThreadLocal<>(() -> new long[2048]);
|
||||
|
||||
public final IterableThreadLocal<int[]> SECTION_BLOCKS = new IterableThreadLocal<>(() -> new int[4096]);
|
||||
|
||||
public final IterableThreadLocal<int[]> INDEX_STORE = new IterableThreadLocal<>(() -> new int[256]);
|
||||
|
||||
/**
|
||||
* Holds data for a palette used in a chunk section
|
||||
*/
|
||||
public static final class Palette {
|
||||
public final class Palette {
|
||||
public int paletteToBlockLength;
|
||||
/**
|
||||
* Reusable buffer array, MUST check paletteToBlockLength for actual length
|
||||
@ -128,12 +219,7 @@ public final class FaweCache implements Trimable {
|
||||
public long[] blockStates;
|
||||
}
|
||||
|
||||
private static final IterableThreadLocal<Palette> PALETTE_CACHE = new IterableThreadLocal<Palette>() {
|
||||
@Override
|
||||
public Palette init() {
|
||||
return new Palette();
|
||||
}
|
||||
};
|
||||
private final IterableThreadLocal<Palette> PALETTE_CACHE = new IterableThreadLocal<>(Palette::new);
|
||||
|
||||
/**
|
||||
* Convert raw char array to palette
|
||||
@ -141,7 +227,7 @@ public final class FaweCache implements Trimable {
|
||||
* @param blocks
|
||||
* @return palette
|
||||
*/
|
||||
public static Palette toPalette(int layerOffset, char[] blocks) {
|
||||
public Palette toPalette(int layerOffset, char[] blocks) {
|
||||
return toPalette(layerOffset, null, blocks);
|
||||
}
|
||||
|
||||
@ -151,11 +237,11 @@ public final class FaweCache implements Trimable {
|
||||
* @param blocks
|
||||
* @return palette
|
||||
*/
|
||||
public static Palette toPalette(int layerOffset, int[] blocks) {
|
||||
public Palette toPalette(int layerOffset, int[] blocks) {
|
||||
return toPalette(layerOffset, blocks, null);
|
||||
}
|
||||
|
||||
private static Palette toPalette(int layerOffset, int[] blocksInts, char[] blocksChars) {
|
||||
private Palette toPalette(int layerOffset, int[] blocksInts, char[] blocksChars) {
|
||||
int[] blockToPalette = BLOCK_TO_PALETTE.get();
|
||||
int[] paletteToBlock = PALETTE_TO_BLOCK.get();
|
||||
long[] blockStates = BLOCK_STATES.get();
|
||||
@ -229,14 +315,9 @@ public final class FaweCache implements Trimable {
|
||||
* Vector cache
|
||||
*/
|
||||
|
||||
public static IterableThreadLocal<MutableBlockVector3> MUTABLE_BLOCKVECTOR3 = new IterableThreadLocal<MutableBlockVector3>() {
|
||||
@Override
|
||||
public MutableBlockVector3 init() {
|
||||
return new MutableBlockVector3();
|
||||
}
|
||||
};
|
||||
public IterableThreadLocal<MutableBlockVector3> MUTABLE_BLOCKVECTOR3 = new IterableThreadLocal<>(MutableBlockVector3::new);
|
||||
|
||||
public static IterableThreadLocal<MutableVector3> MUTABLE_VECTOR3 = new IterableThreadLocal<MutableVector3>() {
|
||||
public IterableThreadLocal<MutableVector3> MUTABLE_VECTOR3 = new IterableThreadLocal<MutableVector3>(MutableVector3::new) {
|
||||
@Override
|
||||
public MutableVector3 init() {
|
||||
return new MutableVector3();
|
||||
@ -246,7 +327,7 @@ public final class FaweCache implements Trimable {
|
||||
/*
|
||||
Conversion methods between JNBT tags and raw values
|
||||
*/
|
||||
public static Map<String, Object> asMap(Object... pairs) {
|
||||
public Map<String, Object> asMap(Object... pairs) {
|
||||
HashMap<String, Object> map = new HashMap<>(pairs.length >> 1);
|
||||
for (int i = 0; i < pairs.length; i += 2) {
|
||||
String key = (String) pairs[i];
|
||||
@ -256,47 +337,47 @@ public final class FaweCache implements Trimable {
|
||||
return map;
|
||||
}
|
||||
|
||||
public static ShortTag asTag(short value) {
|
||||
public ShortTag asTag(short value) {
|
||||
return new ShortTag(value);
|
||||
}
|
||||
|
||||
public static IntTag asTag(int value) {
|
||||
public IntTag asTag(int value) {
|
||||
return new IntTag(value);
|
||||
}
|
||||
|
||||
public static DoubleTag asTag(double value) {
|
||||
public DoubleTag asTag(double value) {
|
||||
return new DoubleTag(value);
|
||||
}
|
||||
|
||||
public static ByteTag asTag(byte value) {
|
||||
public ByteTag asTag(byte value) {
|
||||
return new ByteTag(value);
|
||||
}
|
||||
|
||||
public static FloatTag asTag(float value) {
|
||||
public FloatTag asTag(float value) {
|
||||
return new FloatTag(value);
|
||||
}
|
||||
|
||||
public static LongTag asTag(long value) {
|
||||
public LongTag asTag(long value) {
|
||||
return new LongTag(value);
|
||||
}
|
||||
|
||||
public static ByteArrayTag asTag(byte[] value) {
|
||||
public ByteArrayTag asTag(byte[] value) {
|
||||
return new ByteArrayTag(value);
|
||||
}
|
||||
|
||||
public static IntArrayTag asTag(int[] value) {
|
||||
public IntArrayTag asTag(int[] value) {
|
||||
return new IntArrayTag(value);
|
||||
}
|
||||
|
||||
public static LongArrayTag asTag(long[] value) {
|
||||
public LongArrayTag asTag(long[] value) {
|
||||
return new LongArrayTag(value);
|
||||
}
|
||||
|
||||
public static StringTag asTag(String value) {
|
||||
public StringTag asTag(String value) {
|
||||
return new StringTag(value);
|
||||
}
|
||||
|
||||
public static CompoundTag asTag(Map<String, Object> value) {
|
||||
public CompoundTag asTag(Map<String, Object> value) {
|
||||
HashMap<String, Tag> map = new HashMap<>();
|
||||
for (Map.Entry<String, Object> entry : value.entrySet()) {
|
||||
Object child = entry.getValue();
|
||||
@ -306,7 +387,7 @@ public final class FaweCache implements Trimable {
|
||||
return new CompoundTag(map);
|
||||
}
|
||||
|
||||
public static Tag asTag(Object value) {
|
||||
public Tag asTag(Object value) {
|
||||
if (value instanceof Integer) {
|
||||
return asTag((int) value);
|
||||
} else if (value instanceof Short) {
|
||||
@ -359,7 +440,7 @@ public final class FaweCache implements Trimable {
|
||||
}
|
||||
}
|
||||
|
||||
public static ListTag asTag(Object... values) {
|
||||
public ListTag asTag(Object... values) {
|
||||
Class<? extends Tag> clazz = null;
|
||||
List<Tag> list = new ArrayList<>(values.length);
|
||||
for (Object value : values) {
|
||||
@ -373,7 +454,7 @@ public final class FaweCache implements Trimable {
|
||||
return new ListTag(clazz, list);
|
||||
}
|
||||
|
||||
public static ListTag asTag(Collection values) {
|
||||
public ListTag asTag(Collection values) {
|
||||
Class<? extends Tag> clazz = null;
|
||||
List<Tag> list = new ArrayList<>(values.size());
|
||||
for (Object value : values) {
|
||||
@ -390,7 +471,7 @@ public final class FaweCache implements Trimable {
|
||||
/*
|
||||
Thread stuff
|
||||
*/
|
||||
public static ThreadPoolExecutor newBlockingExecutor() {
|
||||
public ThreadPoolExecutor newBlockingExecutor() {
|
||||
int nThreads = Settings.IMP.QUEUE.PARALLEL_THREADS;
|
||||
ArrayBlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(nThreads);
|
||||
return new ThreadPoolExecutor(nThreads, nThreads,
|
||||
|
@ -106,6 +106,8 @@ public interface IChunk<T extends Future<T>> extends Trimable, Callable<T>, IChu
|
||||
/* set - queues a change */
|
||||
boolean setBiome(int x, int y, int z, BiomeType biome);
|
||||
|
||||
boolean setTile(int x, int y, int z, CompoundTag tag);
|
||||
|
||||
boolean setBlock(int x, int y, int z, BlockStateHolder block);
|
||||
|
||||
@Override
|
||||
@ -126,7 +128,7 @@ public interface IChunk<T extends Future<T>> extends Trimable, Callable<T>, IChu
|
||||
*/
|
||||
@Override
|
||||
default IBlocks reset() {
|
||||
init(getQueue(), getX(), getZ());
|
||||
init(null, getX(), getZ());
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,8 @@ import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
* An interface for getting blocks.
|
||||
*/
|
||||
@ -28,4 +30,8 @@ public interface IChunkGet extends IBlocks, Trimable, InputExtent {
|
||||
default void optimize() {
|
||||
|
||||
}
|
||||
|
||||
<T extends Future<T>> T call(IChunkSet set, Runnable finalize);
|
||||
|
||||
char[] load(int layer);
|
||||
}
|
||||
|
@ -28,6 +28,10 @@ public interface IDelegateChunk<U extends IChunk> extends IChunk {
|
||||
return root;
|
||||
}
|
||||
|
||||
@Override
|
||||
default <T extends Future<T>> T call(IChunkSet set, Runnable finalize) {
|
||||
return getParent().call(set, finalize);
|
||||
}
|
||||
|
||||
@Override
|
||||
default IQueueExtent getQueue() {
|
||||
@ -49,6 +53,11 @@ public interface IDelegateChunk<U extends IChunk> extends IChunk {
|
||||
getParent().flood(flood, mask, block);
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean setTile(int x, int y, int z, CompoundTag tag) {
|
||||
return getParent().setTile(x, y, z, tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean setBiome(int x, int y, int z, BiomeType biome) {
|
||||
return getParent().setBiome(x, y, z, biome);
|
||||
@ -74,6 +83,11 @@ public interface IDelegateChunk<U extends IChunk> extends IChunk {
|
||||
return getParent().getFullBlock(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
default char[] load(int layer) {
|
||||
return getParent().load(layer);
|
||||
}
|
||||
|
||||
@Override
|
||||
default void init(IQueueExtent extent, int chunkX, int chunkZ) {
|
||||
getParent().init(extent, chunkX, chunkZ);
|
||||
|
@ -1,6 +1,35 @@
|
||||
package com.boydti.fawe.beta;
|
||||
|
||||
import com.boydti.fawe.beta.implementation.WorldChunkCache;
|
||||
import com.boydti.fawe.beta.implementation.IChunkCache;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.MaxChangedBlocksException;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.entity.Entity;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
|
||||
import com.sk89q.worldedit.function.generator.GenBase;
|
||||
import com.sk89q.worldedit.function.generator.Resource;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.function.operation.Operation;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.session.ClipboardHolder;
|
||||
import com.sk89q.worldedit.util.Countable;
|
||||
import com.sk89q.worldedit.util.Location;
|
||||
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 javax.annotation.Nullable;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
@ -11,8 +40,43 @@ public interface IDelegateQueueExtent extends IQueueExtent {
|
||||
IQueueExtent getParent();
|
||||
|
||||
@Override
|
||||
default void init(WorldChunkCache cache) {
|
||||
getParent().init(cache);
|
||||
default boolean isQueueEnabled() {
|
||||
return getParent().isQueueEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
default void clearBlockUpdates(Player... players) {
|
||||
getParent().clearBlockUpdates(players);
|
||||
}
|
||||
|
||||
@Override
|
||||
default void sendBlockUpdates(Player... players) {
|
||||
getParent().sendBlockUpdates(players);
|
||||
}
|
||||
|
||||
@Override
|
||||
default void enableQueue() {
|
||||
getParent().enableQueue();
|
||||
}
|
||||
|
||||
@Override
|
||||
default void disableQueue() {
|
||||
getParent().disableQueue();
|
||||
}
|
||||
|
||||
@Override
|
||||
default void init(Extent extent, IChunkCache<IChunkGet> get, IChunkCache<IChunkSet> set) {
|
||||
getParent().init(extent, get, set);
|
||||
}
|
||||
|
||||
@Override
|
||||
default IChunkGet getCachedGet(int x, int z) {
|
||||
return getParent().getCachedGet(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
default IChunkSet getCachedSet(int x, int z) {
|
||||
return getParent().getCachedSet(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -21,10 +85,50 @@ public interface IDelegateQueueExtent extends IQueueExtent {
|
||||
}
|
||||
|
||||
@Override
|
||||
default Future<?> submit(IChunk chunk) {
|
||||
default <T extends Future<T>> T submit(IChunk<T> chunk) {
|
||||
return getParent().submit(chunk);
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean setBlock(int x, int y, int z, BlockStateHolder state) {
|
||||
return getParent().setBlock(x, y, z, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException {
|
||||
return getParent().setTile(x, y, z, tile);
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean setBiome(int x, int y, int z, BiomeType biome) {
|
||||
return getParent().setBiome(x, y, z, biome);
|
||||
}
|
||||
|
||||
@Override
|
||||
default BlockState getBlock(int x, int y, int z) {
|
||||
return getParent().getBlock(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
default BaseBlock getFullBlock(int x, int y, int z) {
|
||||
return getParent().getFullBlock(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
default BiomeType getBiome(int x, int z) {
|
||||
return getParent().getBiome(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
default BlockVector3 getMinimumPoint() {
|
||||
return getParent().getMinimumPoint();
|
||||
}
|
||||
|
||||
@Override
|
||||
default BlockVector3 getMaximumPoint() {
|
||||
return getParent().getMaximumPoint();
|
||||
}
|
||||
|
||||
@Override
|
||||
default IChunk create(boolean isFull) {
|
||||
return getParent().create(isFull);
|
||||
@ -40,8 +144,247 @@ public interface IDelegateQueueExtent extends IQueueExtent {
|
||||
getParent().flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
default ChunkFilterBlock initFilterBlock() {
|
||||
return getParent().initFilterBlock();
|
||||
}
|
||||
|
||||
@Override
|
||||
default int size() {
|
||||
return getParent().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean isEmpty() {
|
||||
return getParent().isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
default void sendChunk(int chunkX, int chunkZ, int bitMask) {
|
||||
getParent().sendChunk(chunkX, chunkZ, bitMask);
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean trim(boolean aggressive) {
|
||||
return getParent().trim(aggressive);
|
||||
}
|
||||
|
||||
@Override
|
||||
default void recycle() {
|
||||
getParent().recycle();
|
||||
}
|
||||
|
||||
@Override
|
||||
default List<? extends Entity> getEntities(Region region) {
|
||||
return getParent().getEntities(region);
|
||||
}
|
||||
|
||||
@Override
|
||||
default List<? extends Entity> getEntities() {
|
||||
return getParent().getEntities();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
default Entity createEntity(Location location, BaseEntity entity) {
|
||||
return getParent().createEntity(location, entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
default void removeEntity(int x, int y, int z, UUID uuid) {
|
||||
getParent().removeEntity(x, y, z, uuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean isWorld() {
|
||||
return getParent().isWorld();
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean regenerateChunk(int x, int z, @Nullable BiomeType type, @Nullable Long seed) {
|
||||
return getParent().regenerateChunk(x, z, type, seed);
|
||||
}
|
||||
|
||||
@Override
|
||||
default int getHighestTerrainBlock(int x, int z, int minY, int maxY) {
|
||||
return getParent().getHighestTerrainBlock(x, z, minY, maxY);
|
||||
}
|
||||
|
||||
@Override
|
||||
default int getHighestTerrainBlock(int x, int z, int minY, int maxY, Mask filter) {
|
||||
return getParent().getHighestTerrainBlock(x, z, minY, maxY, filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
default int getNearestSurfaceLayer(int x, int z, int y, int minY, int maxY) {
|
||||
return getParent().getNearestSurfaceLayer(x, z, y, minY, maxY);
|
||||
}
|
||||
|
||||
@Override
|
||||
default int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, boolean ignoreAir) {
|
||||
return getParent().getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, ignoreAir);
|
||||
}
|
||||
|
||||
@Override
|
||||
default int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY) {
|
||||
return getParent().getNearestSurfaceTerrainBlock(x, z, y, minY, maxY);
|
||||
}
|
||||
|
||||
@Override
|
||||
default int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax) {
|
||||
return getParent().getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax);
|
||||
}
|
||||
|
||||
@Override
|
||||
default int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax, Mask mask) {
|
||||
return getParent().getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, mask);
|
||||
}
|
||||
|
||||
@Override
|
||||
default int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax, boolean ignoreAir) {
|
||||
return getParent().getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, ignoreAir);
|
||||
}
|
||||
|
||||
@Override
|
||||
default void addCaves(Region region) throws WorldEditException {
|
||||
getParent().addCaves(region);
|
||||
}
|
||||
|
||||
@Override
|
||||
default void generate(Region region, GenBase gen) throws WorldEditException {
|
||||
getParent().generate(region, gen);
|
||||
}
|
||||
|
||||
@Override
|
||||
default void addSchems(Region region, Mask mask, List<ClipboardHolder> clipboards, int rarity, boolean rotate) throws WorldEditException {
|
||||
getParent().addSchems(region, mask, clipboards, rarity, rotate);
|
||||
}
|
||||
|
||||
@Override
|
||||
default void spawnResource(Region region, Resource gen, int rarity, int frequency) throws WorldEditException {
|
||||
getParent().spawnResource(region, gen, rarity, frequency);
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean contains(BlockVector3 pt) {
|
||||
return getParent().contains(pt);
|
||||
}
|
||||
|
||||
@Override
|
||||
default void addOre(Region region, Mask mask, Pattern material, int size, int frequency, int rarity, int minY, int maxY) throws WorldEditException {
|
||||
getParent().addOre(region, mask, material, size, frequency, rarity, minY, maxY);
|
||||
}
|
||||
|
||||
@Override
|
||||
default void addOres(Region region, Mask mask) throws WorldEditException {
|
||||
getParent().addOres(region, mask);
|
||||
}
|
||||
|
||||
@Override
|
||||
default List<Countable<BlockType>> getBlockDistribution(Region region) {
|
||||
return getParent().getBlockDistribution(region);
|
||||
}
|
||||
|
||||
@Override
|
||||
default List<Countable<BlockState>> getBlockDistributionWithData(Region region) {
|
||||
return getParent().getBlockDistributionWithData(region);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
default Operation commit() {
|
||||
return getParent().commit();
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean cancel() {
|
||||
return getParent().cancel();
|
||||
}
|
||||
|
||||
@Override
|
||||
default int getMaxY() {
|
||||
return getParent().getMaxY();
|
||||
}
|
||||
|
||||
@Override
|
||||
default BlockArrayClipboard lazyCopy(Region region) {
|
||||
return getParent().lazyCopy(region);
|
||||
}
|
||||
|
||||
@Override
|
||||
default int countBlocks(Region region, Set<BaseBlock> searchBlocks) {
|
||||
return getParent().countBlocks(region, searchBlocks);
|
||||
}
|
||||
|
||||
@Override
|
||||
default int countBlocks(Region region, Mask searchMask) {
|
||||
return getParent().countBlocks(region, searchMask);
|
||||
}
|
||||
|
||||
@Override
|
||||
default <B extends BlockStateHolder<B>> int setBlocks(Region region, B block) throws MaxChangedBlocksException {
|
||||
return getParent().setBlocks(region, block);
|
||||
}
|
||||
|
||||
@Override
|
||||
default int setBlocks(Region region, Pattern pattern) throws MaxChangedBlocksException {
|
||||
return getParent().setBlocks(region, pattern);
|
||||
}
|
||||
|
||||
@Override
|
||||
default <B extends BlockStateHolder<B>> int replaceBlocks(Region region, Set<BaseBlock> filter, B replacement) throws MaxChangedBlocksException {
|
||||
return getParent().replaceBlocks(region, filter, replacement);
|
||||
}
|
||||
|
||||
@Override
|
||||
default int replaceBlocks(Region region, Set<BaseBlock> filter, Pattern pattern) throws MaxChangedBlocksException {
|
||||
return getParent().replaceBlocks(region, filter, pattern);
|
||||
}
|
||||
|
||||
@Override
|
||||
default int replaceBlocks(Region region, Mask mask, Pattern pattern) throws MaxChangedBlocksException {
|
||||
return getParent().replaceBlocks(region, mask, pattern);
|
||||
}
|
||||
|
||||
@Override
|
||||
default int center(Region region, Pattern pattern) throws MaxChangedBlocksException {
|
||||
return getParent().center(region, pattern);
|
||||
}
|
||||
|
||||
@Override
|
||||
default int setBlocks(Set<BlockVector3> vset, Pattern pattern) {
|
||||
return getParent().setBlocks(vset, pattern);
|
||||
}
|
||||
|
||||
@Override
|
||||
default BlockState getBlock(BlockVector3 position) {
|
||||
return getParent().getBlock(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
default BaseBlock getFullBlock(BlockVector3 position) {
|
||||
return getParent().getFullBlock(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
default BiomeType getBiome(BlockVector2 position) {
|
||||
return getParent().getBiome(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
default BiomeType getBiomeType(int x, int z) {
|
||||
return getParent().getBiomeType(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
default <T extends BlockStateHolder<T>> boolean setBlock(BlockVector3 position, T block) throws WorldEditException {
|
||||
return getParent().setBlock(position, block);
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean setBiome(BlockVector2 position, BiomeType biome) {
|
||||
return getParent().setBiome(position, biome);
|
||||
}
|
||||
}
|
||||
|
@ -1,24 +1,24 @@
|
||||
package com.boydti.fawe.beta;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.implementation.WorldChunkCache;
|
||||
import com.boydti.fawe.beta.implementation.IChunkCache;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.registry.Keyed;
|
||||
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 java.io.Flushable;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* TODO: implement Extent (need to refactor Extent first) Interface for a queue based extent which
|
||||
* uses chunks
|
||||
*/
|
||||
public interface IQueueExtent extends Flushable, Trimable, Extent, Keyed {
|
||||
public interface IQueueExtent extends Flushable, Trimable, Extent {
|
||||
|
||||
@Override
|
||||
default boolean isQueueEnabled() {
|
||||
@ -54,7 +54,7 @@ public interface IQueueExtent extends Flushable, Trimable, Extent, Keyed {
|
||||
void disableQueue();
|
||||
|
||||
|
||||
void init(WorldChunkCache world); // TODO NOT IMPLEMENTED replace with supplier
|
||||
void init(Extent extent, IChunkCache<IChunkGet> get, IChunkCache<IChunkSet> set);
|
||||
|
||||
/**
|
||||
* Get the cached get object
|
||||
@ -64,7 +64,7 @@ public interface IQueueExtent extends Flushable, Trimable, Extent, Keyed {
|
||||
* @param supplier
|
||||
* @return
|
||||
*/
|
||||
IChunkGet getCachedGet(int x, int z, Supplier<IChunkGet> supplier);
|
||||
IChunkGet getCachedGet(int x, int z);
|
||||
|
||||
/**
|
||||
* Get the cached chunk set object
|
||||
@ -73,7 +73,7 @@ public interface IQueueExtent extends Flushable, Trimable, Extent, Keyed {
|
||||
* @param supplier
|
||||
* @return
|
||||
*/
|
||||
IChunkSet getCachedSet(int x, int z, Supplier<IChunkSet> supplier);
|
||||
IChunkSet getCachedSet(int x, int z);
|
||||
|
||||
/**
|
||||
* Get the IChunk at a position (and cache it if it's not already)
|
||||
@ -100,6 +100,12 @@ public interface IQueueExtent extends Flushable, Trimable, Extent, Keyed {
|
||||
return chunk.setBlock(x & 15, y, z & 15, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException {
|
||||
final IChunk chunk = getCachedChunk(x >> 4, z >> 4);
|
||||
return chunk.setTile(x & 15, y, z & 15, tile);
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean setBiome(int x, int y, int z, BiomeType biome) {
|
||||
final IChunk chunk = getCachedChunk(x >> 4, z >> 4);
|
||||
@ -130,7 +136,7 @@ public interface IQueueExtent extends Flushable, Trimable, Extent, Keyed {
|
||||
|
||||
@Override
|
||||
default BlockVector3 getMaximumPoint() {
|
||||
return BlockVector3.at(30000000, FaweCache.WORLD_MAX_Y, 30000000);
|
||||
return BlockVector3.at(30000000, FaweCache.IMP.WORLD_MAX_Y, 30000000);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -14,4 +14,6 @@ public interface Trimable {
|
||||
* @return if this object is empty at the end of the trim, and can therefore be deleted
|
||||
*/
|
||||
boolean trim(boolean aggressive);
|
||||
|
||||
default void recycle() {}
|
||||
}
|
||||
|
@ -2,33 +2,22 @@ package com.boydti.fawe.beta.implementation;
|
||||
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.Trimable;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectIterator;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* IGetBlocks may be cached by the WorldChunkCache so that it can be used between multiple
|
||||
* IQueueExtents - avoids conversion between palette and raw data on every block get
|
||||
*/
|
||||
public class WorldChunkCache implements Trimable {
|
||||
public class ChunkCache<T extends Trimable> implements IChunkCache<T> {
|
||||
|
||||
protected final Long2ObjectLinkedOpenHashMap<WeakReference<IChunkGet>> getCache;
|
||||
private final World world;
|
||||
protected final Long2ObjectLinkedOpenHashMap<WeakReference<T>> getCache;
|
||||
private final IChunkCache<T> delegate;
|
||||
|
||||
protected WorldChunkCache(World world) {
|
||||
this.world = world;
|
||||
protected ChunkCache(IChunkCache<T> delegate) {
|
||||
this.getCache = new Long2ObjectLinkedOpenHashMap<>();
|
||||
}
|
||||
|
||||
public World getWorld() {
|
||||
return world;
|
||||
}
|
||||
|
||||
public synchronized int size() {
|
||||
return getCache.size();
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -38,38 +27,47 @@ public class WorldChunkCache implements Trimable {
|
||||
* @param provider used to create if it isn't already cached
|
||||
* @return cached IGetBlocks
|
||||
*/
|
||||
public synchronized IChunkGet get(long index, Supplier<IChunkGet> provider) {
|
||||
final WeakReference<IChunkGet> ref = getCache.get(index);
|
||||
@Override
|
||||
public synchronized T get(int x, int z) {
|
||||
long pair = MathMan.pairInt(x, z);
|
||||
final WeakReference<T> ref = getCache.get(pair);
|
||||
if (ref != null) {
|
||||
final IChunkGet blocks = ref.get();
|
||||
final T blocks = ref.get();
|
||||
if (blocks != null) {
|
||||
return blocks;
|
||||
}
|
||||
}
|
||||
final IChunkGet blocks = provider.get();
|
||||
getCache.put(index, new WeakReference<>(blocks));
|
||||
final T blocks = newChunk(x, z);
|
||||
getCache.put(pair, new WeakReference<>(blocks));
|
||||
return blocks;
|
||||
}
|
||||
|
||||
public T newChunk(int chunkX, int chunkZ) {
|
||||
return delegate.get(chunkX, chunkZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean trim(boolean aggressive) {
|
||||
if (getCache.size() == 0) {
|
||||
return true;
|
||||
}
|
||||
boolean result = true;
|
||||
if (!getCache.isEmpty()) {
|
||||
final ObjectIterator<Long2ObjectMap.Entry<WeakReference<IChunkGet>>> iter = getCache
|
||||
.long2ObjectEntrySet().fastIterator();
|
||||
final ObjectIterator<Long2ObjectMap.Entry<WeakReference<T>>> iter = getCache
|
||||
.long2ObjectEntrySet().fastIterator();
|
||||
while (iter.hasNext()) {
|
||||
final Long2ObjectMap.Entry<WeakReference<IChunkGet>> entry = iter.next();
|
||||
final WeakReference<IChunkGet> value = entry.getValue();
|
||||
final IChunkGet igb = value.get();
|
||||
final Long2ObjectMap.Entry<WeakReference<T>> entry = iter.next();
|
||||
final WeakReference<T> value = entry.getValue();
|
||||
final T igb = value.get();
|
||||
if (igb == null) {
|
||||
iter.remove();
|
||||
} else {
|
||||
result = false;
|
||||
if (!aggressive) {
|
||||
return result;
|
||||
return false;
|
||||
}
|
||||
synchronized (igb) {
|
||||
igb.trim(aggressive);
|
||||
igb.trim(true);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,135 @@
|
||||
package com.boydti.fawe.beta.implementation;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IBlocks;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
public class FallbackChunkGet implements IChunkGet {
|
||||
private final int bx, bz;
|
||||
private final Extent extent;
|
||||
|
||||
public FallbackChunkGet(Extent extent, int chunkX, int chunkZ) {
|
||||
this.extent = extent;
|
||||
this.bx = chunkX << 4;
|
||||
this.bz = chunkZ << 4;
|
||||
}
|
||||
@Override
|
||||
public BaseBlock getFullBlock(int x, int y, int z) {
|
||||
return extent.getFullBlock(bx + x, y, bz + z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeType getBiomeType(int x, int z) {
|
||||
return extent.getBiomeType(bx + x, bz + z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getBlock(int x, int y, int z) {
|
||||
return extent.getBlock(bx + x, y, bz + z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getTag(int x, int y, int z) {
|
||||
return extent.getFullBlock(bx + x, y, bz + z).getNbtData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean trim(boolean aggressive) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Future<T>> T call(IChunkSet set, Runnable finalize) {
|
||||
for (int layer = 0; layer < 16; layer++) {
|
||||
if (set.hasSection(layer)) {
|
||||
char[] arr = set.getArray(layer);
|
||||
int by = layer << 4;
|
||||
for (int y = 0, i = 0; y < 16; y++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int x = 0; x < 16; x++, i++) {
|
||||
char ordinal = arr[i];
|
||||
if (ordinal != 0) {
|
||||
BlockState block = BlockState.getFromOrdinal(ordinal);
|
||||
extent.setBlock(bx + x, by + y, bz + z, block);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Map<Short, CompoundTag> tiles = set.getTiles();
|
||||
if (!tiles.isEmpty()) {
|
||||
for (Map.Entry<Short, CompoundTag> entry : tiles.entrySet()) {
|
||||
short blockHash = entry.getKey();
|
||||
final int x = (blockHash >> 12 & 0xF) + bx;
|
||||
final int y = (blockHash & 0xFF);
|
||||
final int z = (blockHash >> 8 & 0xF) + bz;
|
||||
extent.setTile(bx + x, y, bz + z, entry.getValue());
|
||||
}
|
||||
|
||||
}
|
||||
Set<CompoundTag> spawns = set.getEntities();
|
||||
if (!spawns.isEmpty()) {
|
||||
for (CompoundTag spawn : spawns) {
|
||||
BaseEntity ent = new BaseEntity(spawn);
|
||||
extent.createEntity(ent.getLocation(extent), ent);
|
||||
}
|
||||
}
|
||||
Set<UUID> kills = set.getEntityRemoves();
|
||||
if (!kills.isEmpty()) {
|
||||
for (UUID kill : kills) {
|
||||
extent.removeEntity(0, 0, 0, kill);
|
||||
}
|
||||
}
|
||||
BiomeType[] biomes = set.getBiomes();
|
||||
if (biomes != null) {
|
||||
for (int z = 0, i = 0; z < 16; z++) {
|
||||
for (int x = 0; x < 16; x++, i++) {
|
||||
BiomeType biome = biomes[i];
|
||||
if (biome != null) {
|
||||
extent.setBiome(bx + x, 0, bz + z, biome);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char[] load(int layer) {
|
||||
char[] arr = FaweCache.IMP.SECTION_BITS_TO_CHAR.get();
|
||||
int by = layer << 4;
|
||||
for (int y = 0, i = 0; y < 16; y++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int x = 0; x < 16; x++, i++) {
|
||||
arr[i] = getBlock(bx + x, by + y, bz + z).getOrdinalChar();
|
||||
}
|
||||
}
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSection(int layer) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlocks reset() {
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package com.boydti.fawe.beta.implementation;
|
||||
|
||||
import com.boydti.fawe.beta.Trimable;
|
||||
|
||||
/**
|
||||
* IGetBlocks may be cached by the WorldChunkCache so that it can be used between multiple
|
||||
* IQueueExtents - avoids conversion between palette and raw data on every block get
|
||||
*/
|
||||
public interface IChunkCache<T> extends Trimable {
|
||||
T get(int chunkX, int chunkZ);
|
||||
|
||||
@Override
|
||||
default boolean trim(boolean aggressive) {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
package com.boydti.fawe.beta.implementation;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IBlocks;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.biome.BiomeTypes;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
public enum NullChunkGet implements IChunkGet {
|
||||
INSTANCE
|
||||
;
|
||||
@Override
|
||||
public BaseBlock getFullBlock(int x, int y, int z) {
|
||||
return BlockTypes.AIR.getDefaultState().toBaseBlock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeType getBiomeType(int x, int z) {
|
||||
return BiomeTypes.FOREST;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getBlock(int x, int y, int z) {
|
||||
return BlockTypes.AIR.getDefaultState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getTag(int x, int y, int z) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean trim(boolean aggressive) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Future<T>> T call(IChunkSet set, Runnable finalize) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char[] load(int layer) {
|
||||
return FaweCache.IMP.EMPTY_CHAR_4096;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSection(int layer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlocks reset() {
|
||||
return null;
|
||||
}
|
||||
}
|
@ -3,6 +3,8 @@ package com.boydti.fawe.beta.implementation;
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IChunk;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.boydti.fawe.beta.IQueueExtent;
|
||||
import com.boydti.fawe.beta.Trimable;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
@ -11,6 +13,7 @@ import com.boydti.fawe.util.MemUtil;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.boydti.fawe.wrappers.WorldWrapper;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.HashMap;
|
||||
@ -33,16 +36,11 @@ public abstract class QueueHandler implements Trimable, Runnable {
|
||||
|
||||
private ForkJoinPool forkJoinPoolPrimary = new ForkJoinPool();
|
||||
private ForkJoinPool forkJoinPoolSecondary = new ForkJoinPool();
|
||||
private ThreadPoolExecutor blockingExecutor = FaweCache.newBlockingExecutor();
|
||||
private ThreadPoolExecutor blockingExecutor = FaweCache.IMP.newBlockingExecutor();
|
||||
private ConcurrentLinkedQueue<FutureTask> syncTasks = new ConcurrentLinkedQueue<>();
|
||||
|
||||
private Map<World, WeakReference<WorldChunkCache>> chunkCache = new HashMap<>();
|
||||
private IterableThreadLocal<IQueueExtent> queuePool = new IterableThreadLocal<IQueueExtent>() {
|
||||
@Override
|
||||
public IQueueExtent init() {
|
||||
return create();
|
||||
}
|
||||
};
|
||||
private Map<World, WeakReference<IChunkCache<IChunkGet>>> chunkCache = new HashMap<>();
|
||||
private IterableThreadLocal<IQueueExtent> queuePool = new IterableThreadLocal<>(QueueHandler.this::create);
|
||||
/**
|
||||
* Used to calculate elapsed time in milliseconds and ensure block placement doesn't lag the
|
||||
* server
|
||||
@ -50,6 +48,7 @@ public abstract class QueueHandler implements Trimable, Runnable {
|
||||
private long last;
|
||||
private long allocate = 50;
|
||||
private double targetTPS = 18;
|
||||
|
||||
public QueueHandler() {
|
||||
TaskManager.IMP.repeat(this, 1);
|
||||
}
|
||||
@ -197,18 +196,18 @@ public abstract class QueueHandler implements Trimable, Runnable {
|
||||
* @param world
|
||||
* @return
|
||||
*/
|
||||
public WorldChunkCache getOrCreate(World world) {
|
||||
public IChunkCache<IChunkGet> getOrCreateWorldCache(World world) {
|
||||
world = WorldWrapper.unwrap(world);
|
||||
|
||||
synchronized (chunkCache) {
|
||||
final WeakReference<WorldChunkCache> ref = chunkCache.get(world);
|
||||
final WeakReference<IChunkCache<IChunkGet>> ref = chunkCache.get(world);
|
||||
if (ref != null) {
|
||||
final WorldChunkCache cached = ref.get();
|
||||
final IChunkCache<IChunkGet> cached = ref.get();
|
||||
if (cached != null) {
|
||||
return cached;
|
||||
}
|
||||
}
|
||||
final WorldChunkCache created = new WorldChunkCache(world);
|
||||
final IChunkCache<IChunkGet> created = new ChunkCache<>(world);
|
||||
chunkCache.put(world, new WeakReference<>(created));
|
||||
return created;
|
||||
}
|
||||
@ -222,7 +221,9 @@ public abstract class QueueHandler implements Trimable, Runnable {
|
||||
|
||||
public IQueueExtent getQueue(World world) {
|
||||
final IQueueExtent queue = queuePool.get();
|
||||
queue.init(getOrCreate(world));
|
||||
IChunkCache<IChunkGet> cacheGet = getOrCreateWorldCache(world);
|
||||
IChunkCache<IChunkSet> set = null; // TODO cache?
|
||||
queue.init(world, cacheGet, set);
|
||||
return queue;
|
||||
}
|
||||
|
||||
@ -230,13 +231,13 @@ public abstract class QueueHandler implements Trimable, Runnable {
|
||||
public boolean trim(boolean aggressive) {
|
||||
boolean result = true;
|
||||
synchronized (chunkCache) {
|
||||
final Iterator<Map.Entry<World, WeakReference<WorldChunkCache>>> iter = chunkCache
|
||||
final Iterator<Map.Entry<World, WeakReference<IChunkCache<IChunkGet>>>> iter = chunkCache
|
||||
.entrySet().iterator();
|
||||
while (iter.hasNext()) {
|
||||
final Map.Entry<World, WeakReference<WorldChunkCache>> entry = iter.next();
|
||||
final WeakReference<WorldChunkCache> value = entry.getValue();
|
||||
final WorldChunkCache cache = value.get();
|
||||
if (cache == null || cache.size() == 0 || cache.trim(aggressive)) {
|
||||
final Map.Entry<World, WeakReference<IChunkCache<IChunkGet>>> entry = iter.next();
|
||||
final WeakReference<IChunkCache<IChunkGet>> value = entry.getValue();
|
||||
final IChunkCache<IChunkGet> cache = value.get();
|
||||
if (cache.trim(aggressive)) {
|
||||
iter.remove();
|
||||
continue;
|
||||
}
|
||||
|
@ -1,41 +1,49 @@
|
||||
package com.boydti.fawe.beta.implementation;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.beta.IChunk;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.boydti.fawe.beta.IQueueExtent;
|
||||
import com.boydti.fawe.beta.implementation.blocks.CharSetBlocks;
|
||||
import com.boydti.fawe.beta.implementation.holder.ChunkHolder;
|
||||
import com.boydti.fawe.beta.implementation.holder.ReferenceChunk;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.boydti.fawe.util.MemUtil;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap;
|
||||
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Single threaded implementation for IQueueExtent (still abstract) - Does not implement creation of
|
||||
* chunks (that has to implemented by the platform e.g. Bukkit)
|
||||
* <p>
|
||||
* This queue is reusable {@link #init(WorldChunkCache)}
|
||||
* This queue is reusable {@link #init(IChunkCache)}
|
||||
*/
|
||||
public abstract class SingleThreadQueueExtent implements IQueueExtent {
|
||||
|
||||
// Pool discarded chunks for reuse (can safely be cleared by another thread)
|
||||
private static final ConcurrentLinkedQueue<IChunk> CHUNK_POOL = new ConcurrentLinkedQueue<>();
|
||||
// // Pool discarded chunks for reuse (can safely be cleared by another thread)
|
||||
// private static final ConcurrentLinkedQueue<IChunk> CHUNK_POOL = new ConcurrentLinkedQueue<>();
|
||||
// Chunks currently being queued / worked on
|
||||
private final Long2ObjectLinkedOpenHashMap<IChunk> chunks = new Long2ObjectLinkedOpenHashMap<>();
|
||||
private WorldChunkCache cache;
|
||||
|
||||
private IChunkCache<IChunkGet> cacheGet;
|
||||
private IChunkCache<IChunkSet> cacheSet;
|
||||
private boolean initialized;
|
||||
|
||||
private Thread currentThread;
|
||||
private ConcurrentLinkedQueue<Future> submissions = new ConcurrentLinkedQueue<>();
|
||||
// Last access pointers
|
||||
private IChunk lastChunk;
|
||||
private long lastPair = Long.MAX_VALUE;
|
||||
|
||||
private boolean enabledQueue = true;
|
||||
|
||||
/**
|
||||
* Safety check to ensure that the thread being used matches the one being initialized on. - Can
|
||||
* be removed later
|
||||
@ -48,23 +56,42 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent {
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkGet getCachedGet(int x, int z, Supplier<IChunkGet> supplier) {
|
||||
return cache.get(MathMan.pairInt(x, z), supplier);
|
||||
public void enableQueue() {
|
||||
enabledQueue = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disableQueue() {
|
||||
enabledQueue = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkGet getCachedGet(int x, int z) {
|
||||
return cacheGet.get(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkSet getCachedSet(int x, int z) {
|
||||
return cacheSet.get(x, z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the queue.
|
||||
*/
|
||||
protected synchronized void reset() {
|
||||
if (!initialized) return;
|
||||
checkThread();
|
||||
cache = null;
|
||||
if (!chunks.isEmpty()) {
|
||||
CHUNK_POOL.addAll(chunks.values());
|
||||
for (IChunk chunk : chunks.values()) {
|
||||
chunk.recycle();
|
||||
}
|
||||
chunks.clear();
|
||||
}
|
||||
enabledQueue = true;
|
||||
lastChunk = null;
|
||||
lastPair = Long.MAX_VALUE;
|
||||
currentThread = null;
|
||||
initialized = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -73,17 +100,18 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent {
|
||||
* @param cache
|
||||
*/
|
||||
@Override
|
||||
public synchronized void init(WorldChunkCache cache) {
|
||||
if (this.cache != null) {
|
||||
reset();
|
||||
}
|
||||
public synchronized void init(Extent extent, IChunkCache<IChunkGet> get, IChunkCache<IChunkSet> set) {
|
||||
reset();
|
||||
currentThread = Thread.currentThread();
|
||||
checkNotNull(cache);
|
||||
this.cache = cache;
|
||||
}
|
||||
|
||||
public void returnToPool(IChunk chunk) {
|
||||
CHUNK_POOL.add(chunk);
|
||||
if (get == null) {
|
||||
get = (x, z) -> { throw new UnsupportedOperationException(); };
|
||||
}
|
||||
if (set == null) {
|
||||
set = (x, z) -> CharSetBlocks.newInstance();
|
||||
}
|
||||
this.cacheGet = get;
|
||||
this.cacheSet = set;
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -116,8 +144,9 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent {
|
||||
*/
|
||||
private <T extends Future<T>> T submitUnchecked(IChunk<T> chunk) {
|
||||
if (chunk.isEmpty()) {
|
||||
CHUNK_POOL.add(chunk);
|
||||
return (T) (Future) Futures.immediateFuture(null);
|
||||
chunk.recycle();
|
||||
Future result = Futures.immediateFuture(null);
|
||||
return (T) result;
|
||||
}
|
||||
|
||||
if (Fawe.isMainThread()) {
|
||||
@ -130,7 +159,8 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent {
|
||||
@Override
|
||||
public synchronized boolean trim(boolean aggressive) {
|
||||
// TODO trim individial chunk sections
|
||||
CHUNK_POOL.clear();
|
||||
cacheGet.trim(aggressive);
|
||||
cacheSet.trim(aggressive);
|
||||
if (Thread.currentThread() == currentThread) {
|
||||
lastChunk = null;
|
||||
lastPair = Long.MAX_VALUE;
|
||||
@ -157,10 +187,7 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent {
|
||||
* @return IChunk
|
||||
*/
|
||||
private IChunk poolOrCreate(int X, int Z) {
|
||||
IChunk next = CHUNK_POOL.poll();
|
||||
if (next == null) {
|
||||
next = create(false);
|
||||
}
|
||||
IChunk next = create(false);
|
||||
next.init(this, X, Z);
|
||||
return next;
|
||||
}
|
||||
@ -187,7 +214,7 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent {
|
||||
checkThread();
|
||||
final int size = chunks.size();
|
||||
final boolean lowMem = MemUtil.isMemoryLimited();
|
||||
if (lowMem || size > Settings.IMP.QUEUE.TARGET_SIZE) {
|
||||
if (enabledQueue && (lowMem || size > Settings.IMP.QUEUE.TARGET_SIZE)) {
|
||||
chunk = chunks.removeFirst();
|
||||
final Future future = submitUnchecked(chunk);
|
||||
if (future != null && !future.isDone()) {
|
||||
@ -211,6 +238,11 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent {
|
||||
return chunk;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunk create(boolean isFull) {
|
||||
return ChunkHolder.newInstance();
|
||||
}
|
||||
|
||||
private void pollSubmissions(int targetSize, boolean aggressive) {
|
||||
final int overflow = submissions.size() - targetSize;
|
||||
if (aggressive) {
|
||||
|
@ -63,7 +63,7 @@ public class BitSetBlocks implements IChunkSet {
|
||||
|
||||
@Override
|
||||
public char[] getArray(int layer) {
|
||||
char[] arr = FaweCache.SECTION_BITS_TO_CHAR.get();
|
||||
char[] arr = FaweCache.IMP.SECTION_BITS_TO_CHAR.get();
|
||||
MemBlockSet.IRow nullRowY = row.getRow(layer);
|
||||
if (nullRowY instanceof MemBlockSet.RowY) {
|
||||
char value = blockState.getOrdinalChar();
|
||||
|
@ -6,6 +6,8 @@ import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
public abstract class CharGetBlocks extends CharBlocks implements IChunkGet {
|
||||
|
||||
@Override
|
||||
|
@ -1,6 +1,8 @@
|
||||
package com.boydti.fawe.beta.implementation.blocks;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
@ -14,21 +16,21 @@ import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
public class CharSetBlocks extends CharBlocks implements IChunkSet {
|
||||
private static FaweCache.Pool<CharSetBlocks> POOL = FaweCache.IMP.registerPool(CharSetBlocks.class, CharSetBlocks::new, Settings.IMP.QUEUE.POOL);
|
||||
public static CharSetBlocks newInstance() {
|
||||
return POOL.poll();
|
||||
}
|
||||
|
||||
public BiomeType[] biomes;
|
||||
public HashMap<Short, CompoundTag> tiles;
|
||||
public HashSet<CompoundTag> entities;
|
||||
public HashSet<UUID> entityRemoves;
|
||||
|
||||
public CharSetBlocks(CharBlocks other) {
|
||||
super(other);
|
||||
if (other instanceof CharSetBlocks) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public CharSetBlocks() {
|
||||
private CharSetBlocks() {}
|
||||
|
||||
@Override
|
||||
public void recycle() {
|
||||
POOL.offer(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.boydti.fawe.beta.implementation.holder;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.ChunkFilterBlock;
|
||||
import com.boydti.fawe.beta.Filter;
|
||||
import com.boydti.fawe.beta.FilterBlockMask;
|
||||
@ -10,19 +11,67 @@ import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.boydti.fawe.beta.IQueueExtent;
|
||||
import com.boydti.fawe.beta.implementation.SingleThreadQueueExtent;
|
||||
import com.boydti.fawe.beta.implementation.blocks.CharSetBlocks;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
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 java.util.concurrent.Future;
|
||||
import java.util.function.Supplier;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* An abstract {@link IChunk} class that implements basic get/set blocks
|
||||
*/
|
||||
public abstract class ChunkHolder implements IChunk {
|
||||
public class ChunkHolder<T extends Future<T>> implements IChunk {
|
||||
|
||||
private static FaweCache.Pool<ChunkHolder> POOL = FaweCache.IMP.registerPool(ChunkHolder.class, ChunkHolder::new, Settings.IMP.QUEUE.POOL);
|
||||
|
||||
public static ChunkHolder newInstance() {
|
||||
return POOL.poll();
|
||||
}
|
||||
|
||||
private IChunkGet get;
|
||||
private IChunkSet set;
|
||||
private IBlockDelegate delegate;
|
||||
private IQueueExtent extent;
|
||||
private int chunkX;
|
||||
private int chunkZ;
|
||||
|
||||
public ChunkHolder() {
|
||||
this.delegate = NULL;
|
||||
}
|
||||
|
||||
public void init(IBlockDelegate delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recycle() {
|
||||
delegate = NULL;
|
||||
}
|
||||
|
||||
public IBlockDelegate getDelegate() {
|
||||
return delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IQueueExtent getQueue() {
|
||||
return extent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setTile(int x, int y, int z, CompoundTag tag) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char[] load(int layer) {
|
||||
return getOrCreateGet().load(layer);
|
||||
}
|
||||
|
||||
public static final IBlockDelegate BOTH = new IBlockDelegate() {
|
||||
@Override
|
||||
@ -160,20 +209,6 @@ public abstract class ChunkHolder implements IChunk {
|
||||
return chunk.getFullBlock(x, y, z);
|
||||
}
|
||||
};
|
||||
private IChunkGet get;
|
||||
private IChunkSet set;
|
||||
private IBlockDelegate delegate;
|
||||
private IQueueExtent extent;
|
||||
private int chunkX;
|
||||
private int chunkZ;
|
||||
|
||||
public ChunkHolder() {
|
||||
this.delegate = NULL;
|
||||
}
|
||||
|
||||
public ChunkHolder(IBlockDelegate delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flood(Flood flood, FilterBlockMask mask, ChunkFilterBlock block) {
|
||||
@ -264,14 +299,6 @@ public abstract class ChunkHolder implements IChunk {
|
||||
return set;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the settable part of this chunk (defaults to a char array)
|
||||
* @return
|
||||
*/
|
||||
public IChunkSet createSet() {
|
||||
return new CharSetBlocks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a wrapped set object
|
||||
* - The purpose of wrapping is to allow different extents to intercept / alter behavior
|
||||
@ -279,13 +306,7 @@ public abstract class ChunkHolder implements IChunk {
|
||||
* @return
|
||||
*/
|
||||
private IChunkSet newWrappedSet() {
|
||||
if (extent instanceof SingleThreadQueueExtent) {
|
||||
IChunkSet newSet = extent.getCachedSet(chunkX, chunkZ, this::createSet);
|
||||
if (newSet != null) {
|
||||
return newSet;
|
||||
}
|
||||
}
|
||||
return createSet();
|
||||
return extent.getCachedSet(chunkX, chunkZ);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -295,17 +316,9 @@ public abstract class ChunkHolder implements IChunk {
|
||||
* @return
|
||||
*/
|
||||
private IChunkGet newWrappedGet() {
|
||||
if (extent instanceof SingleThreadQueueExtent) {
|
||||
IChunkGet newGet = extent.getCachedGet(chunkX, chunkZ, this::get);
|
||||
if (newGet != null) {
|
||||
return newGet;
|
||||
}
|
||||
}
|
||||
return get();
|
||||
return extent.getCachedGet(chunkX, chunkZ);
|
||||
}
|
||||
|
||||
public abstract IChunkGet get();
|
||||
|
||||
@Override
|
||||
public void init(IQueueExtent extent, int chunkX, int chunkZ) {
|
||||
this.extent = extent;
|
||||
@ -320,6 +333,22 @@ public abstract class ChunkHolder implements IChunk {
|
||||
get = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized T call() {
|
||||
if (get != null && set != null) {
|
||||
return getOrCreateGet().call(getOrCreateSet(), this::recycle);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T call(IChunkSet set, Runnable finalize) {
|
||||
if (get != null && set != null) {
|
||||
return getOrCreateGet().call(set, finalize);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public IQueueExtent getExtent() {
|
||||
return extent;
|
||||
}
|
||||
|
@ -1,27 +1,29 @@
|
||||
package com.boydti.fawe.beta.implementation.holder;
|
||||
|
||||
import com.boydti.fawe.beta.IChunk;
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.boydti.fawe.beta.IDelegateChunk;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
* Implementation of IDelegateChunk
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
public class DelegateChunk<T extends IChunk> implements IDelegateChunk {
|
||||
public class DelegateChunk<U extends IChunk> implements IDelegateChunk<U> {
|
||||
|
||||
private T parent;
|
||||
private U parent;
|
||||
|
||||
public DelegateChunk(T parent) {
|
||||
public DelegateChunk(U parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final T getParent() {
|
||||
public final U getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
public final void setParent(T parent) {
|
||||
public final void setParent(U parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
}
|
||||
|
@ -475,7 +475,7 @@ public class AnvilCommands {
|
||||
// });
|
||||
// if (useData) {
|
||||
// for (long[] c : map) {
|
||||
// BaseBlock block = FaweCache.CACHE_BLOCK[(int) c[0]];
|
||||
// BaseBlock block = FaweCache.IMP.CACHE_BLOCK[(int) c[0]];
|
||||
// String name = BlockType.fromID(block.getId()).getName();
|
||||
// String str = String.format("%-7s (%.3f%%) %s #%d:%d",
|
||||
// String.valueOf(c[1]),
|
||||
|
@ -293,7 +293,13 @@ public class Settings extends Config {
|
||||
" - Low values may result in FAWE waiting on requests to the main thread",
|
||||
" - Higher values use more memory and isn't noticeably faster",
|
||||
})
|
||||
public int PRELOAD_CHUNKS = 32;
|
||||
public int PRELOAD_CHUNKS = 100000;
|
||||
|
||||
@Comment({
|
||||
"If pooling is enabled (reduces GC, higher memory usage)",
|
||||
" - Enable to improve performance at the expense of memory",
|
||||
})
|
||||
public boolean POOL = true;
|
||||
|
||||
@Comment({
|
||||
"Discard edits which have been idle for a certain amount of time (ms)",
|
||||
|
@ -58,10 +58,10 @@ public class LoggingChangeSet extends AbstractDelegateChangeSet {
|
||||
// loc.x = x;
|
||||
// loc.y = y;
|
||||
// loc.z = z;
|
||||
// oldBlock.id = FaweCache.getId(combinedId4DataFrom);
|
||||
// oldBlock.data = FaweCache.getData(combinedId4DataFrom);
|
||||
// newBlock.id = FaweCache.getId(combinedId4DataTo);
|
||||
// newBlock.data = FaweCache.getData(combinedId4DataTo);
|
||||
// oldBlock.id = FaweCache.IMP.getId(combinedId4DataFrom);
|
||||
// oldBlock.data = FaweCache.IMP.getData(combinedId4DataFrom);
|
||||
// newBlock.id = FaweCache.IMP.getId(combinedId4DataTo);
|
||||
// newBlock.data = FaweCache.IMP.getData(combinedId4DataTo);
|
||||
// // Log to BlocksHub and parent
|
||||
// api.logBlock(loc, player, world, oldBlock, newBlock);
|
||||
parent.add(x, y, z, combinedId4DataFrom, combinedId4DataTo);
|
||||
|
@ -1,7 +1,12 @@
|
||||
package com.boydti.fawe.object.brush.visualization.cfi;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IBlocks;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.boydti.fawe.beta.IQueueExtent;
|
||||
import com.boydti.fawe.beta.implementation.FallbackChunkGet;
|
||||
import com.boydti.fawe.object.FaweInputStream;
|
||||
import com.boydti.fawe.object.FaweOutputStream;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
@ -44,6 +49,7 @@ import com.sk89q.worldedit.session.ClipboardHolder;
|
||||
import com.sk89q.worldedit.util.Location;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.biome.BiomeTypes;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockID;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
@ -58,6 +64,7 @@ import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@ -65,13 +72,6 @@ import javax.annotation.Nullable;
|
||||
public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Drawable, VirtualWorld {
|
||||
private final MutableBlockVector3 mutable = new MutableBlockVector3();
|
||||
|
||||
private final ThreadLocal<int[]> indexStore = new ThreadLocal<int[]>() {
|
||||
@Override
|
||||
protected int[] initialValue() {
|
||||
return new int[256];
|
||||
}
|
||||
};
|
||||
|
||||
private final DifferentialBlockBuffer blocks;
|
||||
protected final DifferentialArray<byte[]> heights;
|
||||
protected final DifferentialArray<byte[]> biomes;
|
||||
@ -1571,7 +1571,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
|
||||
int[] floor = this.floor.get();
|
||||
int[] overlay = this.overlay != null ? this.overlay.get() : null;
|
||||
try {
|
||||
int[] indexes = indexStore.get();
|
||||
int[] indexes = FaweCache.IMP.INDEX_STORE.get();
|
||||
|
||||
int index;
|
||||
int maxY = 0;
|
||||
@ -1902,12 +1902,6 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
|
||||
}));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
IterableThreadLocal.clean(indexStore);
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxY() {
|
||||
return 255;
|
||||
@ -1973,4 +1967,10 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkGet get(int x, int z) {
|
||||
Fawe.debug("Should not be using buffering with HMMG");
|
||||
return new FallbackChunkGet(this, x, z);
|
||||
}
|
||||
}
|
||||
|
@ -79,10 +79,10 @@ public class WritableMCAChunk {
|
||||
}
|
||||
|
||||
public void write(NBTOutputStream nbtOut) throws IOException {
|
||||
int[] blockToPalette = FaweCache.BLOCK_TO_PALETTE.get();
|
||||
int[] paletteToBlock = FaweCache.PALETTE_TO_BLOCK.get();
|
||||
long[] blockstates = FaweCache.BLOCK_STATES.get();
|
||||
int[] blocksCopy = FaweCache.SECTION_BLOCKS.get();
|
||||
int[] blockToPalette = FaweCache.IMP.BLOCK_TO_PALETTE.get();
|
||||
int[] paletteToBlock = FaweCache.IMP.PALETTE_TO_BLOCK.get();
|
||||
long[] blockstates = FaweCache.IMP.BLOCK_STATES.get();
|
||||
int[] blocksCopy = FaweCache.IMP.SECTION_BLOCKS.get();
|
||||
|
||||
nbtOut.writeNamedTagName("", NBTConstants.TYPE_COMPOUND);
|
||||
nbtOut.writeNamedTag("DataVersion", 1631);
|
||||
|
@ -52,7 +52,7 @@ public abstract class FaweChangeSet implements ChangeSet {
|
||||
public FaweChangeSet(String world) {
|
||||
this.worldName = world;
|
||||
this.mainThread = Fawe.get() == null || Fawe.isMainThread();
|
||||
this.layers = FaweCache.CHUNK_LAYERS;
|
||||
this.layers = FaweCache.IMP.CHUNK_LAYERS;
|
||||
}
|
||||
|
||||
public FaweChangeSet(World world) {
|
||||
|
@ -223,7 +223,7 @@ public class ClipboardRemapper {
|
||||
// String name = entry.getKey();
|
||||
// int id = value.get("id").getAsInt();
|
||||
// int data = value.get("data").getAsInt();
|
||||
// int combined = FaweCache.getCombined(id, data);
|
||||
// int combined = FaweCache.IMP.getCombined(id, data);
|
||||
// map.putIfAbsent(name, new ArrayList<>());
|
||||
// map.get(name).add(combined);
|
||||
// }
|
||||
@ -496,7 +496,7 @@ public class ClipboardRemapper {
|
||||
// int combined = block.getCombined();
|
||||
// if (remap[combined]) {
|
||||
// char value = remapCombined[combined];
|
||||
// BaseBlock newBlock = FaweCache.CACHE_BLOCK[value];
|
||||
// BaseBlock newBlock = FaweCache.IMP.CACHE_BLOCK[value];
|
||||
// newBlock.setNbtData(block.getNbtData());
|
||||
// return newBlock;
|
||||
// }
|
||||
|
@ -1,14 +0,0 @@
|
||||
package com.boydti.fawe.object.collection;
|
||||
|
||||
public class ByteStore extends IterableThreadLocal<byte[]> {
|
||||
private final int size;
|
||||
|
||||
public ByteStore(int size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] init() {
|
||||
return new byte[size];
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package com.boydti.fawe.object.collection;
|
||||
|
||||
import com.boydti.fawe.util.IOUtil;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.reflect.Array;
|
||||
@ -8,12 +9,27 @@ import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ConcurrentLinkedDeque;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.IntFunction;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public abstract class IterableThreadLocal<T> extends ThreadLocal<T> implements Iterable<T> {
|
||||
public class IterableThreadLocal<T> extends ThreadLocal<T> implements Iterable<T> {
|
||||
private final ConcurrentLinkedDeque<T> allValues = new ConcurrentLinkedDeque<>();
|
||||
private final Supplier<T> supplier;
|
||||
|
||||
public IterableThreadLocal() {
|
||||
public IterableThreadLocal(Supplier<T> supplier) {
|
||||
this.supplier = supplier;
|
||||
}
|
||||
|
||||
public IterableThreadLocal(Supplier<T> supplier, Function<T, T> modifier) {
|
||||
this.supplier = supplier;
|
||||
}
|
||||
|
||||
public IterableThreadLocal(Supplier<T> supplier, Consumer<T> modifier) {
|
||||
this.supplier = supplier;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -33,7 +49,7 @@ public abstract class IterableThreadLocal<T> extends ThreadLocal<T> implements I
|
||||
}
|
||||
|
||||
public T init() {
|
||||
return null;
|
||||
return supplier.get();
|
||||
}
|
||||
|
||||
public void clean() {
|
||||
|
@ -20,7 +20,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
*/
|
||||
public final class MemBlockSet extends BlockSet {
|
||||
public final static int BITS_PER_WORD = 6;
|
||||
public final static int WORDS = FaweCache.BLOCKS_PER_LAYER >> BITS_PER_WORD;
|
||||
public final static int WORDS = FaweCache.IMP.BLOCKS_PER_LAYER >> BITS_PER_WORD;
|
||||
public final static IRow NULL_ROW_X = new NullRowX();
|
||||
public final static IRow NULL_ROW_Z = new NullRowZ();
|
||||
public final static IRow NULL_ROW_Y = new NullRowY();
|
||||
@ -354,7 +354,7 @@ public final class MemBlockSet extends BlockSet {
|
||||
maxy = y + 1;
|
||||
}
|
||||
by = (Y << 4) + y;
|
||||
if (by == FaweCache.WORLD_MAX_Y) return FaweCache.WORLD_MAX_Y;
|
||||
if (by == FaweCache.IMP.WORLD_MAX_Y) return FaweCache.IMP.WORLD_MAX_Y;
|
||||
break outer;
|
||||
}
|
||||
}
|
||||
@ -823,7 +823,7 @@ public final class MemBlockSet extends BlockSet {
|
||||
private final IRow[] rows;
|
||||
|
||||
public RowZ() {
|
||||
this.rows = new IRow[FaweCache.CHUNK_LAYERS];
|
||||
this.rows = new IRow[FaweCache.IMP.CHUNK_LAYERS];
|
||||
reset();
|
||||
}
|
||||
|
||||
@ -866,7 +866,7 @@ public final class MemBlockSet extends BlockSet {
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
for (int i = 0; i < FaweCache.CHUNK_LAYERS; i++) rows[i] = NULL_ROW_Y;
|
||||
for (int i = 0; i < FaweCache.IMP.CHUNK_LAYERS; i++) rows[i] = NULL_ROW_Y;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,10 +31,10 @@ public abstract class FaweBlockMatcher {
|
||||
// public boolean apply(BaseBlock oldBlock) {
|
||||
// int currentId = oldBlock.getId();
|
||||
// oldBlock.setId(id);
|
||||
// if (FaweCache.hasData(currentId)) {
|
||||
// if (FaweCache.IMP.hasData(currentId)) {
|
||||
// oldBlock.setData(0);
|
||||
// }
|
||||
// if (FaweCache.hasNBT(currentId)) {
|
||||
// if (FaweCache.IMP.hasNBT(currentId)) {
|
||||
// oldBlock.setNbtData(null);
|
||||
// }
|
||||
// return true;
|
||||
@ -47,7 +47,7 @@ public abstract class FaweBlockMatcher {
|
||||
// int currentId = oldBlock.getId();
|
||||
// oldBlock.setId(id);
|
||||
// oldBlock.setData(data);
|
||||
// if (FaweCache.hasNBT(currentId)) {
|
||||
// if (FaweCache.IMP.hasNBT(currentId)) {
|
||||
// oldBlock.setNbtData(null);
|
||||
// }
|
||||
// return true;
|
||||
@ -67,10 +67,10 @@ public abstract class FaweBlockMatcher {
|
||||
// BaseBlock replace = array[random.random(size)];
|
||||
// int currentId = block.getId();
|
||||
// block.setId(replace.getId());
|
||||
// if (FaweCache.hasNBT(currentId)) {
|
||||
// if (FaweCache.IMP.hasNBT(currentId)) {
|
||||
// block.setNbtData(null);
|
||||
// }
|
||||
// if (FaweCache.hasData(currentId) || replace.getData() != 0) {
|
||||
// if (FaweCache.IMP.hasData(currentId) || replace.getData() != 0) {
|
||||
// block.setData(replace.getData());
|
||||
// }
|
||||
// return true;
|
||||
@ -82,7 +82,7 @@ public abstract class FaweBlockMatcher {
|
||||
public static FaweBlockMatcher fromBlock(BaseBlock block, boolean checkData) {
|
||||
// final int id = block.getId();
|
||||
// final int data = block.getData();
|
||||
// if (checkData && FaweCache.hasData(id)) {
|
||||
// if (checkData && FaweCache.IMP.hasData(id)) {
|
||||
// return new FaweBlockMatcher() {
|
||||
// @Override
|
||||
// public boolean apply(BaseBlock block) {
|
||||
@ -104,13 +104,13 @@ public abstract class FaweBlockMatcher {
|
||||
// if (searchBlocks.size() == 1) {
|
||||
// return fromBlock(searchBlocks.iterator().next(), checkData);
|
||||
// }
|
||||
// final boolean[] allowedId = new boolean[FaweCache.getId(Character.MAX_VALUE)];
|
||||
// final boolean[] allowedId = new boolean[FaweCache.IMP.getId(Character.MAX_VALUE)];
|
||||
// for (BaseBlock block : searchBlocks) {
|
||||
// allowedId[block.getId()] = true;
|
||||
// }
|
||||
// final boolean[] allowed = new boolean[Character.MAX_VALUE];
|
||||
// for (BaseBlock block : searchBlocks) {
|
||||
// allowed[FaweCache.getCombined(block)] = true;
|
||||
// allowed[FaweCache.IMP.getCombined(block)] = true;
|
||||
// }
|
||||
// if (checkData) {
|
||||
// return new FaweBlockMatcher() {
|
||||
@ -118,7 +118,7 @@ public abstract class FaweBlockMatcher {
|
||||
// public boolean apply(BaseBlock block) {
|
||||
// int id = block.getId();
|
||||
// if (allowedId[id]) {
|
||||
// if (FaweCache.hasData(id)) {
|
||||
// if (FaweCache.IMP.hasData(id)) {
|
||||
// return allowed[(id << 4) + block.getData()];
|
||||
// }
|
||||
// return true;
|
||||
|
@ -36,7 +36,7 @@ public class FuzzyRegionSelector extends PassthroughExtent implements RegionSele
|
||||
.player(FawePlayer.wrap(player))
|
||||
.changeSetNull()
|
||||
.checkMemory(false)
|
||||
.autoQueue(true)
|
||||
.autoQueue(false)
|
||||
.build());
|
||||
this.player = player;
|
||||
this.region = new FuzzyRegion(world, getExtent(), mask);
|
||||
|
@ -161,7 +161,7 @@ public class MinecraftStructure implements ClipboardReader, ClipboardWriter {
|
||||
if (width > WARN_SIZE || height > WARN_SIZE || length > WARN_SIZE) {
|
||||
Fawe.debug("A structure longer than 32 is unsupported by minecraft (but probably still works)");
|
||||
}
|
||||
Map<String, Object> structure = FaweCache.asMap("version", 1, "author", owner);
|
||||
Map<String, Object> structure = FaweCache.IMP.asMap("version", 1, "author", owner);
|
||||
// ignored: version / owner
|
||||
MutableBlockVector3 mutable = new MutableBlockVector3(0, 0, 0);
|
||||
Int2ObjectArrayMap<Integer> indexes = new Int2ObjectArrayMap<>();
|
||||
@ -211,10 +211,10 @@ public class MinecraftStructure implements ClipboardReader, ClipboardWriter {
|
||||
List<Integer> pos = Arrays.asList(point.getX() - min.getX(),
|
||||
point.getY() - min.getY(), point.getZ() - min.getZ());
|
||||
if (!block.hasNbtData()) {
|
||||
blocks.add(FaweCache.asMap("state", index, "pos", pos));
|
||||
blocks.add(FaweCache.IMP.asMap("state", index, "pos", pos));
|
||||
} else {
|
||||
blocks.add(
|
||||
FaweCache.asMap("state", index, "pos", pos, "nbt", block.getNbtData()));
|
||||
FaweCache.IMP.asMap("state", index, "pos", pos, "nbt", block.getNbtData()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -234,14 +234,14 @@ public class MinecraftStructure implements ClipboardReader, ClipboardWriter {
|
||||
// Replace rotation data
|
||||
nbtMap.put("Rotation", writeRotation(entity.getLocation()));
|
||||
nbtMap.put("id", new StringTag(state.getType().getId()));
|
||||
Map<String, Object> entityMap = FaweCache.asMap("pos", pos, "blockPos", blockPos, "nbt", nbt);
|
||||
Map<String, Object> entityMap = FaweCache.IMP.asMap("pos", pos, "blockPos", blockPos, "nbt", nbt);
|
||||
entities.add(entityMap);
|
||||
}
|
||||
}
|
||||
if (!entities.isEmpty()) {
|
||||
structure.put("entities", entities);
|
||||
}
|
||||
out.writeNamedTag("", FaweCache.asTag(structure));
|
||||
out.writeNamedTag("", FaweCache.IMP.asTag(structure));
|
||||
close();
|
||||
}
|
||||
|
||||
|
@ -25,10 +25,11 @@ public class FaweLocalBlockQueue extends LocalBlockQueue {
|
||||
|
||||
public final IQueueExtent IMP;
|
||||
private final LegacyMapper legacyMapper;
|
||||
private final World world;
|
||||
|
||||
public FaweLocalBlockQueue(String worldName) {
|
||||
super(worldName);
|
||||
World world = FaweAPI.getWorld(worldName);
|
||||
this.world = FaweAPI.getWorld(worldName);
|
||||
IMP = Fawe.get().getQueueHandler().getQueue(world);
|
||||
legacyMapper = LegacyMapper.getInstance();
|
||||
}
|
||||
@ -104,7 +105,7 @@ public class FaweLocalBlockQueue extends LocalBlockQueue {
|
||||
|
||||
@Override
|
||||
public String getWorld() {
|
||||
return IMP.getId();
|
||||
return world.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -134,7 +135,7 @@ public class FaweLocalBlockQueue extends LocalBlockQueue {
|
||||
|
||||
@Override
|
||||
public boolean setTile(int x, int y, int z, CompoundTag tag) {
|
||||
IMP.setTile(x, y, z, (com.sk89q.jnbt.CompoundTag) FaweCache.asTag(tag));
|
||||
IMP.setTile(x, y, z, (com.sk89q.jnbt.CompoundTag) FaweCache.IMP.asTag(tag));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -116,7 +116,7 @@ public class FaweSchematicHandler extends SchematicHandler {
|
||||
public void run(OutputStream output) {
|
||||
try {
|
||||
try (PGZIPOutputStream gzip = new PGZIPOutputStream(output)) {
|
||||
CompoundTag weTag = (CompoundTag) FaweCache.asTag(tag);
|
||||
CompoundTag weTag = (CompoundTag) FaweCache.IMP.asTag(tag);
|
||||
try (NBTOutputStream nos = new NBTOutputStream(gzip)) {
|
||||
Map<String, Tag> map = weTag.getValue();
|
||||
nos.writeNamedTag("Schematic", map.getOrDefault("Schematic", weTag));
|
||||
|
@ -93,7 +93,7 @@ public final class BrushCache {
|
||||
} else {
|
||||
displayMap = ReflectionUtils.getMap(display.getValue());
|
||||
}
|
||||
displayMap.put("Lore", FaweCache.asTag(json.split("\\r?\\n")));
|
||||
displayMap.put("Lore", FaweCache.IMP.asTag(json.split("\\r?\\n")));
|
||||
String primary = (String) tool.getPrimary().getSettings().get(BrushSettings.SettingType.BRUSH);
|
||||
String secondary = (String) tool.getSecondary().getSettings().get(BrushSettings.SettingType.BRUSH);
|
||||
if (primary == null) primary = secondary;
|
||||
|
@ -5,6 +5,11 @@ import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.IntFunction;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public final class IOUtil {
|
||||
|
||||
@ -79,4 +84,30 @@ public final class IOUtil {
|
||||
out.write(buf, 0, r);
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> Supplier<T> supplier(IntFunction<T> funx, int size) {
|
||||
return () -> funx.apply(size);
|
||||
}
|
||||
|
||||
public static <T> Supplier<T> supplier(Supplier<T> supplier, Function<T, T> modifier) {
|
||||
return () -> modifier.apply(supplier.get());
|
||||
}
|
||||
|
||||
public static <T> Supplier<T> supplier(Supplier<T> supplier, Consumer<T> modifier) {
|
||||
return () -> {
|
||||
T instance = supplier.get();
|
||||
modifier.accept(instance);
|
||||
return instance;
|
||||
};
|
||||
}
|
||||
|
||||
public static <T> Supplier<T> supplier(Callable<T> callable) {
|
||||
return () -> {
|
||||
try {
|
||||
return callable.call();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
package com.boydti.fawe.wrappers;
|
||||
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.object.RunnableVal;
|
||||
import com.boydti.fawe.util.ExtentTraverser;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
@ -12,6 +14,8 @@ import com.sk89q.worldedit.blocks.BaseItemStack;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.entity.Entity;
|
||||
import com.sk89q.worldedit.extension.platform.Platform;
|
||||
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.function.operation.Operation;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
||||
@ -57,6 +61,18 @@ public class WorldWrapper extends AbstractWorld {
|
||||
return world;
|
||||
}
|
||||
|
||||
public static World unwrap(Extent extent) {
|
||||
if (extent.isWorld()) {
|
||||
if (extent instanceof World) {
|
||||
return unwrap((World) extent);
|
||||
}
|
||||
if (extent instanceof AbstractDelegateExtent) {
|
||||
return unwrap(new ExtentTraverser<>(extent).find(World.class).get());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private WorldWrapper(World parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
@ -267,4 +283,9 @@ public class WorldWrapper extends AbstractWorld {
|
||||
public BlockVector3 getSpawnPosition() {
|
||||
return parent.getSpawnPosition();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkGet get(int x, int z) {
|
||||
return parent.get(x, z);
|
||||
}
|
||||
}
|
||||
|
@ -164,7 +164,7 @@ import org.slf4j.LoggerFactory;
|
||||
* using the {@link ChangeSetExtent}.</p>
|
||||
*/
|
||||
@SuppressWarnings({"FieldCanBeLocal"})
|
||||
public class EditSession extends PassthroughExtent implements SimpleWorld, AutoCloseable {
|
||||
public class EditSession extends PassthroughExtent implements AutoCloseable {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(EditSession.class);
|
||||
|
||||
@ -3023,33 +3023,10 @@ public class EditSession extends PassthroughExtent implements SimpleWorld, AutoC
|
||||
Direction.DOWN.toBlockVector(),
|
||||
};
|
||||
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return worldName;
|
||||
}
|
||||
|
||||
@Override public @org.jetbrains.annotations.Nullable Path getStoragePath() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean clearContainerBlockContents(BlockVector3 pos) {
|
||||
BaseBlock block = getFullBlock(pos);
|
||||
CompoundTag nbt = block.getNbtData();
|
||||
if (nbt != null) {
|
||||
if (nbt.containsKey("items")) {
|
||||
return setBlock(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ(), block.toBlockState().toBaseBlock());
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean regenerate(final Region region) {
|
||||
return regenerate(region, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean regenerate(final Region region, final EditSession session) {
|
||||
return session.regenerate(region, null, null);
|
||||
}
|
||||
@ -3164,69 +3141,4 @@ public class EditSession extends PassthroughExtent implements SimpleWorld, AutoC
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void simulateBlockMine(BlockVector3 position) {
|
||||
TaskManager.IMP.sync((Supplier<Object>) () -> {
|
||||
world.simulateBlockMine(position);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
public boolean generateTree(TreeGenerator.TreeType type, BlockVector3 position) {
|
||||
return generateTree(type, this, position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean generateTree(TreeGenerator.TreeType type, EditSession editSession, BlockVector3 position) {
|
||||
if (getWorld() != null) {
|
||||
try {
|
||||
return getWorld().generateTree(type, editSession, position);
|
||||
} catch (MaxChangedBlocksException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WeatherType getWeather() {
|
||||
return world.getWeather();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getRemainingWeatherDuration() {
|
||||
return world.getRemainingWeatherDuration();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWeather(WeatherType weatherType) {
|
||||
world.setWeather(weatherType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWeather(WeatherType weatherType, long duration) {
|
||||
world.setWeather(weatherType, duration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dropItem(Vector3 position, BaseItemStack item) {
|
||||
world.dropItem(position, item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean playEffect(Vector3 position, int type, int data) {
|
||||
return world.playEffect(position, type, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean notifyAndLightBlock(BlockVector3 position, BlockState previousType) throws WorldEditException {
|
||||
return world.notifyAndLightBlock(position, previousType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockVector3 getSpawnPosition() {
|
||||
return world.getSpawnPosition();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -618,7 +618,7 @@ public class SelectionCommands {
|
||||
maskOpt = new IdMask(world);
|
||||
}
|
||||
//TODO Make FuzzyRegionSelector accept actors
|
||||
newSelector = new FuzzyRegionSelector((Player) actor, editSession, maskOpt);
|
||||
newSelector = new FuzzyRegionSelector((Player) actor, world, maskOpt);
|
||||
actor.print(BBC.SEL_FUZZY.s());
|
||||
actor.print(BBC.SEL_LIST.s());
|
||||
break;
|
||||
|
@ -22,8 +22,12 @@ package com.sk89q.worldedit.entity;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.ListTag;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.util.Location;
|
||||
import com.sk89q.worldedit.world.NbtValued;
|
||||
import com.sk89q.worldedit.world.entity.EntityType;
|
||||
import com.sk89q.worldedit.world.entity.EntityTypes;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@ -56,6 +60,10 @@ public class BaseEntity implements NbtValued {
|
||||
setNbtData(nbtData);
|
||||
}
|
||||
|
||||
public BaseEntity(CompoundTag tag) {
|
||||
this(EntityTypes.parse(tag.getString("Id")), tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new base entity with no NBT data.
|
||||
*
|
||||
@ -76,6 +84,17 @@ public class BaseEntity implements NbtValued {
|
||||
setNbtData(other.getNbtData());
|
||||
}
|
||||
|
||||
public Location getLocation(Extent extent) {
|
||||
ListTag posTag = nbtData.getListTag("Pos");
|
||||
ListTag rotTag = nbtData.getListTag("Rotation");
|
||||
double x = posTag.getDouble(0);
|
||||
double y = posTag.getDouble(1);
|
||||
double z = posTag.getDouble(2);
|
||||
float yaw = rotTag.getFloat(0);
|
||||
float pitch = rotTag.getFloat(1);
|
||||
return new Location(extent, x, y, z, yaw, pitch);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNbtData() {
|
||||
return true;
|
||||
|
@ -13,7 +13,7 @@ public class MutableBlockVector3 extends BlockVector3 {
|
||||
}
|
||||
|
||||
public static MutableBlockVector3 get(int x, int y, int z) {
|
||||
return FaweCache.MUTABLE_BLOCKVECTOR3.get().setComponents(x, y, z);
|
||||
return FaweCache.IMP.MUTABLE_BLOCKVECTOR3.get().setComponents(x, y, z);
|
||||
}
|
||||
|
||||
public MutableBlockVector3() {}
|
||||
|
@ -10,11 +10,11 @@ public class MutableVector3 extends Vector3 {
|
||||
}
|
||||
|
||||
public static MutableVector3 get(int x, int y, int z) {
|
||||
return FaweCache.MUTABLE_VECTOR3.get().setComponents(x, y, z);
|
||||
return FaweCache.IMP.MUTABLE_VECTOR3.get().setComponents(x, y, z);
|
||||
}
|
||||
|
||||
public static MutableVector3 get(double x, double y, double z) {
|
||||
return FaweCache.MUTABLE_VECTOR3.get().setComponents(x, y, z);
|
||||
return FaweCache.IMP.MUTABLE_VECTOR3.get().setComponents(x, y, z);
|
||||
}
|
||||
|
||||
public MutableVector3(double x, double y, double z) {
|
||||
|
@ -43,12 +43,10 @@ public class LinkedFuture<T extends Future<T>> implements Future<T> {
|
||||
@Override
|
||||
public synchronized T get(long timeout, @NotNull TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
|
||||
if (task != null) {
|
||||
T result = task.get(timeout, unit);
|
||||
if (task != null || !task.isDone()) {
|
||||
task = task.get(timeout, unit);
|
||||
if (task != null) {
|
||||
return (T) this;
|
||||
}
|
||||
task = null;
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -19,6 +19,8 @@
|
||||
|
||||
package com.sk89q.worldedit.world;
|
||||
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.implementation.NullChunkGet;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.MaxChangedBlocksException;
|
||||
@ -132,6 +134,11 @@ public class NullWorld extends AbstractWorld {
|
||||
return BlockVector3.ZERO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkGet get(int x, int z) {
|
||||
return NullChunkGet.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getBlock(int x, int y, int z) {
|
||||
return BlockTypes.AIR.getDefaultState();
|
||||
|
@ -19,6 +19,8 @@
|
||||
|
||||
package com.sk89q.worldedit.world;
|
||||
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.implementation.IChunkCache;
|
||||
import com.boydti.fawe.object.extent.LightingExtent;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.MaxChangedBlocksException;
|
||||
@ -47,7 +49,7 @@ import java.util.Locale;
|
||||
/**
|
||||
* Represents a world (dimension).
|
||||
*/
|
||||
public interface World extends Extent, Keyed {
|
||||
public interface World extends Extent, Keyed, IChunkCache<IChunkGet> {
|
||||
|
||||
/**
|
||||
* Get the name of the world.
|
||||
@ -290,4 +292,7 @@ public interface World extends Extent, Keyed {
|
||||
default String getId() {
|
||||
return getName().replace(" ", "_").toLowerCase(Locale.ROOT);
|
||||
}
|
||||
|
||||
@Override
|
||||
IChunkGet get(int x, int z);
|
||||
}
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren