geforkt von Mirrors/FastAsyncWorldEdit
Remove CUI and other cleaning
Dieser Commit ist enthalten in:
Ursprung
b42553116c
Commit
229182aa63
@ -25,7 +25,6 @@ import com.boydti.fawe.bukkit.util.BukkitTaskMan;
|
||||
import com.boydti.fawe.bukkit.util.ItemUtil;
|
||||
import com.boydti.fawe.bukkit.util.VaultUtil;
|
||||
import com.boydti.fawe.bukkit.util.cui.CUIListener;
|
||||
import com.boydti.fawe.bukkit.util.cui.StructureCUI;
|
||||
import com.boydti.fawe.bukkit.util.image.BukkitImageViewer;
|
||||
import com.boydti.fawe.bukkit.v0.BukkitQueue_0;
|
||||
import com.boydti.fawe.bukkit.v0.BukkitQueue_All;
|
||||
@ -41,7 +40,6 @@ import com.boydti.fawe.regions.FaweMaskManager;
|
||||
import com.boydti.fawe.util.Jars;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.boydti.fawe.util.cui.CUI;
|
||||
import com.boydti.fawe.util.image.ImageViewer;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
@ -64,7 +62,6 @@ import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class FaweBukkit implements IFawe, Listener {
|
||||
@ -149,32 +146,6 @@ public class FaweBukkit implements IFawe, Listener {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public CUI getCUI(FawePlayer player) {
|
||||
if (Settings.IMP.EXPERIMENTAL.VANILLA_CUI) {
|
||||
if (listeningCui && cuiListener == null) return null;
|
||||
listeningCui = true;
|
||||
if (cuiListener == null) {
|
||||
Plugin protocolLib = Bukkit.getPluginManager().getPlugin("ProtocolLib");
|
||||
if (protocolLib != null && protocolLib.isEnabled()) {
|
||||
cuiListener = new CUIListener(plugin);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return new StructureCUI(player);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerPacketListener() {
|
||||
PluginManager manager = Bukkit.getPluginManager();
|
||||
if (packetListener == null && manager.getPlugin("ProtocolLib") != null) {
|
||||
packetListener = new CFIPacketListener(plugin);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized ImageViewer getImageViewer(FawePlayer fp) {
|
||||
if (listeningImages && imageListener == null) return null;
|
||||
|
@ -69,6 +69,7 @@ public class StructureCUI extends CUI {
|
||||
|
||||
private int viewDistance() {
|
||||
Player player = this.<Player>getPlayer().parent;
|
||||
//todo replace with PaperLib.isPaper()
|
||||
if (Bukkit.getVersion().contains("paper")) {
|
||||
return player.getViewDistance();
|
||||
} else {
|
||||
|
@ -56,8 +56,8 @@ import org.bukkit.inventory.ItemStack;
|
||||
* Adapts between Bukkit and WorldEdit equivalent objects.
|
||||
*/
|
||||
public enum BukkitAdapter {
|
||||
INSTANCE
|
||||
;
|
||||
INSTANCE;
|
||||
|
||||
private final IBukkitAdapter adapter;
|
||||
|
||||
BukkitAdapter() {
|
||||
@ -73,14 +73,36 @@ public enum BukkitAdapter {
|
||||
return INSTANCE.adapter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks equality between a WorldEdit BlockType and a Bukkit Material
|
||||
*
|
||||
* @param blockType The WorldEdit BlockType
|
||||
* @param type The Bukkit Material
|
||||
* @return If they are equal
|
||||
*/
|
||||
public static boolean equals(BlockType blockType, Material type) {
|
||||
return getAdapter().equals(blockType, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert any WorldEdit world into an equivalent wrapped Bukkit world.
|
||||
*
|
||||
* <p>If a matching world cannot be found, a {@link RuntimeException}
|
||||
* will be thrown.</p>
|
||||
*
|
||||
* @param world the world
|
||||
* @return a wrapped Bukkit world
|
||||
*/
|
||||
public static BukkitWorld asBukkitWorld(World world) {
|
||||
return getAdapter().asBukkitWorld(world);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a WorldEdit world from a Bukkit world.
|
||||
*
|
||||
* @param world the Bukkit world
|
||||
* @return a WorldEdit world
|
||||
*/
|
||||
public static World adapt(org.bukkit.World world) {
|
||||
return getAdapter().adapt(world);
|
||||
}
|
||||
@ -89,11 +111,25 @@ public enum BukkitAdapter {
|
||||
return getAdapter().adapt(world);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a WorldEdit location from a Bukkit location.
|
||||
*
|
||||
* @param location the Bukkit location
|
||||
* @return a WorldEdit location
|
||||
*/
|
||||
public static Location adapt(org.bukkit.Location location) {
|
||||
checkNotNull(location);
|
||||
return getAdapter().adapt(location);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Bukkit location from a WorldEdit location.
|
||||
*
|
||||
* @param location the WorldEdit location
|
||||
* @return a Bukkit location
|
||||
*/
|
||||
public static org.bukkit.Location adapt(Location location) {
|
||||
checkNotNull(location);
|
||||
return getAdapter().adapt(location);
|
||||
}
|
||||
|
||||
@ -102,10 +138,21 @@ public enum BukkitAdapter {
|
||||
}
|
||||
|
||||
public static org.bukkit.Location adapt(org.bukkit.World world, BlockVector3 position) {
|
||||
checkNotNull(world);
|
||||
checkNotNull(position);
|
||||
return getAdapter().adapt(world, position);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Bukkit location from a WorldEdit location with a Bukkit world.
|
||||
*
|
||||
* @param world the Bukkit world
|
||||
* @param location the WorldEdit location
|
||||
* @return a Bukkit location
|
||||
*/
|
||||
public static org.bukkit.Location adapt(org.bukkit.World world, Location location) {
|
||||
checkNotNull(world);
|
||||
checkNotNull(location);
|
||||
return getAdapter().adapt(world, location);
|
||||
}
|
||||
|
||||
@ -113,23 +160,58 @@ public enum BukkitAdapter {
|
||||
return getAdapter().asVector(location);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a WorldEdit Vector from a Bukkit location.
|
||||
*
|
||||
* @param location The Bukkit location
|
||||
* @return a WorldEdit vector
|
||||
*/
|
||||
public static BlockVector3 asBlockVector(org.bukkit.Location location) {
|
||||
checkNotNull(location);
|
||||
return getAdapter().asBlockVector(location);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a WorldEdit entity from a Bukkit entity.
|
||||
*
|
||||
* @param entity the Bukkit entity
|
||||
* @return a WorldEdit entity
|
||||
*/
|
||||
public static Entity adapt(org.bukkit.entity.Entity entity) {
|
||||
checkNotNull(entity);
|
||||
return getAdapter().adapt(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Bukkit Material form a WorldEdit ItemType
|
||||
*
|
||||
* @param itemType The WorldEdit ItemType
|
||||
* @return The Bukkit Material
|
||||
*/
|
||||
public static Material adapt(ItemType itemType) {
|
||||
checkNotNull(itemType);
|
||||
return getAdapter().adapt(itemType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Bukkit Material form a WorldEdit BlockType
|
||||
*
|
||||
* @param blockType The WorldEdit BlockType
|
||||
* @return The Bukkit Material
|
||||
*/
|
||||
public static Material adapt(BlockType blockType) {
|
||||
checkNotNull(blockType);
|
||||
return getAdapter().adapt(blockType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a WorldEdit GameMode from a Bukkit one.
|
||||
*
|
||||
* @param gameMode Bukkit GameMode
|
||||
* @return WorldEdit GameMode
|
||||
*/
|
||||
public static GameMode adapt(org.bukkit.GameMode gameMode) {
|
||||
checkNotNull(gameMode);
|
||||
return getAdapter().adapt(gameMode);
|
||||
}
|
||||
|
||||
@ -161,15 +243,37 @@ public enum BukkitAdapter {
|
||||
return getAdapter().adapt(entityType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a Material to a BlockType
|
||||
*
|
||||
* @param material The material
|
||||
* @return The blocktype
|
||||
*/
|
||||
public static BlockType asBlockType(Material material) {
|
||||
checkNotNull(material);
|
||||
return getAdapter().asBlockType(material);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a Material to a ItemType
|
||||
*
|
||||
* @param material The material
|
||||
* @return The itemtype
|
||||
*/
|
||||
public static ItemType asItemType(Material material) {
|
||||
checkNotNull(material);
|
||||
return getAdapter().asItemType(material);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a WorldEdit BlockState from a Bukkit BlockData
|
||||
*
|
||||
* @param blockData The Bukkit BlockData
|
||||
* @return The WorldEdit BlockState
|
||||
*/
|
||||
public static BlockState adapt(BlockData blockData) {
|
||||
checkNotNull(blockData);
|
||||
return getAdapter().adapt(blockData);
|
||||
}
|
||||
|
||||
@ -183,7 +287,8 @@ public enum BukkitAdapter {
|
||||
* @param block The WorldEdit BlockStateHolder
|
||||
* @return The Bukkit BlockData
|
||||
*/
|
||||
public static <B extends BlockStateHolder<B>> BlockData adapt(B block) {
|
||||
public static BlockData adapt(BlockStateHolder block) {
|
||||
checkNotNull(block);
|
||||
return getAdapter().adapt(block);
|
||||
}
|
||||
|
||||
@ -191,15 +296,40 @@ public enum BukkitAdapter {
|
||||
return getAdapter().getBlockData(combinedId);
|
||||
}
|
||||
|
||||
public static BlockState asBlockState(ItemStack itemStack) {
|
||||
/**
|
||||
* Create a WorldEdit BlockState from a Bukkit ItemStack
|
||||
*
|
||||
* @param itemStack The Bukkit ItemStack
|
||||
* @return The WorldEdit BlockState
|
||||
*/
|
||||
public static BlockState asBlockState(ItemStack itemStack) throws WorldEditException {
|
||||
checkNotNull(itemStack);
|
||||
if (itemStack.getType().isBlock()) {
|
||||
return getAdapter().asBlockState(itemStack);
|
||||
} else {
|
||||
throw new NotABlockException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a WorldEdit BaseItemStack from a Bukkit ItemStack
|
||||
*
|
||||
* @param itemStack The Bukkit ItemStack
|
||||
* @return The WorldEdit BaseItemStack
|
||||
*/
|
||||
public static BaseItemStack adapt(ItemStack itemStack) {
|
||||
checkNotNull(itemStack);
|
||||
return getAdapter().adapt(itemStack);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Bukkit ItemStack from a WorldEdit BaseItemStack
|
||||
*
|
||||
* @param item The WorldEdit BaseItemStack
|
||||
* @return The Bukkit ItemStack
|
||||
*/
|
||||
public static ItemStack adapt(BaseItemStack item) {
|
||||
checkNotNull(item);
|
||||
return getAdapter().adapt(item);
|
||||
}
|
||||
|
||||
|
@ -109,8 +109,8 @@ public class BukkitPlayer extends AbstractPlayerActor {
|
||||
if (itemStack.getType().getId().equalsIgnoreCase(WorldEdit.getInstance().getConfiguration().wandItem)) {
|
||||
inv.remove(newItem);
|
||||
}
|
||||
final ItemStack item = player.getItemInHand();
|
||||
player.setItemInHand(newItem);
|
||||
final ItemStack item = player.getInventory().getItemInMainHand();
|
||||
player.getInventory().setItemInMainHand(newItem);
|
||||
HashMap<Integer, ItemStack> overflow = inv.addItem(item);
|
||||
if (!overflow.isEmpty()) {
|
||||
TaskManager.IMP.sync(new RunnableVal<Object>() {
|
||||
@ -216,7 +216,7 @@ public class BukkitPlayer extends AbstractPlayerActor {
|
||||
if (params.length > 0) {
|
||||
send = send + "|" + StringUtil.joinString(params, "|");
|
||||
}
|
||||
player.sendPluginMessage(plugin, WorldEditPlugin.getCuiPluginChannel(), send.getBytes(CUIChannelListener.UTF_8_CHARSET));
|
||||
player.sendPluginMessage(plugin, WorldEditPlugin.CUI_PLUGIN_CHANNEL, send.getBytes(CUIChannelListener.UTF_8_CHARSET));
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
@ -305,7 +305,7 @@ public class BukkitPlayer extends AbstractPlayerActor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendFakeBlock(BlockVector3 pos, BlockStateHolder block) {
|
||||
public <B extends BlockStateHolder<B>> void sendFakeBlock(BlockVector3 pos, B block) {
|
||||
Location loc = new Location(player.getWorld(), pos.getX(), pos.getY(), pos.getZ());
|
||||
if (block == null) {
|
||||
player.sendBlockChange(loc, player.getWorld().getBlockAt(loc).getBlockData());
|
||||
|
@ -100,7 +100,7 @@ public class BukkitServerInterface implements MultiUserPlatform {
|
||||
return player;
|
||||
} else {
|
||||
org.bukkit.entity.Player bukkitPlayer = server.getPlayerExact(player.getName());
|
||||
return bukkitPlayer != null ? plugin.wrapPlayer(bukkitPlayer) : null;
|
||||
return bukkitPlayer != null ? WorldEditPlugin.getInstance().wrapPlayer(bukkitPlayer) : null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -177,7 +177,7 @@ public class BukkitServerInterface implements MultiUserPlatform {
|
||||
public Collection<Actor> getConnectedUsers() {
|
||||
List<Actor> users = new ArrayList<>();
|
||||
for (org.bukkit.entity.Player player : Bukkit.getServer().getOnlinePlayers()) {
|
||||
users.add(plugin.wrapPlayer(player));
|
||||
users.add(WorldEditPlugin.getInstance().wrapPlayer(player));
|
||||
}
|
||||
return users;
|
||||
}
|
||||
|
@ -19,7 +19,6 @@
|
||||
|
||||
package com.sk89q.worldedit.bukkit;
|
||||
|
||||
import com.bekvon.bukkit.residence.commands.message;
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.bukkit.FaweBukkit;
|
||||
import com.boydti.fawe.bukkit.adapter.v1_13_1.Spigot_v1_13_R2;
|
||||
@ -34,47 +33,35 @@ import com.sk89q.worldedit.bukkit.adapter.AdapterLoadException;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplLoader;
|
||||
import com.sk89q.worldedit.event.platform.CommandEvent;
|
||||
import com.sk89q.worldedit.event.platform.CommandSuggestionEvent;
|
||||
import com.sk89q.worldedit.event.platform.PlatformReadyEvent;
|
||||
import com.sk89q.worldedit.extension.input.InputParseException;
|
||||
import com.sk89q.worldedit.extension.input.ParserContext;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import com.sk89q.worldedit.extension.platform.Capability;
|
||||
import com.sk89q.worldedit.extension.platform.Platform;
|
||||
import com.sk89q.worldedit.extent.inventory.BlockBag;
|
||||
import com.sk89q.worldedit.registry.state.Property;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BlockCategory;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.block.FuzzyBlockState;
|
||||
import com.sk89q.worldedit.world.entity.EntityType;
|
||||
import com.sk89q.worldedit.world.item.ItemCategory;
|
||||
import com.sk89q.worldedit.world.item.ItemType;
|
||||
import com.sk89q.worldedit.world.registry.LegacyMapper;
|
||||
import org.bstats.bukkit.Metrics;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Tag;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.TabCompleter;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.PluginDescriptionFile;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.plugin.java.JavaPluginLoader;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -111,7 +98,7 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter
|
||||
lookupNamesField.setAccessible(true);
|
||||
List<Plugin> plugins = (List<Plugin>) pluginsField.get(manager);
|
||||
lookupNames = (Map<String, Plugin>) lookupNamesField.get(manager);
|
||||
pluginsField.set(manager, plugins = new ArrayList<Plugin>(plugins) {
|
||||
pluginsField.set(manager, new ArrayList<Plugin>(plugins) {
|
||||
@Override
|
||||
public boolean add(Plugin plugin) {
|
||||
if (plugin.getName().startsWith("AsyncWorldEdit")) {
|
||||
@ -126,7 +113,7 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter
|
||||
});
|
||||
lookupNamesField.set(manager, lookupNames = new ConcurrentHashMap<String, Plugin>(lookupNames) {
|
||||
@Override
|
||||
public Plugin put(String key, Plugin plugin) {
|
||||
public Plugin put(@NotNull String key, @NotNull Plugin plugin) {
|
||||
if (plugin.getName().startsWith("AsyncWorldEdit") || plugin.getName().startsWith("BetterShutdown")) {
|
||||
return null;
|
||||
}
|
||||
@ -157,15 +144,11 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter
|
||||
setEnabled(true);
|
||||
}
|
||||
|
||||
public static String getCuiPluginChannel() {
|
||||
return CUI_PLUGIN_CHANNEL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
if (INSTANCE != null) return;
|
||||
rename();
|
||||
this.INSTANCE = this;
|
||||
INSTANCE = this;
|
||||
FaweBukkit imp = new FaweBukkit(this);
|
||||
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
@ -190,6 +173,7 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter
|
||||
if (INSTANCE != null) return;
|
||||
onLoad();
|
||||
setupTags(); // these have to be done post-world since they rely on MC registries. the other ones just use Bukkit enums
|
||||
//TODO: FAWE -- This needs to be moved to onLoad()
|
||||
setupRegistries();
|
||||
WorldEdit.getInstance().loadMappings();
|
||||
|
||||
@ -226,28 +210,30 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter
|
||||
}
|
||||
// Block & Item
|
||||
for (Material material : Material.values()) {
|
||||
// if (material.isBlock() && !material.isLegacy()) {
|
||||
// BlockType.REGISTRY.register(material.getKey().toString(), new BlockType(material.getKey().toString(), blockState -> {
|
||||
// // TODO Use something way less hacky than this.
|
||||
// ParserContext context = new ParserContext();
|
||||
// context.setPreferringWildcard(true);
|
||||
// context.setTryLegacy(false);
|
||||
// context.setRestricted(false);
|
||||
// try {
|
||||
// FuzzyBlockState state = (FuzzyBlockState) WorldEdit.getInstance().getBlockFactory().parseFromInput(
|
||||
// BukkitAdapter.adapt(blockState.getBlockType()).createBlockData().getAsString(), context
|
||||
// ).toImmutableState();
|
||||
// BlockState defaultState = blockState.getBlockType().getAllStates().get(0);
|
||||
// for (Map.Entry<Property<?>, Object> propertyObjectEntry : state.getStates().entrySet()) {
|
||||
// defaultState = defaultState.with((Property) propertyObjectEntry.getKey(), propertyObjectEntry.getValue());
|
||||
// }
|
||||
// return defaultState;
|
||||
// } catch (InputParseException e) {
|
||||
// e.printStackTrace();
|
||||
// return blockState;
|
||||
// }
|
||||
// }));
|
||||
// }
|
||||
/*
|
||||
if (material.isBlock() && !material.isLegacy()) {
|
||||
BlockType.REGISTRY.register(material.getKey().toString(), new BlockType(material.getKey().toString(), blockState -> {
|
||||
// TODO Use something way less hacky than this.
|
||||
ParserContext context = new ParserContext();
|
||||
context.setPreferringWildcard(true);
|
||||
context.setTryLegacy(false);
|
||||
context.setRestricted(false);
|
||||
try {
|
||||
FuzzyBlockState state = (FuzzyBlockState) WorldEdit.getInstance().getBlockFactory().parseFromInput(
|
||||
BukkitAdapter.adapt(blockState.getBlockType()).createBlockData().getAsString(), context
|
||||
).toImmutableState();
|
||||
BlockState defaultState = blockState.getBlockType().getAllStates().get(0);
|
||||
for (Map.Entry<Property<?>, Object> propertyObjectEntry : state.getStates().entrySet()) {
|
||||
defaultState = defaultState.with((Property) propertyObjectEntry.getKey(), propertyObjectEntry.getValue());
|
||||
}
|
||||
return defaultState;
|
||||
} catch (InputParseException e) {
|
||||
e.printStackTrace();
|
||||
return blockState;
|
||||
}
|
||||
}));
|
||||
}
|
||||
*/
|
||||
if (material.isItem() && !material.isLegacy()) {
|
||||
ItemType.REGISTRY.register(material.getKey().toString(), new ItemType(material.getKey().toString()));
|
||||
}
|
||||
@ -276,47 +262,15 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter
|
||||
}
|
||||
|
||||
private void rename() {
|
||||
// {
|
||||
// PluginDescriptionFile desc = getDescription();
|
||||
// if (desc != null) {
|
||||
// try {
|
||||
// Field nameField = PluginDescriptionFile.class.getDeclaredField("name");
|
||||
// nameField.setAccessible(true);
|
||||
// nameField.set(desc, "FastAsyncWorldEdit");
|
||||
// Field descriptionField = JavaPlugin.class.getDeclaredField("description");
|
||||
// descriptionField.setAccessible(true);
|
||||
// descriptionField.set(this, desc);
|
||||
// } catch (Throwable ignore) {
|
||||
// ignore.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
{
|
||||
File dir = getDataFolder();
|
||||
if (dir != null) {
|
||||
dir = new File(dir.getParentFile(), "FastAsyncWorldEdit");
|
||||
try {
|
||||
Field descriptionField = JavaPlugin.class.getDeclaredField("dataFolder");
|
||||
descriptionField.setAccessible(true);
|
||||
descriptionField.set(this, dir);
|
||||
} catch (Throwable ignore) {
|
||||
ignore.printStackTrace();
|
||||
} catch (Throwable throwable) {
|
||||
throwable.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
// {
|
||||
// Logger logger = getLogger();
|
||||
// if (logger != null) {
|
||||
// try {
|
||||
// Field nameField = Logger.class.getDeclaredField("name");
|
||||
// nameField.setAccessible(true);
|
||||
// nameField.set(logger, "FastAsyncWorldEdit");
|
||||
// } catch (Throwable ignore) {
|
||||
// ignore.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
{
|
||||
File pluginsFolder = MainUtil.getJarFile().getParentFile();
|
||||
for (File file : pluginsFolder.listFiles()) {
|
||||
if (file.length() == 1988) return;
|
||||
@ -334,7 +288,6 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter
|
||||
MainUtil.copyFile(MainUtil.getJarFile(), "DummyFawe.src", pluginsFolder, "update" + File.separator + "DummyFawe.jar");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void fail(Runnable run, String message) {
|
||||
try {
|
||||
@ -470,20 +423,20 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter
|
||||
return true;
|
||||
}
|
||||
|
||||
// @Deprecated Using Async tab complete (rather than main thread)
|
||||
// @Override
|
||||
// public List<String> onTabComplete(CommandSender sender, Command cmd, String commandLabel, String[] args) {
|
||||
// // Add the command to the array because the underlying command handling
|
||||
// // code of WorldEdit expects it
|
||||
// String[] split = new String[args.length + 1];
|
||||
// System.arraycopy(args, 0, split, 1, args.length);
|
||||
// split[0] = cmd.getName();
|
||||
//
|
||||
// CommandSuggestionEvent event = new CommandSuggestionEvent(wrapCommandSender(sender), Joiner.on(" ").join(split));
|
||||
// getWorldEdit().getEventBus().post(event);
|
||||
//
|
||||
// return event.getSuggestions();
|
||||
// }
|
||||
/*
|
||||
@Override
|
||||
public List<String> onTabComplete(CommandSender sender, Command cmd, String commandLabel, String[] args) {
|
||||
// Add the command to the array because the underlying command handling
|
||||
// code of WorldEdit expects it
|
||||
String[] split = new String[args.length + 1];
|
||||
System.arraycopy(args, 0, split, 1, args.length);
|
||||
split[0] = cmd.getName();
|
||||
|
||||
CommandSuggestionEvent event = new CommandSuggestionEvent(wrapCommandSender(sender), Joiner.on(" ").join(split));
|
||||
getWorldEdit().getEventBus().post(event);
|
||||
return event.getSuggestions();
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gets the session for the player.
|
||||
|
@ -9,7 +9,6 @@ import com.boydti.fawe.regions.general.plot.PlotSquaredFeature;
|
||||
import com.boydti.fawe.util.*;
|
||||
import com.boydti.fawe.util.chat.ChatManager;
|
||||
import com.boydti.fawe.util.chat.PlainChatManager;
|
||||
import com.boydti.fawe.util.cui.CUI;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.extension.factory.DefaultTransformParser;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
@ -199,25 +198,6 @@ public class Fawe {
|
||||
public void onDisable() {
|
||||
}
|
||||
|
||||
public CUI getCUI(Actor actor) {
|
||||
FawePlayer<Object> fp = FawePlayer.wrap(actor);
|
||||
CUI cui = fp.getMeta("CUI");
|
||||
if (cui == null) {
|
||||
cui = Fawe.imp().getCUI(fp);
|
||||
if (cui != null) {
|
||||
synchronized (fp) {
|
||||
CUI tmp = fp.getMeta("CUI");
|
||||
if (tmp == null) {
|
||||
fp.setMeta("CUI", cui);
|
||||
} else {
|
||||
cui = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return cui;
|
||||
}
|
||||
|
||||
public ChatManager getChatManager() {
|
||||
return chatManager;
|
||||
}
|
||||
@ -315,11 +295,10 @@ public class Fawe {
|
||||
Settings.IMP.PLATFORM = IMP.getPlatform().replace("\"", "");
|
||||
try (InputStream stream = getClass().getResourceAsStream("/fawe.properties");
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(stream))) {
|
||||
// java.util.Scanner scanner = new java.util.Scanner(stream).useDelimiter("\\A");
|
||||
String versionString = br.readLine();
|
||||
String commitString = br.readLine();
|
||||
String dateString = br.readLine();
|
||||
// scanner.close();
|
||||
br.close();
|
||||
this.version = FaweVersion.tryParse(versionString, commitString, dateString);
|
||||
Settings.IMP.DATE = new Date(100 + version.year, version.month, version.day).toGMTString();
|
||||
Settings.IMP.BUILD = "https://ci.athion.net/job/FastAsyncWorldEdit-Breaking/" + version.build;
|
||||
@ -381,7 +360,7 @@ public class Fawe {
|
||||
try {
|
||||
String arch = System.getenv("PROCESSOR_ARCHITECTURE");
|
||||
String wow64Arch = System.getenv("PROCESSOR_ARCHITEW6432");
|
||||
boolean x86OS = arch.endsWith("64") || wow64Arch != null && wow64Arch.endsWith("64") ? false : true;
|
||||
boolean x86OS = !arch.endsWith("64") && (wow64Arch == null || !wow64Arch.endsWith("64"));
|
||||
boolean x86JVM = System.getProperty("sun.arch.data.model").equals("32");
|
||||
if (x86OS != x86JVM) {
|
||||
debug("====== UPGRADE TO 64-BIT JAVA ======");
|
||||
|
@ -5,7 +5,6 @@ import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.object.FaweQueue;
|
||||
import com.boydti.fawe.regions.FaweMaskManager;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.boydti.fawe.util.cui.CUI;
|
||||
import com.boydti.fawe.util.image.ImageViewer;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
|
||||
@ -36,12 +35,8 @@ public interface IFawe {
|
||||
|
||||
void startMetrics();
|
||||
|
||||
default CUI getCUI(FawePlayer player) { return null; }
|
||||
|
||||
default ImageViewer getImageViewer(FawePlayer player) { return null; }
|
||||
|
||||
default void registerPacketListener() {}
|
||||
|
||||
default int getPlayerCount() {
|
||||
return Fawe.get().getCachedPlayers().size();
|
||||
}
|
||||
|
@ -65,12 +65,9 @@ public class PlotLoader {
|
||||
area.setMeta("lastPlot", new PlotId(0, 0));
|
||||
}
|
||||
PlotId lastId = (PlotId) area.getMeta("lastPlot");
|
||||
while (true) {
|
||||
do {
|
||||
lastId = Auto.getNextPlotId(lastId, 1);
|
||||
if (area.canClaim(player, lastId, lastId)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (!area.canClaim(player, lastId, lastId));
|
||||
area.setMeta("lastPlot", lastId);
|
||||
this.value = area.getPlot(lastId);
|
||||
this.value.setOwner(player.getUUID());
|
||||
|
@ -339,11 +339,6 @@ public class Settings extends Config {
|
||||
"Allows brushes to be persistent (default: true)",
|
||||
})
|
||||
public boolean PERSISTENT_BRUSHES = true;
|
||||
@Comment({
|
||||
"[SAFE] Enable CUI without needing the mod installed (Requires ProtocolLib)",
|
||||
})
|
||||
public boolean VANILLA_CUI = false;
|
||||
|
||||
|
||||
@Comment({
|
||||
"Disable using native libraries",
|
||||
|
@ -37,19 +37,14 @@ import javax.swing.border.EmptyBorder;
|
||||
|
||||
public class InstallerFrame extends JFrame {
|
||||
private final InvisiblePanel loggerPanel;
|
||||
private Color LIGHT_GRAY = new Color(0x66, 0x66, 0x66);
|
||||
private Color GRAY = new Color(0x44, 0x44, 0x46);
|
||||
private Color DARK_GRAY = new Color(0x33, 0x33, 0x36);
|
||||
private Color DARKER_GRAY = new Color(0x26, 0x26, 0x28);
|
||||
private Color DARKER_GRAY;
|
||||
private Color INVISIBLE = new Color(0, 0, 0, 0);
|
||||
private Color OFF_WHITE = new Color(200, 200, 200);
|
||||
|
||||
private JTextArea loggerTextArea;
|
||||
private BrowseButton browse;
|
||||
|
||||
public InstallerFrame() throws Exception {
|
||||
final MovablePanel movable = new MovablePanel(this);
|
||||
|
||||
Container content = this.getContentPane();
|
||||
content.add(movable);
|
||||
this.setSize(480, 320);
|
||||
@ -61,20 +56,19 @@ public class InstallerFrame extends JFrame {
|
||||
this.setLocation(x, y);
|
||||
this.setVisible(true);
|
||||
this.setOpacity(0);
|
||||
movable.setBackground(DARK_GRAY);
|
||||
movable.setBackground(Color.darkGray);
|
||||
movable.setLayout(new BorderLayout());
|
||||
|
||||
fadeIn();
|
||||
|
||||
JPanel topBar = new InvisiblePanel(new BorderLayout());
|
||||
{
|
||||
JPanel topBarLeft = new InvisiblePanel();
|
||||
JPanel topBarRight = new InvisiblePanel();
|
||||
|
||||
JLabel title = new JLabel("FastAsyncWorldEdit Installer");
|
||||
title.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
title.setAlignmentX(Component.RIGHT_ALIGNMENT);
|
||||
title.setForeground(LIGHT_GRAY);
|
||||
title.setForeground(Color.lightGray);
|
||||
|
||||
MinimizeButton minimize = new MinimizeButton(this);
|
||||
CloseButton exit = new CloseButton();
|
||||
@ -85,20 +79,19 @@ public class InstallerFrame extends JFrame {
|
||||
|
||||
topBar.add(topBarLeft, BorderLayout.CENTER);
|
||||
topBar.add(topBarRight, BorderLayout.EAST);
|
||||
}
|
||||
final JPanel mainContent = new InvisiblePanel(new BorderLayout());
|
||||
{
|
||||
DARKER_GRAY = new Color(0x26, 0x26, 0x28);
|
||||
final JPanel browseContent = new InvisiblePanel(new BorderLayout());
|
||||
File dir = MainUtil.getWorkingDirectory("minecraft");
|
||||
JLabel folder = new JLabel("Folder: ");
|
||||
folder.setForeground(OFF_WHITE);
|
||||
folder.setForeground(Color.white);
|
||||
final InteractiveButton text = new InteractiveButton(dir.getPath(), DARKER_GRAY) {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
browse.actionPerformed(e);
|
||||
}
|
||||
};
|
||||
text.setForeground(OFF_WHITE);
|
||||
text.setForeground(Color.white);
|
||||
text.setBackground(DARKER_GRAY);
|
||||
text.setOpaque(true);
|
||||
text.setBorder(new EmptyBorder(4, 4, 4, 4));
|
||||
@ -130,11 +123,12 @@ public class InstallerFrame extends JFrame {
|
||||
this.loggerPanel.setBackground(Color.GREEN);
|
||||
loggerPanel.setPreferredSize(new Dimension(416, 160));
|
||||
loggerTextArea = new JTextArea(12, 52);
|
||||
Color GRAY = new Color(0x44, 0x44, 0x46);
|
||||
loggerTextArea.setBackground(GRAY);
|
||||
loggerTextArea.setForeground(DARKER_GRAY);
|
||||
loggerTextArea.setFont(new Font(loggerTextArea.getFont().getName(), Font.PLAIN, 9));
|
||||
JScrollPane scroll = new JScrollPane(loggerTextArea, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
|
||||
scroll.setBackground(DARK_GRAY);
|
||||
scroll.setBackground(Color.darkGray);
|
||||
scroll.setBorder(new EmptyBorder(0, 0, 0, 0));
|
||||
loggerPanel.add(scroll);
|
||||
loggerPanel.setVisible(false);
|
||||
@ -143,14 +137,8 @@ public class InstallerFrame extends JFrame {
|
||||
mainContent.add(browseContent, BorderLayout.NORTH);
|
||||
mainContent.add(installContent, BorderLayout.CENTER);
|
||||
mainContent.add(loggerPanel, BorderLayout.SOUTH);
|
||||
}
|
||||
JPanel bottomBar = new InvisiblePanel();
|
||||
{
|
||||
try {
|
||||
InputStream stream = getClass().getResourceAsStream("/fawe.properties");
|
||||
java.util.Scanner scanner = new java.util.Scanner(stream).useDelimiter("\\A");
|
||||
String versionString = scanner.next().trim();
|
||||
scanner.close();
|
||||
FaweVersion version = null;
|
||||
String date = new Date(100 + version.year, version.month, version.day).toGMTString();
|
||||
String build = "https://ci.athion.net/job/FastAsyncWorldEdit/" + version.build;
|
||||
@ -171,7 +159,6 @@ public class InstallerFrame extends JFrame {
|
||||
URL issue = new URL("https://github.com/boy0001/FastAsyncWorldedit/issues/new");
|
||||
URLButton issueButton = new URLButton(issue, "Report Issue");
|
||||
bottomBar.add(issueButton);
|
||||
}
|
||||
|
||||
// We want to add these a bit later
|
||||
movable.add(topBar, BorderLayout.NORTH);
|
||||
@ -214,9 +201,7 @@ public class InstallerFrame extends JFrame {
|
||||
prompt("You must select a folder, not a file");
|
||||
return;
|
||||
}
|
||||
Thread installThread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Thread installThread = new Thread(() -> {
|
||||
List<String> supported = Arrays.asList("v1710", "v189", "v194", "v110", "v111");
|
||||
String supportedString = null;
|
||||
for (String version : supported) {
|
||||
@ -292,8 +277,8 @@ public class InstallerFrame extends JFrame {
|
||||
mods.mkdirs();
|
||||
} else {
|
||||
for (File file : mods.listFiles()) {
|
||||
String name = file.getName().toLowerCase();
|
||||
if ((name.contains("worldedit") || name.contains("fawe"))) {
|
||||
String name1 = file.getName().toLowerCase();
|
||||
if ((name1.contains("worldedit") || name1.contains("fawe"))) {
|
||||
debug("Delete existing: " + file.getName());
|
||||
file.delete();
|
||||
}
|
||||
@ -332,15 +317,12 @@ public class InstallerFrame extends JFrame {
|
||||
prompt("[ERROR] Copy installer failed, please copy this installer jar manually");
|
||||
}
|
||||
prompt("Installation complete!\nLaunch the game using the forge profile.");
|
||||
}
|
||||
});
|
||||
installThread.start();
|
||||
}
|
||||
|
||||
public void fadeIn() {
|
||||
Thread thread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Thread thread = new Thread(() -> {
|
||||
for (float i = 0; i <= 1; i += 0.001) {
|
||||
InstallerFrame.this.setOpacity(i);
|
||||
try {
|
||||
@ -349,7 +331,6 @@ public class InstallerFrame extends JFrame {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
thread.start();
|
||||
}
|
||||
|
@ -1,206 +0,0 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.boydti.fawe.object.io.zstd;
|
||||
|
||||
import static com.boydti.fawe.object.io.zstd.UnsafeUtil.UNSAFE;
|
||||
import static com.boydti.fawe.object.io.zstd.Util.highestBit;
|
||||
import static com.boydti.fawe.object.io.zstd.Util.verify;
|
||||
import static com.boydti.fawe.object.io.zstd.ZstdFrameDecompressor.SIZE_OF_LONG;
|
||||
|
||||
/**
|
||||
* Bit streams are encoded as a byte-aligned little-endian stream. Thus, bits are laid out
|
||||
* in the following manner, and the stream is read from right to left.
|
||||
* <p>
|
||||
* <p>
|
||||
* ... [16 17 18 19 20 21 22 23] [8 9 10 11 12 13 14 15] [0 1 2 3 4 5 6 7]
|
||||
*/
|
||||
class BitStream
|
||||
{
|
||||
private BitStream()
|
||||
{
|
||||
}
|
||||
|
||||
public static boolean isEndOfStream(long startAddress, long currentAddress, int bitsConsumed)
|
||||
{
|
||||
return startAddress == currentAddress && bitsConsumed == Long.SIZE;
|
||||
}
|
||||
|
||||
static long readTail(Object inputBase, long inputAddress, int inputSize)
|
||||
{
|
||||
long bits = UNSAFE.getByte(inputBase, inputAddress) & 0xFF;
|
||||
|
||||
switch (inputSize) {
|
||||
case 7:
|
||||
bits |= (UNSAFE.getByte(inputBase, inputAddress + 6) & 0xFFL) << 48;
|
||||
case 6:
|
||||
bits |= (UNSAFE.getByte(inputBase, inputAddress + 5) & 0xFFL) << 40;
|
||||
case 5:
|
||||
bits |= (UNSAFE.getByte(inputBase, inputAddress + 4) & 0xFFL) << 32;
|
||||
case 4:
|
||||
bits |= (UNSAFE.getByte(inputBase, inputAddress + 3) & 0xFFL) << 24;
|
||||
case 3:
|
||||
bits |= (UNSAFE.getByte(inputBase, inputAddress + 2) & 0xFFL) << 16;
|
||||
case 2:
|
||||
bits |= (UNSAFE.getByte(inputBase, inputAddress + 1) & 0xFFL) << 8;
|
||||
}
|
||||
|
||||
return bits;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return numberOfBits in the low order bits of a long
|
||||
*/
|
||||
public static long peekBits(int bitsConsumed, long bitContainer, int numberOfBits)
|
||||
{
|
||||
return (((bitContainer << bitsConsumed) >>> 1) >>> (63 - numberOfBits));
|
||||
}
|
||||
|
||||
/**
|
||||
* numberOfBits must be > 0
|
||||
*
|
||||
* @return numberOfBits in the low order bits of a long
|
||||
*/
|
||||
public static long peekBitsFast(int bitsConsumed, long bitContainer, int numberOfBits)
|
||||
{
|
||||
return ((bitContainer << bitsConsumed) >>> (64 - numberOfBits));
|
||||
}
|
||||
|
||||
static class Initializer
|
||||
{
|
||||
private final Object inputBase;
|
||||
private final long startAddress;
|
||||
private final long endAddress;
|
||||
private long bits;
|
||||
private long currentAddress;
|
||||
private int bitsConsumed;
|
||||
|
||||
public Initializer(Object inputBase, long startAddress, long endAddress)
|
||||
{
|
||||
this.inputBase = inputBase;
|
||||
this.startAddress = startAddress;
|
||||
this.endAddress = endAddress;
|
||||
}
|
||||
|
||||
public long getBits()
|
||||
{
|
||||
return bits;
|
||||
}
|
||||
|
||||
public long getCurrentAddress()
|
||||
{
|
||||
return currentAddress;
|
||||
}
|
||||
|
||||
public int getBitsConsumed()
|
||||
{
|
||||
return bitsConsumed;
|
||||
}
|
||||
|
||||
public void initialize()
|
||||
{
|
||||
verify(endAddress - startAddress >= 1, startAddress, "Bitstream is empty");
|
||||
|
||||
int lastByte = UNSAFE.getByte(inputBase, endAddress - 1) & 0xFF;
|
||||
verify(lastByte != 0, endAddress, "Bitstream end mark not present");
|
||||
|
||||
bitsConsumed = SIZE_OF_LONG - highestBit(lastByte);
|
||||
|
||||
int inputSize = (int) (endAddress - startAddress);
|
||||
if (inputSize >= SIZE_OF_LONG) { /* normal case */
|
||||
currentAddress = endAddress - SIZE_OF_LONG;
|
||||
bits = UNSAFE.getLong(inputBase, currentAddress);
|
||||
}
|
||||
else {
|
||||
currentAddress = startAddress;
|
||||
bits = readTail(inputBase, startAddress, inputSize);
|
||||
|
||||
bitsConsumed += (SIZE_OF_LONG - inputSize) * 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static final class Loader
|
||||
{
|
||||
private final Object inputBase;
|
||||
private final long startAddress;
|
||||
private long bits;
|
||||
private long currentAddress;
|
||||
private int bitsConsumed;
|
||||
private boolean overflow;
|
||||
|
||||
public Loader(Object inputBase, long startAddress, long currentAddress, long bits, int bitsConsumed)
|
||||
{
|
||||
this.inputBase = inputBase;
|
||||
this.startAddress = startAddress;
|
||||
this.bits = bits;
|
||||
this.currentAddress = currentAddress;
|
||||
this.bitsConsumed = bitsConsumed;
|
||||
}
|
||||
|
||||
public long getBits()
|
||||
{
|
||||
return bits;
|
||||
}
|
||||
|
||||
public long getCurrentAddress()
|
||||
{
|
||||
return currentAddress;
|
||||
}
|
||||
|
||||
public int getBitsConsumed()
|
||||
{
|
||||
return bitsConsumed;
|
||||
}
|
||||
|
||||
public boolean isOverflow()
|
||||
{
|
||||
return overflow;
|
||||
}
|
||||
|
||||
public boolean load()
|
||||
{
|
||||
if (bitsConsumed > 64) {
|
||||
overflow = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
else if (currentAddress == startAddress) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int bytes = bitsConsumed >>> 3; // divide by 8
|
||||
if (currentAddress >= startAddress + SIZE_OF_LONG) {
|
||||
if (bytes > 0) {
|
||||
currentAddress -= bytes;
|
||||
bits = UNSAFE.getLong(inputBase, currentAddress);
|
||||
}
|
||||
bitsConsumed &= 0b111;
|
||||
}
|
||||
else if (currentAddress - bytes < startAddress) {
|
||||
bytes = (int) (currentAddress - startAddress);
|
||||
currentAddress = startAddress;
|
||||
bitsConsumed -= bytes * SIZE_OF_LONG;
|
||||
bits = UNSAFE.getLong(inputBase, startAddress);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
currentAddress -= bytes;
|
||||
bitsConsumed -= bytes * SIZE_OF_LONG;
|
||||
bits = UNSAFE.getLong(inputBase, currentAddress);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,176 +0,0 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.boydti.fawe.object.io.zstd;
|
||||
|
||||
import static com.boydti.fawe.object.io.zstd.BitStream.peekBits;
|
||||
import static com.boydti.fawe.object.io.zstd.FseTableReader.FSE_MAX_SYMBOL_VALUE;
|
||||
import static com.boydti.fawe.object.io.zstd.UnsafeUtil.UNSAFE;
|
||||
import static sun.misc.Unsafe.ARRAY_BYTE_BASE_OFFSET;
|
||||
|
||||
class FiniteStateEntropy
|
||||
{
|
||||
private static final int MAX_TABLE_LOG = 12;
|
||||
|
||||
private final FiniteStateEntropy.Table table;
|
||||
private final FseTableReader reader = new FseTableReader();
|
||||
|
||||
public FiniteStateEntropy(int maxLog)
|
||||
{
|
||||
table = new FiniteStateEntropy.Table(maxLog);
|
||||
}
|
||||
|
||||
public int decompress(final Object inputBase, final long inputAddress, final long inputLimit, byte[] weights)
|
||||
{
|
||||
long input = inputAddress;
|
||||
input += reader.readFseTable(table, inputBase, input, inputLimit, FSE_MAX_SYMBOL_VALUE, MAX_TABLE_LOG);
|
||||
|
||||
final Object outputBase = weights;
|
||||
final long outputAddress = ARRAY_BYTE_BASE_OFFSET;
|
||||
final long outputLimit = outputAddress + weights.length;
|
||||
|
||||
long output = outputAddress;
|
||||
|
||||
// initialize bit stream
|
||||
BitStream.Initializer initializer = new BitStream.Initializer(inputBase, input, inputLimit);
|
||||
initializer.initialize();
|
||||
int bitsConsumed = initializer.getBitsConsumed();
|
||||
long currentAddress = initializer.getCurrentAddress();
|
||||
long bits = initializer.getBits();
|
||||
|
||||
// initialize first FSE stream
|
||||
int state1 = (int) peekBits(bitsConsumed, bits, table.log2Size);
|
||||
bitsConsumed += table.log2Size;
|
||||
|
||||
BitStream.Loader loader = new BitStream.Loader(inputBase, input, currentAddress, bits, bitsConsumed);
|
||||
loader.load();
|
||||
bits = loader.getBits();
|
||||
bitsConsumed = loader.getBitsConsumed();
|
||||
currentAddress = loader.getCurrentAddress();
|
||||
|
||||
// initialize second FSE stream
|
||||
int state2 = (int) peekBits(bitsConsumed, bits, table.log2Size);
|
||||
bitsConsumed += table.log2Size;
|
||||
|
||||
loader = new BitStream.Loader(inputBase, input, currentAddress, bits, bitsConsumed);
|
||||
loader.load();
|
||||
bits = loader.getBits();
|
||||
bitsConsumed = loader.getBitsConsumed();
|
||||
currentAddress = loader.getCurrentAddress();
|
||||
|
||||
byte[] symbols = table.symbol;
|
||||
byte[] numbersOfBits = table.numberOfBits;
|
||||
int[] newStates = table.newState;
|
||||
|
||||
// decode 4 symbols per loop
|
||||
while (output < outputLimit) {
|
||||
int numberOfBits;
|
||||
|
||||
UNSAFE.putByte(outputBase, output, symbols[state1]);
|
||||
numberOfBits = numbersOfBits[state1];
|
||||
state1 = (int) (newStates[state1] + peekBits(bitsConsumed, bits, numberOfBits));
|
||||
bitsConsumed += numberOfBits;
|
||||
|
||||
UNSAFE.putByte(outputBase, output + 1, symbols[state2]);
|
||||
numberOfBits = numbersOfBits[state2];
|
||||
state2 = (int) (newStates[state2] + peekBits(bitsConsumed, bits, numberOfBits));
|
||||
bitsConsumed += numberOfBits;
|
||||
|
||||
UNSAFE.putByte(outputBase, output + 2, symbols[state1]);
|
||||
numberOfBits = numbersOfBits[state1];
|
||||
state1 = (int) (newStates[state1] + peekBits(bitsConsumed, bits, numberOfBits));
|
||||
bitsConsumed += numberOfBits;
|
||||
|
||||
UNSAFE.putByte(outputBase, output + 3, symbols[state2]);
|
||||
numberOfBits = numbersOfBits[state2];
|
||||
state2 = (int) (newStates[state2] + peekBits(bitsConsumed, bits, numberOfBits));
|
||||
bitsConsumed += numberOfBits;
|
||||
|
||||
output += ZstdFrameDecompressor.SIZE_OF_INT;
|
||||
|
||||
loader = new BitStream.Loader(inputBase, input, currentAddress, bits, bitsConsumed);
|
||||
boolean done = loader.load();
|
||||
bitsConsumed = loader.getBitsConsumed();
|
||||
bits = loader.getBits();
|
||||
currentAddress = loader.getCurrentAddress();
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while (true) {
|
||||
UNSAFE.putByte(outputBase, output++, symbols[state1]);
|
||||
int numberOfBits = numbersOfBits[state1];
|
||||
state1 = (int) (newStates[state1] + peekBits(bitsConsumed, bits, numberOfBits));
|
||||
bitsConsumed += numberOfBits;
|
||||
|
||||
loader = new BitStream.Loader(inputBase, input, currentAddress, bits, bitsConsumed);
|
||||
loader.load();
|
||||
bitsConsumed = loader.getBitsConsumed();
|
||||
bits = loader.getBits();
|
||||
currentAddress = loader.getCurrentAddress();
|
||||
|
||||
if (loader.isOverflow()) {
|
||||
UNSAFE.putByte(outputBase, output++, symbols[state2]);
|
||||
break;
|
||||
}
|
||||
|
||||
UNSAFE.putByte(outputBase, output++, symbols[state2]);
|
||||
int numberOfBits1 = numbersOfBits[state2];
|
||||
state2 = (int) (newStates[state2] + peekBits(bitsConsumed, bits, numberOfBits1));
|
||||
bitsConsumed += numberOfBits1;
|
||||
|
||||
loader = new BitStream.Loader(inputBase, input, currentAddress, bits, bitsConsumed);
|
||||
loader.load();
|
||||
bitsConsumed = loader.getBitsConsumed();
|
||||
bits = loader.getBits();
|
||||
currentAddress = loader.getCurrentAddress();
|
||||
|
||||
if (loader.isOverflow()) {
|
||||
UNSAFE.putByte(outputBase, output++, symbols[state1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (int) (output - outputAddress);
|
||||
}
|
||||
|
||||
public static final class Table
|
||||
{
|
||||
int log2Size;
|
||||
final int[] newState;
|
||||
final byte[] symbol;
|
||||
final byte[] numberOfBits;
|
||||
|
||||
public Table(int log2Size)
|
||||
{
|
||||
int size = 1 << log2Size;
|
||||
newState = new int[size];
|
||||
symbol = new byte[size];
|
||||
numberOfBits = new byte[size];
|
||||
}
|
||||
|
||||
public Table(int log2Size, int[] newState, byte[] symbol, byte[] numberOfBits)
|
||||
{
|
||||
int size = 1 << log2Size;
|
||||
if (newState.length != size || symbol.length != size || numberOfBits.length != size) {
|
||||
throw new IllegalArgumentException("Expected arrays to match provided size");
|
||||
}
|
||||
|
||||
this.log2Size = log2Size;
|
||||
this.newState = newState;
|
||||
this.symbol = symbol;
|
||||
this.numberOfBits = numberOfBits;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,182 +0,0 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.boydti.fawe.object.io.zstd;
|
||||
|
||||
import static com.boydti.fawe.object.io.zstd.UnsafeUtil.UNSAFE;
|
||||
import static com.boydti.fawe.object.io.zstd.Util.highestBit;
|
||||
import static com.boydti.fawe.object.io.zstd.Util.verify;
|
||||
|
||||
class FseTableReader
|
||||
{
|
||||
private static final int FSE_MIN_TABLE_LOG = 5;
|
||||
|
||||
public static final int FSE_MAX_SYMBOL_VALUE = 255;
|
||||
private final short[] nextSymbol = new short[FSE_MAX_SYMBOL_VALUE + 1];
|
||||
private final short[] normalizedCounters = new short[FSE_MAX_SYMBOL_VALUE + 1];
|
||||
|
||||
public int readFseTable(FiniteStateEntropy.Table table, Object inputBase, long inputAddress, long inputLimit, int maxSymbol, int maxTableLog)
|
||||
{
|
||||
// read table headers
|
||||
long input = inputAddress;
|
||||
verify(inputLimit - inputAddress >= 4, input, "Not enough input bytes");
|
||||
|
||||
int threshold;
|
||||
int symbolNumber = 0;
|
||||
boolean previousIsZero = false;
|
||||
|
||||
int bitStream = UNSAFE.getInt(inputBase, input);
|
||||
|
||||
int tableLog = (bitStream & 0xF) + FSE_MIN_TABLE_LOG;
|
||||
|
||||
int numberOfBits = tableLog + 1;
|
||||
bitStream >>>= 4;
|
||||
int bitCount = 4;
|
||||
|
||||
verify(tableLog <= maxTableLog, input, "FSE table size exceeds maximum allowed size");
|
||||
|
||||
int remaining = (1 << tableLog) + 1;
|
||||
threshold = 1 << tableLog;
|
||||
|
||||
while (remaining > 1 && symbolNumber <= maxSymbol) {
|
||||
if (previousIsZero) {
|
||||
int n0 = symbolNumber;
|
||||
while ((bitStream & 0xFFFF) == 0xFFFF) {
|
||||
n0 += 24;
|
||||
if (input < inputLimit - 5) {
|
||||
input += 2;
|
||||
bitStream = (UNSAFE.getInt(inputBase, input) >>> bitCount);
|
||||
}
|
||||
else {
|
||||
// end of bit stream
|
||||
bitStream >>>= 16;
|
||||
bitCount += 16;
|
||||
}
|
||||
}
|
||||
while ((bitStream & 3) == 3) {
|
||||
n0 += 3;
|
||||
bitStream >>>= 2;
|
||||
bitCount += 2;
|
||||
}
|
||||
n0 += bitStream & 3;
|
||||
bitCount += 2;
|
||||
|
||||
verify(n0 <= maxSymbol, input, "Symbol larger than max value");
|
||||
|
||||
while (symbolNumber < n0) {
|
||||
normalizedCounters[symbolNumber++] = 0;
|
||||
}
|
||||
if ((input <= inputLimit - 7) || (input + (bitCount >>> 3) <= inputLimit - 4)) {
|
||||
input += bitCount >>> 3;
|
||||
bitCount &= 7;
|
||||
bitStream = UNSAFE.getInt(inputBase, input) >>> bitCount;
|
||||
}
|
||||
else {
|
||||
bitStream >>>= 2;
|
||||
}
|
||||
}
|
||||
|
||||
short max = (short) ((2 * threshold - 1) - remaining);
|
||||
short count;
|
||||
|
||||
if ((bitStream & (threshold - 1)) < max) {
|
||||
count = (short) (bitStream & (threshold - 1));
|
||||
bitCount += numberOfBits - 1;
|
||||
}
|
||||
else {
|
||||
count = (short) (bitStream & (2 * threshold - 1));
|
||||
if (count >= threshold) {
|
||||
count -= max;
|
||||
}
|
||||
bitCount += numberOfBits;
|
||||
}
|
||||
count--; // extra accuracy
|
||||
|
||||
remaining -= Math.abs(count);
|
||||
normalizedCounters[symbolNumber++] = count;
|
||||
previousIsZero = count == 0;
|
||||
while (remaining < threshold) {
|
||||
numberOfBits--;
|
||||
threshold >>>= 1;
|
||||
}
|
||||
|
||||
if ((input <= inputLimit - 7) || (input + (bitCount >> 3) <= inputLimit - 4)) {
|
||||
input += bitCount >>> 3;
|
||||
bitCount &= 7;
|
||||
}
|
||||
else {
|
||||
bitCount -= (int) (8 * (inputLimit - 4 - input));
|
||||
input = inputLimit - 4;
|
||||
}
|
||||
bitStream = UNSAFE.getInt(inputBase, input) >>> (bitCount & 31);
|
||||
}
|
||||
|
||||
verify(remaining == 1 && bitCount <= 32, input, "Input is corrupted");
|
||||
|
||||
maxSymbol = symbolNumber - 1;
|
||||
verify(maxSymbol <= FSE_MAX_SYMBOL_VALUE, input, "Max symbol value too large (too many symbols for FSE)");
|
||||
|
||||
input += (bitCount + 7) >> 3;
|
||||
|
||||
// populate decoding table
|
||||
int symbolCount = maxSymbol + 1;
|
||||
int tableSize = 1 << tableLog;
|
||||
int highThreshold = tableSize - 1;
|
||||
|
||||
table.log2Size = tableLog;
|
||||
|
||||
for (byte symbol = 0; symbol < symbolCount; symbol++) {
|
||||
if (normalizedCounters[symbol] == -1) {
|
||||
table.symbol[highThreshold--] = symbol;
|
||||
nextSymbol[symbol] = 1;
|
||||
}
|
||||
else {
|
||||
nextSymbol[symbol] = normalizedCounters[symbol];
|
||||
}
|
||||
}
|
||||
|
||||
// spread symbols
|
||||
int tableMask = tableSize - 1;
|
||||
int step = (tableSize >>> 1) + (tableSize >>> 3) + 3;
|
||||
int position = 0;
|
||||
for (byte symbol = 0; symbol < symbolCount; symbol++) {
|
||||
for (int i = 0; i < normalizedCounters[symbol]; i++) {
|
||||
table.symbol[position] = symbol;
|
||||
do {
|
||||
position = (position + step) & tableMask;
|
||||
}
|
||||
while (position > highThreshold);
|
||||
}
|
||||
}
|
||||
|
||||
// position must reach all cells once, otherwise normalizedCounter is incorrect
|
||||
verify(position == 0, input, "Input is corrupted");
|
||||
|
||||
for (int i = 0; i < tableSize; i++) {
|
||||
byte symbol = table.symbol[i];
|
||||
short nextState = nextSymbol[symbol]++;
|
||||
table.numberOfBits[i] = (byte) (tableLog - highestBit(nextState));
|
||||
table.newState[i] = (short) ((nextState << table.numberOfBits[i]) - tableSize);
|
||||
}
|
||||
|
||||
return (int) (input - inputAddress);
|
||||
}
|
||||
|
||||
public static void buildRleTable(FiniteStateEntropy.Table table, byte value)
|
||||
{
|
||||
table.log2Size = 0;
|
||||
table.symbol[0] = value;
|
||||
table.newState[0] = 0;
|
||||
table.numberOfBits[0] = 0;
|
||||
}
|
||||
}
|
@ -1,317 +0,0 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.boydti.fawe.object.io.zstd;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
|
||||
import static com.boydti.fawe.object.io.zstd.BitStream.isEndOfStream;
|
||||
import static com.boydti.fawe.object.io.zstd.BitStream.peekBitsFast;
|
||||
import static com.boydti.fawe.object.io.zstd.UnsafeUtil.UNSAFE;
|
||||
import static com.boydti.fawe.object.io.zstd.Util.isPowerOf2;
|
||||
import static com.boydti.fawe.object.io.zstd.Util.verify;
|
||||
import static com.boydti.fawe.object.io.zstd.ZstdFrameDecompressor.SIZE_OF_INT;
|
||||
import static com.boydti.fawe.object.io.zstd.ZstdFrameDecompressor.SIZE_OF_SHORT;
|
||||
|
||||
class Huffman
|
||||
{
|
||||
private static final int MAX_SYMBOL = 255;
|
||||
private static final int MAX_TABLE_LOG = 12;
|
||||
|
||||
// stats
|
||||
private final byte[] weights = new byte[MAX_SYMBOL + 1];
|
||||
private final int[] ranks = new int[MAX_TABLE_LOG + 1];
|
||||
|
||||
// table
|
||||
private int tableLog = -1;
|
||||
private final byte[] symbols = new byte[1 << MAX_TABLE_LOG];
|
||||
private final byte[] numbersOfBits = new byte[1 << MAX_TABLE_LOG];
|
||||
|
||||
private final FiniteStateEntropy finiteStateEntropy = new FiniteStateEntropy(6);
|
||||
|
||||
public boolean isLoaded()
|
||||
{
|
||||
return tableLog != -1;
|
||||
}
|
||||
|
||||
public int readTable(final Object inputBase, final long inputAddress, final int size)
|
||||
{
|
||||
Arrays.fill(ranks, 0);
|
||||
long input = inputAddress;
|
||||
|
||||
// read table header
|
||||
verify(size > 0, input, "Not enough input bytes");
|
||||
int inputSize = UNSAFE.getByte(inputBase, input++) & 0xFF;
|
||||
|
||||
int outputSize;
|
||||
if (inputSize >= 128) {
|
||||
outputSize = inputSize - 127;
|
||||
inputSize = ((outputSize + 1) / 2);
|
||||
|
||||
verify(inputSize + 1 <= size, input, "Not enough input bytes");
|
||||
verify(outputSize <= MAX_SYMBOL + 1, input, "Input is corrupted");
|
||||
|
||||
for (int i = 0; i < outputSize; i += 2) {
|
||||
int value = UNSAFE.getByte(inputBase, input + i / 2) & 0xFF;
|
||||
weights[i] = (byte) (value >>> 4);
|
||||
weights[i + 1] = (byte) (value & 0b1111);
|
||||
}
|
||||
}
|
||||
else {
|
||||
verify(inputSize + 1 <= size, input, "Not enough input bytes");
|
||||
|
||||
outputSize = finiteStateEntropy.decompress(inputBase, input, input + inputSize, weights);
|
||||
}
|
||||
|
||||
int totalWeight = 0;
|
||||
for (int i = 0; i < outputSize; i++) {
|
||||
ranks[weights[i]]++;
|
||||
totalWeight += (1 << weights[i]) >> 1; // TODO same as 1 << (weights[n] - 1)?
|
||||
}
|
||||
verify(totalWeight != 0, input, "Input is corrupted");
|
||||
|
||||
tableLog = Util.highestBit(totalWeight) + 1;
|
||||
verify(tableLog <= MAX_TABLE_LOG, input, "Input is corrupted");
|
||||
|
||||
int total = 1 << tableLog;
|
||||
int rest = total - totalWeight;
|
||||
verify(isPowerOf2(rest), input, "Input is corrupted");
|
||||
|
||||
int lastWeight = Util.highestBit(rest) + 1;
|
||||
|
||||
weights[outputSize] = (byte) lastWeight;
|
||||
ranks[lastWeight]++;
|
||||
|
||||
int numberOfSymbols = outputSize + 1;
|
||||
|
||||
// populate table
|
||||
int nextRankStart = 0;
|
||||
for (int i = 1; i < tableLog + 1; ++i) {
|
||||
int current = nextRankStart;
|
||||
nextRankStart += ranks[i] << (i - 1);
|
||||
ranks[i] = current;
|
||||
}
|
||||
|
||||
for (int n = 0; n < numberOfSymbols; n++) {
|
||||
int weight = weights[n];
|
||||
int length = (1 << weight) >> 1; // TODO: 1 << (weight - 1) ??
|
||||
|
||||
byte symbol = (byte) n;
|
||||
byte numberOfBits = (byte) (tableLog + 1 - weight);
|
||||
for (int i = ranks[weight]; i < ranks[weight] + length; i++) {
|
||||
symbols[i] = symbol;
|
||||
numbersOfBits[i] = numberOfBits;
|
||||
}
|
||||
ranks[weight] += length;
|
||||
}
|
||||
|
||||
verify(ranks[1] >= 2 && (ranks[1] & 1) == 0, input, "Input is corrupted");
|
||||
|
||||
return inputSize + 1;
|
||||
}
|
||||
|
||||
public void decodeSingleStream(final Object inputBase, final long inputAddress, final long inputLimit, final Object outputBase, final long outputAddress, final long outputLimit)
|
||||
{
|
||||
BitStream.Initializer initializer = new BitStream.Initializer(inputBase, inputAddress, inputLimit);
|
||||
initializer.initialize();
|
||||
|
||||
long bits = initializer.getBits();
|
||||
int bitsConsumed = initializer.getBitsConsumed();
|
||||
long currentAddress = initializer.getCurrentAddress();
|
||||
|
||||
int tableLog = this.tableLog;
|
||||
byte[] numbersOfBits = this.numbersOfBits;
|
||||
byte[] symbols = this.symbols;
|
||||
|
||||
// 4 symbols at a time
|
||||
long output = outputAddress;
|
||||
long fastOutputLimit = outputLimit - 4;
|
||||
while (output < fastOutputLimit) {
|
||||
BitStream.Loader loader = new BitStream.Loader(inputBase, inputAddress, currentAddress, bits, bitsConsumed);
|
||||
boolean done = loader.load();
|
||||
bits = loader.getBits();
|
||||
bitsConsumed = loader.getBitsConsumed();
|
||||
currentAddress = loader.getCurrentAddress();
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
|
||||
bitsConsumed = decodeSymbol(outputBase, output, bits, bitsConsumed, tableLog, numbersOfBits, symbols);
|
||||
bitsConsumed = decodeSymbol(outputBase, output + 1, bits, bitsConsumed, tableLog, numbersOfBits, symbols);
|
||||
bitsConsumed = decodeSymbol(outputBase, output + 2, bits, bitsConsumed, tableLog, numbersOfBits, symbols);
|
||||
bitsConsumed = decodeSymbol(outputBase, output + 3, bits, bitsConsumed, tableLog, numbersOfBits, symbols);
|
||||
output += SIZE_OF_INT;
|
||||
}
|
||||
|
||||
decodeTail(inputBase, inputAddress, currentAddress, bitsConsumed, bits, outputBase, output, outputLimit);
|
||||
}
|
||||
|
||||
public void decode4Streams(final Object inputBase, final long inputAddress, final long inputLimit, final Object outputBase, final long outputAddress, final long outputLimit)
|
||||
{
|
||||
verify(inputLimit - inputAddress >= 10, inputAddress, "Input is corrupted"); // jump table + 1 byte per stream
|
||||
|
||||
long start1 = inputAddress + 3 * SIZE_OF_SHORT; // for the shorts we read below
|
||||
long start2 = start1 + (UNSAFE.getShort(inputBase, inputAddress) & 0xFFFF);
|
||||
long start3 = start2 + (UNSAFE.getShort(inputBase, inputAddress + 2) & 0xFFFF);
|
||||
long start4 = start3 + (UNSAFE.getShort(inputBase, inputAddress + 4) & 0xFFFF);
|
||||
|
||||
BitStream.Initializer initializer = new BitStream.Initializer(inputBase, start1, start2);
|
||||
initializer.initialize();
|
||||
int stream1bitsConsumed = initializer.getBitsConsumed();
|
||||
long stream1currentAddress = initializer.getCurrentAddress();
|
||||
long stream1bits = initializer.getBits();
|
||||
|
||||
initializer = new BitStream.Initializer(inputBase, start2, start3);
|
||||
initializer.initialize();
|
||||
int stream2bitsConsumed = initializer.getBitsConsumed();
|
||||
long stream2currentAddress = initializer.getCurrentAddress();
|
||||
long stream2bits = initializer.getBits();
|
||||
|
||||
initializer = new BitStream.Initializer(inputBase, start3, start4);
|
||||
initializer.initialize();
|
||||
int stream3bitsConsumed = initializer.getBitsConsumed();
|
||||
long stream3currentAddress = initializer.getCurrentAddress();
|
||||
long stream3bits = initializer.getBits();
|
||||
|
||||
initializer = new BitStream.Initializer(inputBase, start4, inputLimit);
|
||||
initializer.initialize();
|
||||
int stream4bitsConsumed = initializer.getBitsConsumed();
|
||||
long stream4currentAddress = initializer.getCurrentAddress();
|
||||
long stream4bits = initializer.getBits();
|
||||
|
||||
int segmentSize = (int) ((outputLimit - outputAddress + 3) / 4);
|
||||
|
||||
long outputStart2 = outputAddress + segmentSize;
|
||||
long outputStart3 = outputStart2 + segmentSize;
|
||||
long outputStart4 = outputStart3 + segmentSize;
|
||||
|
||||
long output1 = outputAddress;
|
||||
long output2 = outputStart2;
|
||||
long output3 = outputStart3;
|
||||
long output4 = outputStart4;
|
||||
|
||||
long fastOutputLimit = outputLimit - 7;
|
||||
int tableLog = this.tableLog;
|
||||
byte[] numbersOfBits = this.numbersOfBits;
|
||||
byte[] symbols = this.symbols;
|
||||
|
||||
while (output4 < fastOutputLimit) {
|
||||
stream1bitsConsumed = decodeSymbol(outputBase, output1, stream1bits, stream1bitsConsumed, tableLog, numbersOfBits, symbols);
|
||||
stream2bitsConsumed = decodeSymbol(outputBase, output2, stream2bits, stream2bitsConsumed, tableLog, numbersOfBits, symbols);
|
||||
stream3bitsConsumed = decodeSymbol(outputBase, output3, stream3bits, stream3bitsConsumed, tableLog, numbersOfBits, symbols);
|
||||
stream4bitsConsumed = decodeSymbol(outputBase, output4, stream4bits, stream4bitsConsumed, tableLog, numbersOfBits, symbols);
|
||||
|
||||
stream1bitsConsumed = decodeSymbol(outputBase, output1 + 1, stream1bits, stream1bitsConsumed, tableLog, numbersOfBits, symbols);
|
||||
stream2bitsConsumed = decodeSymbol(outputBase, output2 + 1, stream2bits, stream2bitsConsumed, tableLog, numbersOfBits, symbols);
|
||||
stream3bitsConsumed = decodeSymbol(outputBase, output3 + 1, stream3bits, stream3bitsConsumed, tableLog, numbersOfBits, symbols);
|
||||
stream4bitsConsumed = decodeSymbol(outputBase, output4 + 1, stream4bits, stream4bitsConsumed, tableLog, numbersOfBits, symbols);
|
||||
|
||||
stream1bitsConsumed = decodeSymbol(outputBase, output1 + 2, stream1bits, stream1bitsConsumed, tableLog, numbersOfBits, symbols);
|
||||
stream2bitsConsumed = decodeSymbol(outputBase, output2 + 2, stream2bits, stream2bitsConsumed, tableLog, numbersOfBits, symbols);
|
||||
stream3bitsConsumed = decodeSymbol(outputBase, output3 + 2, stream3bits, stream3bitsConsumed, tableLog, numbersOfBits, symbols);
|
||||
stream4bitsConsumed = decodeSymbol(outputBase, output4 + 2, stream4bits, stream4bitsConsumed, tableLog, numbersOfBits, symbols);
|
||||
|
||||
stream1bitsConsumed = decodeSymbol(outputBase, output1 + 3, stream1bits, stream1bitsConsumed, tableLog, numbersOfBits, symbols);
|
||||
stream2bitsConsumed = decodeSymbol(outputBase, output2 + 3, stream2bits, stream2bitsConsumed, tableLog, numbersOfBits, symbols);
|
||||
stream3bitsConsumed = decodeSymbol(outputBase, output3 + 3, stream3bits, stream3bitsConsumed, tableLog, numbersOfBits, symbols);
|
||||
stream4bitsConsumed = decodeSymbol(outputBase, output4 + 3, stream4bits, stream4bitsConsumed, tableLog, numbersOfBits, symbols);
|
||||
|
||||
output1 += SIZE_OF_INT;
|
||||
output2 += SIZE_OF_INT;
|
||||
output3 += SIZE_OF_INT;
|
||||
output4 += SIZE_OF_INT;
|
||||
|
||||
BitStream.Loader loader = new BitStream.Loader(inputBase, start1, stream1currentAddress, stream1bits, stream1bitsConsumed);
|
||||
boolean done = loader.load();
|
||||
stream1bitsConsumed = loader.getBitsConsumed();
|
||||
stream1bits = loader.getBits();
|
||||
stream1currentAddress = loader.getCurrentAddress();
|
||||
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
|
||||
loader = new BitStream.Loader(inputBase, start2, stream2currentAddress, stream2bits, stream2bitsConsumed);
|
||||
done = loader.load();
|
||||
stream2bitsConsumed = loader.getBitsConsumed();
|
||||
stream2bits = loader.getBits();
|
||||
stream2currentAddress = loader.getCurrentAddress();
|
||||
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
|
||||
loader = new BitStream.Loader(inputBase, start3, stream3currentAddress, stream3bits, stream3bitsConsumed);
|
||||
done = loader.load();
|
||||
stream3bitsConsumed = loader.getBitsConsumed();
|
||||
stream3bits = loader.getBits();
|
||||
stream3currentAddress = loader.getCurrentAddress();
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
|
||||
loader = new BitStream.Loader(inputBase, start4, stream4currentAddress, stream4bits, stream4bitsConsumed);
|
||||
done = loader.load();
|
||||
stream4bitsConsumed = loader.getBitsConsumed();
|
||||
stream4bits = loader.getBits();
|
||||
stream4currentAddress = loader.getCurrentAddress();
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
verify(output1 <= outputStart2 && output2 <= outputStart3 && output3 <= outputStart4, inputAddress, "Input is corrupted");
|
||||
|
||||
/// finish streams one by one
|
||||
decodeTail(inputBase, start1, stream1currentAddress, stream1bitsConsumed, stream1bits, outputBase, output1, outputStart2);
|
||||
decodeTail(inputBase, start2, stream2currentAddress, stream2bitsConsumed, stream2bits, outputBase, output2, outputStart3);
|
||||
decodeTail(inputBase, start3, stream3currentAddress, stream3bitsConsumed, stream3bits, outputBase, output3, outputStart4);
|
||||
decodeTail(inputBase, start4, stream4currentAddress, stream4bitsConsumed, stream4bits, outputBase, output4, outputLimit);
|
||||
}
|
||||
|
||||
private void decodeTail(final Object inputBase, final long startAddress, long currentAddress, int bitsConsumed, long bits, final Object outputBase, long outputAddress, final long outputLimit)
|
||||
{
|
||||
int tableLog = this.tableLog;
|
||||
byte[] numbersOfBits = this.numbersOfBits;
|
||||
byte[] symbols = this.symbols;
|
||||
|
||||
// closer to the end
|
||||
while (outputAddress < outputLimit) {
|
||||
BitStream.Loader loader = new BitStream.Loader(inputBase, startAddress, currentAddress, bits, bitsConsumed);
|
||||
boolean done = loader.load();
|
||||
bitsConsumed = loader.getBitsConsumed();
|
||||
bits = loader.getBits();
|
||||
currentAddress = loader.getCurrentAddress();
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
|
||||
bitsConsumed = decodeSymbol(outputBase, outputAddress++, bits, bitsConsumed, tableLog, numbersOfBits, symbols);
|
||||
}
|
||||
|
||||
// not more data in bit stream, so no need to reload
|
||||
while (outputAddress < outputLimit) {
|
||||
bitsConsumed = decodeSymbol(outputBase, outputAddress++, bits, bitsConsumed, tableLog, numbersOfBits, symbols);
|
||||
}
|
||||
|
||||
verify(isEndOfStream(startAddress, currentAddress, bitsConsumed), startAddress, "Bit stream is not fully consumed");
|
||||
}
|
||||
|
||||
private static int decodeSymbol(Object outputBase, long outputAddress, long bitContainer, int bitsConsumed, int tableLog, byte[] numbersOfBits, byte[] symbols)
|
||||
{
|
||||
int value = (int) peekBitsFast(bitsConsumed, bitContainer, tableLog);
|
||||
UNSAFE.putByte(outputBase, outputAddress, symbols[value]);
|
||||
return bitsConsumed + numbersOfBits[value];
|
||||
}
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.boydti.fawe.object.io.zstd;
|
||||
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.nio.Buffer;
|
||||
|
||||
final class UnsafeUtil
|
||||
{
|
||||
public static final Unsafe UNSAFE;
|
||||
private static final Field ADDRESS_ACCESSOR;
|
||||
|
||||
private UnsafeUtil() {}
|
||||
|
||||
static {
|
||||
try {
|
||||
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
|
||||
theUnsafe.setAccessible(true);
|
||||
UNSAFE = (Unsafe) theUnsafe.get(null);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
try {
|
||||
Field field = Buffer.class.getDeclaredField("address");
|
||||
field.setAccessible(true);
|
||||
ADDRESS_ACCESSOR = field;
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static long getAddress(Buffer buffer)
|
||||
{
|
||||
try {
|
||||
return (long) ADDRESS_ACCESSOR.get(buffer);
|
||||
}
|
||||
catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,108 +0,0 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.boydti.fawe.object.io.zstd;
|
||||
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
|
||||
import static com.boydti.fawe.object.io.zstd.UnsafeUtil.getAddress;
|
||||
import static sun.misc.Unsafe.ARRAY_BYTE_BASE_OFFSET;
|
||||
|
||||
public class ZstdDecompressor
|
||||
{
|
||||
private final ZstdFrameDecompressor decompressor = new ZstdFrameDecompressor();
|
||||
|
||||
public int decompress(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset, int maxOutputLength)
|
||||
throws MalformedInputException
|
||||
{
|
||||
long inputAddress = ARRAY_BYTE_BASE_OFFSET + inputOffset;
|
||||
long inputLimit = inputAddress + inputLength;
|
||||
long outputAddress = ARRAY_BYTE_BASE_OFFSET + outputOffset;
|
||||
long outputLimit = outputAddress + maxOutputLength;
|
||||
|
||||
return decompressor.decompress(input, inputAddress, inputLimit, output, outputAddress, outputLimit);
|
||||
}
|
||||
|
||||
public void decompress(ByteBuffer input, ByteBuffer output)
|
||||
throws MalformedInputException
|
||||
{
|
||||
Object inputBase;
|
||||
long inputAddress;
|
||||
long inputLimit;
|
||||
if (input.isDirect()) {
|
||||
inputBase = null;
|
||||
long address = getAddress(input);
|
||||
inputAddress = address + input.position();
|
||||
inputLimit = address + input.limit();
|
||||
}
|
||||
else if (input.hasArray()) {
|
||||
inputBase = input.array();
|
||||
inputAddress = ARRAY_BYTE_BASE_OFFSET + input.arrayOffset() + input.position();
|
||||
inputLimit = ARRAY_BYTE_BASE_OFFSET + input.arrayOffset() + input.limit();
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Unsupported input ByteBuffer implementation " + input.getClass().getName());
|
||||
}
|
||||
|
||||
Object outputBase;
|
||||
long outputAddress;
|
||||
long outputLimit;
|
||||
if (output.isDirect()) {
|
||||
outputBase = null;
|
||||
long address = getAddress(output);
|
||||
outputAddress = address + output.position();
|
||||
outputLimit = address + output.limit();
|
||||
}
|
||||
else if (output.hasArray()) {
|
||||
outputBase = output.array();
|
||||
outputAddress = ARRAY_BYTE_BASE_OFFSET + output.arrayOffset() + output.position();
|
||||
outputLimit = ARRAY_BYTE_BASE_OFFSET + output.arrayOffset() + output.limit();
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Unsupported output ByteBuffer implementation " + output.getClass().getName());
|
||||
}
|
||||
|
||||
// HACK: Assure JVM does not collect Slice wrappers while decompressing, since the
|
||||
// collection may trigger freeing of the underlying memory resulting in a segfault
|
||||
// There is no other known way to signal to the JVM that an object should not be
|
||||
// collected in a block, and technically, the JVM is allowed to eliminate these locks.
|
||||
synchronized (input) {
|
||||
synchronized (output) {
|
||||
int written = new ZstdFrameDecompressor().decompress(inputBase, inputAddress, inputLimit, outputBase, outputAddress, outputLimit);
|
||||
output.position(output.position() + written);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static long getDecompressedSize(byte[] input, int offset, int length)
|
||||
{
|
||||
int baseAddress = ARRAY_BYTE_BASE_OFFSET + offset;
|
||||
return ZstdFrameDecompressor.getDecompressedSize(input, baseAddress, baseAddress + length);
|
||||
}
|
||||
}
|
@ -1,958 +0,0 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.boydti.fawe.object.io.zstd;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
|
||||
import static com.boydti.fawe.object.io.zstd.BitStream.peekBits;
|
||||
import static com.boydti.fawe.object.io.zstd.UnsafeUtil.UNSAFE;
|
||||
import static com.boydti.fawe.object.io.zstd.Util.fail;
|
||||
import static com.boydti.fawe.object.io.zstd.Util.mask;
|
||||
import static com.boydti.fawe.object.io.zstd.Util.verify;
|
||||
import static sun.misc.Unsafe.ARRAY_BYTE_BASE_OFFSET;
|
||||
|
||||
class ZstdFrameDecompressor
|
||||
{
|
||||
private static final int MIN_MATCH = 3;
|
||||
|
||||
private static final int[] DEC_32_TABLE = {4, 1, 2, 1, 4, 4, 4, 4};
|
||||
private static final int[] DEC_64_TABLE = {0, 0, 0, -1, 0, 1, 2, 3};
|
||||
|
||||
private static final int MAGIC_NUMBER = 0xFD2FB528; // v0.5
|
||||
|
||||
private static final int MIN_SEQUENCES_SIZE = 1;
|
||||
private static final int MIN_BLOCK_SIZE = 1 // block type tag
|
||||
+ 1 // min size of raw or rle length header
|
||||
+ MIN_SEQUENCES_SIZE;
|
||||
|
||||
private static final int MAX_BLOCK_SIZE = 128 * 1024;
|
||||
|
||||
private static final int MIN_WINDOW_LOG = 10;
|
||||
private static final int MAX_WINDOW_SIZE = 1 << 23;
|
||||
|
||||
public static final int SIZE_OF_BYTE = 1;
|
||||
public static final int SIZE_OF_SHORT = 2;
|
||||
public static final int SIZE_OF_INT = 4;
|
||||
public static final int SIZE_OF_LONG = 8;
|
||||
|
||||
private static final long SIZE_OF_BLOCK_HEADER = 3;
|
||||
|
||||
// block types
|
||||
private static final int RAW_BLOCK = 0;
|
||||
private static final int RLE_BLOCK = 1;
|
||||
private static final int COMPRESSED_BLOCK = 2;
|
||||
|
||||
// literal block types
|
||||
private static final int RAW_LITERALS_BLOCK = 0;
|
||||
private static final int RLE_LITERALS_BLOCK = 1;
|
||||
private static final int COMPRESSED_LITERALS_BLOCK = 2;
|
||||
private static final int REPEAT_STATS_LITERALS_BLOCK = 3;
|
||||
|
||||
private static final int LONG_NUMBER_OF_SEQUENCES = 0x7F00;
|
||||
|
||||
private static final int MAX_LITERALS_LENGTH_SYMBOL = 35;
|
||||
private static final int MAX_MATCH_LENGTH_SYMBOL = 52;
|
||||
private static final int MAX_OFFSET_CODE_SYMBOL = 28;
|
||||
|
||||
private static final int LITERALS_LENGTH_FSE_LOG = 9;
|
||||
private static final int MATCH_LENGTH_FSE_LOG = 9;
|
||||
private static final int OFFSET_CODES_FSE_LOG = 8;
|
||||
|
||||
private static final int SET_BASIC = 0;
|
||||
private static final int SET_RLE = 1;
|
||||
private static final int SET_COMPRESSED = 2;
|
||||
private static final int SET_REPEAT = 3;
|
||||
|
||||
private static final int[] LITERALS_LENGTH_BASE = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 18, 20, 22, 24, 28, 32, 40, 48, 64, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000,
|
||||
0x2000, 0x4000, 0x8000, 0x10000};
|
||||
|
||||
private static final int[] MATCH_LENGTH_BASE = {
|
||||
3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
|
||||
19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
|
||||
35, 37, 39, 41, 43, 47, 51, 59, 67, 83, 99, 0x83, 0x103, 0x203, 0x403, 0x803,
|
||||
0x1003, 0x2003, 0x4003, 0x8003, 0x10003};
|
||||
|
||||
private static final int[] OFFSET_CODES_BASE = {
|
||||
0, 1, 1, 5, 0xD, 0x1D, 0x3D, 0x7D,
|
||||
0xFD, 0x1FD, 0x3FD, 0x7FD, 0xFFD, 0x1FFD, 0x3FFD, 0x7FFD,
|
||||
0xFFFD, 0x1FFFD, 0x3FFFD, 0x7FFFD, 0xFFFFD, 0x1FFFFD, 0x3FFFFD, 0x7FFFFD,
|
||||
0xFFFFFD, 0x1FFFFFD, 0x3FFFFFD, 0x7FFFFFD, 0xFFFFFFD};
|
||||
|
||||
private static final int[] LITERALS_LENGTH_BITS = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 1, 1, 1, 2, 2, 3, 3, 4, 6, 7, 8, 9, 10, 11, 12,
|
||||
13, 14, 15, 16};
|
||||
|
||||
private static final int[] MATCH_LENGTH_BITS = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 7, 8, 9, 10, 11,
|
||||
12, 13, 14, 15, 16};
|
||||
|
||||
private static final FiniteStateEntropy.Table DEFAULT_LITERALS_LENGTH_TABLE = new FiniteStateEntropy.Table(
|
||||
6,
|
||||
new int[] {
|
||||
0, 16, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 32, 0, 0, 32, 0, 32, 0, 32, 0, 0, 32, 0, 32, 0, 32, 0, 0, 16, 32, 0, 0, 48, 16, 32, 32, 32,
|
||||
32, 32, 32, 32, 32, 0, 32, 32, 32, 32, 32, 32, 0, 0, 0, 0},
|
||||
new byte[] {
|
||||
0, 0, 1, 3, 4, 6, 7, 9, 10, 12, 14, 16, 18, 19, 21, 22, 24, 25, 26, 27, 29, 31, 0, 1, 2, 4, 5, 7, 8, 10, 11, 13, 16, 17, 19, 20, 22, 23, 25, 25, 26, 28, 30, 0,
|
||||
1, 2, 3, 5, 6, 8, 9, 11, 12, 15, 17, 18, 20, 21, 23, 24, 35, 34, 33, 32},
|
||||
new byte[] {
|
||||
4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 6, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 4, 4, 5, 5, 5, 5, 5, 5, 5, 6, 5, 5, 5, 5, 5, 5, 4, 4, 5, 6, 6, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||
6, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6});
|
||||
|
||||
private static final FiniteStateEntropy.Table DEFAULT_OFFSET_CODES_TABLE = new FiniteStateEntropy.Table(
|
||||
5,
|
||||
new int[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0},
|
||||
new byte[] {0, 6, 9, 15, 21, 3, 7, 12, 18, 23, 5, 8, 14, 20, 2, 7, 11, 17, 22, 4, 8, 13, 19, 1, 6, 10, 16, 28, 27, 26, 25, 24},
|
||||
new byte[] {5, 4, 5, 5, 5, 5, 4, 5, 5, 5, 5, 4, 5, 5, 5, 4, 5, 5, 5, 5, 4, 5, 5, 5, 4, 5, 5, 5, 5, 5, 5, 5});
|
||||
|
||||
private static final FiniteStateEntropy.Table DEFAULT_MATCH_LENGTH_TABLE = new FiniteStateEntropy.Table(
|
||||
6,
|
||||
new int[] {
|
||||
0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 32, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 48, 16, 32, 32, 32, 32,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
new byte[] {
|
||||
0, 1, 2, 3, 5, 6, 8, 10, 13, 16, 19, 22, 25, 28, 31, 33, 35, 37, 39, 41, 43, 45, 1, 2, 3, 4, 6, 7, 9, 12, 15, 18, 21, 24, 27, 30, 32, 34, 36, 38, 40, 42, 44, 1,
|
||||
1, 2, 4, 5, 7, 8, 11, 14, 17, 20, 23, 26, 29, 52, 51, 50, 49, 48, 47, 46},
|
||||
new byte[] {
|
||||
6, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6,
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6});
|
||||
|
||||
private final byte[] literals = new byte[MAX_BLOCK_SIZE + SIZE_OF_LONG]; // extra space to allow for long-at-a-time copy
|
||||
|
||||
// current buffer containing literals
|
||||
private Object literalsBase;
|
||||
private long literalsAddress;
|
||||
private long literalsLimit;
|
||||
|
||||
private final int[] previousOffsets = new int[3];
|
||||
|
||||
private final FiniteStateEntropy.Table literalsLengthTable = new FiniteStateEntropy.Table(LITERALS_LENGTH_FSE_LOG);
|
||||
private final FiniteStateEntropy.Table offsetCodesTable = new FiniteStateEntropy.Table(OFFSET_CODES_FSE_LOG);
|
||||
private final FiniteStateEntropy.Table matchLengthTable = new FiniteStateEntropy.Table(MATCH_LENGTH_FSE_LOG);
|
||||
|
||||
private FiniteStateEntropy.Table currentLiteralsLengthTable;
|
||||
private FiniteStateEntropy.Table currentOffsetCodesTable;
|
||||
private FiniteStateEntropy.Table currentMatchLengthTable;
|
||||
|
||||
private final Huffman huffman = new Huffman();
|
||||
private final FseTableReader fse = new FseTableReader();
|
||||
|
||||
public int decompress(
|
||||
final Object inputBase,
|
||||
final long inputAddress,
|
||||
final long inputLimit,
|
||||
final Object outputBase,
|
||||
final long outputAddress,
|
||||
final long outputLimit)
|
||||
{
|
||||
if (outputAddress == outputLimit) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
reset();
|
||||
|
||||
long input = inputAddress;
|
||||
long output = outputAddress;
|
||||
|
||||
input += verifyMagic(inputBase, inputAddress, inputLimit);
|
||||
|
||||
FrameHeader frameHeader = readFrameHeader(inputBase, input, inputLimit);
|
||||
input += frameHeader.headerSize;
|
||||
|
||||
boolean lastBlock;
|
||||
do {
|
||||
verify(input + SIZE_OF_BLOCK_HEADER <= inputLimit, input, "Not enough input bytes");
|
||||
|
||||
// read block header
|
||||
int header = UNSAFE.getInt(inputBase, input) & 0xFF_FFFF;
|
||||
input += SIZE_OF_BLOCK_HEADER;
|
||||
|
||||
lastBlock = (header & 1) != 0;
|
||||
int blockType = (header >>> 1) & 0b11;
|
||||
int blockSize = (header >>> 3) & 0x1F_FFFF; // 21 bits
|
||||
|
||||
int decodedSize;
|
||||
switch (blockType) {
|
||||
case RAW_BLOCK:
|
||||
verify(inputAddress + blockSize <= inputLimit, input, "Not enough input bytes");
|
||||
decodedSize = decodeRawBlock(inputBase, input, blockSize, outputBase, output, outputLimit);
|
||||
input += blockSize;
|
||||
break;
|
||||
case RLE_BLOCK:
|
||||
verify(inputAddress + 1 <= inputLimit, input, "Not enough input bytes");
|
||||
decodedSize = decodeRleBlock(blockSize, inputBase, input, outputBase, output, outputLimit);
|
||||
input += 1;
|
||||
break;
|
||||
case COMPRESSED_BLOCK:
|
||||
verify(inputAddress + blockSize <= inputLimit, input, "Not enough input bytes");
|
||||
decodedSize = decodeCompressedBlock(inputBase, input, blockSize, outputBase, output, outputLimit, frameHeader.windowSize);
|
||||
input += blockSize;
|
||||
break;
|
||||
default:
|
||||
throw fail(input, "Invalid block type");
|
||||
}
|
||||
|
||||
output += decodedSize;
|
||||
}
|
||||
while (!lastBlock);
|
||||
|
||||
if (frameHeader.hasChecksum) {
|
||||
// TODO checksum
|
||||
}
|
||||
|
||||
return (int) (output - outputAddress);
|
||||
}
|
||||
|
||||
private void reset()
|
||||
{
|
||||
previousOffsets[0] = 1;
|
||||
previousOffsets[1] = 4;
|
||||
previousOffsets[2] = 8;
|
||||
|
||||
currentLiteralsLengthTable = null;
|
||||
currentOffsetCodesTable = null;
|
||||
currentMatchLengthTable = null;
|
||||
}
|
||||
|
||||
private static int decodeRawBlock(Object inputBase, long inputAddress, int blockSize, Object outputBase, long outputAddress, long outputLimit)
|
||||
{
|
||||
verify(outputAddress + blockSize <= outputLimit, inputAddress, "Output buffer too small");
|
||||
|
||||
UNSAFE.copyMemory(inputBase, inputAddress, outputBase, outputAddress, blockSize);
|
||||
return blockSize;
|
||||
}
|
||||
|
||||
private static int decodeRleBlock(int size, Object inputBase, long inputAddress, Object outputBase, long outputAddress, long outputLimit)
|
||||
{
|
||||
verify(outputAddress + size <= outputLimit, inputAddress, "Output buffer too small");
|
||||
|
||||
long output = outputAddress;
|
||||
long value = UNSAFE.getByte(inputBase, inputAddress) & 0xFFL;
|
||||
|
||||
int remaining = size;
|
||||
if (remaining >= SIZE_OF_LONG) {
|
||||
long packed = value
|
||||
| (value << 8)
|
||||
| (value << 16)
|
||||
| (value << 24)
|
||||
| (value << 32)
|
||||
| (value << 40)
|
||||
| (value << 48)
|
||||
| (value << 56);
|
||||
|
||||
do {
|
||||
UNSAFE.putLong(outputBase, output, packed);
|
||||
output += SIZE_OF_LONG;
|
||||
remaining -= SIZE_OF_LONG;
|
||||
}
|
||||
while (remaining >= SIZE_OF_LONG);
|
||||
}
|
||||
|
||||
for (int i = 0; i < remaining; i++) {
|
||||
UNSAFE.putByte(outputBase, output, (byte) value);
|
||||
output++;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
private int decodeCompressedBlock(Object inputBase, final long inputAddress, int blockSize, Object outputBase, long outputAddress, long outputLimit, int windowSize)
|
||||
{
|
||||
long inputLimit = inputAddress + blockSize;
|
||||
long input = inputAddress;
|
||||
|
||||
verify(blockSize <= MAX_BLOCK_SIZE, input, "Expected match length table to be present");
|
||||
verify(blockSize >= MIN_BLOCK_SIZE, input, "Compressed block size too small");
|
||||
|
||||
// decode literals
|
||||
int literalsBlockType = UNSAFE.getByte(inputBase, input) & 0b11;
|
||||
|
||||
switch (literalsBlockType) {
|
||||
case RAW_LITERALS_BLOCK: {
|
||||
input += decodeRawLiterals(inputBase, input, inputLimit);
|
||||
break;
|
||||
}
|
||||
case RLE_LITERALS_BLOCK: {
|
||||
input += decodeRleLiterals(inputBase, input, blockSize);
|
||||
break;
|
||||
}
|
||||
case REPEAT_STATS_LITERALS_BLOCK:
|
||||
verify(huffman.isLoaded(), input, "Dictionary is corrupted");
|
||||
case COMPRESSED_LITERALS_BLOCK: {
|
||||
input += decodeCompressedLiterals(inputBase, input, blockSize, literalsBlockType);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw fail(input, "Invalid literals block encoding type");
|
||||
}
|
||||
|
||||
verify(windowSize <= MAX_WINDOW_SIZE, input, "Window size too large (not yet supported)");
|
||||
|
||||
return decompressSequences(
|
||||
inputBase, input, inputAddress + blockSize,
|
||||
outputBase, outputAddress, outputLimit,
|
||||
literalsBase, literalsAddress, literalsLimit);
|
||||
}
|
||||
|
||||
private int decompressSequences(
|
||||
final Object inputBase, final long inputAddress, final long inputLimit,
|
||||
final Object outputBase, final long outputAddress, final long outputLimit,
|
||||
final Object literalsBase, final long literalsAddress, final long literalsLimit)
|
||||
{
|
||||
final long fastOutputLimit = outputLimit - SIZE_OF_LONG;
|
||||
|
||||
long input = inputAddress;
|
||||
long output = outputAddress;
|
||||
|
||||
long literalsInput = literalsAddress;
|
||||
|
||||
int size = (int) (inputLimit - inputAddress);
|
||||
verify(size >= MIN_SEQUENCES_SIZE, input, "Not enough input bytes");
|
||||
|
||||
// decode header
|
||||
int sequenceCount = UNSAFE.getByte(inputBase, input++) & 0xFF;
|
||||
if (sequenceCount != 0) {
|
||||
if (sequenceCount == 255) {
|
||||
verify(input + SIZE_OF_SHORT <= inputLimit, input, "Not enough input bytes");
|
||||
sequenceCount = (UNSAFE.getShort(inputBase, input) & 0xFFFF) + LONG_NUMBER_OF_SEQUENCES;
|
||||
input += SIZE_OF_SHORT;
|
||||
}
|
||||
else if (sequenceCount > 127) {
|
||||
verify(input < inputLimit, input, "Not enough input bytes");
|
||||
sequenceCount = ((sequenceCount - 128) << 8) + (UNSAFE.getByte(inputBase, input++) & 0xFF);
|
||||
}
|
||||
|
||||
verify(input + SIZE_OF_INT <= inputLimit, input, "Not enough input bytes");
|
||||
|
||||
byte type = UNSAFE.getByte(inputBase, input++);
|
||||
|
||||
int literalsLengthType = (type & 0xFF) >>> 6;
|
||||
int offsetCodesType = (type >>> 4) & 0b11;
|
||||
int matchLengthType = (type >>> 2) & 0b11;
|
||||
|
||||
input = computeLiteralsTable(literalsLengthType, inputBase, input, inputLimit);
|
||||
input = computeOffsetsTable(offsetCodesType, inputBase, input, inputLimit);
|
||||
input = computeMatchLengthTable(matchLengthType, inputBase, input, inputLimit);
|
||||
|
||||
// decompress sequences
|
||||
BitStream.Initializer initializer = new BitStream.Initializer(inputBase, input, inputLimit);
|
||||
initializer.initialize();
|
||||
int bitsConsumed = initializer.getBitsConsumed();
|
||||
long bits = initializer.getBits();
|
||||
long currentAddress = initializer.getCurrentAddress();
|
||||
|
||||
FiniteStateEntropy.Table currentLiteralsLengthTable = this.currentLiteralsLengthTable;
|
||||
FiniteStateEntropy.Table currentOffsetCodesTable = this.currentOffsetCodesTable;
|
||||
FiniteStateEntropy.Table currentMatchLengthTable = this.currentMatchLengthTable;
|
||||
|
||||
int literalsLengthState = (int) peekBits(bitsConsumed, bits, currentLiteralsLengthTable.log2Size);
|
||||
bitsConsumed += currentLiteralsLengthTable.log2Size;
|
||||
|
||||
int offsetCodesState = (int) peekBits(bitsConsumed, bits, currentOffsetCodesTable.log2Size);
|
||||
bitsConsumed += currentOffsetCodesTable.log2Size;
|
||||
|
||||
int matchLengthState = (int) peekBits(bitsConsumed, bits, currentMatchLengthTable.log2Size);
|
||||
bitsConsumed += currentMatchLengthTable.log2Size;
|
||||
|
||||
int[] previousOffsets = this.previousOffsets;
|
||||
|
||||
byte[] literalsLengthNumbersOfBits = currentLiteralsLengthTable.numberOfBits;
|
||||
int[] literalsLengthNewStates = currentLiteralsLengthTable.newState;
|
||||
byte[] literalsLengthSymbols = currentLiteralsLengthTable.symbol;
|
||||
|
||||
byte[] matchLengthNumbersOfBits = currentMatchLengthTable.numberOfBits;
|
||||
int[] matchLengthNewStates = currentMatchLengthTable.newState;
|
||||
byte[] matchLengthSymbols = currentMatchLengthTable.symbol;
|
||||
|
||||
byte[] offsetCodesNumbersOfBits = currentOffsetCodesTable.numberOfBits;
|
||||
int[] offsetCodesNewStates = currentOffsetCodesTable.newState;
|
||||
byte[] offsetCodesSymbols = currentOffsetCodesTable.symbol;
|
||||
|
||||
while (sequenceCount > 0) {
|
||||
sequenceCount--;
|
||||
|
||||
BitStream.Loader loader = new BitStream.Loader(inputBase, input, currentAddress, bits, bitsConsumed);
|
||||
loader.load();
|
||||
bitsConsumed = loader.getBitsConsumed();
|
||||
bits = loader.getBits();
|
||||
currentAddress = loader.getCurrentAddress();
|
||||
if (loader.isOverflow()) {
|
||||
verify(sequenceCount == 0, input, "Not all sequences were consumed");
|
||||
break;
|
||||
}
|
||||
|
||||
// decode sequence
|
||||
int literalsLengthCode = literalsLengthSymbols[literalsLengthState];
|
||||
int matchLengthCode = matchLengthSymbols[matchLengthState];
|
||||
int offsetCode = offsetCodesSymbols[offsetCodesState];
|
||||
|
||||
int literalsLengthBits = LITERALS_LENGTH_BITS[literalsLengthCode];
|
||||
int matchLengthBits = MATCH_LENGTH_BITS[matchLengthCode];
|
||||
int offsetBits = offsetCode;
|
||||
|
||||
int offset = OFFSET_CODES_BASE[offsetCode];
|
||||
if (offsetCode > 0) {
|
||||
offset += peekBits(bitsConsumed, bits, offsetBits);
|
||||
bitsConsumed += offsetBits;
|
||||
}
|
||||
|
||||
if (offsetCode <= 1) {
|
||||
if (literalsLengthCode == 0) {
|
||||
offset++;
|
||||
}
|
||||
|
||||
if (offset != 0) {
|
||||
int temp;
|
||||
if (offset == 3) {
|
||||
temp = previousOffsets[0] - 1;
|
||||
}
|
||||
else {
|
||||
temp = previousOffsets[offset];
|
||||
}
|
||||
|
||||
if (temp == 0) {
|
||||
temp = 1;
|
||||
}
|
||||
|
||||
if (offset != 1) {
|
||||
previousOffsets[2] = previousOffsets[1];
|
||||
}
|
||||
previousOffsets[1] = previousOffsets[0];
|
||||
previousOffsets[0] = temp;
|
||||
|
||||
offset = temp;
|
||||
}
|
||||
else {
|
||||
offset = previousOffsets[0];
|
||||
}
|
||||
}
|
||||
else {
|
||||
previousOffsets[2] = previousOffsets[1];
|
||||
previousOffsets[1] = previousOffsets[0];
|
||||
previousOffsets[0] = offset;
|
||||
}
|
||||
|
||||
int matchLength = MATCH_LENGTH_BASE[matchLengthCode];
|
||||
if (matchLengthCode > 31) {
|
||||
matchLength += peekBits(bitsConsumed, bits, matchLengthBits);
|
||||
bitsConsumed += matchLengthBits;
|
||||
}
|
||||
|
||||
int literalsLength = LITERALS_LENGTH_BASE[literalsLengthCode];
|
||||
if (literalsLengthCode > 15) {
|
||||
literalsLength += peekBits(bitsConsumed, bits, literalsLengthBits);
|
||||
bitsConsumed += literalsLengthBits;
|
||||
}
|
||||
|
||||
int totalBits = literalsLengthBits + matchLengthBits + offsetBits;
|
||||
if (totalBits > 64 - 7 - (LITERALS_LENGTH_FSE_LOG + MATCH_LENGTH_FSE_LOG + OFFSET_CODES_FSE_LOG)) {
|
||||
BitStream.Loader loader1 = new BitStream.Loader(inputBase, input, currentAddress, bits, bitsConsumed);
|
||||
loader1.load();
|
||||
|
||||
bitsConsumed = loader1.getBitsConsumed();
|
||||
bits = loader1.getBits();
|
||||
currentAddress = loader1.getCurrentAddress();
|
||||
}
|
||||
|
||||
int numberOfBits;
|
||||
|
||||
numberOfBits = literalsLengthNumbersOfBits[literalsLengthState];
|
||||
literalsLengthState = (int) (literalsLengthNewStates[literalsLengthState] + peekBits(bitsConsumed, bits, numberOfBits)); // <= 9 bits
|
||||
bitsConsumed += numberOfBits;
|
||||
|
||||
numberOfBits = matchLengthNumbersOfBits[matchLengthState];
|
||||
matchLengthState = (int) (matchLengthNewStates[matchLengthState] + peekBits(bitsConsumed, bits, numberOfBits)); // <= 9 bits
|
||||
bitsConsumed += numberOfBits;
|
||||
|
||||
numberOfBits = offsetCodesNumbersOfBits[offsetCodesState];
|
||||
offsetCodesState = (int) (offsetCodesNewStates[offsetCodesState] + peekBits(bitsConsumed, bits, numberOfBits)); // <= 8 bits
|
||||
bitsConsumed += numberOfBits;
|
||||
|
||||
final long literalOutputLimit = output + literalsLength;
|
||||
final long matchOutputLimit = literalOutputLimit + matchLength;
|
||||
|
||||
verify(matchOutputLimit <= outputLimit, input, "Output buffer too small");
|
||||
verify(literalsInput + literalsLength <= literalsLimit, input, "Input is corrupted");
|
||||
|
||||
long matchAddress = literalOutputLimit - offset;
|
||||
|
||||
if (literalOutputLimit > fastOutputLimit) {
|
||||
executeLastSequence(outputBase, output, literalOutputLimit, matchOutputLimit, fastOutputLimit, literalsInput, matchAddress);
|
||||
}
|
||||
else {
|
||||
// copy literals. literalOutputLimit <= fastOutputLimit, so we can copy
|
||||
// long at a time with over-copy
|
||||
output = copyLiterals(outputBase, literalsBase, output, literalsInput, literalOutputLimit);
|
||||
copyMatch(outputBase, fastOutputLimit, output, offset, matchOutputLimit, matchAddress);
|
||||
}
|
||||
output = matchOutputLimit;
|
||||
literalsInput += literalsLength;
|
||||
}
|
||||
}
|
||||
|
||||
// last literal segment
|
||||
output = copyLastLiteral(outputBase, literalsBase, literalsLimit, output, literalsInput);
|
||||
|
||||
return (int) (output - outputAddress);
|
||||
}
|
||||
|
||||
private long copyLastLiteral(Object outputBase, Object literalsBase, long literalsLimit, long output, long literalsInput)
|
||||
{
|
||||
long lastLiteralsSize = literalsLimit - literalsInput;
|
||||
UNSAFE.copyMemory(literalsBase, literalsInput, outputBase, output, lastLiteralsSize);
|
||||
output += lastLiteralsSize;
|
||||
return output;
|
||||
}
|
||||
|
||||
private void copyMatch(Object outputBase, long fastOutputLimit, long output, int offset, long matchOutputLimit, long matchAddress)
|
||||
{
|
||||
matchAddress = copyMatchHead(outputBase, output, offset, matchAddress);
|
||||
output += SIZE_OF_LONG;
|
||||
|
||||
copyMatchTail(outputBase, fastOutputLimit, output, matchOutputLimit, matchAddress);
|
||||
}
|
||||
|
||||
private void copyMatchTail(Object outputBase, long fastOutputLimit, long output, long matchOutputLimit, long matchAddress)
|
||||
{
|
||||
if (matchOutputLimit > fastOutputLimit) {
|
||||
while (output < fastOutputLimit) {
|
||||
UNSAFE.putLong(outputBase, output, UNSAFE.getLong(outputBase, matchAddress));
|
||||
matchAddress += SIZE_OF_LONG;
|
||||
output += SIZE_OF_LONG;
|
||||
}
|
||||
|
||||
while (output < matchOutputLimit) {
|
||||
UNSAFE.putByte(outputBase, output++, UNSAFE.getByte(outputBase, matchAddress++));
|
||||
}
|
||||
}
|
||||
else {
|
||||
while (output < matchOutputLimit) {
|
||||
UNSAFE.putLong(outputBase, output, UNSAFE.getLong(outputBase, matchAddress));
|
||||
matchAddress += SIZE_OF_LONG;
|
||||
output += SIZE_OF_LONG;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private long copyMatchHead(Object outputBase, long output, int offset, long matchAddress)
|
||||
{
|
||||
// copy match
|
||||
if (offset < 8) {
|
||||
// 8 bytes apart so that we can copy long-at-a-time below
|
||||
int increment32 = DEC_32_TABLE[offset];
|
||||
int decrement64 = DEC_64_TABLE[offset];
|
||||
|
||||
UNSAFE.putByte(outputBase, output, UNSAFE.getByte(outputBase, matchAddress));
|
||||
UNSAFE.putByte(outputBase, output + 1, UNSAFE.getByte(outputBase, matchAddress + 1));
|
||||
UNSAFE.putByte(outputBase, output + 2, UNSAFE.getByte(outputBase, matchAddress + 2));
|
||||
UNSAFE.putByte(outputBase, output + 3, UNSAFE.getByte(outputBase, matchAddress + 3));
|
||||
matchAddress += increment32;
|
||||
|
||||
UNSAFE.putInt(outputBase, output + 4, UNSAFE.getInt(outputBase, matchAddress));
|
||||
matchAddress -= decrement64;
|
||||
}
|
||||
else {
|
||||
UNSAFE.putLong(outputBase, output, UNSAFE.getLong(outputBase, matchAddress));
|
||||
matchAddress += SIZE_OF_LONG;
|
||||
}
|
||||
return matchAddress;
|
||||
}
|
||||
|
||||
private long copyLiterals(Object outputBase, Object literalsBase, long output, long literalsInput, long literalOutputLimit)
|
||||
{
|
||||
long literalInput = literalsInput;
|
||||
do {
|
||||
UNSAFE.putLong(outputBase, output, UNSAFE.getLong(literalsBase, literalInput));
|
||||
output += SIZE_OF_LONG;
|
||||
literalInput += SIZE_OF_LONG;
|
||||
}
|
||||
while (output < literalOutputLimit);
|
||||
output = literalOutputLimit; // correction in case we over-copied
|
||||
return output;
|
||||
}
|
||||
|
||||
private long computeMatchLengthTable(int matchLengthType, Object inputBase, long input, long inputLimit)
|
||||
{
|
||||
switch (matchLengthType) {
|
||||
case SET_RLE:
|
||||
verify(input < inputLimit, input, "Not enough input bytes");
|
||||
|
||||
byte value = UNSAFE.getByte(inputBase, input++);
|
||||
verify(value <= MAX_MATCH_LENGTH_SYMBOL, input, "Value exceeds expected maximum value");
|
||||
|
||||
FseTableReader.buildRleTable(matchLengthTable, value);
|
||||
currentMatchLengthTable = matchLengthTable;
|
||||
break;
|
||||
case SET_BASIC:
|
||||
currentMatchLengthTable = DEFAULT_MATCH_LENGTH_TABLE;
|
||||
break;
|
||||
case SET_REPEAT:
|
||||
verify(currentMatchLengthTable != null, input, "Expected match length table to be present");
|
||||
break;
|
||||
case SET_COMPRESSED:
|
||||
input += fse.readFseTable(matchLengthTable, inputBase, input, inputLimit, MAX_MATCH_LENGTH_SYMBOL, MATCH_LENGTH_FSE_LOG);
|
||||
currentMatchLengthTable = matchLengthTable;
|
||||
break;
|
||||
default:
|
||||
throw fail(input, "Invalid match length encoding type");
|
||||
}
|
||||
return input;
|
||||
}
|
||||
|
||||
private long computeOffsetsTable(int offsetCodesType, Object inputBase, long input, long inputLimit)
|
||||
{
|
||||
switch (offsetCodesType) {
|
||||
case SET_RLE:
|
||||
verify(input < inputLimit, input, "Not enough input bytes");
|
||||
|
||||
byte value = UNSAFE.getByte(inputBase, input++);
|
||||
verify(value <= MAX_OFFSET_CODE_SYMBOL, input, "Value exceeds expected maximum value");
|
||||
|
||||
FseTableReader.buildRleTable(offsetCodesTable, value);
|
||||
currentOffsetCodesTable = offsetCodesTable;
|
||||
break;
|
||||
case SET_BASIC:
|
||||
currentOffsetCodesTable = DEFAULT_OFFSET_CODES_TABLE;
|
||||
break;
|
||||
case SET_REPEAT:
|
||||
verify(currentOffsetCodesTable != null, input, "Expected match length table to be present");
|
||||
break;
|
||||
case SET_COMPRESSED:
|
||||
input += fse.readFseTable(offsetCodesTable, inputBase, input, inputLimit, MAX_OFFSET_CODE_SYMBOL, OFFSET_CODES_FSE_LOG);
|
||||
currentOffsetCodesTable = offsetCodesTable;
|
||||
break;
|
||||
default:
|
||||
throw fail(input, "Invalid offset code encoding type");
|
||||
}
|
||||
return input;
|
||||
}
|
||||
|
||||
private long computeLiteralsTable(int literalsLengthType, Object inputBase, long input, long inputLimit)
|
||||
{
|
||||
switch (literalsLengthType) {
|
||||
case SET_RLE:
|
||||
verify(input < inputLimit, input, "Not enough input bytes");
|
||||
|
||||
byte value = UNSAFE.getByte(inputBase, input++);
|
||||
verify(value <= MAX_LITERALS_LENGTH_SYMBOL, input, "Value exceeds expected maximum value");
|
||||
|
||||
FseTableReader.buildRleTable(literalsLengthTable, value);
|
||||
currentLiteralsLengthTable = literalsLengthTable;
|
||||
break;
|
||||
case SET_BASIC:
|
||||
currentLiteralsLengthTable = DEFAULT_LITERALS_LENGTH_TABLE;
|
||||
break;
|
||||
case SET_REPEAT:
|
||||
verify(currentLiteralsLengthTable != null, input, "Expected match length table to be present");
|
||||
break;
|
||||
case SET_COMPRESSED:
|
||||
input += fse.readFseTable(literalsLengthTable, inputBase, input, inputLimit, MAX_LITERALS_LENGTH_SYMBOL, LITERALS_LENGTH_FSE_LOG);
|
||||
currentLiteralsLengthTable = literalsLengthTable;
|
||||
break;
|
||||
default:
|
||||
throw fail(input, "Invalid literals length encoding type");
|
||||
}
|
||||
return input;
|
||||
}
|
||||
|
||||
private void executeLastSequence(Object outputBase, long output, long literalOutputLimit, long matchOutputLimit, long fastOutputLimit, long literalInput, long matchAddress)
|
||||
{
|
||||
// copy literals
|
||||
if (output < fastOutputLimit) {
|
||||
// wild copy
|
||||
do {
|
||||
UNSAFE.putLong(outputBase, output, UNSAFE.getLong(literalsBase, literalInput));
|
||||
output += SIZE_OF_LONG;
|
||||
literalInput += SIZE_OF_LONG;
|
||||
}
|
||||
while (output < fastOutputLimit);
|
||||
|
||||
literalInput -= output - fastOutputLimit;
|
||||
output = fastOutputLimit;
|
||||
}
|
||||
|
||||
while (output < literalOutputLimit) {
|
||||
UNSAFE.putByte(outputBase, output, UNSAFE.getByte(literalsBase, literalInput));
|
||||
output++;
|
||||
literalInput++;
|
||||
}
|
||||
|
||||
// copy match
|
||||
while (output < matchOutputLimit) {
|
||||
UNSAFE.putByte(outputBase, output, UNSAFE.getByte(outputBase, matchAddress));
|
||||
output++;
|
||||
matchAddress++;
|
||||
}
|
||||
}
|
||||
|
||||
private int decodeCompressedLiterals(Object inputBase, final long inputAddress, int blockSize, int literalsBlockType)
|
||||
{
|
||||
long input = inputAddress;
|
||||
verify(blockSize >= 5, input, "Not enough input bytes");
|
||||
|
||||
// compressed
|
||||
int compressedSize;
|
||||
int uncompressedSize;
|
||||
boolean singleStream = false;
|
||||
int headerSize;
|
||||
int type = (UNSAFE.getByte(inputBase, input) >> 2) & 0b11;
|
||||
switch (type) {
|
||||
case 0:
|
||||
singleStream = true;
|
||||
case 1: {
|
||||
int header = UNSAFE.getInt(inputBase, input);
|
||||
|
||||
headerSize = 3;
|
||||
uncompressedSize = (header >>> 4) & mask(10);
|
||||
compressedSize = (header >>> 14) & mask(10);
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
int header = UNSAFE.getInt(inputBase, input);
|
||||
|
||||
headerSize = 4;
|
||||
uncompressedSize = (header >>> 4) & mask(14);
|
||||
compressedSize = (header >>> 18) & mask(14);
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
// read 5 little-endian bytes
|
||||
long header = UNSAFE.getByte(inputBase, input) & 0xFF |
|
||||
(UNSAFE.getInt(inputBase, input + 1) & 0xFFFF_FFFFL) << 8;
|
||||
|
||||
headerSize = 5;
|
||||
uncompressedSize = (int) ((header >>> 4) & mask(18));
|
||||
compressedSize = (int) ((header >>> 22) & mask(18));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw fail(input, "Invalid literals header size type");
|
||||
}
|
||||
|
||||
verify(uncompressedSize <= MAX_BLOCK_SIZE, input, "Block exceeds maximum size");
|
||||
verify(headerSize + compressedSize <= blockSize, input, "Input is corrupted");
|
||||
|
||||
input += headerSize;
|
||||
|
||||
long inputLimit = input + compressedSize;
|
||||
if (literalsBlockType != REPEAT_STATS_LITERALS_BLOCK) {
|
||||
input += huffman.readTable(inputBase, input, compressedSize);
|
||||
}
|
||||
|
||||
literalsBase = literals;
|
||||
literalsAddress = ARRAY_BYTE_BASE_OFFSET;
|
||||
literalsLimit = ARRAY_BYTE_BASE_OFFSET + uncompressedSize;
|
||||
|
||||
if (singleStream) {
|
||||
huffman.decodeSingleStream(inputBase, input, inputLimit, literals, literalsAddress, literalsLimit);
|
||||
}
|
||||
else {
|
||||
huffman.decode4Streams(inputBase, input, inputLimit, literals, literalsAddress, literalsLimit);
|
||||
}
|
||||
|
||||
return headerSize + compressedSize;
|
||||
}
|
||||
|
||||
private int decodeRleLiterals(Object inputBase, final long inputAddress, int blockSize)
|
||||
{
|
||||
long input = inputAddress;
|
||||
int outputSize;
|
||||
|
||||
int type = (UNSAFE.getByte(inputBase, input) >> 2) & 0b11;
|
||||
switch (type) {
|
||||
case 0:
|
||||
case 2:
|
||||
outputSize = (UNSAFE.getByte(inputBase, input) & 0xFF) >>> 3;
|
||||
input++;
|
||||
break;
|
||||
case 1:
|
||||
outputSize = (UNSAFE.getShort(inputBase, input) & 0xFFFF) >>> 4;
|
||||
input += 2;
|
||||
break;
|
||||
case 3:
|
||||
// we need at least 4 bytes (3 for the header, 1 for the payload)
|
||||
verify(blockSize >= SIZE_OF_INT, input, "Not enough input bytes");
|
||||
outputSize = (UNSAFE.getInt(inputBase, input) & 0xFF_FFFF) >>> 4;
|
||||
input += 3;
|
||||
break;
|
||||
default:
|
||||
throw fail(input, "Invalid RLE literals header encoding type");
|
||||
}
|
||||
|
||||
verify(outputSize <= MAX_BLOCK_SIZE, input, "Output exceeds maximum block size");
|
||||
|
||||
byte value = UNSAFE.getByte(inputBase, input++);
|
||||
Arrays.fill(literals, 0, outputSize + SIZE_OF_LONG, value);
|
||||
|
||||
literalsBase = literals;
|
||||
literalsAddress = ARRAY_BYTE_BASE_OFFSET;
|
||||
literalsLimit = ARRAY_BYTE_BASE_OFFSET + outputSize;
|
||||
|
||||
return (int) (input - inputAddress);
|
||||
}
|
||||
|
||||
private int decodeRawLiterals(Object inputBase, final long inputAddress, long inputLimit)
|
||||
{
|
||||
long input = inputAddress;
|
||||
int type = (UNSAFE.getByte(inputBase, input) >> 2) & 0b11;
|
||||
|
||||
int literalSize;
|
||||
switch (type) {
|
||||
case 0:
|
||||
case 2:
|
||||
literalSize = (UNSAFE.getByte(inputBase, input) & 0xFF) >>> 3;
|
||||
input++;
|
||||
break;
|
||||
case 1:
|
||||
literalSize = (UNSAFE.getShort(inputBase, input) & 0xFFFF) >>> 4;
|
||||
input += 2;
|
||||
break;
|
||||
case 3:
|
||||
// read 3 little-endian bytes
|
||||
int header = ((UNSAFE.getByte(inputBase, input) & 0xFF) |
|
||||
((UNSAFE.getShort(inputBase, input + 1) & 0xFFFF) << 8));
|
||||
|
||||
literalSize = header >>> 4;
|
||||
input += 3;
|
||||
break;
|
||||
default:
|
||||
throw fail(input, "Invalid raw literals header encoding type");
|
||||
}
|
||||
|
||||
verify(input + literalSize <= inputLimit, input, "Not enough input bytes");
|
||||
|
||||
// Set literals pointer to [input, literalSize], but only if we can copy 8 bytes at a time during sequence decoding
|
||||
// Otherwise, copy literals into buffer that's big enough to guarantee that
|
||||
if (literalSize > (inputLimit - input) - SIZE_OF_LONG) {
|
||||
literalsBase = literals;
|
||||
literalsAddress = ARRAY_BYTE_BASE_OFFSET;
|
||||
literalsLimit = ARRAY_BYTE_BASE_OFFSET + literalSize;
|
||||
|
||||
UNSAFE.copyMemory(inputBase, input, literals, literalsAddress, literalSize);
|
||||
Arrays.fill(literals, literalSize, literalSize + SIZE_OF_LONG, (byte) 0);
|
||||
}
|
||||
else {
|
||||
literalsBase = inputBase;
|
||||
literalsAddress = input;
|
||||
literalsLimit = literalsAddress + literalSize;
|
||||
}
|
||||
input += literalSize;
|
||||
|
||||
return (int) (input - inputAddress);
|
||||
}
|
||||
|
||||
private static FrameHeader readFrameHeader(final Object inputBase, final long inputAddress, final long inputLimit)
|
||||
{
|
||||
long input = inputAddress;
|
||||
verify(input < inputLimit, input, "Not enough input bytes");
|
||||
|
||||
int frameHeaderDescriptor = UNSAFE.getByte(inputBase, input++) & 0xFF;
|
||||
boolean singleSegment = (frameHeaderDescriptor & 0b100000) != 0;
|
||||
int dictionaryDescriptor = frameHeaderDescriptor & 0b11;
|
||||
int contentSizeDescriptor = frameHeaderDescriptor >>> 6;
|
||||
|
||||
int headerSize = 1 +
|
||||
(singleSegment ? 0 : 1) +
|
||||
(dictionaryDescriptor == 0 ? 0 : (1 << (dictionaryDescriptor - 1))) +
|
||||
(contentSizeDescriptor == 0 ? (singleSegment ? 1 : 0) : (1 << contentSizeDescriptor));
|
||||
|
||||
verify(headerSize <= inputLimit - inputAddress, input, "Not enough input bytes");
|
||||
|
||||
// decode window size
|
||||
int windowSize = -1;
|
||||
if (!singleSegment) {
|
||||
int windowDescriptor = UNSAFE.getByte(inputBase, input++) & 0xFF;
|
||||
int exponent = windowDescriptor >>> 3;
|
||||
int mantissa = windowDescriptor & 0b111;
|
||||
|
||||
int base = 1 << (MIN_WINDOW_LOG + exponent);
|
||||
windowSize = base + (base / 8) * mantissa;
|
||||
}
|
||||
|
||||
// decode dictionary id
|
||||
long dictionaryId = -1;
|
||||
switch (dictionaryDescriptor) {
|
||||
case 1:
|
||||
dictionaryId = UNSAFE.getByte(inputBase, input) & 0xFF;
|
||||
input += SIZE_OF_BYTE;
|
||||
break;
|
||||
case 2:
|
||||
dictionaryId = UNSAFE.getShort(inputBase, input) & 0xFFFF;
|
||||
input += SIZE_OF_SHORT;
|
||||
break;
|
||||
case 3:
|
||||
dictionaryId = UNSAFE.getInt(inputBase, input) & 0xFFFF_FFFFL;
|
||||
input += SIZE_OF_INT;
|
||||
break;
|
||||
}
|
||||
verify(dictionaryId == -1, input, "Custom dictionaries not supported");
|
||||
|
||||
// decode content size
|
||||
long contentSize = -1;
|
||||
switch (contentSizeDescriptor) {
|
||||
case 0:
|
||||
if (singleSegment) {
|
||||
contentSize = UNSAFE.getByte(inputBase, input) & 0xFF;
|
||||
input += SIZE_OF_BYTE;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
contentSize = UNSAFE.getShort(inputBase, input) & 0xFFFF;
|
||||
contentSize += 256;
|
||||
input += SIZE_OF_SHORT;
|
||||
break;
|
||||
case 2:
|
||||
contentSize = UNSAFE.getInt(inputBase, input) & 0xFFFF_FFFFL;
|
||||
input += SIZE_OF_INT;
|
||||
break;
|
||||
case 3:
|
||||
contentSize = UNSAFE.getLong(inputBase, input);
|
||||
input += SIZE_OF_LONG;
|
||||
break;
|
||||
}
|
||||
|
||||
boolean hasChecksum = (frameHeaderDescriptor & 0b100) != 0;
|
||||
|
||||
return new FrameHeader(
|
||||
input - inputAddress,
|
||||
windowSize,
|
||||
contentSize,
|
||||
dictionaryId,
|
||||
hasChecksum);
|
||||
}
|
||||
|
||||
public static long getDecompressedSize(final Object inputBase, final long inputAddress, final long inputLimit)
|
||||
{
|
||||
long input = inputAddress;
|
||||
input += verifyMagic(inputBase, input, inputLimit);
|
||||
return readFrameHeader(inputBase, input, inputLimit).contentSize;
|
||||
}
|
||||
|
||||
private static int verifyMagic(Object inputBase, long inputAddress, long inputLimit)
|
||||
{
|
||||
verify(inputLimit - inputAddress >= 4, inputAddress, "Not enough input bytes");
|
||||
|
||||
int magic = UNSAFE.getInt(inputBase, inputAddress);
|
||||
if (magic != MAGIC_NUMBER) {
|
||||
throw new MalformedInputException(inputAddress, "Invalid magic prefix: " + Integer.toHexString(magic));
|
||||
}
|
||||
|
||||
return SIZE_OF_INT;
|
||||
}
|
||||
}
|
@ -23,7 +23,6 @@ public class ReflectionUtils {
|
||||
return t.isInstance(o) ? t.cast(o) : null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T extends Enum<?>> T addEnum(Class<T> enumType, String enumName) {
|
||||
try {
|
||||
return addEnum(enumType, enumName, new Class<?>[]{}, new Object[]{});
|
||||
|
@ -157,19 +157,6 @@ public class PlayerWrapper extends AbstractPlayerActor {
|
||||
parent.setGameMode(gameMode);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////
|
||||
/////////////////////////////////////////
|
||||
/////////////////////////////////////////
|
||||
|
||||
/////////////////////////////////////////
|
||||
/////////////////////////////////////////
|
||||
/////////////////////////////////////////
|
||||
|
||||
/////////////////////////////////////////
|
||||
/////////////////////////////////////////
|
||||
/////////////////////////////////////////
|
||||
|
||||
|
||||
@Override
|
||||
public void findFreePosition(final Location searchPos) {
|
||||
TaskManager.IMP.sync(new RunnableVal<Boolean>() {
|
||||
|
@ -19,19 +19,13 @@
|
||||
|
||||
package com.sk89q.util;
|
||||
|
||||
import sun.reflect.ConstructorAccessor;
|
||||
import sun.reflect.FieldAccessor;
|
||||
import sun.reflect.ReflectionFactory;
|
||||
|
||||
import java.lang.reflect.*;
|
||||
import java.util.*;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public final class ReflectionUtil {
|
||||
|
||||
private ReflectionUtil() {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T getField(Object from, String name) {
|
||||
if (from instanceof Class)
|
||||
return getField((Class) from, null, name);
|
||||
|
@ -570,6 +570,7 @@ public class LocalSession implements TextureHolder {
|
||||
newEditSession.setBlocks(changeSet, ChangeSetExecutor.Type.REDO);
|
||||
return newEditSession;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -625,14 +626,6 @@ public class LocalSession implements TextureHolder {
|
||||
return selector;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use {@link #getRegionSelector(World)}
|
||||
*/
|
||||
@Deprecated
|
||||
public RegionSelector getRegionSelector() {
|
||||
return selector;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the region selector.
|
||||
*
|
||||
@ -646,16 +639,6 @@ public class LocalSession implements TextureHolder {
|
||||
this.selector = selector;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the region is fully defined.
|
||||
*
|
||||
* @return true if a region selection is defined
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean isRegionDefined() {
|
||||
return selector.isDefined();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the region is fully defined for the specified world.
|
||||
*
|
||||
@ -670,14 +653,6 @@ public class LocalSession implements TextureHolder {
|
||||
return selector.isDefined();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use {@link #getSelection(World)}
|
||||
*/
|
||||
@Deprecated
|
||||
public Region getRegion() throws IncompleteRegionException {
|
||||
return selector.getRegion();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the selection region. If you change the region, you should
|
||||
* call learnRegionChanges(). If the selection is defined in
|
||||
@ -907,7 +882,7 @@ public class LocalSession implements TextureHolder {
|
||||
public BlockVector3 getPlacementPosition(Player player) throws IncompleteRegionException {
|
||||
checkNotNull(player);
|
||||
if (!placeAtPos1) {
|
||||
return player.getBlockIn().toBlockPoint();
|
||||
return player.getBlockIn().toVector().toBlockPoint();
|
||||
}
|
||||
|
||||
return selector.getPrimaryPosition();
|
||||
@ -976,6 +951,12 @@ public class LocalSession implements TextureHolder {
|
||||
this.pickaxeMode = tool;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the tool assigned to the item.
|
||||
*
|
||||
* @param item the item type
|
||||
* @return the tool, which may be {@code null}
|
||||
*/
|
||||
@Nullable
|
||||
public Tool getTool(ItemType item) {
|
||||
return tools[item.getInternalId()];
|
||||
@ -1012,11 +993,6 @@ public class LocalSession implements TextureHolder {
|
||||
return getBrushTool(item.getDefaultState(), null, true);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public BrushTool getBrushTool(BaseItem item) throws InvalidToolBindException {
|
||||
return getBrushTool(item, null, true);
|
||||
}
|
||||
|
||||
public BrushTool getBrushTool(Player player) throws InvalidToolBindException {
|
||||
return getBrushTool(player, true);
|
||||
}
|
||||
@ -1048,7 +1024,6 @@ public class LocalSession implements TextureHolder {
|
||||
* @param tool the tool to set, which can be {@code null}
|
||||
* @throws InvalidToolBindException if the item can't be bound to that item
|
||||
*/
|
||||
@Deprecated
|
||||
public void setTool(ItemType item, @Nullable Tool tool) throws InvalidToolBindException {
|
||||
setTool(item.getDefaultState(), tool, null);
|
||||
}
|
||||
@ -1141,7 +1116,6 @@ public class LocalSession implements TextureHolder {
|
||||
public void tellVersion(Actor player) {
|
||||
}
|
||||
|
||||
|
||||
public boolean shouldUseServerCUI() {
|
||||
return this.useServerCUI;
|
||||
}
|
||||
@ -1209,9 +1183,8 @@ public class LocalSession implements TextureHolder {
|
||||
|
||||
if (hasCUISupport) {
|
||||
actor.dispatchCUIEvent(event);
|
||||
} else if (actor.isPlayer()) {
|
||||
CUI cui = Fawe.get().getCUI(actor);
|
||||
if (cui != null) cui.dispatchCUIEvent(event);
|
||||
} else if (useServerCUI) {
|
||||
updateServerCUI(actor);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1243,12 +1216,13 @@ public class LocalSession implements TextureHolder {
|
||||
CUIRegion tempSel = (CUIRegion) selector;
|
||||
|
||||
if (tempSel.getProtocolVersion() > cuiVersion) {
|
||||
dispatchCUIEvent(actor, new SelectionShapeEvent(tempSel.getLegacyTypeID()));
|
||||
actor.dispatchCUIEvent(new SelectionShapeEvent(tempSel.getLegacyTypeID()));
|
||||
tempSel.describeLegacyCUI(this, actor);
|
||||
} else {
|
||||
dispatchCUIEvent(actor, new SelectionShapeEvent(tempSel.getTypeID()));
|
||||
actor.dispatchCUIEvent(new SelectionShapeEvent(tempSel.getTypeID()));
|
||||
tempSel.describeCUI(this, actor);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -1259,6 +1233,11 @@ public class LocalSession implements TextureHolder {
|
||||
*/
|
||||
public void describeCUI(Actor actor) {
|
||||
checkNotNull(actor);
|
||||
|
||||
if (!hasCUISupport) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (selector instanceof CUIRegion) {
|
||||
CUIRegion tempSel = (CUIRegion) selector;
|
||||
|
||||
@ -1285,18 +1264,15 @@ public class LocalSession implements TextureHolder {
|
||||
String[] split = text.split("\\|", 2);
|
||||
if (split.length > 1 && split[0].equalsIgnoreCase("v")) { // enough fields and right message
|
||||
if (split[1].length() > 4) {
|
||||
this.failedCuiAttempts++;
|
||||
this.failedCuiAttempts ++;
|
||||
return;
|
||||
}
|
||||
setCUISupport(true);
|
||||
try {
|
||||
setCUIVersion(Integer.parseInt(split[1]));
|
||||
} catch (NumberFormatException e) {
|
||||
String msg = e.getMessage();
|
||||
if (msg != null && msg.length() > 256) msg = msg.substring(0, 256);
|
||||
this.failedCuiAttempts++;
|
||||
WorldEdit.logger.warn("Error while reading CUI init message for player " + uuid + ": " + msg);
|
||||
|
||||
WorldEdit.logger.warn("Error while reading CUI init message: " + e.getMessage());
|
||||
this.failedCuiAttempts ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1364,7 +1340,6 @@ public class LocalSession implements TextureHolder {
|
||||
* @param player the player
|
||||
* @return an edit session
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public EditSession createEditSession(Player player) {
|
||||
checkNotNull(player);
|
||||
|
||||
|
@ -23,7 +23,7 @@ import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweVersion;
|
||||
import com.boydti.fawe.config.BBC;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.util.*;
|
||||
import com.boydti.fawe.util.IncendoPaster;
|
||||
import com.sk89q.minecraft.util.commands.Command;
|
||||
import com.sk89q.minecraft.util.commands.CommandContext;
|
||||
import com.sk89q.minecraft.util.commands.CommandPermissions;
|
||||
@ -32,16 +32,24 @@ import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.event.platform.ConfigurationLoadEvent;
|
||||
import com.sk89q.worldedit.extension.platform.*;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import com.sk89q.worldedit.extension.platform.Capability;
|
||||
import com.sk89q.worldedit.extension.platform.Capability;
|
||||
import com.sk89q.worldedit.extension.platform.CommandManager;
|
||||
import com.sk89q.worldedit.extension.platform.Platform;
|
||||
import com.sk89q.worldedit.extension.platform.Platform;
|
||||
import com.sk89q.worldedit.extension.platform.PlatformManager;
|
||||
import com.sk89q.worldedit.extension.platform.PlatformManager;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
|
||||
@Command(aliases = {"worldedit", "we", "fawe"}, desc = "Updating, informational, debug and help commands")
|
||||
public class WorldEditCommands {
|
||||
@ -54,7 +62,7 @@ public class WorldEditCommands {
|
||||
}
|
||||
|
||||
@Command(
|
||||
aliases = {"version", "ver"},
|
||||
aliases = { "version", "ver" },
|
||||
usage = "",
|
||||
desc = "Get WorldEdit/FAWE version",
|
||||
min = 0,
|
||||
@ -64,9 +72,9 @@ public class WorldEditCommands {
|
||||
public void version(Actor actor) throws WorldEditException {
|
||||
FaweVersion fVer = Fawe.get().getVersion();
|
||||
String fVerStr = fVer == null ? "unknown" : "-" + fVer.build;
|
||||
actor.print(BBC.getPrefix() + "FastAsyncWorldEdit-1.13" + fVerStr + " by Empire92");
|
||||
actor.print("FastAsyncWorldEdit-1.13" + fVerStr + " by Empire92");
|
||||
if (fVer != null) {
|
||||
actor.printDebug("------------------------------------");
|
||||
actor.printDebug("----------- Platforms -----------");
|
||||
FaweVersion version = Fawe.get().getVersion();
|
||||
Date date = new GregorianCalendar(2000 + version.year, version.month - 1, version.day).getTime();
|
||||
actor.printDebug(" - DATE: " + date.toLocaleString());
|
||||
@ -76,11 +84,13 @@ public class WorldEditCommands {
|
||||
actor.printDebug("------------------------------------");
|
||||
}
|
||||
PlatformManager pm = we.getPlatformManager();
|
||||
actor.printDebug("Platforms:");
|
||||
|
||||
actor.printDebug("----------- Platforms -----------");
|
||||
for (Platform platform : pm.getPlatforms()) {
|
||||
actor.printDebug(String.format(" - %s", platform.getPlatformName()));
|
||||
actor.printDebug(String.format("* %s", platform.getPlatformName()));
|
||||
}
|
||||
actor.printDebug("Capabilities:");
|
||||
|
||||
actor.printDebug("----------- Capabilities -----------");
|
||||
for (Capability capability : Capability.values()) {
|
||||
Platform platform = pm.queryCapability(capability);
|
||||
actor.printDebug(String.format(" - %s: %s", capability.name(), platform != null ? platform.getPlatformName() : "NONE"));
|
||||
@ -90,7 +100,7 @@ public class WorldEditCommands {
|
||||
}
|
||||
|
||||
@Command(
|
||||
aliases = {"reload"},
|
||||
aliases = { "reload" },
|
||||
usage = "",
|
||||
desc = "Reload configuration and translations",
|
||||
min = 0,
|
||||
@ -102,7 +112,7 @@ public class WorldEditCommands {
|
||||
we.getEventBus().post(new ConfigurationLoadEvent(we.getPlatformManager().queryCapability(Capability.CONFIGURATION).getConfiguration()));
|
||||
Fawe.get().setupConfigs();
|
||||
CommandManager.getInstance().register(we.getPlatformManager().queryCapability(Capability.USER_COMMANDS));
|
||||
actor.print(BBC.getPrefix() + "Reloaded FastAsyncWorldEdit configuration and translation files");
|
||||
actor.print("Configuration and translations reloaded!");
|
||||
}
|
||||
|
||||
@Command(
|
||||
@ -139,7 +149,7 @@ public class WorldEditCommands {
|
||||
}
|
||||
|
||||
@Command(
|
||||
aliases = {"cui"},
|
||||
aliases = { "cui" },
|
||||
usage = "",
|
||||
desc = "Complete CUI handshake (internal usage)",
|
||||
min = 0,
|
||||
@ -151,7 +161,7 @@ public class WorldEditCommands {
|
||||
}
|
||||
|
||||
@Command(
|
||||
aliases = {"tz"},
|
||||
aliases = { "tz" },
|
||||
usage = "[timezone]",
|
||||
desc = "Set your timezone for snapshots",
|
||||
min = 1,
|
||||
@ -165,13 +175,14 @@ public class WorldEditCommands {
|
||||
}
|
||||
|
||||
@Command(
|
||||
aliases = {"help"},
|
||||
aliases = { "help" },
|
||||
usage = "[<command>]",
|
||||
desc = "Displays help for FAWE commands",
|
||||
min = 0,
|
||||
max = -1,
|
||||
queued = false
|
||||
)
|
||||
@CommandPermissions("worldedit.help")
|
||||
public void help(Actor actor, CommandContext args) throws WorldEditException {
|
||||
UtilityCommands.help(args, we, actor);
|
||||
}
|
||||
|
@ -42,7 +42,6 @@ import com.sk89q.worldedit.world.gamemode.GameMode;
|
||||
import com.sk89q.worldedit.world.gamemode.GameModes;
|
||||
import com.sk89q.worldedit.world.item.ItemType;
|
||||
import com.sk89q.worldedit.world.item.ItemTypes;
|
||||
import com.sk89q.worldedit.world.registry.BlockMaterial;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
@ -137,7 +136,7 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
|
||||
final BlockVector3 pos = BlockVector3.at(x, y, z);
|
||||
final BlockState id = world.getBlock(pos);
|
||||
if (id.getBlockType().getMaterial().isMovementBlocker()) {
|
||||
setPosition(new Location(world, Vector3.at(x + 0.5, y + + BlockTypeUtil.centralTopLimit(id), z + 0.5)));
|
||||
setPosition(Vector3.at(x + 0.5, y + 1, z + 0.5));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -158,47 +157,36 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
|
||||
final int z = pos.getBlockZ();
|
||||
final Extent world = pos.getExtent();
|
||||
|
||||
int maxY = world.getMaxY();
|
||||
if (y >= maxY) return false;
|
||||
byte free = 0;
|
||||
byte spots = 0;
|
||||
|
||||
BlockMaterial initialMaterial = world.getBlockType(BlockVector3.at(x, y, z)).getMaterial();
|
||||
|
||||
boolean lastState = initialMaterial.isMovementBlocker() && initialMaterial.isFullCube();
|
||||
|
||||
double height = 1.85;
|
||||
double freeStart = -1;
|
||||
|
||||
for (int level = y + 1; level <= maxY + 2; level++) {
|
||||
BlockState state;
|
||||
if (level >= maxY) state = BlockTypes.VOID_AIR.getDefaultState();
|
||||
else state = world.getBlock(BlockVector3.at(x, level, z));
|
||||
BlockType type = state.getBlockType();
|
||||
BlockMaterial material = type.getMaterial();
|
||||
|
||||
if (!material.isFullCube() || !material.isMovementBlocker()) {
|
||||
if (!lastState) {
|
||||
lastState = BlockTypeUtil.centralBottomLimit(state) != 1;
|
||||
continue;
|
||||
}
|
||||
if (freeStart == -1) {
|
||||
freeStart = level + BlockTypeUtil.centralTopLimit(state);
|
||||
while (y <= world.getMaximumPoint().getY() + 2) {
|
||||
if (!world.getBlock(BlockVector3.at(x, y, z)).getBlockType().getMaterial().isMovementBlocker()) {
|
||||
++free;
|
||||
} else {
|
||||
double bottomLimit = BlockTypeUtil.centralBottomLimit(state);
|
||||
double space = level + bottomLimit - freeStart;
|
||||
if (space >= height) {
|
||||
setPosition(Vector3.at(x + 0.5, freeStart, z + 0.5));
|
||||
free = 0;
|
||||
}
|
||||
|
||||
if (free == 2) {
|
||||
++spots;
|
||||
if (spots == 2) {
|
||||
final BlockVector3 platform = BlockVector3.at(x, y - 2, z);
|
||||
final BlockState block = world.getBlock(platform);
|
||||
final com.sk89q.worldedit.world.block.BlockType type = block.getBlockType();
|
||||
|
||||
// Don't get put in lava!
|
||||
if (type == BlockTypes.LAVA) {
|
||||
return false;
|
||||
}
|
||||
|
||||
setPosition(platform.toVector3().add(0.5, 1, 0.5));
|
||||
return true;
|
||||
}
|
||||
// Not enough room, reset the free position
|
||||
if (bottomLimit != 1) {
|
||||
freeStart = -1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
freeStart = -1;
|
||||
lastState = true;
|
||||
}
|
||||
|
||||
++y;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -206,52 +194,44 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
|
||||
public boolean descendLevel() {
|
||||
final Location pos = getBlockIn();
|
||||
final int x = pos.getBlockX();
|
||||
int y = Math.max(0, pos.getBlockY());
|
||||
int y = Math.max(0, pos.getBlockY() - 1);
|
||||
final int z = pos.getBlockZ();
|
||||
final Extent world = pos.getExtent();
|
||||
|
||||
BlockMaterial initialMaterial = world.getBlockType(BlockVector3.at(x, y, z)).getMaterial();
|
||||
byte free = 0;
|
||||
|
||||
boolean lastState = initialMaterial.isMovementBlocker() && initialMaterial.isFullCube();
|
||||
|
||||
double height = 1.85;
|
||||
double freeEnd = -1;
|
||||
|
||||
int maxY = world.getMaxY();
|
||||
if (y <= 2) return false;
|
||||
|
||||
for (int level = y + 1; level > 0; level--) {
|
||||
BlockState state;
|
||||
if (level >= maxY) state = BlockTypes.VOID_AIR.getDefaultState();
|
||||
else state = world.getBlock(BlockVector3.at(x, level, z));
|
||||
BlockType type = state.getBlockType();
|
||||
BlockMaterial material = type.getMaterial();
|
||||
|
||||
if (!material.isFullCube() || !material.isMovementBlocker()) {
|
||||
if (!lastState) {
|
||||
lastState = BlockTypeUtil.centralTopLimit(state) != 0;
|
||||
continue;
|
||||
}
|
||||
if (freeEnd == -1) {
|
||||
freeEnd = level + BlockTypeUtil.centralBottomLimit(state);
|
||||
while (y >= 1) {
|
||||
if (!world.getBlock(BlockVector3.at(x, y, z)).getBlockType().getMaterial().isMovementBlocker()) {
|
||||
++free;
|
||||
} else {
|
||||
double topLimit = BlockTypeUtil.centralTopLimit(state);
|
||||
double freeStart = level + topLimit;
|
||||
double space = freeEnd - freeStart;
|
||||
if (space >= height) {
|
||||
setPosition(Vector3.at(x + 0.5, freeStart, z + 0.5));
|
||||
free = 0;
|
||||
}
|
||||
|
||||
if (free == 2) {
|
||||
// So we've found a spot, but we have to drop the player
|
||||
// lightly and also check to see if there's something to
|
||||
// stand upon
|
||||
while (y >= 0) {
|
||||
final BlockVector3 platform = BlockVector3.at(x, y, z);
|
||||
final BlockState block = world.getBlock(platform);
|
||||
final BlockType type = block.getBlockType();
|
||||
|
||||
// Don't want to end up in lava
|
||||
if (!type.getMaterial().isAir() && type != BlockTypes.LAVA) {
|
||||
// Found a block!
|
||||
setPosition(platform.toVector3().add(0.5, 1, 0.5));
|
||||
return true;
|
||||
}
|
||||
// Not enough room, reset the free position
|
||||
if (topLimit != 0) {
|
||||
freeEnd = -1;
|
||||
|
||||
--y;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
lastState = true;
|
||||
freeEnd = -1;
|
||||
}
|
||||
|
||||
--y;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -326,7 +306,7 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
|
||||
if (!getLocation().getExtent().getBlock(spot).getBlockType().getMaterial().isMovementBlocker()) {
|
||||
getLocation().getExtent().setBlock(spot, BlockTypes.GLASS.getDefaultState());
|
||||
}
|
||||
}catch (WorldEditException e) {
|
||||
} catch (WorldEditException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
setPosition(Vector3.at(x + 0.5, y, z + 0.5));
|
||||
@ -334,12 +314,12 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
|
||||
|
||||
@Override
|
||||
public Location getBlockIn() {
|
||||
return getLocation().setPosition(getLocation().floor());
|
||||
return getLocation().setPosition(getLocation().toVector().floor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location getBlockOn() {
|
||||
return getLocation().setPosition(getLocation().setY(getLocation().getY() - 1).floor());
|
||||
return getLocation().setPosition(getLocation().setY(getLocation().getY() - 1).toVector().floor());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -393,7 +373,7 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
|
||||
if (typeId.hasBlockType()) {
|
||||
return typeId.getBlockType().getDefaultState().toBaseBlock();
|
||||
} else {
|
||||
return BlockTypes.AIR.getDefaultState().toBaseBlock();
|
||||
throw new NotABlockException();
|
||||
}
|
||||
}
|
||||
|
||||
@ -414,7 +394,7 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
|
||||
boolean inFree = false;
|
||||
|
||||
while ((block = hitBlox.getNextBlock()) != null) {
|
||||
boolean free = !world.getBlock(block.toBlockPoint()).getBlockType().getMaterial().isMovementBlocker();
|
||||
boolean free = !world.getBlock(block.toVector().toBlockPoint()).getBlockType().getMaterial().isMovementBlocker();
|
||||
|
||||
if (firstBlock) {
|
||||
firstBlock = false;
|
||||
|
@ -57,6 +57,7 @@ import java.util.EnumMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
@ -139,9 +140,9 @@ public class PlatformManager {
|
||||
|
||||
// Check whether this platform was chosen to be the preferred one
|
||||
// for any capability and be sure to remove it
|
||||
Iterator<Map.Entry<Capability, Platform>> it = preferences.entrySet().iterator();
|
||||
Iterator<Entry<Capability, Platform>> it = preferences.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Map.Entry<Capability, Platform> entry = it.next();
|
||||
Entry<Capability, Platform> entry = it.next();
|
||||
if (entry.getValue().equals(platform)) {
|
||||
entry.getKey().unload(this, entry.getValue());
|
||||
it.remove();
|
||||
@ -347,6 +348,7 @@ public class PlatformManager {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (session.hasSuperPickAxe() && player.isHoldingPickAxe()) {
|
||||
final BlockTool superPickaxe = session.getSuperPickaxe();
|
||||
if (superPickaxe != null && superPickaxe.canUse(player)) {
|
||||
@ -357,8 +359,8 @@ public class PlatformManager {
|
||||
return;
|
||||
}
|
||||
}
|
||||
final Tool tool = session.getTool(player);
|
||||
if (tool != null && tool instanceof DoubleActionBlockTool) {
|
||||
Tool tool = session.getTool(player);
|
||||
if (tool instanceof DoubleActionBlockTool) {
|
||||
if (tool.canUse(player)) {
|
||||
FawePlayer<?> fp = FawePlayer.wrap(player);
|
||||
final Player maskedPlayerWrapper = new LocationMaskedPlayerWrapper(PlayerWrapper.wrap((Player) actor), ((Player) actor).getLocation());
|
||||
@ -372,6 +374,7 @@ public class PlatformManager {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (event.getType() == Interaction.OPEN) {
|
||||
if (session.isToolControlEnabled() && player.getItemInHand(HandSide.MAIN_HAND).getType().getId().equals(getConfiguration().wandItem)) {
|
||||
if (!actor.hasPermission("worldedit.selection.pos")) {
|
||||
@ -392,12 +395,13 @@ public class PlatformManager {
|
||||
}
|
||||
}, false, true);
|
||||
}
|
||||
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
final Tool tool = session.getTool(player);
|
||||
if (tool != null && tool instanceof BlockTool) {
|
||||
Tool tool = session.getTool(player);
|
||||
if (tool instanceof BlockTool) {
|
||||
if (tool.canUse(player)) {
|
||||
FawePlayer<?> fp = FawePlayer.wrap(player);
|
||||
if (fp.checkAction()) {
|
||||
@ -439,8 +443,8 @@ public class PlatformManager {
|
||||
// Create a proxy actor with a potentially different world for
|
||||
// making changes to the world
|
||||
Player actor = createProxyActor(event.getPlayer());
|
||||
final Player player = new LocationMaskedPlayerWrapper(PlayerWrapper.wrap(actor), actor.getLocation(), true);
|
||||
final LocalSession session = worldEdit.getSessionManager().get(player);
|
||||
Player player = new LocationMaskedPlayerWrapper(PlayerWrapper.wrap(actor), actor.getLocation(), true);
|
||||
LocalSession session = worldEdit.getSessionManager().get(player);
|
||||
|
||||
VirtualWorld virtual = session.getVirtualWorld();
|
||||
if (virtual != null) {
|
||||
@ -451,7 +455,7 @@ public class PlatformManager {
|
||||
try {
|
||||
switch (event.getInputType()) {
|
||||
case PRIMARY: {
|
||||
if (getConfiguration().navigationWandMaxDistance > 0 && player.getItemInHand(HandSide.MAIN_HAND).getType().getId().equals(getConfiguration().navigationWand)) {
|
||||
if ((getConfiguration().navigationWandMaxDistance > 0) && player.getItemInHand(HandSide.MAIN_HAND).getType().getId().equals(getConfiguration().navigationWand)) {
|
||||
if (!player.hasPermission("worldedit.navigation.jumpto.tool")) {
|
||||
return;
|
||||
}
|
||||
@ -476,6 +480,7 @@ public class PlatformManager {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@ -521,5 +526,4 @@ public class PlatformManager {
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -19,12 +19,9 @@
|
||||
|
||||
package com.sk89q.worldedit.extension.platform;
|
||||
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.blocks.BaseItemStack;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
@ -36,13 +33,13 @@ import com.sk89q.worldedit.session.SessionKey;
|
||||
import com.sk89q.worldedit.util.HandSide;
|
||||
import com.sk89q.worldedit.util.Location;
|
||||
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 javax.annotation.Nullable;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class PlayerProxy extends AbstractPlayerActor {
|
||||
|
||||
@ -50,7 +47,6 @@ public class PlayerProxy extends AbstractPlayerActor {
|
||||
private final Actor permActor;
|
||||
private final Actor cuiActor;
|
||||
private final World world;
|
||||
private Vector3 offset = Vector3.ZERO;
|
||||
|
||||
public PlayerProxy(Player basePlayer, Actor permActor, Actor cuiActor, World world) {
|
||||
checkNotNull(basePlayer);
|
||||
@ -63,10 +59,6 @@ public class PlayerProxy extends AbstractPlayerActor {
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
public void setOffset(Vector3 position) {
|
||||
this.offset = position;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BaseBlock getBlockInHand(HandSide handSide) throws WorldEditException {
|
||||
@ -105,13 +97,12 @@ public class PlayerProxy extends AbstractPlayerActor {
|
||||
|
||||
@Override
|
||||
public BaseEntity getState() {
|
||||
throw new UnsupportedOperationException("Can't withPropertyId() on a player");
|
||||
throw new UnsupportedOperationException("Can't getState() on a player");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location getLocation() {
|
||||
Location loc = this.basePlayer.getLocation();
|
||||
return new Location(loc.getExtent(), loc.add(offset), loc.getDirection());
|
||||
return basePlayer.getLocation();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -194,4 +185,3 @@ public class PlayerProxy extends AbstractPlayerActor {
|
||||
return basePlayer;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,6 @@ import com.sk89q.jnbt.Tag;
|
||||
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.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
@ -152,7 +151,6 @@ public class ServerCUIHandler {
|
||||
structureTag.put("showboundingbox", new ByteTag((byte) 1));
|
||||
structureTag.put("id", new StringTag(BlockTypes.STRUCTURE_BLOCK.getId()));
|
||||
|
||||
// return BlockTypes.STRUCTURE_BLOCK.getDefaultState().toBaseBlock(new CompoundTag(structureTag));
|
||||
return BlockTypes.STRUCTURE_BLOCK.getDefaultState().toBaseBlock(new CompoundTag(structureTag));
|
||||
}
|
||||
}
|
||||
|
@ -98,5 +98,4 @@ public class SphereRegionSelector extends EllipsoidRegionSelector {
|
||||
return "sphere";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren