chunk sending / cfi

This commit is contained in:
Jesse Boyd 2019-10-26 14:21:49 +01:00
parent 1b28dcda40
commit 8356004ec9
No known key found for this signature in database
GPG Key ID: 59F1DE6293AF6E1F
56 changed files with 1378 additions and 999 deletions

View File

@ -20,6 +20,7 @@ repositories {
maven { url = uri("https://repo.destroystokyo.com/repository/maven-public//") }
maven { url = uri("http://repo.dmulloy2.net/content/groups/public/") }
maven { url = uri("http://ci.ender.zone/plugin/repository/everything/") }
maven { url = uri("https://repo.inventivetalent.org/content/groups/public/")}
}
configurations.all {
@ -49,6 +50,9 @@ dependencies {
exclude("com.sk89q.worldedit.worldedit-libs", "bukkit")
exclude("com.sk89q.worldedit.worldedit-libs", "core")
}
"implementation"("org.inventivetalent:mapmanager:1.7.3-SNAPSHOT") { isTransitive = false }
"implementation"("org.inventivetalent:mapmanager:1.7.3-SNAPSHOT") { isTransitive = false }
"implementation"("com.massivecraft:factions:2.8.0") { isTransitive = false }
"implementation"("com.drtshock:factions:1.6.9.5") { isTransitive = false }
"implementation"("com.github.TechFortress:GriefPrevention:16.12.0") { isTransitive = false }

View File

@ -3,6 +3,8 @@ package com.boydti.fawe.bukkit;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.IFawe;
import com.boydti.fawe.beta.implementation.QueueHandler;
import com.boydti.fawe.beta.preloader.AsyncPreloader;
import com.boydti.fawe.beta.preloader.Preloader;
import com.boydti.fawe.bukkit.adapter.BukkitQueueHandler;
import com.boydti.fawe.bukkit.listener.BrushListener;
import com.boydti.fawe.bukkit.listener.BukkitImageListener;
@ -55,14 +57,14 @@ import org.bukkit.plugin.java.JavaPlugin;
public class FaweBukkit implements IFawe, Listener {
// private final WorldEditPlugin plugin;
private final Plugin plugin;
private VaultUtil vault;
private ItemUtil itemUtil;
private boolean listeningImages;
private BukkitImageListener imageListener;
//private CFIPacketListener packetListener;
public static boolean PAPER;
public VaultUtil getVault() {
return this.vault;
@ -70,6 +72,13 @@ public class FaweBukkit implements IFawe, Listener {
public FaweBukkit(Plugin plugin) {
this.plugin = plugin;
try {
Class.forName("com.destroystokyo.paper.Namespaced");
PAPER = true;
} catch (Throwable e) {
e.printStackTrace();
// TODO no paper
}
try {
Settings.IMP.TICK_LIMITER.ENABLED = !Bukkit.hasWhitelist();
Fawe.set(this);
@ -398,4 +407,12 @@ public class FaweBukkit implements IFawe, Listener {
return null;
// return ((BlocksHubBukkit) blocksHubPlugin).getApi();
}
@Override
public Preloader getPreloader() {
if (PAPER) {
return new AsyncPreloader();
}
return null;
}
}

View File

@ -2,6 +2,7 @@ package com.boydti.fawe.bukkit.adapter.mc1_14;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.bukkit.FaweBukkit;
import com.boydti.fawe.bukkit.adapter.DelegateLock;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.collection.BitArray4096;
@ -21,6 +22,7 @@ import net.minecraft.server.v1_14_R1.DataPaletteBlock;
import net.minecraft.server.v1_14_R1.DataPaletteLinear;
import net.minecraft.server.v1_14_R1.GameProfileSerializer;
import net.minecraft.server.v1_14_R1.IBlockData;
import net.minecraft.server.v1_14_R1.PacketPlayOutMapChunk;
import net.minecraft.server.v1_14_R1.PlayerChunk;
import net.minecraft.server.v1_14_R1.PlayerChunkMap;
import org.bukkit.craftbukkit.v1_14_R1.CraftChunk;
@ -133,8 +135,6 @@ public class BukkitAdapter_1_14 {
}
}
private static boolean PAPER = true;
public static Chunk ensureLoaded(net.minecraft.server.v1_14_R1.World nmsWorld, int X, int Z) {
Chunk nmsChunk = nmsWorld.getChunkIfLoaded(X, Z);
if (nmsChunk != null) {
@ -143,7 +143,7 @@ public class BukkitAdapter_1_14 {
if (Fawe.isMainThread()) {
return nmsWorld.getChunkAt(X, Z);
}
if (PAPER) {
if (FaweBukkit.PAPER) {
CraftWorld craftWorld = nmsWorld.getWorld();
CompletableFuture<org.bukkit.Chunk> future = craftWorld.getChunkAtAsync(X, Z, true);
try {
@ -154,8 +154,7 @@ public class BukkitAdapter_1_14 {
} catch (ExecutionException e) {
e.printStackTrace();
} catch (Throwable e) {
System.out.println("Error, cannot load chunk async (paper not installed?)");
PAPER = false;
e.printStackTrace();
}
}
// TODO optimize

View File

@ -19,6 +19,7 @@
package com.boydti.fawe.bukkit.adapter.mc1_14;
import com.bekvon.bukkit.residence.commands.material;
import com.boydti.fawe.Fawe;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
@ -132,6 +133,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.OptionalInt;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.function.Supplier;
@ -590,6 +592,13 @@ public final class Spigot_v1_14_R4 extends CachedBukkitAdapter implements Bukkit
}
}
@Override
public OptionalInt getInternalBlockStateId(BlockState state) {
BlockMaterial_1_14 material = (BlockMaterial_1_14) state.getMaterial();
IBlockData mcState = material.getCraftBlockData().getState();
return OptionalInt.of(Block.REGISTRY_ID.getId(mcState));
}
@Override
public BlockState adapt(BlockData blockData) {
CraftBlockData cbd = ((CraftBlockData) blockData);

View File

@ -1,111 +0,0 @@
package com.boydti.fawe.bukkit.chat;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Collection;
import org.apache.commons.lang.Validate;
/**
* Represents a wrapper around an array class of an arbitrary reference type,
* which properly implements "value" hash code and equality functions.
* <p>
* This class is intended for use as a key to a map.
* </p>
*
* @param <E> The type of elements in the array.
* @author Glen Husman
* @see Arrays
*/
public final class ArrayWrapper<E> {
/**
* Creates an array wrapper with some elements.
*
* @param elements The elements of the array.
*/
@SafeVarargs
public ArrayWrapper(E... elements) {
setArray(elements);
}
private E[] _array;
/**
* Retrieves a reference to the wrapped array instance.
*
* @return The array wrapped by this instance.
*/
public E[] getArray() {
return _array;
}
/**
* Set this wrapper to wrap a new array instance.
*
* @param array The new wrapped array.
*/
public void setArray(E[] array) {
Validate.notNull(array, "The array must not be null.");
_array = array;
}
/**
* Determines if this object has a value equivalent to another object.
*
* @see Arrays#equals(Object[], Object[])
*/
@SuppressWarnings("rawtypes")
@Override
public boolean equals(Object other) {
if (!(other instanceof ArrayWrapper)) {
return false;
}
return Arrays.equals(_array, ((ArrayWrapper) other)._array);
}
/**
* Gets the hash code represented by this objects value.
*
* @return This object's hash code.
* @see Arrays#hashCode(Object[])
*/
@Override
public int hashCode() {
return Arrays.hashCode(_array);
}
/**
* Converts an iterable element collection to an array of elements.
* The iteration order of the specified object will be used as the array element order.
*
* @param list The iterable of objects which will be converted to an array.
* @param c The type of the elements of the array.
* @return An array of elements in the specified iterable.
*/
@SuppressWarnings("unchecked")
public static <T> T[] toArray(Iterable<? extends T> list, Class<T> c) {
int size = -1;
if (list instanceof Collection<?>) {
@SuppressWarnings("rawtypes")
Collection coll = (Collection) list;
size = coll.size();
}
if (size < 0) {
size = 0;
// Ugly hack: Count it ourselves
for (@SuppressWarnings("unused") T element : list) {
size++;
}
}
T[] result = (T[]) Array.newInstance(c, size);
int i = 0;
for (T element : list) { // Assumes iteration order is consistent
result[i++] = element; // Assign array element at index THEN increment counter
}
return result;
}
}

View File

@ -1,18 +0,0 @@
package com.boydti.fawe.bukkit.chat;
import com.google.gson.stream.JsonWriter;
import java.io.IOException;
/**
* Represents an object that can be serialized to a JSON writer instance.
*/
interface JsonRepresentedObject {
/**
* Writes the JSON representation of this object to the specified writer.
* @param writer The JSON writer which will receive the object.
* @throws IOException If an error occurs writing to the stream.
*/
public void writeJson(JsonWriter writer) throws IOException;
}

View File

@ -1,46 +0,0 @@
package com.boydti.fawe.bukkit.chat;
import com.google.gson.stream.JsonWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.bukkit.configuration.serialization.ConfigurationSerializable;
/**
* Represents a JSON string value.
* Writes by this object will not write name values nor begin/end objects in the JSON stream.
* All writes merely write the represented string value.
*/
final class JsonString implements JsonRepresentedObject, ConfigurationSerializable {
private String _value;
public JsonString(CharSequence value) {
_value = value == null ? null : value.toString();
}
@Override
public void writeJson(JsonWriter writer) throws IOException {
writer.value(getValue());
}
public String getValue() {
return _value;
}
public Map<String, Object> serialize() {
HashMap<String, Object> theSingleValue = new HashMap<>();
theSingleValue.put("stringValue", _value);
return theSingleValue;
}
public static JsonString deserialize(Map<String, Object> map) {
return new JsonString(map.get("stringValue").toString());
}
@Override
public String toString() {
return _value;
}
}

View File

@ -1,201 +0,0 @@
package com.boydti.fawe.bukkit.chat;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import org.bukkit.Bukkit;
/**
* A class containing static utility methods and caches which are intended as reflective conveniences.
* Unless otherwise noted, upon failure methods will return {@code null}.
*/
public final class Reflection {
/**
* Stores loaded classes from the {@code net.minecraft.server} package.
*/
private static final Map<String, Class<?>> _loadedNMSClasses = new HashMap<>();
/**
* Stores loaded classes from the {@code org.bukkit.craftbukkit} package (and subpackages).
*/
private static final Map<String, Class<?>> _loadedOBCClasses = new HashMap<>();
private static final Map<Class<?>, Map<String, Field>> _loadedFields = new HashMap<>();
/**
* Contains loaded methods in a cache.
* The map maps [types to maps of [method names to maps of [parameter types to method instances]]].
*/
private static final Map<Class<?>, Map<String, Map<ArrayWrapper<Class<?>>, Method>>> _loadedMethods = new HashMap<>();
private static String _versionString;
private Reflection() { }
/**
* Gets the version string from the package name of the CraftBukkit server implementation.
* This is needed to bypass the JAR package name changing on each update.
*
* @return The version string of the OBC and NMS packages, <em>including the trailing dot</em>.
*/
public synchronized static String getVersion() {
if (_versionString == null) {
String name = Bukkit.getServer().getClass().getPackage().getName();
_versionString = name.substring(name.lastIndexOf('.') + 1) + ".";
}
return _versionString;
}
/**
* Gets a {@link Class} object representing a type contained within the {@code net.minecraft.server} versioned package.
* The class instances returned by this method are cached, such that no lookup will be done twice (unless multiple threads are accessing this method simultaneously).
*
* @param className The name of the class, excluding the package, within NMS.
* @return The class instance representing the specified NMS class, or {@code null} if it could not be loaded.
*/
public synchronized static Class<?> getNMSClass(String className) {
if (_loadedNMSClasses.containsKey(className)) {
return _loadedNMSClasses.get(className);
}
String fullName = "net.minecraft.server." + getVersion() + className;
Class<?> clazz;
try {
clazz = Class.forName(fullName);
} catch (ClassNotFoundException e) {
_loadedNMSClasses.put(className, null);
throw new RuntimeException(e);
}
_loadedNMSClasses.put(className, clazz);
return clazz;
}
/**
* Gets a {@link Class} object representing a type contained within the {@code org.bukkit.craftbukkit} versioned package.
* The class instances returned by this method are cached, such that no lookup will be done twice (unless multiple threads are accessing this method simultaneously).
*
* @param className The name of the class, excluding the package, within OBC. This name may contain a subpackage name, such as {@code inventory.CraftItemStack}.
* @return The class instance representing the specified OBC class, or {@code null} if it could not be loaded.
*/
public synchronized static Class<?> getOBCClass(String className) {
if (_loadedOBCClasses.containsKey(className)) {
return _loadedOBCClasses.get(className);
}
String fullName = "org.bukkit.craftbukkit." + getVersion() + className;
Class<?> clazz;
try {
clazz = Class.forName(fullName);
} catch (ClassNotFoundException e) {
_loadedOBCClasses.put(className, null);
throw new RuntimeException(e);
}
_loadedOBCClasses.put(className, clazz);
return clazz;
}
/**
* Attempts to get the NMS handle of a CraftBukkit object.
* <p>
* The only match currently attempted by this method is a retrieval by using a parameterless {@code getHandle()} method implemented by the runtime type of the specified object.
* </p>
*
* @param obj The object for which to retrieve an NMS handle.
* @return The NMS handle of the specified object, or {@code null} if it could not be retrieved using {@code getHandle()}.
*/
public synchronized static Object getHandle(Object obj) throws InvocationTargetException, IllegalAccessException, IllegalArgumentException {
return getMethod(obj.getClass(), "getHandle").invoke(obj);
}
/**
* Retrieves a {@link Field} instance declared by the specified class with the specified name.
* Java access modifiers are ignored during this retrieval. No guarantee is made as to whether the field
* returned will be an instance or static field.
* <p>
* A global caching mechanism within this class is used to store fields. Combined with synchronization, this guarantees that
* no field will be reflectively looked up twice.
* </p>
* <p>
* If a field is deemed suitable for return, {@link Field#setAccessible(boolean) setAccessible} will be invoked with an argument of {@code true} before it is returned.
* This ensures that callers do not have to check or worry about Java access modifiers when dealing with the returned instance.
* </p>
*
* @param clazz The class which contains the field to retrieve.
* @param name The declared name of the field in the class.
* @return A field object with the specified name declared by the specified class.
* @see Class#getDeclaredField(String)
*/
public synchronized static Field getField(Class<?> clazz, String name) {
Map<String, Field> loaded;
if (!_loadedFields.containsKey(clazz)) {
loaded = new HashMap<>();
_loadedFields.put(clazz, loaded);
} else {
loaded = _loadedFields.get(clazz);
}
if (loaded.containsKey(name)) {
// If the field is loaded (or cached as not existing), return the relevant value, which might be null
return loaded.get(name);
}
try {
Field field = clazz.getDeclaredField(name);
field.setAccessible(true);
loaded.put(name, field);
return field;
} catch (NoSuchFieldException | SecurityException e) {
// Error loading
e.printStackTrace();
// Cache field as not existing
loaded.put(name, null);
return null;
}
}
/**
* Retrieves a {@link Method} instance declared by the specified class with the specified name and argument types.
* Java access modifiers are ignored during this retrieval. No guarantee is made as to whether the field
* returned will be an instance or static field.
* <p>
* A global caching mechanism within this class is used to store method. Combined with synchronization, this guarantees that
* no method will be reflectively looked up twice.
* <p>
* If a method is deemed suitable for return, {@link Method#setAccessible(boolean) setAccessible} will be invoked with an argument of {@code true} before it is returned.
* This ensures that callers do not have to check or worry about Java access modifiers when dealing with the returned instance.
* <p>
* This method does <em>not</em> search superclasses of the specified type for methods with the specified signature.
* Callers wishing this behavior should use {@link Class#getDeclaredMethod(String, Class...)}.
*
* @param clazz The class which contains the method to retrieve.
* @param name The declared name of the method in the class.
* @param args The formal argument types of the method.
* @return A method object with the specified name declared by the specified class.
*/
public synchronized static Method getMethod(Class<?> clazz, String name, Class<?>... args) {
if (!_loadedMethods.containsKey(clazz)) {
_loadedMethods.put(clazz, new HashMap<>());
}
Map<String, Map<ArrayWrapper<Class<?>>, Method>> loadedMethodNames = _loadedMethods.get(clazz);
if (!loadedMethodNames.containsKey(name)) {
loadedMethodNames.put(name, new HashMap<>());
}
Map<ArrayWrapper<Class<?>>, Method> loadedSignatures = loadedMethodNames.get(name);
ArrayWrapper<Class<?>> wrappedArg = new ArrayWrapper<>(args);
if (loadedSignatures.containsKey(wrappedArg)) {
return loadedSignatures.get(wrappedArg);
}
for (Method m : clazz.getMethods()) {
if (m.getName().equals(name) && Arrays.equals(args, m.getParameterTypes())) {
m.setAccessible(true);
loadedSignatures.put(wrappedArg, m);
return m;
}
}
loadedSignatures.put(wrappedArg, null);
return null;
}
}

View File

@ -1,4 +0,0 @@
package com.boydti.fawe.bukkit.listener;
public class ChunkCache {
}

View File

@ -0,0 +1,196 @@
package com.boydti.fawe.bukkit.preloader;
import com.boydti.fawe.Fawe;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.plugin.PluginBase;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.PluginLoader;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.InputStream;
import java.lang.ref.PhantomReference;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger;
public class PluginPreloader extends PluginBase {
private World world;
private Set<BlockVector2> loaded;
private int index;
private AtomicBoolean invalidator;
private final Object invalidatorLock;
public PluginPreloader() {
invalidator = new AtomicBoolean();
invalidatorLock = new Object();
}
public AtomicBoolean invalidate() {
synchronized (invalidatorLock) {
invalidator.set(false);
return invalidator = new AtomicBoolean(true);
}
}
private synchronized void unload() {
World oldWorld = world;
if (oldWorld != null) {
Set<BlockVector2> toUnload = loaded;
if (loaded != null && index > 0) {
Iterator<BlockVector2> iter = toUnload.iterator();
Fawe.get().getQueueHandler().sync(() -> {
for (int i = 0; i < index && iter.hasNext(); i++) {
BlockVector2 chunk = iter.next();
world.removePluginChunkTicket(chunk.getX(), chunk.getZ(), this);
}
});
}
}
this.world = null;
this.loaded = null;
this.index = 0;
}
public void update(Region region) {
AtomicBoolean invalidator = invalidate();
synchronized (this) {
com.sk89q.worldedit.world.World weWorld = region.getWorld();
if (weWorld == null) {
return;
}
unload();
index = 0;
world = BukkitAdapter.adapt(weWorld);
loaded = region.getChunks();
Iterator<BlockVector2> iter = loaded.iterator();
if (!invalidator.get()) return;
Fawe.get().getQueueHandler().syncWhenFree(() -> {
for (; iter.hasNext() && invalidator.get();index++) {
BlockVector2 chunk = iter.next();
if (!world.isChunkLoaded(chunk.getX(), chunk.getZ())) {
world.addPluginChunkTicket(chunk.getX(), chunk.getZ(), this);
}
}
});
}
}
public void clear() {
invalidate();
unload();
}
@Override
public @NotNull File getDataFolder() {
return null;
}
@Override
public @NotNull PluginDescriptionFile getDescription() {
return null;
}
@Override
public @NotNull FileConfiguration getConfig() {
return null;
}
@Override
public @Nullable InputStream getResource(@NotNull String filename) {
return null;
}
@Override
public void saveConfig() {
}
@Override
public void saveDefaultConfig() {
}
@Override
public void saveResource(@NotNull String resourcePath, boolean replace) {
}
@Override
public void reloadConfig() {
}
@Override
public @NotNull PluginLoader getPluginLoader() {
return null;
}
@Override
public @NotNull Server getServer() {
return null;
}
@Override
public boolean isEnabled() {
return true;
}
@Override
public void onDisable() {
}
@Override
public void onLoad() {
}
@Override
public void onEnable() {
}
@Override
public boolean isNaggable() {
return false;
}
@Override
public void setNaggable(boolean canNag) {
}
@Override
public @Nullable ChunkGenerator getDefaultWorldGenerator(@NotNull String worldName, @Nullable String id) {
return null;
}
@Override
public @NotNull Logger getLogger() {
return null;
}
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
return false;
}
@Override
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) {
return null;
}
}

View File

@ -19,173 +19,173 @@ import org.bukkit.entity.ItemFrame;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
//import org.inventivetalent.mapmanager.MapManagerPlugin;
//import org.inventivetalent.mapmanager.controller.MapController;
//import org.inventivetalent.mapmanager.controller.MultiMapController;
//import org.inventivetalent.mapmanager.manager.MapManager;
//import org.inventivetalent.mapmanager.wrapper.MapWrapper;
import org.inventivetalent.mapmanager.MapManagerPlugin;
import org.inventivetalent.mapmanager.controller.MapController;
import org.inventivetalent.mapmanager.controller.MultiMapController;
import org.inventivetalent.mapmanager.manager.MapManager;
import org.inventivetalent.mapmanager.wrapper.MapWrapper;
public class BukkitImageViewer implements ImageViewer {
// private final MapManager mapManager;
// private final Player player;
// private BufferedImage last;
private final MapManager mapManager;
private final Player player;
private BufferedImage last;
private ItemFrame[][] frames;
// private boolean reverse;
private boolean reverse;
public BukkitImageViewer(Player player) {
// mapManager = ((MapManagerPlugin) Bukkit.getPluginManager().getPlugin("MapManager")).getMapManager();
// this.player = player;
mapManager = ((MapManagerPlugin) Bukkit.getPluginManager().getPlugin("MapManager")).getMapManager();
this.player = player;
}
//
public void selectFrame(ItemFrame start) {
// Location pos1 = start.getLocation().clone();
// Location pos2 = start.getLocation().clone();
//
// BlockFace facing = start.getFacing();
// int planeX = facing.getModX() == 0 ? 1 : 0;
// int planeY = facing.getModY() == 0 ? 1 : 0;
// int planeZ = facing.getModZ() == 0 ? 1 : 0;
//
// ItemFrame[][] res = find(pos1, pos2, facing);
// Location tmp;
// while (true) {
// if (res != null) {
// frames = res;
// }
// tmp = pos1.clone().subtract(planeX, planeY, planeZ);
// if ((res = find(tmp, pos2, facing)) != null) {
// pos1 = tmp;
// continue;
// }
// tmp = pos2.clone().add(planeX, planeY, planeZ);
// if ((res = find(pos1, tmp, facing)) != null) {
// pos2 = tmp;
// continue;
// }
// tmp = pos1.clone().subtract(planeX, 0, planeZ);
// if ((res = find(tmp, pos2, facing)) != null) {
// pos1 = tmp;
// continue;
// }
// tmp = pos2.clone().add(planeX, 0, planeZ);
// if ((res = find(pos1, tmp, facing)) != null) {
// pos2 = tmp;
// continue;
// }
// tmp = pos1.clone().subtract(0, 1, 0);
// if ((res = find(tmp, pos2, facing)) != null) {
// pos1 = tmp;
// continue;
// }
// tmp = pos2.clone().add(0, 1, 0);
// if ((res = find(pos1, tmp, facing)) != null) {
// pos2 = tmp;
// continue;
// }
// break;
// }
Location pos1 = start.getLocation().clone();
Location pos2 = start.getLocation().clone();
BlockFace facing = start.getFacing();
int planeX = facing.getModX() == 0 ? 1 : 0;
int planeY = facing.getModY() == 0 ? 1 : 0;
int planeZ = facing.getModZ() == 0 ? 1 : 0;
ItemFrame[][] res = find(pos1, pos2, facing);
Location tmp;
while (true) {
if (res != null) {
frames = res;
}
tmp = pos1.clone().subtract(planeX, planeY, planeZ);
if ((res = find(tmp, pos2, facing)) != null) {
pos1 = tmp;
continue;
}
tmp = pos2.clone().add(planeX, planeY, planeZ);
if ((res = find(pos1, tmp, facing)) != null) {
pos2 = tmp;
continue;
}
tmp = pos1.clone().subtract(planeX, 0, planeZ);
if ((res = find(tmp, pos2, facing)) != null) {
pos1 = tmp;
continue;
}
tmp = pos2.clone().add(planeX, 0, planeZ);
if ((res = find(pos1, tmp, facing)) != null) {
pos2 = tmp;
continue;
}
tmp = pos1.clone().subtract(0, 1, 0);
if ((res = find(tmp, pos2, facing)) != null) {
pos1 = tmp;
continue;
}
tmp = pos2.clone().add(0, 1, 0);
if ((res = find(pos1, tmp, facing)) != null) {
pos2 = tmp;
continue;
}
break;
}
}
//
public ItemFrame[][] getItemFrames() {
return frames;
}
//
// private ItemFrame[][] find(Location pos1, Location pos2, BlockFace facing) {
// try {
// Location distance = pos2.clone().subtract(pos1).add(1, 1, 1);
// int width = Math.max(distance.getBlockX(), distance.getBlockZ());
// ItemFrame[][] frames = new ItemFrame[width][distance.getBlockY()];
//
// World world = pos1.getWorld();
//
// this.reverse = (facing == BlockFace.NORTH || facing == BlockFace.EAST);
// int v = 0;
// for (double y = pos1.getY(); y <= pos2.getY(); y++, v++) {
// int h = 0;
// for (double z = pos1.getZ(); z <= pos2.getZ(); z++) {
// for (double x = pos1.getX(); x <= pos2.getX(); x++, h++) {
// Location pos = new Location(world, x, y, z);
// Collection<Entity> entities = world.getNearbyEntities(pos, 0.1, 0.1, 0.1);
// boolean contains = false;
// for (Entity ent : entities) {
// if (ent instanceof ItemFrame && ((ItemFrame) ent).getFacing() == facing) {
// ItemFrame itemFrame = (ItemFrame) ent;
// itemFrame.setRotation(Rotation.NONE);
// contains = true;
// frames[reverse ? width - 1 - h : h][v] = (ItemFrame) ent;
// break;
// }
// }
// if (!contains) return null;
// }
// }
// }
// return frames;
// } catch (Throwable e) {
// e.printStackTrace();
// }
// return null;
// }
private ItemFrame[][] find(Location pos1, Location pos2, BlockFace facing) {
try {
Location distance = pos2.clone().subtract(pos1).add(1, 1, 1);
int width = Math.max(distance.getBlockX(), distance.getBlockZ());
ItemFrame[][] frames = new ItemFrame[width][distance.getBlockY()];
World world = pos1.getWorld();
this.reverse = (facing == BlockFace.NORTH || facing == BlockFace.EAST);
int v = 0;
for (double y = pos1.getY(); y <= pos2.getY(); y++, v++) {
int h = 0;
for (double z = pos1.getZ(); z <= pos2.getZ(); z++) {
for (double x = pos1.getX(); x <= pos2.getX(); x++, h++) {
Location pos = new Location(world, x, y, z);
Collection<Entity> entities = world.getNearbyEntities(pos, 0.1, 0.1, 0.1);
boolean contains = false;
for (Entity ent : entities) {
if (ent instanceof ItemFrame && ((ItemFrame) ent).getFacing() == facing) {
ItemFrame itemFrame = (ItemFrame) ent;
itemFrame.setRotation(Rotation.NONE);
contains = true;
frames[reverse ? width - 1 - h : h][v] = (ItemFrame) ent;
break;
}
}
if (!contains) return null;
}
}
}
return frames;
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}
@Override
public void view(Drawable drawable) {
// view(null, drawable);
view(null, drawable);
}
//
// private void view(@Nullable BufferedImage image, @Nullable Drawable drawable) {
// if (image == null && drawable == null) throw new IllegalArgumentException("An image or drawable must be provided. Both cannot be null");
// boolean initializing = last == null;
//
// if (this.frames != null) {
// if (image == null && drawable != null) image = drawable.draw();
// last = image;
// int width = frames.length;
// int height = frames[0].length;
// BufferedImage scaled = ImageUtil.getScaledInstance(image, 128 * width, 128 * height, RenderingHints.VALUE_INTERPOLATION_BILINEAR, false);
// MapWrapper mapWrapper = mapManager.wrapMultiImage(scaled, width, height);
// MultiMapController controller = (MultiMapController) mapWrapper.getController();
// controller.addViewer(player);
// controller.sendContent(player);
// controller.showInFrames(player, frames, true);
// } else {
// int slot = getMapSlot(player);
// if (slot == -1) {
// if (initializing) {
// player.getInventory().setItemInMainHand(new ItemStack(Material.MAP));
// } else {
// return;
// }
// } else if (player.getInventory().getHeldItemSlot() != slot) {
// player.getInventory().setHeldItemSlot(slot);
// }
// if (image == null && drawable != null) image = drawable.draw();
// last = image;
// BufferedImage scaled = ImageUtil.getScaledInstance(image, 128, 128, RenderingHints.VALUE_INTERPOLATION_BILINEAR, false);
// MapWrapper mapWrapper = mapManager.wrapImage(scaled);
// MapController controller = mapWrapper.getController();
// controller.addViewer(player);
// controller.sendContent(player);
// controller.showInHand(player, true);
// }
// }
//
// private int getMapSlot(Player player) {
// PlayerInventory inventory = player.getInventory();
// for (int i = 0; i < 9; i++) {
// ItemStack item = inventory.getItem(i);
// if (item != null && item.getType() == Material.MAP) {
// return i;
// }
// }
// return -1;
// }
//
private void view(@Nullable BufferedImage image, @Nullable Drawable drawable) {
if (image == null && drawable == null) throw new IllegalArgumentException("An image or drawable must be provided. Both cannot be null");
boolean initializing = last == null;
if (this.frames != null) {
if (image == null && drawable != null) image = drawable.draw();
last = image;
int width = frames.length;
int height = frames[0].length;
BufferedImage scaled = ImageUtil.getScaledInstance(image, 128 * width, 128 * height, RenderingHints.VALUE_INTERPOLATION_BILINEAR, false);
MapWrapper mapWrapper = mapManager.wrapMultiImage(scaled, width, height);
MultiMapController controller = (MultiMapController) mapWrapper.getController();
controller.addViewer(player);
controller.sendContent(player);
controller.showInFrames(player, frames, true);
} else {
int slot = getMapSlot(player);
if (slot == -1) {
if (initializing) {
player.getInventory().setItemInMainHand(new ItemStack(Material.MAP));
} else {
return;
}
} else if (player.getInventory().getHeldItemSlot() != slot) {
player.getInventory().setHeldItemSlot(slot);
}
if (image == null && drawable != null) image = drawable.draw();
last = image;
BufferedImage scaled = ImageUtil.getScaledInstance(image, 128, 128, RenderingHints.VALUE_INTERPOLATION_BILINEAR, false);
MapWrapper mapWrapper = mapManager.wrapImage(scaled);
MapController controller = mapWrapper.getController();
controller.addViewer(player);
controller.sendContent(player);
controller.showInHand(player, true);
}
}
private int getMapSlot(Player player) {
PlayerInventory inventory = player.getInventory();
for (int i = 0; i < 9; i++) {
ItemStack item = inventory.getItem(i);
if (item != null && item.getType() == Material.MAP) {
return i;
}
}
return -1;
}
public void refresh() {
// if (last != null) view(last, null);
if (last != null) view(last, null);
}
@Override
public void close() throws IOException {
// last = null;
last = null;
}
}

View File

@ -34,6 +34,7 @@ import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.OptionalInt;
public class BukkitBlockRegistry extends BundledBlockRegistry {
@ -93,6 +94,10 @@ public class BukkitBlockRegistry extends BundledBlockRegistry {
this.material = bukkitMaterial;
}
public int getId() {
return material.getId();
}
@Override
public boolean isAir() {
switch (material) {
@ -132,4 +137,9 @@ public class BukkitBlockRegistry extends BundledBlockRegistry {
}
return blocks;
}
@Override
public OptionalInt getInternalBlockStateId(BlockState state) {
return WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBlockStateId(state);
}
}

View File

@ -24,6 +24,10 @@ import com.boydti.fawe.bukkit.FaweBukkit;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.RunnableVal;
import com.boydti.fawe.util.TaskManager;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.ProtocolManager;
import com.comphenix.protocol.injector.netty.WirePacket;
import com.sk89q.util.StringUtil;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
@ -47,10 +51,13 @@ import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.block.BlockTypes;
import com.sk89q.worldedit.world.gamemode.GameMode;
import com.sk89q.worldedit.world.gamemode.GameModes;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.UUID;
import java.util.function.Supplier;
import javax.annotation.Nullable;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
@ -359,6 +366,21 @@ public class BukkitPlayer extends AbstractPlayerActor {
}
}
@Override
public void sendFakeChunk(int chunkX, int chunkZ, Supplier<byte[]> data) {
ProtocolManager manager = ProtocolLibrary.getProtocolManager();
// check if the chunk is in range
if (true) {
try {
byte[] raw = data.get();
WirePacket packet = new WirePacket(PacketType.Play.Server.MAP_CHUNK, raw);
manager.sendWirePacket(getPlayer(), packet);
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
@Override
public void sendTitle(String title, String sub) {
player.sendTitle(ChatColor.GOLD + title, ChatColor.GOLD + sub, 0, 70, 20);

View File

@ -21,7 +21,9 @@ package com.sk89q.worldedit.bukkit;
import static com.google.common.base.Preconditions.checkNotNull;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.bukkit.FaweBukkit;
import com.boydti.fawe.bukkit.adapter.mc1_14.BukkitGetBlocks_1_14;
import com.boydti.fawe.config.Settings;
import com.sk89q.jnbt.CompoundTag;
@ -317,8 +319,19 @@ public class BukkitWorld extends AbstractWorld {
@Override
public void checkLoadedChunk(BlockVector3 pt) {
World world = getWorld();
world.getChunkAt(pt.getBlockX() >> 4, pt.getBlockZ() >> 4);
int X = pt.getBlockX() >> 4;
int Z = pt.getBlockZ() >> 4;
if (Fawe.isMainThread()) {
world.getChunkAt(X, Z);
} else if (!world.isChunkLoaded(X, Z)) {
if (FaweBukkit.PAPER) {
world.getChunkAtAsync(X, Z, true);
} else {
Fawe.get().getQueueHandler().sync(() -> {
world.getChunkAt(X, Z);
});
}
}
}
@Override
@ -516,7 +529,8 @@ public class BukkitWorld extends AbstractWorld {
}
@Override
public void sendChunk(int X, int Z, int mask) {
public void refreshChunk(int X, int Z) {
getWorld().refreshChunk(X, Z);
}
@Override

View File

@ -84,6 +84,7 @@ import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.world.ChunkUnloadEvent;
import org.bukkit.event.world.WorldInitEvent;
import org.bukkit.metadata.FixedMetadataValue;
import org.bukkit.metadata.MetadataValue;
@ -560,16 +561,24 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter
*/
public BukkitPlayer wrapPlayer(Player player) {
synchronized (player) {
@NotNull List<MetadataValue> meta = player.getMetadata("WE");
if (meta == null || meta.isEmpty()) {
BukkitPlayer wePlayer = new BukkitPlayer(this, player);
BukkitPlayer wePlayer = getCachedPlayer(player);
if (wePlayer == null) {
wePlayer = new BukkitPlayer(this, player);
player.setMetadata("WE", new FixedMetadataValue(this, wePlayer));
return wePlayer;
}
return (BukkitPlayer) meta.get(0).value();
return wePlayer;
}
}
public BukkitPlayer getCachedPlayer(Player player) {
List<MetadataValue> meta = player.getMetadata("WE");
if (meta == null || meta.isEmpty()) {
return null;
}
return (BukkitPlayer) meta.get(0).value();
}
public Actor wrapCommandSender(CommandSender sender) {
if (sender instanceof Player) {
return wrapPlayer((Player) sender);

View File

@ -228,6 +228,8 @@ public enum FaweCache implements Trimable {
* Holds data for a palette used in a chunk section
*/
public final class Palette {
public int bitsPerEntry;
public int paletteToBlockLength;
/**
* Reusable buffer array, MUST check paletteToBlockLength for actual length
@ -319,6 +321,7 @@ public enum FaweCache implements Trimable {
// Construct palette
Palette palette = PALETTE_CACHE.get();
palette.bitsPerEntry = bitsPerEntry;
palette.paletteToBlockLength = num_palette;
palette.paletteToBlock = paletteToBlock;

View File

@ -1,6 +1,8 @@
package com.boydti.fawe;
import com.boydti.fawe.beta.implementation.QueueHandler;
import com.boydti.fawe.beta.preloader.AsyncPreloader;
import com.boydti.fawe.beta.preloader.Preloader;
import com.boydti.fawe.object.FaweCommand;
import com.boydti.fawe.regions.FaweMaskManager;
import com.boydti.fawe.util.TaskManager;
@ -54,4 +56,6 @@ public interface IFawe {
QueueHandler getQueueHandler();
Preloader getPreloader();
}

View File

@ -1,61 +0,0 @@
package com.boydti.fawe.beta;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class ChunkFuture implements Future<Void> {
private final IChunk chunk;
private volatile boolean cancelled;
private volatile boolean done;
public ChunkFuture(IChunk chunk) {
this.chunk = chunk;
}
public IChunk getChunk() {
return chunk;
}
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
cancelled = true;
return !done;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public boolean isDone() {
return done;
}
@Override
public Void get() throws InterruptedException, ExecutionException {
synchronized (chunk) {
if (!done) {
this.wait();
}
}
return null;
}
@Override
public Void get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
synchronized (chunk) {
if (!done) {
this.wait(unit.toMillis(timeout));
if (!done) {
throw new TimeoutException();
}
}
}
return null;
}
}

View File

@ -1,5 +1,6 @@
package com.boydti.fawe.beta;
import com.boydti.fawe.FaweCache;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.biome.BiomeType;
@ -19,5 +20,20 @@ public interface IBlocks extends Trimable {
BlockState getBlock(int x, int y, int z);
Map<BlockVector3, CompoundTag> getTiles();
Set<CompoundTag> getEntities();
BiomeType getBiomeType(int x, int z);
default int getBitMask() {
int mask = 0;
for (int layer = 0; layer < FaweCache.IMP.CHUNK_LAYERS; layer++) {
if (hasSection(layer));
mask |= (1 << layer);
}
return mask;
}
IBlocks reset();
}

View File

@ -28,8 +28,10 @@ public interface IChunkGet extends IBlocks, Trimable, InputExtent {
CompoundTag getTag(int x, int y, int z);
@Override
Map<BlockVector3, CompoundTag> getTiles();
@Override
Set<CompoundTag> getEntities();
@Override

View File

@ -38,8 +38,13 @@ public interface IChunkSet extends IBlocks, OutputExtent {
BiomeType[] getBiomes();
@Override
BiomeType getBiomeType(int x, int z);
@Override
Map<BlockVector3, CompoundTag> getTiles();
@Override
Set<CompoundTag> getEntities();
@Override

View File

@ -45,16 +45,6 @@ public interface IDelegateQueueExtent extends IQueueExtent {
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();

View File

@ -31,22 +31,6 @@ public interface IQueueExtent extends Flushable, Trimable, Extent, IBatchProcess
return true;
}
/**
* Clear any block updates
* @param players
*/
default void clearBlockUpdates(Player... players) {
throw new UnsupportedOperationException("TODO NOT IMPLEMENTED");
}
/**
* Send all the chunks as block updates
* @param players
*/
default void sendBlockUpdates(Player... players) {
throw new UnsupportedOperationException("TODO NOT IMPLEMENTED");
}
/**
* Must ensure that it is enqueued with QueueHandler
*/

View File

@ -0,0 +1,126 @@
package com.boydti.fawe.beta.implementation;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.beta.IBlocks;
import com.boydti.fawe.object.FaweOutputStream;
import com.boydti.fawe.object.io.FastByteArrayOutputStream;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.world.block.BlockID;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.registry.BlockRegistry;
import java.util.function.Function;
import java.util.function.Supplier;
public class ChunkPacket implements Function<byte[], byte[]>, Supplier<byte[]> {
private final boolean full;
private final boolean biomes;
private final IBlocks chunk;
private final int chunkX;
private final int chunkZ;
public ChunkPacket(int chunkX, int chunkZ, IBlocks chunk, boolean replaceAllSections, boolean sendBiomeData) {
this.chunkX = chunkX;
this.chunkZ = chunkZ;
this.chunk = chunk;
this.full = replaceAllSections;
this.biomes = sendBiomeData;
}
@Override
@Deprecated
public byte[] get() {
System.out.println("TODO deprecated, use buffer");
return apply(new byte[8192]);
}
@Override
public byte[] apply(byte[] buffer) {
try {
FastByteArrayOutputStream baos = new FastByteArrayOutputStream();
FaweOutputStream fos = new FaweOutputStream(baos);
fos.writeInt(this.chunkX);
fos.writeInt(this.chunkZ);
fos.writeBoolean(this.full);
fos.writeVarInt(this.chunk.getBitMask()); // writeVarInt
// TODO write NBTTagCompound of HeightMaps
fos.writeVarInt(0); // (Entities / NBT)
// TODO write chunk data to byte[]
{
BlockRegistry registry = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS).getRegistries().getBlockRegistry();
try (FastByteArrayOutputStream sectionByteArray = new FastByteArrayOutputStream(buffer); FaweOutputStream sectionWriter = new FaweOutputStream(sectionByteArray)) {
for (int layer = 0; layer < FaweCache.IMP.CHUNK_LAYERS; layer++) {
if (!this.chunk.hasSection(layer)) continue;
char[] ids = this.chunk.getArray(layer);
FaweCache.Palette palette = FaweCache.IMP.toPalette(0, ids);
int nonEmpty = 0; // TODO optimize into same loop as toPalette
for (char id :ids) {
if (id != 0) nonEmpty++;
}
sectionWriter.writeShort(nonEmpty); // non empty
sectionWriter.writeByte(palette.bitsPerEntry); // bits per block
sectionWriter.writeVarInt(palette.paletteToBlockLength);
for (int i = 0; i < palette.paletteToBlockLength; i++) {
int ordinal = palette.paletteToBlock[i];
switch (ordinal) {
case BlockID.CAVE_AIR:
case BlockID.VOID_AIR:
case BlockID.AIR:
case BlockID.__RESERVED__:
sectionWriter.writeByte(0);
break;
default:
BlockState state = BlockState.getFromOrdinal(ordinal);
int mcId = registry.getInternalBlockStateId(state).getAsInt();
sectionWriter.writeVarInt(mcId);
}
}
sectionWriter.writeVarInt(palette.blockStatesLength);
for (int i = 0; i < palette.blockStatesLength; i++) {
sectionWriter.writeLong(palette.blockStates[i]);
}
}
// TODO write biomes
// boolean writeBiomes = true;
// for (int x = 0; x < 16; x++) {
// for (int z = 0; z < 16; z++) {
// BiomeType biome = this.chunk.getBiomeType(x, z);
// if (biome == null) {
// if (writeBiomes) {
// break;
// } else {
// biome = BiomeTypes.FOREST;
// }
// }
// }
// }
if (this.full) {
for (int i = 0; i < 256; i++) {
sectionWriter.writeInt(0);
}
}
fos.writeVarInt(sectionByteArray.getSize());
for (byte[] arr : sectionByteArray.toByteArrays()) {
fos.write(arr);
}
}
}
// TODO entities / NBT
fos.writeVarInt(0); // (Entities / NBT)
return baos.toByteArray();
} catch (Throwable e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}

View File

@ -0,0 +1,40 @@
package com.boydti.fawe.beta.implementation;
import com.boydti.fawe.beta.IBatchProcessor;
import com.boydti.fawe.beta.IChunk;
import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.IChunkSet;
import com.boydti.fawe.object.extent.NullExtent;
import com.google.common.base.Suppliers;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
import com.sk89q.worldedit.extent.Extent;
import java.util.function.Supplier;
import java.util.stream.Stream;
public class ChunkSendProcessor extends AbstractDelegateExtent implements IBatchProcessor {
private final Supplier<Stream<Player>> players;
public ChunkSendProcessor(Supplier<Stream<Player>> players) {
super(new NullExtent());
this.players = players;
}
@Override
public IChunkSet processSet(IChunk chunk, IChunkGet get, IChunkSet set) {
int chunkX = chunk.getX();
int chunkZ = chunk.getZ();
boolean replaceAll = true;
boolean sendBiome = set.getBiomes() != null;
ChunkPacket packet = new ChunkPacket(chunkX, chunkZ, set, replaceAll, sendBiome);
Supplier<byte[]> packetData = Suppliers.memoize(packet::get);
players.get().forEach(plr -> plr.sendFakeChunk(chunkX, chunkZ, packetData));
return set;
}
@Override
public Extent construct(Extent child) {
return null;
}
}

View File

@ -170,6 +170,7 @@ public class ParallelQueueExtent extends PassthroughExtent implements IQueueWrap
if (vset instanceof Region) {
setBlocks((Region) vset, pattern);
}
// TODO optimize parallel
for (BlockVector3 blockVector3 : vset) {
pattern.apply(this, blockVector3, blockVector3);
}

View File

@ -19,6 +19,7 @@ import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutionException;
@ -39,6 +40,7 @@ public abstract class QueueHandler implements Trimable, Runnable {
private ForkJoinPool forkJoinPoolSecondary = new ForkJoinPool();
private ThreadPoolExecutor blockingExecutor = FaweCache.IMP.newBlockingExecutor();
private ConcurrentLinkedQueue<FutureTask> syncTasks = new ConcurrentLinkedQueue<>();
private ConcurrentLinkedQueue<FutureTask> syncWhenFree = new ConcurrentLinkedQueue<>();
private Map<World, WeakReference<IChunkCache<IChunkGet>>> chunkGetCache = new HashMap<>();
private CleanableThreadLocal<IQueueExtent> queuePool = new CleanableThreadLocal<>(QueueHandler.this::create);
@ -60,53 +62,61 @@ public abstract class QueueHandler implements Trimable, Runnable {
throw new IllegalStateException("Not main thread");
}
if (!syncTasks.isEmpty()) {
long now = System.currentTimeMillis();
targetTPS = 18 - Math.max(Settings.IMP.QUEUE.EXTRA_TIME_MS * 0.05, 0);
long diff = 50 + this.last - (this.last = now);
long absDiff = Math.abs(diff);
if (diff == 0) {
allocate = Math.min(50, allocate + 1);
} else if (diff < 0) {
allocate = Math.max(5, allocate + diff);
} else if (!Fawe.get().getTimer().isAbove(targetTPS)) {
allocate = Math.max(5, allocate - 1);
}
long currentAllocate = allocate - absDiff;
long currentAllocate = getAllocate();
if (!MemUtil.isMemoryFree()) {
// TODO reduce mem usage
// FaweCache trim
// Preloader trim
}
boolean wait = false;
do {
Runnable task = syncTasks.poll();
if (task == null) {
if (wait) {
synchronized (syncTasks) {
try {
syncTasks.wait(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
task = syncTasks.poll();
wait = false;
} else {
break;
}
}
if (task != null) {
task.run();
wait = true;
}
} while (System.currentTimeMillis() - now < currentAllocate);
operate(syncTasks, last, currentAllocate);
} else if (!syncWhenFree.isEmpty()) {
operate(syncWhenFree, last, getAllocate());
} else {
// trim??
}
while (!syncTasks.isEmpty()) {
final FutureTask task = syncTasks.poll();
}
private long getAllocate() {
long now = System.currentTimeMillis();
targetTPS = 18 - Math.max(Settings.IMP.QUEUE.EXTRA_TIME_MS * 0.05, 0);
long diff = 50 + this.last - (this.last = now);
long absDiff = Math.abs(diff);
if (diff == 0) {
allocate = Math.min(50, allocate + 1);
} else if (diff < 0) {
allocate = Math.max(5, allocate + diff);
} else if (!Fawe.get().getTimer().isAbove(targetTPS)) {
allocate = Math.max(5, allocate - 1);
}
return allocate - absDiff;
}
private void operate(Queue<FutureTask> queue, long start, long currentAllocate) {
boolean wait = false;
do {
Runnable task = queue.poll();
if (task == null) {
if (wait) {
synchronized (syncTasks) {
try {
queue.wait(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
task = queue.poll();
wait = false;
} else {
break;
}
}
if (task != null) {
task.run();
wait = true;
}
}
} while (System.currentTimeMillis() - start < currentAllocate);
}
public <T extends Future<T>> void complete(Future<T> task) {
@ -136,50 +146,83 @@ public abstract class QueueHandler implements Trimable, Runnable {
}
public <T> Future<T> sync(Runnable run, T value) {
return sync(run, value, syncTasks);
}
public <T> Future<T> sync(Runnable run) {
return sync(run, syncTasks);
}
public <T> Future<T> sync(Callable<T> call) throws Exception {
return sync(call, syncTasks);
}
public <T> Future<T> sync(Supplier<T> call) {
return sync(call, syncTasks);
}
// Lower priorty sync task (runs only when there are no other tasks)
public <T> Future<T> syncWhenFree(Runnable run, T value) {
return sync(run, value, syncWhenFree);
}
public <T> Future<T> syncWhenFree(Runnable run) {
return sync(run, syncWhenFree);
}
public <T> Future<T> syncWhenFree(Callable<T> call) throws Exception {
return sync(call, syncWhenFree);
}
public <T> Future<T> syncWhenFree(Supplier<T> call) {
return sync(call, syncWhenFree);
}
private <T> Future<T> sync(Runnable run, T value, Queue<FutureTask> queue) {
if (Fawe.isMainThread()) {
run.run();
return Futures.immediateFuture(value);
}
final FutureTask<T> result = new FutureTask<>(run, value);
syncTasks.add(result);
notifySync();
queue.add(result);
notifySync(queue);
return result;
}
public <T> Future<T> sync(Runnable run) {
private <T> Future<T> sync(Runnable run, Queue<FutureTask> queue) {
if (Fawe.isMainThread()) {
run.run();
return Futures.immediateCancelledFuture();
}
final FutureTask<T> result = new FutureTask<>(run, null);
syncTasks.add(result);
notifySync();
queue.add(result);
notifySync(queue);
return result;
}
public <T> Future<T> sync(Callable<T> call) throws Exception {
private <T> Future<T> sync(Callable<T> call, Queue<FutureTask> queue) throws Exception {
if (Fawe.isMainThread()) {
return Futures.immediateFuture(call.call());
}
final FutureTask<T> result = new FutureTask<>(call);
syncTasks.add(result);
notifySync();
queue.add(result);
notifySync(queue);
return result;
}
public <T> Future<T> sync(Supplier<T> call) {
private <T> Future<T> sync(Supplier<T> call, Queue<FutureTask> queue) {
if (Fawe.isMainThread()) {
return Futures.immediateFuture(call.get());
}
final FutureTask<T> result = new FutureTask<>(call::get);
syncTasks.add(result);
notifySync();
queue.add(result);
notifySync(queue);
return result;
}
private void notifySync() {
synchronized (syncTasks) {
syncTasks.notifyAll();
private void notifySync(Object object) {
synchronized (object) {
object.notifyAll();
}
}

View File

@ -115,6 +115,11 @@ public class BitSetBlocks implements IChunkSet {
return null;
}
@Override
public BiomeType getBiomeType(int x, int z) {
return null;
}
@Override
public Map<BlockVector3, CompoundTag> getTiles() {
return null;

View File

@ -11,7 +11,7 @@ import com.sk89q.worldedit.world.block.BlockTypes;
import java.util.Map;
import java.util.Set;
public class CharBlocks implements IBlocks {
public abstract class CharBlocks implements IBlocks {
public static final Section FULL = new Section() {
@Override

View File

@ -43,6 +43,11 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet {
return biomes;
}
@Override
public BiomeType getBiomeType(int x, int z) {
return biomes[(z << 4) | x];
}
@Override
public Map<BlockVector3, CompoundTag> getTiles() {
return tiles == null ? Collections.emptyMap() : tiles;

View File

@ -0,0 +1,110 @@
package com.boydti.fawe.beta.preloader;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.object.collection.MutablePair;
import com.boydti.fawe.util.FaweTimer;
import com.sk89q.worldedit.IncompleteRegionException;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.world.World;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
public class AsyncPreloader implements Preloader, Runnable {
private final ConcurrentHashMap<UUID, MutablePair<World, Set<BlockVector2>>> update;
public AsyncPreloader() {
this.update = new ConcurrentHashMap<>();
Fawe.get().getQueueHandler().async(this);
}
@Override
public void cancel(Player player) {
cancelAndGet(player);
}
private MutablePair<World, Set<BlockVector2>> cancelAndGet(Player player) {
MutablePair<World, Set<BlockVector2>> existing = update.get(player.getUniqueId());
if (existing != null) {
existing.setValue(null);
}
return existing;
}
@Override
public void update(Player player) {
LocalSession session = WorldEdit.getInstance().getSessionManager().getIfPresent(player);
if (session == null) return;
World world = player.getWorld();
MutablePair<World, Set<BlockVector2>> existing = cancelAndGet(player);
try {
Region region = session.getSelection(world);
if (!(region instanceof CuboidRegion) || region.getArea() > 50466816) {
// TOO LARGE or NOT CUBOID
return;
}
if (existing == null) {
MutablePair<World, Set<BlockVector2>> previous = update.putIfAbsent(player.getUniqueId(), existing = new MutablePair<>());
if (previous != null) {
existing = previous;
}
synchronized (existing) { // Ensure key & value are mutated together
existing.setKey(world);
existing.setValue(region.getChunks());
}
synchronized (update) {
update.notify();
}
}
} catch (IncompleteRegionException ignore){}
}
@Override
public void run() {
FaweTimer timer = Fawe.get().getTimer();
try {
while (true) {
if (!update.isEmpty()) {
if (timer.getTPS() > 19) {
Iterator<Map.Entry<UUID, MutablePair<World, Set<BlockVector2>>>> plrIter = update.entrySet().iterator();
Map.Entry<UUID, MutablePair<World, Set<BlockVector2>>> entry = plrIter.next();
MutablePair<World, Set<BlockVector2>> pair = entry.getValue();
World world = pair.getKey();
Set<BlockVector2> chunks = pair.getValue();
if (chunks != null) {
Iterator<BlockVector2> chunksIter = chunks.iterator();
while (chunksIter.hasNext() && pair.getValue() == chunks) { // Ensure the queued load is still valid
BlockVector2 chunk = chunksIter.next();
queueLoad(world, chunk);
}
}
plrIter.remove();
} else {
Thread.sleep(1000);
}
} else {
synchronized (update) {
update.wait();
}
}
}
} catch (InterruptedException e) {
e.printStackTrace();
return;
}
}
public void queueLoad(World world, BlockVector2 chunk) {
world.checkLoadedChunk(BlockVector3.at(chunk.getX() << 4, 0, chunk.getZ() << 4));
}
}

View File

@ -0,0 +1,9 @@
package com.boydti.fawe.beta.preloader;
import com.sk89q.worldedit.entity.Player;
public interface Preloader {
void cancel(Player player);
void update(Player player);
}

View File

@ -432,7 +432,7 @@ public class CFICommands {
Clipboard clipboard = holder.getClipboard();
boolean[] ids = new boolean[BlockTypes.size()];
for (BlockVector3 pt : clipboard.getRegion()) {
ids[clipboard.getBlock(pt).getInternalBlockTypeId()] = true;
ids[clipboard.getBlock(pt).getBlockType().getInternalId()] = true;
}
blocks = new HashSet<>();
for (int combined = 0; combined < ids.length; combined++) {
@ -606,7 +606,7 @@ public class CFICommands {
@CommandPermissions("worldedit.anvil.cfi")
public void waterId(Player fp, BlockStateHolder block) throws WorldEditException {
CFISettings settings = assertSettings(fp);
settings.getGenerator().setWaterId(block.getBlockType().getInternalId());
settings.getGenerator().setWater(block.toImmutableState());
fp.print("Set water id!");
settings.resetComponent();
@ -621,7 +621,7 @@ public class CFICommands {
@CommandPermissions("worldedit.anvil.cfi")
public void baseId(Player fp, BlockStateHolder block) throws WorldEditException {
CFISettings settings = assertSettings(fp);
settings.getGenerator().setBedrockId(block.getBlockType().getInternalId());
settings.getGenerator().setBedrock(block.toImmutableState());
fp.print(TextComponent.of("Set base id!"));
settings.resetComponent();
component(fp);

View File

@ -0,0 +1,8 @@
package com.boydti.fawe.object;
import java.util.function.Supplier;
public interface Lazy<T> extends Supplier<T> {
Supplier<T> init();
public default T get() { return init().get(); }
}

View File

@ -47,7 +47,7 @@ public class VisualExtent extends AbstractDelegateExtent {
@Override
public Operation commit() {
IQueueExtent queue = (IQueueExtent) getExtent();
queue.sendBlockUpdates(this.player);
System.out.println("Send block updates");
return null;
}
@ -59,7 +59,7 @@ public class VisualExtent extends AbstractDelegateExtent {
public void clear() {
IQueueExtent queue = (IQueueExtent) getExtent();
queue.clearBlockUpdates(player);
System.out.println("Clear");
queue.cancel();
}
}

View File

@ -0,0 +1,142 @@
package com.boydti.fawe.object.brush.visualization.cfi;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.util.MathMan;
import com.boydti.fawe.util.TextureUtil;
import com.sk89q.worldedit.world.block.BlockID;
import com.sk89q.worldedit.world.block.BlockTypes;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.TimeUnit;
public final class CFIDrawer {
private final HeightMapMCAGenerator gen;
private final TextureUtil tu;
private final ForkJoinPool pool;
public CFIDrawer(HeightMapMCAGenerator generator, TextureUtil textureUtil) {
this.gen = generator;
this.tu = textureUtil;
this.pool = new ForkJoinPool();
}
public CFIDrawer(HeightMapMCAGenerator generator) {
this(generator, Fawe.get().getCachedTextureUtil(false, 0, 100));
}
public BufferedImage draw() {
BufferedImage img = new BufferedImage(gen.getWidth(), gen.getLength(), BufferedImage.TYPE_INT_RGB);
final char[] overlay = gen.overlay == null ? gen.floor.get() : gen.overlay.get();
final char[] floor = gen.floor.get();
final char[] main = gen.main.get();
final byte[] heights = gen.heights.get();
final byte[] biomes = gen.biomes.get();
final int waterHeight = gen.primitives.waterHeight;
final int width = gen.getWidth();
final int length = gen.getLength();
int[] raw = ((DataBufferInt) img.getRaster().getDataBuffer()).getData();
int parallelism = pool.getParallelism();
int size = (heights.length + parallelism - 1) / parallelism;
for (int i = 0; i < parallelism; i++) {
int start = i * size;
int end = Math.min(heights.length, start + size);
pool.submit((Runnable) () -> {
for (int index = start; index < end; index ++) {
int height = (heights[index] & 0xFF);
char ordinal;
if ((ordinal = overlay[index]) == 0) {
height--;
ordinal = floor[index];
if (ordinal == 0) {
height--;
ordinal = main[index];
}
}
// draw ordinal
int color;
switch (ordinal >> 4) {
case 2:
color = getAverageBiomeColor(biomes, width, index);
break;
case 78:
color = (0xDD << 16) + (0xDD << 8) + (0xDD << 0);
break;
default:
color = tu.getColor(BlockTypes.getFromStateOrdinal(ordinal));
break;
}
int slope = getSlope(heights, width, index, height);
if (slope != 0) {
slope = (slope << 3) + (slope << 2);
int r = MathMan.clamp(((color >> 16) & 0xFF) + slope, 0, 255);
int g = MathMan.clamp(((color >> 8) & 0xFF) + slope, 0, 255);
int b = MathMan.clamp(((color >> 0) & 0xFF) + slope, 0, 255);
color = (r << 16) + (g << 8) + (b << 0);
}
if (height + 1 < waterHeight) {
char waterId = gen.primitives.waterOrdinal;
int waterColor = 0;
switch (waterId) {
case BlockID.WATER:
color = tu.averageColor((0x11 << 16) + (0x66 << 8) + (0xCC), color);
break;
case BlockID.LAVA:
color = (0xCC << 16) + (0x33 << 8) + (0);
break;
default:
color = tu.getColor(BlockTypes.getFromStateOrdinal(waterId));
break;
}
}
raw[index] = color;
}
});
}
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
pool.shutdownNow();
return img;
}
private final int getAverageBiomeColor(byte[] biomes, int width, int index) {
int c0 = tu.getBiome(biomes[index] & 0xFF).grassCombined;
int c2 = getBiome(biomes, index + 1 + width, index);
int c1 = getBiome(biomes, index - 1 - width, index);
// int c3 = getBiome(biomes, index + width, index);
// int c4 = getBiome(biomes, index - width, index);
int r = ((c0 >> 16) & 0xFF) + ((c1 >> 16) & 0xFF) + ((c2 >> 16) & 0xFF);// + ((c3 >> 16) & 0xFF) + ((c4 >> 16) & 0xFF);
int g = ((c0 >> 8) & 0xFF) + ((c1 >> 8) & 0xFF) + ((c2 >> 8) & 0xFF);// + ((c3 >> 8) & 0xFF) + ((c4 >> 8) & 0xFF);
int b = ((c0) & 0xFF) + ((c1) & 0xFF) + ((c2) & 0xFF);// + ((c3) & 0xFF) + ((c4) & 0xFF);
r = r * 85 >> 8;
g = g * 85 >> 8;
b = b * 85 >> 8;
return (r << 16) + (g << 8) + (b);
}
private final int getBiome(byte[] biomes, int newIndex, int index) {
if (newIndex < 0 || newIndex >= biomes.length) newIndex = index;
int biome = biomes[newIndex] & 0xFF;
return tu.getBiome(biome).grassCombined;
}
private int getSlope(byte[] heights, int width, int index, int height) {
return (
+ getHeight(heights, index + 1, height)
// + getHeight(heights, index + width, height)
+ getHeight(heights, index + width + 1, height)
- getHeight(heights, index - 1, height)
// - getHeight(heights, index - width, height)
- getHeight(heights, index - width - 1, height)
);
}
private int getHeight(byte[] heights, int index, int height) {
if (index < 0 || index >= heights.length) return height;
return heights[index] & 0xFF;
}
}

View File

@ -3,6 +3,8 @@ package com.boydti.fawe.object.brush.visualization.cfi;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.IChunkSet;
import com.boydti.fawe.beta.implementation.ChunkPacket;
import com.boydti.fawe.beta.implementation.FallbackChunkGet;
import com.boydti.fawe.object.FaweInputStream;
import com.boydti.fawe.object.FaweOutputStream;
@ -15,7 +17,6 @@ import com.boydti.fawe.object.collection.DifferentialBlockBuffer;
import com.boydti.fawe.object.collection.LocalBlockVector2DSet;
import com.boydti.fawe.object.collection.SummedAreaTable;
import com.boydti.fawe.object.exception.FaweChunkLoadException;
import com.boydti.fawe.object.exception.FaweException;
import com.boydti.fawe.object.schematic.Schematic;
import com.boydti.fawe.util.CachedTextureUtil;
import com.boydti.fawe.util.RandomTextureUtil;
@ -23,6 +24,7 @@ import com.boydti.fawe.util.ReflectionUtils;
import com.boydti.fawe.util.TextureUtil;
import com.boydti.fawe.util.image.Drawable;
import com.boydti.fawe.util.image.ImageViewer;
import com.google.common.base.Suppliers;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalSession;
@ -64,6 +66,7 @@ import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.Supplier;
import javax.annotation.Nullable;
// TODO FIXME
@ -73,9 +76,9 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
private final DifferentialBlockBuffer blocks;
protected final DifferentialArray<byte[]> heights;
protected final DifferentialArray<byte[]> biomes;
protected final DifferentialArray<int[]> floor;
protected final DifferentialArray<int[]> main;
protected DifferentialArray<int[]> overlay;
protected final DifferentialArray<char[]> floor;
protected final DifferentialArray<char[]> main;
protected DifferentialArray<char[]> overlay;
protected final CFIPrimitives primitives = new CFIPrimitives();
private CFIPrimitives oldPrimitives = new CFIPrimitives();
@ -86,8 +89,8 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
int worldThickness;
boolean randomVariation = true;
int biomePriority;
int waterId = BlockID.WATER;
int bedrockId = BlockID.BEDROCK;
char waterOrdinal = BlockID.WATER;
char bedrockOrdinal = BlockID.BEDROCK;
boolean modifiedMain;
@Override
@ -225,13 +228,13 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
blocks = new DifferentialBlockBuffer(width, length);
heights = new DifferentialArray<>(new byte[getArea()]);
biomes = new DifferentialArray<>(new byte[getArea()]);
floor = new DifferentialArray<>(new int[getArea()]);
main = new DifferentialArray<>(new int[getArea()]);
floor = new DifferentialArray<>(new char[getArea()]);
main = new DifferentialArray<>(new char[getArea()]);
int stone = BlockID.STONE;
int grass = BlockTypes.GRASS_BLOCK.getDefaultState().with(PropertyKey.SNOWY, false).getInternalId();
Arrays.fill(main.getIntArray(), stone);
Arrays.fill(floor.getIntArray(), grass);
char stone = BlockID.STONE;
char grass = BlockTypes.GRASS_BLOCK.getDefaultState().with(PropertyKey.SNOWY, false).getOrdinalChar();
Arrays.fill(overlay.getCharArray(), stone);
Arrays.fill(overlay.getCharArray(), grass);
}
public Metadatable getMetaData() {
@ -259,10 +262,10 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
return player;
}
private int[][][] getChunkArray(int x, int z) {
int[][][][][] blocksData = blocks.get();
private char[][][] getChunkArray(int x, int z) {
char[][][][][] blocksData = blocks.get();
if (blocksData == null) return null;
int[][][][] arr = blocksData[z];
char[][][][] arr = blocksData[z];
return arr != null ? arr[x] : null;
}
@ -320,8 +323,20 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
}
@Override
public void sendChunk(int X, int Z, int mask) {
throw new UnsupportedOperationException("TODO NOT IMPLEMENTED"); // add method to adapter to send custom chunk
public void refreshChunk(int chunkX, int chunkZ) {
IChunkSet chunk = getChunk(chunkX, chunkZ);
ChunkPacket packet = new ChunkPacket(chunkX, chunkZ, chunk, true, true);
player.sendFakeChunk(chunkX, chunkZ, packet::get);
}
public IChunkSet getChunk(int chunkX, int chunkZ) {
// TODO don't generate new Writeable MCA chunk
System.out.println("TODO don't generate new Writeable MCA chunk");
WritableMCAChunk tmp = new WritableMCAChunk();
int bx = chunkX << 4;
int bz = chunkZ << 4;
write(tmp, bx, bx + 15, bz, bz + 15);
return tmp;
}
public TextureUtil getRawTextureUtil() {
@ -349,8 +364,8 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
}
}
public void setBedrockId(int bedrockId) {
this.primitives.bedrockId = bedrockId;
public void setBedrock(BlockState bedrock) {
this.primitives.bedrockOrdinal = bedrock.getOrdinalChar();
}
public void setFloorThickness(int floorThickness) {
@ -365,8 +380,8 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
this.primitives.waterHeight = waterHeight;
}
public void setWaterId(int waterId) {
this.primitives.waterId = waterId;
public void setWater(BlockState water) {
this.primitives.waterOrdinal = water.getOrdinalChar();
}
public void setTextureRandomVariation(boolean randomVariation) {
@ -390,10 +405,10 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
}
public void smooth(BlockVector2 min, BlockVector2 max, int radius, int iterations) {
int snowLayer = BlockTypes.SNOW.getInternalId();
int snowBlock = BlockTypes.SNOW_BLOCK.getInternalId();
int snowLayer = BlockTypes.SNOW.getDefaultState().getOrdinalChar();
int snowBlock = BlockTypes.SNOW_BLOCK.getDefaultState().getOrdinalChar();
int[] floor = this.floor.get();
char[] floor = this.floor.get();
byte[] heights = this.heights.get();
int width = getWidth();
@ -421,7 +436,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
int index = zIndex + minX;
for (int x = minX; x <= maxX; x++, index++, localIndex++) {
int combined = floor[index];
if (BlockTypes.getFromStateId(combined) == BlockTypes.SNOW) {
if (BlockTypes.getFromStateOrdinal(combined) == BlockTypes.SNOW) {
layers[localIndex] = (char) (((heights[index] & 0xFF) << 3) + (floor[index] >> BlockTypes.BIT_OFFSET) - 7);
} else {
layers[localIndex] = (char) ((heights[index] & 0xFF) << 3);
@ -453,16 +468,15 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
private final void setLayerHeight(int index, int blockHeight, int layerHeight) {
int floorState = floor.get()[index];
BlockType type = BlockTypes.getFromStateId(floorState);
switch (type.getInternalId()) {
switch (floorState) {
case BlockID.SNOW:
case BlockID.SNOW_BLOCK:
if (layerHeight != 0) {
this.heights.setByte(index, (byte) (blockHeight + 1));
this.floor.setInt(index, BlockTypes.SNOW.getInternalId() + layerHeight);
this.floor.setInt(index, BlockTypes.SNOW.getDefaultState().getOrdinalChar() + layerHeight);
} else {
this.heights.setByte(index, (byte) blockHeight);
this.floor.setInt(index, BlockTypes.SNOW_BLOCK.getInternalId());
this.floor.setInt(index, BlockTypes.SNOW_BLOCK.getDefaultState().getOrdinalChar());
}
break;
default:
@ -479,16 +493,15 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
private final void setLayerHeightRaw(int index, int blockHeight, int layerHeight) {
int floorState = floor.get()[index];
BlockType type = BlockTypes.getFromStateId(floorState);
switch (type.getInternalId()) {
switch (floorState) {
case BlockID.SNOW:
case BlockID.SNOW_BLOCK:
if (layerHeight != 0) {
this.heights.getByteArray()[index] = (byte) (blockHeight + 1);
this.floor.getIntArray()[index] = BlockTypes.SNOW.getInternalId() + layerHeight;
this.overlay.getCharArray()[index] = (char) (BlockTypes.SNOW.getDefaultState().getOrdinalChar() + layerHeight);
} else {
this.heights.getByteArray()[index] = (byte) blockHeight;
this.floor.getIntArray()[index] = BlockTypes.SNOW_BLOCK.getInternalId();
this.overlay.getCharArray()[index] = BlockTypes.SNOW_BLOCK.getDefaultState().getOrdinalChar();
}
break;
default:
@ -498,7 +511,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
}
private void smooth(BufferedImage img, Mask mask, boolean white, int radius, int iterations) {
int[] floor = this.floor.get();
char[] floor = this.floor.get();
byte[] heights = this.heights.get();
long[] copy = new long[heights.length];
@ -511,7 +524,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
for (int j = 0; j < iterations; j++) {
for (int i = 0; i < heights.length; i++) {
int combined = floor[i];
if (BlockTypes.getFromStateId(combined) == BlockTypes.SNOW) {
if (BlockTypes.getFromStateOrdinal(combined) == BlockTypes.SNOW) {
layers[i] = (char) (((heights[i] & 0xFF) << 3) + (floor[i] >> BlockTypes.BIT_OFFSET) - 7);
} else {
layers[i] = (char) ((heights[i] & 0xFF) << 3);
@ -704,7 +717,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
return setBlock(position.getBlockX(), position.getBlockY(), position.getBlockZ(), block);
}
private boolean setBlock(int x, int y, int z, int combined) {
private boolean setBlock(int x, int y, int z, char combined) {
int index = z * getWidth() + x;
if (index < 0 || index >= getArea()) return false;
int height = heights.getByte(index) & 0xFF;
@ -713,8 +726,8 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
floor.setInt(index, combined);
return true;
case 1:
int mainId = main.getInt(index);
int floorId = floor.getInt(index);
char mainId = overlay.getChar(index);
char floorId = overlay.getChar(index);
floor.setInt(index, combined);
byte currentHeight = heights.getByte(index);
@ -870,7 +883,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
for (int cz = scz; cz <= ecz; cz++) {
for (int cx = scx; cx <= ecx; cx++) {
world.sendChunk(cx + OX, cz + OZ, 0);
world.refreshChunk(cx + OX, cz + OZ);
}
}
}
@ -890,20 +903,19 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
return BiomeTypes.get(biomes.getByte(index));
}
// @Override
public int getCombinedId4Data(int x, int y, int z) throws FaweChunkLoadException {
public int getOrdinal(int x, int y, int z) throws FaweChunkLoadException {
int index = z * getWidth() + x;
if (y < 0) return 0;
if (index < 0 || index >= getArea() || x < 0 || x >= getWidth()) return 0;
int height = heights.getByte(index) & 0xFF;
if (y > height) {
if (y == height + 1) {
return overlay != null ? overlay.getInt(index) : 0;
return overlay != null ? overlay.getChar(index) : 0;
}
if (blocks != null) {
short chunkX = (short) (x >> 4);
short chunkZ = (short) (z >> 4);
int[][][] map = getChunkArray(chunkX, chunkZ);
char[][][] map = getChunkArray(chunkX, chunkZ);
if (map != null) {
int combined = get(map, x, y, z);
if (combined != 0) {
@ -912,16 +924,16 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
}
}
if (y <= primitives.waterHeight) {
return primitives.waterId << 4;
return primitives.waterOrdinal;
}
return 0;
} else if (y == height) {
return floor.getInt(index);
return overlay.getChar(index);
} else {
if (blocks != null) {
short chunkX = (short) (x >> 4);
short chunkZ = (short) (z >> 4);
int[][][] map = getChunkArray(chunkX, chunkZ);
char[][][] map = getChunkArray(chunkX, chunkZ);
if (map != null) {
int combined = get(map, x, y, z);
if (combined != 0) {
@ -929,13 +941,13 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
}
}
}
return main.getInt(index);
return overlay.getChar(index);
}
}
@Override
public boolean setBlock(int x, int y, int z, BlockStateHolder block) throws WorldEditException {
return this.setBlock(x, y, z, block.getInternalId());
return this.setBlock(x, y, z, block.getOrdinalChar());
}
@Override
@ -950,7 +962,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
public BlockState getFloor(int x, int z) {
int index = z * getWidth() + x;
return BlockState.getFromInternalId(floor.getInt(index));
return BlockState.getFromOrdinal(overlay.getChar(index));
}
public int getHeight(int x, int z) {
@ -964,19 +976,19 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
public void setFloor(int x, int z, BlockStateHolder block) {
int index = z * getWidth() + x;
floor.setInt(index, block.getInternalId());
floor.setInt(index, block.getOrdinalChar());
}
@Override
public BlockState getBlock(int x, int y, int z) {
return BlockState.getFromInternalId(getCombinedId4Data(x, y, z));
return BlockState.getFromOrdinal(getOrdinal(x, y, z));
}
@Override
public int getNearestSurfaceLayer(int x, int z, int y, int minY, int maxY) {
int index = z * getWidth() + x;
if (index < 0 || index >= getArea()) index = Math.floorMod(index, getArea());
return ((heights.getByte(index) & 0xFF) << 3) + (floor.getInt(index) & 0xFF) + 1;
return ((heights.getByte(index) & 0xFF) << 3) + (overlay.getChar(index) & 0xFF) + 1;
}
@Override
@ -1017,9 +1029,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
@Override
public BufferedImage draw() {
// TODO NOT IMPLEMENTED
// return new HeightMapMCADrawer(this).draw();
return null;
return new CFIDrawer(this).draw();
}
public void setBiomePriority(int value) {
@ -1044,12 +1054,12 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
int maxIndex = getArea() - 1;
biomes.record(() -> floor.record(() -> main.record(() -> {
int[] mainArr = main.get();
int[] floorArr = floor.get();
char[] mainArr = main.get();
char[] floorArr = floor.get();
byte[] biomesArr = biomes.get();
int index = 0;
int[] buffer = new int[2];
char[] buffer = new char[2];
for (int z = 0; z < img.getHeight(); z++) {
mutable.mutZ(z);
for (int x = 0; x < img.getWidth(); x++, index++) {
@ -1065,7 +1075,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
}
int color = img.getRGB(x, z);
if (textureUtil.getIsBlockCloserThanBiome(buffer, color, primitives.biomePriority)) {
int combined = buffer[0];
char combined = buffer[0];
mainArr[index] = combined;
floorArr[index] = combined;
}
@ -1079,23 +1089,20 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
if (img.getWidth() != getWidth() || img.getHeight() != getLength())
throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
TextureUtil textureUtil = getTextureUtil();
int widthIndex = img.getWidth() - 1;
int heightIndex = img.getHeight() - 1;
int maxIndex = getArea() - 1;
biomes.record(() -> floor.record(() -> main.record(() -> {
int[] mainArr = main.get();
int[] floorArr = floor.get();
char[] mainArr = main.get();
char[] floorArr = floor.get();
byte[] biomesArr = biomes.get();
int[] buffer = new int[2];
char[] buffer = new char[2];
int index = 0;
for (int y = 0; y < img.getHeight(); y++) {
boolean yBiome = y > 0 && y < heightIndex;
for (int x = 0; x < img.getWidth(); x++, index++) {
int color = img.getRGB(x, y);
if (textureUtil.getIsBlockCloserThanBiome(buffer, color, primitives.biomePriority)) {
int combined = buffer[0];
char combined = buffer[0];
mainArr[index] = combined;
floorArr[index] = combined;
}
@ -1135,8 +1142,8 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
TextureUtil textureUtil = getTextureUtil();
floor.record(() -> main.record(() -> {
int[] mainArr = main.get();
int[] floorArr = floor.get();
char[] mainArr = main.get();
char[] floorArr = floor.get();
int index = 0;
for (int z = 0; z < getLength(); z++) {
@ -1147,7 +1154,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
int color = img.getRGB(x, z);
BlockType block = textureUtil.getNearestBlock(color);
if (block != null) {
int combined = block.getInternalId();
char combined = block.getDefaultState().getOrdinalChar();
mainArr[index] = combined;
floorArr[index] = combined;
}
@ -1165,8 +1172,8 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
floor.record(() -> main.record(() -> {
int[] mainArr = main.get();
int[] floorArr = floor.get();
char[] mainArr = main.get();
char[] floorArr = floor.get();
int index = 0;
for (int z = 0; z < getLength(); z++) {
@ -1178,7 +1185,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
int color = img.getRGB(x, z);
BlockType block = textureUtil.getNearestBlock(color);
if (block != null) {
int combined = block.getInternalId();
char combined = block.getDefaultState().getOrdinalChar();
mainArr[index] = combined;
floorArr[index] = combined;
} else {
@ -1197,8 +1204,8 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
TextureUtil textureUtil = getTextureUtil();
floor.record(() -> main.record(() -> {
int[] mainArr = main.get();
int[] floorArr = floor.get();
char[] mainArr = main.get();
char[] floorArr = floor.get();
int index = 0;
for (int z = 0; z < img.getHeight(); z++) {
@ -1206,7 +1213,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
int color = img.getRGB(x, z);
BlockType block = textureUtil.getNearestBlock(color);
if (block != null) {
int combined = block.getInternalId();
char combined = block.getDefaultState().getOrdinalChar();
mainArr[index] = combined;
floorArr[index] = combined;
} else {
@ -1224,8 +1231,8 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
TextureUtil textureUtil = getTextureUtil();
floor.record(() -> main.record(() -> {
int[] mainArr = main.get();
int[] floorArr = floor.get();
char[] mainArr = main.get();
char[] floorArr = floor.get();
int index = 0;
for (int y = 0; y < img.getHeight(); y++) {
@ -1233,8 +1240,8 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
int color = img.getRGB(x, y);
BlockType[] layer = textureUtil.getNearestLayer(color);
if (layer != null) {
floorArr[index] = layer[0].getInternalId();
mainArr[index] = layer[1].getInternalId();
floorArr[index] = layer[0].getDefaultState().getOrdinalChar();
mainArr[index] = layer[1].getDefaultState().getOrdinalChar();
}
index++;
}
@ -1260,18 +1267,18 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
public void setOverlay(BufferedImage img, Pattern pattern, boolean white) {
if (pattern instanceof BlockStateHolder) {
setOverlay(img, ((BlockStateHolder) pattern).getInternalId(), white);
setOverlay(img, ((BlockStateHolder) pattern).getOrdinalChar(), white);
} else if (pattern instanceof BlockType) {
setOverlay(img, ((BlockType) pattern).getInternalId(), white);
setOverlay(img, ((BlockType) pattern).getDefaultState().getOrdinalChar(), white);
} else {
if (img.getWidth() != getWidth() || img.getHeight() != getLength())
throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
if (overlay == null) {
overlay = new DifferentialArray<>(new int[getArea()]);
overlay = new DifferentialArray<>(new char[getArea()]);
}
overlay.record(() -> {
int[] overlayArr = overlay.get();
char[] overlayArr = overlay.get();
int index = 0;
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
@ -1281,7 +1288,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
.nextInt(256) <= height) {
mutable.mutX(x);
mutable.mutY(height);
overlayArr[index] = pattern.apply(mutable).getInternalId();
overlayArr[index] = pattern.apply(mutable).getOrdinalChar();
}
}
}
@ -1292,14 +1299,14 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
public void setMain(BufferedImage img, Pattern pattern, boolean white) {
if (pattern instanceof BlockStateHolder) {
setMain(img, ((BlockStateHolder) pattern).getInternalId(), white);
setMain(img, ((BlockStateHolder) pattern).getOrdinalChar(), white);
} else {
if (img.getWidth() != getWidth() || img.getHeight() != getLength())
throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
primitives.modifiedMain = true;
main.record(() -> {
int[] mainArr = main.get();
char[] mainArr = main.get();
int index = 0;
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
@ -1309,7 +1316,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
.nextInt(256) <= height) {
mutable.mutX(x);
mutable.mutY(height);
mainArr[index] = pattern.apply(mutable).getInternalId();
mainArr[index] = pattern.apply(mutable).getOrdinalChar();
}
}
}
@ -1319,13 +1326,13 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
public void setFloor(BufferedImage img, Pattern pattern, boolean white) {
if (pattern instanceof BlockStateHolder) {
setFloor(img, ((BlockStateHolder) pattern).getInternalId(), white);
setFloor(img, ((BlockStateHolder) pattern).getOrdinalChar(), white);
} else {
if (img.getWidth() != getWidth() || img.getHeight() != getLength())
throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
floor.record(() -> {
int[] floorArr = floor.get();
char[] floorArr = floor.get();
int index = 0;
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
@ -1335,7 +1342,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
.nextInt(256) <= height) {
mutable.mutX(x);
mutable.mutY(height);
floorArr[index] = pattern.apply(mutable).getInternalId();
floorArr[index] = pattern.apply(mutable).getOrdinalChar();
}
}
}
@ -1345,15 +1352,15 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
public void setColumn(BufferedImage img, Pattern pattern, boolean white) {
if (pattern instanceof BlockStateHolder) {
setColumn(img, ((BlockStateHolder) pattern).getInternalId(), white);
setColumn(img, ((BlockStateHolder) pattern).getOrdinalChar(), white);
} else {
if (img.getWidth() != getWidth() || img.getHeight() != getLength())
throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
primitives.modifiedMain = true;
main.record(() -> floor.record(() -> {
int[] floorArr = floor.get();
int[] mainArr = main.get();
char[] floorArr = floor.get();
char[] mainArr = main.get();
int index = 0;
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
@ -1363,7 +1370,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
.nextInt(256) <= height) {
mutable.mutX(x);
mutable.mutY(height);
int combined = pattern.apply(mutable).getInternalId();
char combined = pattern.apply(mutable).getOrdinalChar();
mainArr[index] = combined;
floorArr[index] = combined;
}
@ -1375,10 +1382,10 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
public void setOverlay(Mask mask, Pattern pattern) {
if (pattern instanceof BlockStateHolder) {
setOverlay(mask, ((BlockStateHolder) pattern).getInternalId());
setOverlay(mask, ((BlockStateHolder) pattern).getOrdinalChar());
} else {
int index = 0;
if (overlay == null) overlay = new DifferentialArray<>(new int[getArea()]);
if (overlay == null) overlay = new DifferentialArray<>(new char[getArea()]);
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
for (int x = 0; x < getWidth(); x++, index++) {
@ -1386,7 +1393,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
mutable.mutX(x);
mutable.mutY(y);
if (mask.test(mutable)) {
overlay.setInt(index, pattern.apply(mutable).getInternalId());
overlay.setInt(index, pattern.apply(mutable).getOrdinalChar());
}
}
}
@ -1395,7 +1402,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
public void setFloor(Mask mask, Pattern pattern) {
if (pattern instanceof BlockStateHolder) {
setFloor(mask, ((BlockStateHolder) pattern).getInternalId());
setFloor(mask, ((BlockStateHolder) pattern).getOrdinalChar());
} else {
int index = 0;
for (int z = 0; z < getLength(); z++) {
@ -1405,7 +1412,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
mutable.mutX(x);
mutable.mutY(y);
if (mask.test(mutable)) {
floor.setInt(index, pattern.apply(mutable).getInternalId());
floor.setInt(index, pattern.apply(mutable).getOrdinalChar());
}
}
}
@ -1414,7 +1421,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
public void setMain(Mask mask, Pattern pattern) {
if (pattern instanceof BlockStateHolder) {
setMain(mask, ((BlockStateHolder) pattern).getInternalId());
setMain(mask, ((BlockStateHolder) pattern).getOrdinalChar());
} else {
primitives.modifiedMain = true;
int index = 0;
@ -1425,7 +1432,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
mutable.mutX(x);
mutable.mutY(y);
if (mask.test(mutable)) {
main.setInt(index, pattern.apply(mutable).getInternalId());
main.setInt(index, pattern.apply(mutable).getOrdinalChar());
}
}
}
@ -1434,7 +1441,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
public void setColumn(Mask mask, Pattern pattern) {
if (pattern instanceof BlockStateHolder) {
setColumn(mask, ((BlockStateHolder) pattern).getInternalId());
setColumn(mask, ((BlockStateHolder) pattern).getOrdinalChar());
} else {
primitives.modifiedMain = true;
int index = 0;
@ -1445,7 +1452,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
mutable.mutX(x);
mutable.mutY(y);
if (mask.test(mutable)) {
int combined = pattern.apply(mutable).getInternalId();
int combined = pattern.apply(mutable).getOrdinalChar();
floor.setInt(index, combined);
main.setInt(index, combined);
}
@ -1460,10 +1467,10 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
public void setFloor(Pattern value) {
if (value instanceof BlockStateHolder) {
setFloor(((BlockStateHolder) value).getInternalId());
setFloor(((BlockStateHolder) value).getOrdinalChar());
} else {
floor.record(() -> {
int[] floorArr = floor.get();
char[] floorArr = floor.get();
int index = 0;
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
@ -1471,7 +1478,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
int y = heights.getByte(index) & 0xFF;
mutable.mutX(x);
mutable.mutY(y);
floorArr[index] = value.apply(mutable).getInternalId();
floorArr[index] = value.apply(mutable).getOrdinalChar();
}
}
});
@ -1480,11 +1487,11 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
public void setColumn(Pattern value) {
if (value instanceof BlockStateHolder) {
setColumn(((BlockStateHolder) value).getInternalId());
setColumn(((BlockStateHolder) value).getOrdinalChar());
} else {
main.record(() -> floor.record(() -> {
int[] floorArr = floor.get();
int[] mainArr = main.get();
char[] floorArr = floor.get();
char[] mainArr = main.get();
int index = 0;
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
@ -1492,7 +1499,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
int y = heights.getByte(index) & 0xFF;
mutable.mutX(x);
mutable.mutY(y);
int combined = value.apply(mutable).getInternalId();
char combined = value.apply(mutable).getOrdinalChar();
mainArr[index] = combined;
floorArr[index] = combined;
}
@ -1503,10 +1510,10 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
public void setMain(Pattern value) {
if (value instanceof BlockStateHolder) {
setMain(((BlockStateHolder) value).getInternalId());
setMain(((BlockStateHolder) value).getOrdinalChar());
} else {
main.record(() -> {
int[] mainArr = main.get();
char[] mainArr = main.get();
int index = 0;
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
@ -1514,7 +1521,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
int y = heights.getByte(index) & 0xFF;
mutable.mutX(x);
mutable.mutY(y);
mainArr[index] = value.apply(mutable).getInternalId();
mainArr[index] = value.apply(mutable).getOrdinalChar();
}
}
});
@ -1522,12 +1529,12 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
}
public void setOverlay(Pattern value) {
if (overlay == null) overlay = new DifferentialArray<>(new int[getArea()]);
if (overlay == null) overlay = new DifferentialArray<>(new char[getArea()]);
if (value instanceof BlockStateHolder) {
setOverlay(((BlockStateHolder) value).getInternalId());
setOverlay(((BlockStateHolder) value).getOrdinalChar());
} else {
overlay.record(() -> {
int[] overlayArr = overlay.get();
char[] overlayArr = overlay.get();
int index = 0;
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
@ -1535,7 +1542,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
int y = heights.getByte(index) & 0xFF;
mutable.mutX(x);
mutable.mutY(y);
overlayArr[index] = value.apply(mutable).getInternalId();
overlayArr[index] = value.apply(mutable).getOrdinalChar();
}
}
});
@ -1567,16 +1574,16 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
public WritableMCAChunk write(WritableMCAChunk chunk, int csx, int cex, int csz, int cez) {
byte[] heights = this.heights.get();
byte[] biomes = this.biomes.get();
int[] main = this.main.get();
int[] floor = this.floor.get();
int[] overlay = this.overlay != null ? this.overlay.get() : null;
char[] main = this.main.get();
char[] floor = this.floor.get();
char[] overlay = this.overlay != null ? this.overlay.get() : null;
try {
int[] indexes = FaweCache.IMP.INDEX_STORE.get();
int index;
int maxY = 0;
int minY = Integer.MAX_VALUE;
int[] heightMap = chunk.biomes;
byte[] heightMap = chunk.biomes;
int globalIndex;
for (int z = csz; z <= cez; z++) {
globalIndex = z * getWidth() + csx;
@ -1584,7 +1591,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
for (int x = csx; x <= cex; x++, index++, globalIndex++) {
indexes[index] = globalIndex;
int height = heights[globalIndex] & 0xFF;
heightMap[index] = height;
heightMap[index] = (byte) height;
maxY = Math.max(maxY, height);
minY = Math.min(minY, height);
}
@ -1599,7 +1606,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
}
if (primitives.waterHeight != 0) {
int maxIndex = primitives.waterHeight << 8;
Arrays.fill(chunk.blocks, 0, maxIndex, primitives.waterId);
Arrays.fill(chunk.blocks, 0, maxIndex, primitives.waterOrdinal);
}
if (primitives.modifiedMain) { // If the main block is modified, we can't short circuit this
@ -1607,7 +1614,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
index = (z & 15) << 4;
for (int x = csx; x <= cex; x++, index++) {
globalIndex = indexes[index];
int mainCombined = main[globalIndex];
char mainCombined = main[globalIndex];
for (int y = 0; y < minY; y++) {
chunk.blocks[index + (y << 8)] = mainCombined;
}
@ -1615,7 +1622,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
}
} else {
int maxIndex = minY << 8;
Arrays.fill(chunk.blocks, 0, maxIndex, BlockID.STONE);
Arrays.fill(chunk.blocks, 0, maxIndex, (char) BlockID.STONE);
}
final boolean hasFloorThickness = primitives.floorThickness != 0 || primitives.worldThickness != 0;
@ -1630,13 +1637,13 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
index = (z & 15) << 4;
for (int x = csx; x <= cex; x++, index++) {
globalIndex = indexes[index];
int height = heightMap[index];
int height = heightMap[index] & 0xFF;
int maxMainY = height;
int minMainY = minY;
int mainCombined = main[globalIndex];
char mainCombined = main[globalIndex];
int floorCombined = floor[globalIndex];
char floorCombined = floor[globalIndex];
if (hasFloorThickness) {
if (x > 0) maxMainY = Math.min(heights[globalIndex - 1] & 0xFF, maxMainY);
if (x < getWidth() - 1) maxMainY = Math.min(heights[globalIndex + 1] & 0xFF, maxMainY);
@ -1671,33 +1678,33 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
}
if (hasOverlay) {
int overlayCombined = overlay[globalIndex];
char overlayCombined = overlay[globalIndex];
int overlayIndex = index + (height + 1 << 8);
chunk.blocks[overlayIndex] = overlayCombined;
}
if (primitives.bedrockId != 0) {
chunk.blocks[index] = primitives.bedrockId;
if (primitives.bedrockOrdinal != 0) {
chunk.blocks[index] = primitives.bedrockOrdinal;
}
}
}
int[][][] localBlocks = getChunkArray(chunk.getX(), chunk.getZ());
char[][][] localBlocks = getChunkArray(chunk.getX(), chunk.getZ());
if (localBlocks != null) {
index = 0;
for (int layer = 0; layer < 16; layer++) {
int by = layer << 4;
int ty = by + 15;
for (int y = by; y <= ty; y++, index += 256) {
int[][] yBlocks = localBlocks[y];
char[][] yBlocks = localBlocks[y];
if (yBlocks != null) {
chunk.hasSections[layer] = true;
for (int z = 0; z < yBlocks.length; z++) {
int[] zBlocks = yBlocks[z];
char[] zBlocks = yBlocks[z];
if (zBlocks != null) {
int zIndex = index + (z << 4);
for (int x = 0; x < zBlocks.length; x++, zIndex++) {
int combined = zBlocks[x];
char combined = zBlocks[x];
if (combined == 0) continue;
chunk.blocks[zIndex] = combined;
}
@ -1719,24 +1726,24 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
return chunk;
}
private void setUnsafe(int[][][] map, int combined, int x, int y, int z) {
int[][] yMap = map[y];
private void setUnsafe(char[][][] map, char combined, int x, int y, int z) {
char[][] yMap = map[y];
if (yMap == null) {
map[y] = yMap = new int[16][];
map[y] = yMap = new char[16][];
}
int[] zMap = yMap[z];
char[] zMap = yMap[z];
if (zMap == null) {
yMap[z] = zMap = new int[16];
yMap[z] = zMap = new char[16];
}
zMap[x] = combined;
}
private int get(int[][][] map, int x, int y, int z) {
int[][] yMap = map[y];
private int get(char[][][] map, int x, int y, int z) {
char[][] yMap = map[y];
if (yMap == null) {
return 0;
}
int[] zMap = yMap[z & 15];
char[] zMap = yMap[z & 15];
if (zMap == null) {
return 0;
}
@ -1745,7 +1752,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
private void setOverlay(Mask mask, int combined) {
int index = 0;
if (overlay == null) overlay = new DifferentialArray<>(new int[getArea()]);
if (overlay == null) overlay = new DifferentialArray<>(new char[getArea()]);
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
for (int x = 0; x < getWidth(); x++, index++) {
@ -1807,29 +1814,29 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
}
}
private void setFloor(int value) {
private void setFloor(char value) {
floor.record(() -> Arrays.fill(floor.get(), value));
}
private void setColumn(int value) {
private void setColumn(char value) {
setFloor(value);
setMain(value);
}
private void setMain(int value) {
private void setMain(char value) {
primitives.modifiedMain = true;
main.record(() -> Arrays.fill(main.get(), value));
}
private void setOverlay(int value) {
if (overlay == null) overlay = new DifferentialArray<>(new int[getArea()]);
private void setOverlay(char value) {
if (overlay == null) overlay = new DifferentialArray<>(new char[getArea()]);
overlay.record(() -> Arrays.fill(overlay.get(), value));
}
private void setOverlay(BufferedImage img, int combined, boolean white) {
private void setOverlay(BufferedImage img, char combined, boolean white) {
if (img.getWidth() != getWidth() || img.getHeight() != getLength())
throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
if (overlay == null) overlay = new DifferentialArray<>(new int[getArea()]);
if (overlay == null) overlay = new DifferentialArray<>(new char[getArea()]);
overlay.record(() -> {
int index = 0;
@ -1845,7 +1852,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
});
}
private void setMain(BufferedImage img, int combined, boolean white) {
private void setMain(BufferedImage img, char combined, boolean white) {
if (img.getWidth() != getWidth() || img.getHeight() != getLength())
throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
primitives.modifiedMain = true;
@ -1864,7 +1871,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
});
}
private void setFloor(BufferedImage img, int combined, boolean white) {
private void setFloor(BufferedImage img, char combined, boolean white) {
if (img.getWidth() != getWidth() || img.getHeight() != getLength())
throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
@ -1882,7 +1889,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
});
}
private void setColumn(BufferedImage img, int combined, boolean white) {
private void setColumn(BufferedImage img, char combined, boolean white) {
if (img.getWidth() != getWidth() || img.getHeight() != getLength())
throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
primitives.modifiedMain = true;

View File

@ -84,7 +84,7 @@ public abstract class MCAWriter implements Extent {
@Override
protected WritableMCAChunk initialValue() {
WritableMCAChunk chunk = new WritableMCAChunk();
Arrays.fill(chunk.blocks, BlockID.AIR);
Arrays.fill(chunk.blocks, (char) BlockID.AIR);
// Arrays.fill(chunk.skyLight, (byte) 255);
return chunk;
}
@ -142,11 +142,12 @@ public abstract class MCAWriter implements Extent {
pool.submit(() -> {
try {
WritableMCAChunk chunk = chunkStore.get();
chunk.clear(fcx, fcz);
chunk.reset();
chunk.setPosition(fcx, fcz);
chunk = write(chunk, csx, cex, csz, cez);
if (chunk != null) {
// Generation offset
chunk.setLoc( fcx + (getOffsetX() >> 4), fcz + (getOffsetZ() >> 4));
chunk.setPosition( fcx + (getOffsetX() >> 4), fcz + (getOffsetZ() >> 4));
// Compress
byte[] bytes = chunk.toBytes(byteStore1.get());

View File

@ -1,39 +1,44 @@
package com.boydti.fawe.object.brush.visualization.cfi;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.beta.IChunkSet;
import com.boydti.fawe.object.collection.BitArray4096;
import com.boydti.fawe.object.collection.BlockVector3ChunkMap;
import com.boydti.fawe.object.io.FastByteArrayOutputStream;
import com.boydti.fawe.util.MathMan;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.ListTag;
import com.sk89q.jnbt.NBTConstants;
import com.sk89q.jnbt.NBTOutputStream;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.registry.state.Property;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.biome.BiomeTypes;
import com.sk89q.worldedit.world.block.BlockID;
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 java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
public class WritableMCAChunk {
public class WritableMCAChunk implements IChunkSet {
public final boolean[] hasSections = new boolean[16];
public final byte[] skyLight = new byte[65536];
public final byte[] blockLight = new byte[65536];
public boolean hasBiomes = false;
public final int[] biomes = new int[256];
public final byte[] biomes = new byte[256];
public final int[] blocks = new int[65536];
public final char[] blocks = new char[65536];
public Map<Short, CompoundTag> tiles = new HashMap<>();
public BlockVector3ChunkMap<CompoundTag> tiles = new BlockVector3ChunkMap<CompoundTag>();
public Map<UUID, CompoundTag> entities = new HashMap<>();
public long inhabitedTime = System.currentTimeMillis();
public long lastUpdate;
@ -54,14 +59,18 @@ public class WritableMCAChunk {
return chunkZ;
}
public void setLoc(int X, int Z) {
@Override
public boolean hasSection(int layer) {
return hasSections[layer];
}
public void setPosition(int X, int Z) {
this.chunkX = X;
this.chunkZ = Z;
}
public void clear(int X, int Z) {
this.chunkX = X;
this.chunkZ = Z;
@Override
public IChunkSet reset() {
if (!tiles.isEmpty()) {
tiles.clear();
}
@ -76,6 +85,7 @@ public class WritableMCAChunk {
blocks[i] = BlockID.AIR;
}
Arrays.fill(hasSections, false);
return this;
}
public void write(NBTOutputStream nbtOut) throws IOException {
@ -192,13 +202,13 @@ public class WritableMCAChunk {
}
out.writeNamedTagName("BlockLight", NBTConstants.TYPE_BYTE_ARRAY);
out.writeInt(2048);
out.write(blockLight, layer << 11, 1 << 11);
out.writeNamedTagName("SkyLight", NBTConstants.TYPE_BYTE_ARRAY);
out.writeInt(2048);
out.write(skyLight, layer << 11, 1 << 11);
// out.writeNamedTagName("BlockLight", NBTConstants.TYPE_BYTE_ARRAY);
// out.writeInt(2048);
// out.write(blockLight, layer << 11, 1 << 11);
//
// out.writeNamedTagName("SkyLight", NBTConstants.TYPE_BYTE_ARRAY);
// out.writeInt(2048);
// out.write(skyLight, layer << 11, 1 << 11);
out.writeEndTag();
@ -250,6 +260,15 @@ public class WritableMCAChunk {
return deleted;
}
@Override
public boolean isEmpty() {
if (deleted) return true;
for (boolean hasSection : hasSections) {
if (hasSection) return false;
}
return true;
}
public boolean isModified() {
return modified != 0;
}
@ -272,14 +291,17 @@ public class WritableMCAChunk {
return bitMask;
}
public void setTile(int x, int y, int z, CompoundTag tile) {
@Override
public boolean setTile(int x, int y, int z, CompoundTag tile) {
setModified();
short pair = MathMan.tripleBlockCoord(x, y, z);
if (tile != null) {
tiles.put(pair, tile);
tiles.put(x, y, z, tile);
} else {
tiles.remove(pair);
if (tiles.remove(x, y, z) == null) {
return false;
}
}
return true;
}
public void setEntity(CompoundTag entityTag) {
@ -289,17 +311,39 @@ public class WritableMCAChunk {
entities.put(new UUID(most, least), entityTag);
}
public void setBiome(int x, int z, BiomeType biome) {
@Override
public BiomeType getBiomeType(int x, int z) {
return BiomeTypes.get(this.biomes[(z << 4) | x] & 0xFF);
}
@Override
public BiomeType[] getBiomes() {
BiomeType[] tmp = new BiomeType[256];
for (int i = 0; i < 256; i++) {
tmp[i] = BiomeTypes.get(this.biomes[i] & 0xFF);
}
return tmp;
}
@Override
public boolean setBiome(BlockVector2 pos, BiomeType biome) {
return this.setBiome(pos.getX(), 0, pos.getZ(), biome);
}
@Override
public boolean setBiome(int x, int y, int z, BiomeType biome) {
setModified();
biomes[x + (z << 4)] = biome.getInternalId();
biomes[x + (z << 4)] = (byte) biome.getInternalId();
return true;
}
public Set<CompoundTag> getEntities() {
return new HashSet<>(entities.values());
}
public Map<Short, CompoundTag> getTiles() {
return tiles == null ? new HashMap<>() : tiles;
@Override
public Map<BlockVector3, CompoundTag> getTiles() {
return tiles == null ? Collections.emptyMap() : tiles;
}
public CompoundTag getTile(int x, int y, int z) {
@ -310,94 +354,51 @@ public class WritableMCAChunk {
return tiles.get(pair);
}
public boolean doesSectionExist(int cy) {
return hasSections[cy];
}
private final int getIndex(int x, int y, int z) {
return x | (z << 4) | (y << 8);
}
public int getBlockCombinedId(int x, int y, int z) {
public int getBlockOrdinal(int x, int y, int z) {
return blocks[x | (z << 4) | (y << 8)];
}
public BiomeType[] getBiomeArray() {
return null;
@Override
public BlockState getBlock(int x, int y, int z) {
int ordinal = getBlockOrdinal(x, y, z);
return BlockState.getFromOrdinal(ordinal);
}
public Set<UUID> getEntityRemoves() {
return new HashSet<>();
}
public void setSkyLight(int x, int y, int z, int value) {
setNibble(getIndex(x, y, z), skyLight, value);
@Override
public boolean setBlock(int x, int y, int z, BlockStateHolder holder) {
setBlock(x, y, z, holder.getOrdinalChar());
holder.applyTileEntity(this, x, y, z);
return true;
}
public void setBlockLight(int x, int y, int z, int value) {
setNibble(getIndex(x, y, z), blockLight, value);
}
public int getSkyLight(int x, int y, int z) {
if (!hasSections[y >> 4]) {
return 0;
}
return getNibble(getIndex(x, y, z), skyLight);
}
public int getBlockLight(int x, int y, int z) {
if (!hasSections[y >> 4]) {
return 0;
}
return getNibble(getIndex(x, y, z), blockLight);
}
public void setFullbright() {
for (int layer = 0; layer < 16; layer++) {
if (hasSections[layer]) {
Arrays.fill(skyLight, layer << 7, ((layer + 1) << 7), (byte) 255);
}
@Override
public void setBlocks(int layer, char[] data) {
int offset = layer << 12;
for (int i = 0; i < 4096; i++) {
blocks[offset + i] = data[i];
}
}
public void removeLight() {
for (int i = 0; i < 16; i++) {
removeLight(i);
@Override
public char[] getArray(int layer) {
char[] tmp = FaweCache.IMP.SECTION_BITS_TO_CHAR.get();
int offset = layer << 12;
for (int i = 0; i < 4096; i++) {
tmp[i] = blocks[offset + i];
}
return tmp;
}
public void removeLight(int i) {
if (hasSections[i]) {
Arrays.fill(skyLight, i << 7, ((i + 1) << 7), (byte) 0);
Arrays.fill(blockLight, i << 7, ((i + 1) << 7), (byte) 0);
}
}
public int getNibble(int index, byte[] array) {
int indexShift = index >> 1;
if ((index & 1) == 0) {
return array[indexShift] & 15;
} else {
return array[indexShift] >> 4 & 15;
}
}
public void setNibble(int index, byte[] array, int value) {
int indexShift = index >> 1;
byte existing = array[indexShift];
int valueShift = value << 4;
if (existing == value + valueShift) {
return;
}
if ((index & 1) == 0) {
array[indexShift] = (byte) (existing & 240 | value);
} else {
array[indexShift] = (byte) (existing & 15 | valueShift);
}
}
public void setBlock(int x, int y, int z, int combinedId) {
blocks[getIndex(x, y, z)] = combinedId;
public void setBlock(int x, int y, int z, char ordinal) {
blocks[getIndex(x, y, z)] = ordinal;
}
public void setBiome(BiomeType biome) {
@ -407,4 +408,9 @@ public class WritableMCAChunk {
public void removeEntity(UUID uuid) {
entities.remove(uuid);
}
@Override
public boolean trim(boolean aggressive) {
return isEmpty();
}
}

View File

@ -47,6 +47,11 @@ public class BlockVector3ChunkMap<T> implements Map<BlockVector3, T>, IAdaptedMa
return map.put(key, value);
}
public T remove(int x, int y, int z) {
short key = MathMan.tripleBlockCoord(x, y, z);
return map.remove(key);
}
public boolean contains(int x, int y, int z) {
short key = MathMan.tripleBlockCoord(x, y, z);
return map.containsKey(key);

View File

@ -265,9 +265,9 @@ public final class DifferentialArray<T> implements DifferentialCollection<T> {
return dataBytes[index];
}
// public char getChar(int index) {
// return dataChars[index];
// }
public char getChar(int index) {
return dataChars[index];
}
public int getInt(int index) {
return dataInts[index];

View File

@ -9,12 +9,12 @@ import java.lang.reflect.Array;
* Records changes made through the {@link #set(int, int, int, int)} method<br/>
* Changes are not recorded if you edit the raw data
*/
public final class DifferentialBlockBuffer implements DifferentialCollection<int[][][][][]> {
public final class DifferentialBlockBuffer implements DifferentialCollection<char[][][][][]> {
private final int width, length;
private final int t1, t2;
private int[][][][][] data;
private int[][][][][] changes;
private char[][][][][] data;
private char[][][][][] changes;
public DifferentialBlockBuffer(int width, int length) {
this.width = width;
@ -24,7 +24,7 @@ public final class DifferentialBlockBuffer implements DifferentialCollection<int
}
@Override
public int[][][][][] get() {
public char[][][][][] get() {
return data;
}
@ -116,72 +116,72 @@ public final class DifferentialBlockBuffer implements DifferentialCollection<int
changes = null;
}
public void set(int x, int y, int z, int combined) {
public void set(int x, int y, int z, char combined) {
if (combined == 0) combined = 1;
int localX = x & 15;
int localZ = z & 15;
int chunkX = x >> 4;
int chunkZ = z >> 4;
if (data == null) {
data = new int[t1][][][][];
changes = new int[0][][][][];
data = new char[t1][][][][];
changes = new char[0][][][][];
}
int[][][][] arr = data[chunkZ];
char[][][][] arr = data[chunkZ];
if (arr == null) {
arr = data[chunkZ] = new int[t2][][][];
arr = data[chunkZ] = new char[t2][][][];
}
int[][][] arr2 = arr[chunkX];
char[][][] arr2 = arr[chunkX];
if (arr2 == null) {
arr2 = arr[chunkX] = new int[256][][];
arr2 = arr[chunkX] = new char[256][][];
}
int[][] yMap = arr2[y];
char[][] yMap = arr2[y];
if (yMap == null) {
arr2[y] = yMap = new int[16][];
arr2[y] = yMap = new char[16][];
}
boolean newSection;
int current;
int[] zMap = yMap[localZ];
char[] zMap = yMap[localZ];
if (zMap == null) {
yMap[localZ] = zMap = new int[16];
yMap[localZ] = zMap = new char[16];
if (changes == null) {
changes = new int[t1][][][][];
changes = new char[t1][][][][];
} else if (changes != null && changes.length != 0) {
initialChange(changes, chunkX, chunkZ, localX, localZ, y, (int) -combined);
initialChange(changes, chunkX, chunkZ, localX, localZ, y, (char) -combined);
}
} else {
if (changes == null || changes.length == 0) changes = new int[t1][][][][];
appendChange(changes, chunkX, chunkZ, localX, localZ, y, (int) (zMap[localX] - combined));
if (changes == null || changes.length == 0) changes = new char[t1][][][][];
appendChange(changes, chunkX, chunkZ, localX, localZ, y, (char) (zMap[localX] - combined));
}
zMap[localX] = combined;
}
private void initialChange(int[][][][][] src, int chunkX, int chunkZ, int localX, int localZ, int y, int combined) {
int[][][][] arr = src[chunkZ];
private void initialChange(char[][][][][] src, int chunkX, int chunkZ, int localX, int localZ, int y, char combined) {
char[][][][] arr = src[chunkZ];
if (arr == null) {
src[chunkZ] = new int[0][][][];
src[chunkZ] = new char[0][][][];
return;
} else if (arr.length == 0) return;
int[][][] arr2 = arr[chunkX];
char[][][] arr2 = arr[chunkX];
if (arr2 == null) {
arr[chunkX] = new int[0][][];
arr[chunkX] = new char[0][][];
return;
} else if (arr2.length == 0) return;
int[][] yMap = arr2[y];
char[][] yMap = arr2[y];
if (yMap == null) {
arr2[y] = new int[0][];
arr2[y] = new char[0][];
return;
} else if (yMap.length == 0) return;
int[] zMap = yMap[localZ];
char[] zMap = yMap[localZ];
if (zMap == null) {
yMap[localZ] = new int[0];
yMap[localZ] = new char[0];
return;
} else if (zMap.length == 0) return;
@ -189,23 +189,23 @@ public final class DifferentialBlockBuffer implements DifferentialCollection<int
zMap[localX] = combined;
}
private void appendChange(int[][][][][] src, int chunkX, int chunkZ, int localX, int localZ, int y, int combined) {
int[][][][] arr = src[chunkZ];
private void appendChange(char[][][][][] src, int chunkX, int chunkZ, int localX, int localZ, int y, char combined) {
char[][][][] arr = src[chunkZ];
if (arr == null || arr.length == 0) {
arr = src[chunkZ] = new int[t2][][][];
arr = src[chunkZ] = new char[t2][][][];
}
int[][][] arr2 = arr[chunkX];
char[][][] arr2 = arr[chunkX];
if (arr2 == null || arr2.length == 0) {
arr2 = arr[chunkX] = new int[256][][];
arr2 = arr[chunkX] = new char[256][][];
}
int[][] yMap = arr2[y];
char[][] yMap = arr2[y];
if (yMap == null || yMap.length == 0) {
arr2[y] = yMap = new int[16][];
arr2[y] = yMap = new char[16][];
}
int[] zMap = yMap[localZ];
char[] zMap = yMap[localZ];
if (zMap == null || zMap.length == 0) {
yMap[localZ] = zMap = new int[16];
yMap[localZ] = zMap = new char[16];
}
zMap[localX] = combined;
}

View File

@ -220,4 +220,15 @@ public class FastByteArrayOutputStream extends OutputStream {
size += index;
index = 0;
}
@Override
public void close() {
}
public void reset() {
Arrays.fill(buffer, (byte) 0);
index = 0;
size = 0;
buffers.clear();
}
}

View File

@ -122,7 +122,7 @@ public class FaweLocalBlockQueue extends LocalBlockQueue {
@Override
public void refreshChunk(int x, int z) {
world.sendChunk(x, z, 0);
world.refreshChunk(x, z);
}
@Override

View File

@ -51,7 +51,7 @@ public class DelegateTextureUtil extends TextureUtil {
}
@Override
public boolean getIsBlockCloserThanBiome(int[] blockAndBiomeIdOutput, int color, int biomePriority) {
public boolean getIsBlockCloserThanBiome(char[] blockAndBiomeIdOutput, int color, int biomePriority) {
return parent.getIsBlockCloserThanBiome(blockAndBiomeIdOutput, color, biomePriority);
}

View File

@ -10,11 +10,11 @@ import java.util.Base64;
public enum Jars {
MM_v1_4_0("https://github.com/InventivetalentDev/MapManager/releases/download/1.4.0-SNAPSHOT/MapManager_v1.4.0-SNAPSHOT.jar",
"AEO5SKBUGN4YJRS8XGGNLBM2QRZPTI1KF0/1W1URTGA=", 163279),
MM_v1_4_0("https://github.com/InventivetalentDev/MapManager/releases/download/1.7.3-SNAPSHOT/MapManager_v1.7.3-SNAPSHOT.jar",
"M3YLUQZZ66K2DMVDCYLEU38U3ZKRKHRAXQGGPVKFO6G=", 554831),
PL_v3_6_0("https://github.com/InventivetalentDev/PacketListenerAPI/releases/download/3.6.0-SNAPSHOT/PacketListenerAPI_v3.6.0-SNAPSHOT.jar",
"OYBE75VIU+NNWHRVREBLDARWA+/TBDQZ1RC562QULBA=", 166508),
PL_v3_6_0("https://github.com/InventivetalentDev/PacketListenerAPI/releases/download/3.7.3-SNAPSHOT/PacketListenerAPI_v3.7.3-SNAPSHOT.jar",
"ETDBRZLN5PRVDFR/MSQDPM6JJER3WQOKHCN8FUXO5ZM=", 167205),
;

View File

@ -41,7 +41,7 @@ public class RandomTextureUtil extends CachedTextureUtil {
}
@Override
public boolean getIsBlockCloserThanBiome(int[] blockAndBiomeIdOutput, int color, int biomePriority) {
public boolean getIsBlockCloserThanBiome(char[] blockAndBiomeIdOutput, int color, int biomePriority) {
BlockType block = getNearestBlock(color);
int[] mix = biomeMixes.getOrDefault(color, null);
if (mix == null) {
@ -55,8 +55,8 @@ public class RandomTextureUtil extends CachedTextureUtil {
int biomeId = mix[index];
int biomeAvColor = mix[3];
int blockColor = getColor(block);
blockAndBiomeIdOutput[0] = block.getInternalId();
blockAndBiomeIdOutput[1] = biomeId;
blockAndBiomeIdOutput[0] = block.getDefaultState().getOrdinalChar();
blockAndBiomeIdOutput[1] = (char) biomeId;
if (colorDistance(biomeAvColor, color) - biomePriority > colorDistance(blockColor, color)) {
return true;
}

View File

@ -497,13 +497,13 @@ public class TextureUtil implements TextureHolder {
return biomes[biome];
}
public boolean getIsBlockCloserThanBiome(int[] blockAndBiomeIdOutput, int color,
public boolean getIsBlockCloserThanBiome(char[] blockAndBiomeIdOutput, int color,
int biomePriority) {
BlockType block = getNearestBlock(color);
TextureUtil.BiomeColor biome = getNearestBiome(color);
int blockColor = getColor(block);
blockAndBiomeIdOutput[0] = block.getDefaultState().getOrdinalChar();
blockAndBiomeIdOutput[1] = biome.id;
blockAndBiomeIdOutput[1] = (char) biome.id;
if (colorDistance(biome.grassCombined, color) - biomePriority > colorDistance(blockColor,
color)) {
return true;

View File

@ -235,8 +235,8 @@ public class WorldWrapper extends AbstractWorld {
}
@Override
public void sendChunk(int X, int Z, int mask) {
parent.sendChunk(X, Z, mask);
public void refreshChunk(int X, int Z) {
parent.refreshChunk(X, Z);
}
@Override

View File

@ -682,7 +682,12 @@ public class LocalSession implements TextureHolder {
public Region getSelection(World world) throws IncompleteRegionException {
checkNotNull(world);
if (selector.getIncompleteRegion().getWorld() == null || !selector.getIncompleteRegion().getWorld().equals(world)) {
throw new IncompleteRegionException();
throw new IncompleteRegionException() {
@Override
public synchronized Throwable fillInStackTrace() {
return this;
}
};
}
return selector.getRegion();
}
@ -1288,6 +1293,8 @@ public class LocalSession implements TextureHolder {
public void describeCUI(Actor actor) {
checkNotNull(actor);
// TODO preload
if (!hasCUISupport) {
return;
}

View File

@ -74,7 +74,8 @@ public class DistanceWand extends BrushTool implements DoubleActionTraceTool {
private Location getTarget(Player player) {
Location target;
Mask mask = getTraceMask();
if (this.range < MAX_RANGE) {
int range = getRange();
if (range < MAX_RANGE) {
target = player.getBlockTrace(getRange(), true, mask);
} else {
target = player.getBlockTrace(MAX_RANGE, false, mask);

View File

@ -23,6 +23,10 @@ public interface MapMetadatable extends Metadatable {
return !getRawMeta().isEmpty();
}
default Object putIfAbsent(String key, Object value) {
return getRawMeta().putIfAbsent(key, value);
}
/**
* Get the metadata for a key.
*

View File

@ -20,7 +20,6 @@
package com.sk89q.worldedit.entity;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.brush.visualization.VirtualWorld;
import com.boydti.fawe.object.clipboard.DiskOptimizedClipboard;
@ -39,7 +38,6 @@ import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.regions.RegionOperationException;
import com.sk89q.worldedit.regions.RegionSelector;
import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.util.Direction;
@ -49,11 +47,10 @@ import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.gamemode.GameMode;
import java.io.File;
import java.text.NumberFormat;
import javax.annotation.Nullable;
import org.enginehub.piston.inject.InjectedValueAccess;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.util.function.Supplier;
/**
* Represents a player
@ -324,6 +321,8 @@ public interface Player extends Entity, Actor {
*/
<B extends BlockStateHolder<B>> void sendFakeBlock(BlockVector3 pos, @Nullable B block);
void sendFakeChunk(int chunkX, int chunkZ, Supplier<byte[]> data);
public Region[] getCurrentRegions();
Region[] getCurrentRegions(FaweMaskManager.MaskType type);

View File

@ -41,6 +41,7 @@ import com.sk89q.worldedit.world.gamemode.GameMode;
import javax.annotation.Nullable;
import java.util.UUID;
import java.util.function.Supplier;
public class PlayerProxy extends AbstractPlayerActor {
@ -211,6 +212,11 @@ public class PlayerProxy extends AbstractPlayerActor {
basePlayer.sendFakeBlock(pos, block);
}
@Override
public void sendFakeChunk(int chunkX, int chunkZ, Supplier<byte[]> data) {
basePlayer.sendFakeChunk(chunkX, chunkZ, data);
}
@Override
public void sendTitle(String title, String sub) {
basePlayer.sendTitle(title, sub);

View File

@ -148,7 +148,7 @@ public class NullWorld extends AbstractWorld {
}
@Override
public void sendChunk(int X, int Z, int mask) {
public void refreshChunk(int X, int Z) {
}

View File

@ -300,7 +300,7 @@ public interface World extends Extent, Keyed, IChunkCache<IChunkGet> {
* @param chunkZ
* @param bitMask
*/
void sendChunk(final int X, final int Z, final int mask);
void refreshChunk(final int X, final int Z);
@Override
IChunkGet get(int x, int z);