@@ -1,354 +0,0 @@
|
||||
package org.bukkit.craftbukkit.util;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
|
||||
/**
|
||||
* Executes tasks using a multi-stage process executor. Synchronous executions are via {@link AsynchronousExecutor#finishActive()} or the {@link AsynchronousExecutor#get(Object)} methods.
|
||||
* <li \> Stage 1 creates the object from a parameter, and is usually called asynchronously.
|
||||
* <li \> Stage 2 takes the parameter and object from stage 1 and does any synchronous processing to prepare it.
|
||||
* <li \> Stage 3 takes the parameter and object from stage 1, as well as a callback that was registered, and performs any synchronous calculations.
|
||||
*
|
||||
* @param <P> The type of parameter you provide to make the object that will be created. It should implement {@link Object#hashCode()} and {@link Object#equals(Object)} if you want to get the value early.
|
||||
* @param <T> The type of object you provide. This is created in stage 1, and passed to stage 2, 3, and returned if get() is called.
|
||||
* @param <C> The type of callback you provide. You may register many of these to be passed to the provider in stage 3, one at a time.
|
||||
* @param <E> A type of exception you may throw and expect to be handled by the main thread
|
||||
* @author Wesley Wolfe (c) 2012, 2014
|
||||
*/
|
||||
public final class AsynchronousExecutor<P, T, C, E extends Throwable> {
|
||||
|
||||
public static interface CallBackProvider<P, T, C, E extends Throwable> extends ThreadFactory {
|
||||
|
||||
/**
|
||||
* Normally an asynchronous call, but can be synchronous
|
||||
*
|
||||
* @param parameter parameter object provided
|
||||
* @return the created object
|
||||
*/
|
||||
T callStage1(P parameter) throws E;
|
||||
|
||||
/**
|
||||
* Synchronous call
|
||||
*
|
||||
* @param parameter parameter object provided
|
||||
* @param object the previously created object
|
||||
*/
|
||||
void callStage2(P parameter, T object) throws E;
|
||||
|
||||
/**
|
||||
* Synchronous call, called multiple times, once per registered callback
|
||||
*
|
||||
* @param parameter parameter object provided
|
||||
* @param object the previously created object
|
||||
* @param callback the current callback to execute
|
||||
*/
|
||||
void callStage3(P parameter, T object, C callback) throws E;
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
static final AtomicIntegerFieldUpdater STATE_FIELD = AtomicIntegerFieldUpdater.newUpdater(AsynchronousExecutor.Task.class, "state");
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private static boolean set(AsynchronousExecutor.Task $this, int expected, int value) {
|
||||
return STATE_FIELD.compareAndSet($this, expected, value);
|
||||
}
|
||||
|
||||
class Task implements Runnable {
|
||||
static final int PENDING = 0x0;
|
||||
static final int STAGE_1_ASYNC = PENDING + 1;
|
||||
static final int STAGE_1_SYNC = STAGE_1_ASYNC + 1;
|
||||
static final int STAGE_1_COMPLETE = STAGE_1_SYNC + 1;
|
||||
static final int FINISHED = STAGE_1_COMPLETE + 1;
|
||||
|
||||
volatile int state = PENDING;
|
||||
final P parameter;
|
||||
T object;
|
||||
final List<C> callbacks = new LinkedList<C>();
|
||||
E t = null;
|
||||
|
||||
Task(final P parameter) {
|
||||
this.parameter = parameter;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
if (initAsync()) {
|
||||
finished.add(this);
|
||||
}
|
||||
}
|
||||
|
||||
boolean initAsync() {
|
||||
if (set(this, PENDING, STAGE_1_ASYNC)) {
|
||||
boolean ret = true;
|
||||
|
||||
try {
|
||||
init();
|
||||
} finally {
|
||||
if (set(this, STAGE_1_ASYNC, STAGE_1_COMPLETE)) {
|
||||
// No one is/will be waiting
|
||||
} else {
|
||||
// We know that the sync thread will be waiting
|
||||
synchronized (this) {
|
||||
if (state != STAGE_1_SYNC) {
|
||||
// They beat us to the synchronized block
|
||||
this.notifyAll();
|
||||
} else {
|
||||
// We beat them to the synchronized block
|
||||
}
|
||||
state = STAGE_1_COMPLETE; // They're already synchronized, atomic locks are not needed
|
||||
}
|
||||
// We want to return false, because we know a synchronous task already handled the finish()
|
||||
ret = false; // Don't return inside finally; VERY bad practice.
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void initSync() {
|
||||
if (set(this, PENDING, STAGE_1_COMPLETE)) {
|
||||
// If we succeed that variable switch, good as done
|
||||
init();
|
||||
} else if (set(this, STAGE_1_ASYNC, STAGE_1_SYNC)) {
|
||||
// Async thread is running, but this shouldn't be likely; we need to sync to wait on them because of it.
|
||||
synchronized (this) {
|
||||
if (set(this, STAGE_1_SYNC, PENDING)) { // They might NOT synchronized yet, atomic lock IS needed
|
||||
// We are the first into the lock
|
||||
while (state != STAGE_1_COMPLETE) {
|
||||
try {
|
||||
this.wait();
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new RuntimeException("Unable to handle interruption on " + parameter, e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// They beat us to the synchronized block
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Async thread is not pending, the more likely situation for a task not pending
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
void init() {
|
||||
try {
|
||||
object = provider.callStage1(parameter);
|
||||
} catch (final Throwable t) {
|
||||
this.t = (E) t;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
T get() throws E {
|
||||
initSync();
|
||||
if (callbacks.isEmpty()) {
|
||||
// 'this' is a placeholder to prevent callbacks from being empty during finish call
|
||||
// See get method below
|
||||
callbacks.add((C) this);
|
||||
}
|
||||
finish();
|
||||
return object;
|
||||
}
|
||||
|
||||
void finish() throws E {
|
||||
switch (state) {
|
||||
default:
|
||||
case PENDING:
|
||||
case STAGE_1_ASYNC:
|
||||
case STAGE_1_SYNC:
|
||||
throw new IllegalStateException("Attempting to finish unprepared(" + state + ") task(" + parameter + ")");
|
||||
case STAGE_1_COMPLETE:
|
||||
try {
|
||||
if (t != null) {
|
||||
throw t;
|
||||
}
|
||||
if (callbacks.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final CallBackProvider<P, T, C, E> provider = AsynchronousExecutor.this.provider;
|
||||
final P parameter = this.parameter;
|
||||
final T object = this.object;
|
||||
|
||||
provider.callStage2(parameter, object);
|
||||
for (C callback : callbacks) {
|
||||
if (callback == this) {
|
||||
// 'this' is a placeholder to prevent callbacks from being empty on a get() call
|
||||
// See get method above
|
||||
continue;
|
||||
}
|
||||
provider.callStage3(parameter, object, callback);
|
||||
}
|
||||
} finally {
|
||||
tasks.remove(parameter);
|
||||
state = FINISHED;
|
||||
}
|
||||
case FINISHED:
|
||||
}
|
||||
}
|
||||
|
||||
boolean drop() {
|
||||
if (set(this, PENDING, FINISHED)) {
|
||||
// If we succeed that variable switch, good as forgotten
|
||||
tasks.remove(parameter);
|
||||
return true;
|
||||
} else {
|
||||
// We need the async thread to finish normally to properly dispose of the task
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final CallBackProvider<P, T, C, E> provider;
|
||||
final Queue<Task> finished = new ConcurrentLinkedQueue<Task>();
|
||||
final Map<P, Task> tasks = new HashMap<P, Task>();
|
||||
final ThreadPoolExecutor pool;
|
||||
|
||||
/**
|
||||
* Uses a thread pool to pass executions to the provider.
|
||||
* @see AsynchronousExecutor
|
||||
*/
|
||||
public AsynchronousExecutor(final CallBackProvider<P, T, C, E> provider, final int coreSize) {
|
||||
Validate.notNull(provider, "Provider cannot be null");
|
||||
this.provider = provider;
|
||||
|
||||
// We have an unbound queue size so do not need a max thread size
|
||||
pool = new ThreadPoolExecutor(coreSize, Integer.MAX_VALUE, 60l, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), provider);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a callback to the parameter provided, adding parameter to the queue if needed.
|
||||
* <p>
|
||||
* This should always be synchronous.
|
||||
*/
|
||||
public void add(P parameter, C callback) {
|
||||
Task task = tasks.get(parameter);
|
||||
if (task == null) {
|
||||
tasks.put(parameter, task = new Task(parameter));
|
||||
pool.execute(task);
|
||||
}
|
||||
task.callbacks.add(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* This removes a particular callback from the specified parameter.
|
||||
* <p>
|
||||
* If no callbacks remain for a given parameter, then the {@link CallBackProvider CallBackProvider's} stages may be omitted from execution.
|
||||
* Stage 3 will have no callbacks, stage 2 will be skipped unless a {@link #get(Object)} is used, and stage 1 will be avoided on a best-effort basis.
|
||||
* <p>
|
||||
* Subsequent calls to {@link #getSkipQueue(Object)} will always work.
|
||||
* <p>
|
||||
* Subsequent calls to {@link #get(Object)} might work.
|
||||
* <p>
|
||||
* This should always be synchronous
|
||||
* @return true if no further execution for the parameter is possible, such that, no exceptions will be thrown in {@link #finishActive()} for the parameter, and {@link #get(Object)} will throw an {@link IllegalStateException}, false otherwise
|
||||
* @throws IllegalStateException if parameter is not in the queue anymore
|
||||
* @throws IllegalStateException if the callback was not specified for given parameter
|
||||
*/
|
||||
public boolean drop(P parameter, C callback) throws IllegalStateException {
|
||||
final Task task = tasks.get(parameter);
|
||||
if (task == null) {
|
||||
return true;
|
||||
}
|
||||
if (!task.callbacks.remove(callback)) {
|
||||
throw new IllegalStateException("Unknown " + callback + " for " + parameter);
|
||||
}
|
||||
if (task.callbacks.isEmpty()) {
|
||||
return task.drop();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method attempts to skip the waiting period for said parameter.
|
||||
* <p>
|
||||
* This should always be synchronous.
|
||||
* @throws IllegalStateException if the parameter is not in the queue anymore, or sometimes if called from asynchronous thread
|
||||
*/
|
||||
public T get(P parameter) throws E, IllegalStateException {
|
||||
final Task task = tasks.get(parameter);
|
||||
if (task == null) {
|
||||
throw new IllegalStateException("Unknown " + parameter);
|
||||
}
|
||||
return task.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a parameter as if it was in the queue, without ever passing to another thread.
|
||||
*/
|
||||
public T getSkipQueue(P parameter) throws E {
|
||||
return skipQueue(parameter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a parameter as if it was in the queue, without ever passing to another thread.
|
||||
*/
|
||||
public T getSkipQueue(P parameter, C callback) throws E {
|
||||
final T object = skipQueue(parameter);
|
||||
provider.callStage3(parameter, object, callback);
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a parameter as if it was in the queue, without ever passing to another thread.
|
||||
*/
|
||||
public T getSkipQueue(P parameter, C...callbacks) throws E {
|
||||
final CallBackProvider<P, T, C, E> provider = this.provider;
|
||||
final T object = skipQueue(parameter);
|
||||
for (C callback : callbacks) {
|
||||
provider.callStage3(parameter, object, callback);
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a parameter as if it was in the queue, without ever passing to another thread.
|
||||
*/
|
||||
public T getSkipQueue(P parameter, Iterable<C> callbacks) throws E {
|
||||
final CallBackProvider<P, T, C, E> provider = this.provider;
|
||||
final T object = skipQueue(parameter);
|
||||
for (C callback : callbacks) {
|
||||
provider.callStage3(parameter, object, callback);
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
private T skipQueue(P parameter) throws E {
|
||||
Task task = tasks.get(parameter);
|
||||
if (task != null) {
|
||||
return task.get();
|
||||
}
|
||||
T object = provider.callStage1(parameter);
|
||||
provider.callStage2(parameter, object);
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the 'heartbeat' that should be called synchronously to finish any pending tasks
|
||||
*/
|
||||
public void finishActive() throws E {
|
||||
final Queue<Task> finished = this.finished;
|
||||
while (!finished.isEmpty()) {
|
||||
finished.poll().finish();
|
||||
}
|
||||
}
|
||||
|
||||
public void setActiveThreads(final int coreSize) {
|
||||
pool.setCorePoolSize(coreSize);
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package org.bukkit.craftbukkit.util;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import net.minecraft.server.BlockPosition;
|
||||
import net.minecraft.server.IBlockData;
|
||||
@@ -38,6 +39,10 @@ public class BlockStateListPopulator extends DummyGeneratorAccess {
|
||||
}
|
||||
}
|
||||
|
||||
public Set<BlockPosition> getBlocks() {
|
||||
return list.keySet();
|
||||
}
|
||||
|
||||
public List<CraftBlockState> getList() {
|
||||
return new ArrayList<>(list.values());
|
||||
}
|
||||
|
||||
@@ -140,6 +140,28 @@ public class Commodore
|
||||
{
|
||||
if ( modern )
|
||||
{
|
||||
if ( owner.equals( "org/bukkit/Material" ) )
|
||||
{
|
||||
switch ( name )
|
||||
{
|
||||
case "CACTUS_GREEN":
|
||||
name = "GREEN_DYE";
|
||||
break;
|
||||
case "DANDELION_YELLOW":
|
||||
name = "YELLOW_DYE";
|
||||
break;
|
||||
case "ROSE_RED":
|
||||
name = "RED_DYE";
|
||||
break;
|
||||
case "SIGN":
|
||||
name = "OAK_SIGN";
|
||||
break;
|
||||
case "WALL_SIGN":
|
||||
name = "OAK_WALL_SIGN";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
super.visitFieldInsn( opcode, owner, name, desc );
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ import org.bukkit.material.MaterialData;
|
||||
public class CraftLegacy {
|
||||
|
||||
private static final Map<Byte, Material> SPAWN_EGGS = new HashMap<>();
|
||||
private static final Set<String> whitelistedStates = new HashSet<>(Arrays.asList("explode", "check_decay", "decayable"));
|
||||
private static final Set<String> whitelistedStates = new HashSet<>(Arrays.asList("explode", "check_decay", "decayable", "facing"));
|
||||
private static final Map<MaterialData, Item> materialToItem = new HashMap<>(16384);
|
||||
private static final Map<Item, MaterialData> itemToMaterial = new HashMap<>(1024);
|
||||
private static final Map<MaterialData, IBlockData> materialToData = new HashMap<>(4096);
|
||||
@@ -311,7 +311,7 @@ public class CraftLegacy {
|
||||
SPAWN_EGGS.put((byte) EntityType.PIG_ZOMBIE.getTypeId(), Material.ZOMBIE_PIGMAN_SPAWN_EGG);
|
||||
SPAWN_EGGS.put((byte) EntityType.ZOMBIE_VILLAGER.getTypeId(), Material.ZOMBIE_VILLAGER_SPAWN_EGG);
|
||||
|
||||
DispenserRegistry.c();
|
||||
DispenserRegistry.init();
|
||||
|
||||
for (Material material : Material.values()) {
|
||||
if (!material.isLegacy()) {
|
||||
@@ -324,11 +324,11 @@ public class CraftLegacy {
|
||||
MaterialData matData = new MaterialData(material, data);
|
||||
Dynamic blockTag = DataConverterFlattenData.b(material.getId() << 4 | data);
|
||||
// TODO: better skull conversion, chests
|
||||
if (blockTag.getString("Name").contains("%%FILTER_ME%%")) {
|
||||
if (blockTag.get("Name").asString("").contains("%%FILTER_ME%%")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String name = blockTag.getString("Name");
|
||||
String name = blockTag.get("Name").asString("");
|
||||
// TODO: need to fix
|
||||
if (name.equals("minecraft:portal")) {
|
||||
name = "minecraft:nether_portal";
|
||||
@@ -341,9 +341,9 @@ public class CraftLegacy {
|
||||
IBlockData blockData = block.getBlockData();
|
||||
BlockStateList states = block.getStates();
|
||||
|
||||
Optional<Dynamic> propMap = blockTag.get("Properties");
|
||||
Optional<NBTTagCompound> propMap = blockTag.getElement("Properties");
|
||||
if (propMap.isPresent()) {
|
||||
NBTTagCompound properties = (NBTTagCompound) propMap.get().getValue();
|
||||
NBTTagCompound properties = propMap.get();
|
||||
for (String dataKey : properties.getKeys()) {
|
||||
IBlockState state = states.a(dataKey);
|
||||
|
||||
@@ -402,7 +402,7 @@ public class CraftLegacy {
|
||||
|
||||
Dynamic<NBTBase> converted = DataConverterRegistry.a().update(DataConverterTypes.ITEM_STACK, new Dynamic<NBTBase>(DynamicOpsNBT.a, stack), -1, CraftMagicNumbers.INSTANCE.getDataVersion());
|
||||
|
||||
String newId = converted.getString("id");
|
||||
String newId = converted.get("id").asString("");
|
||||
// Recover spawn eggs with invalid data
|
||||
if (newId.equals("minecraft:spawn_egg")) {
|
||||
newId = "minecraft:pig_spawn_egg";
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package org.bukkit.craftbukkit.util;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.io.Files;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import com.mojang.datafixers.Dynamic;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
@@ -16,13 +18,18 @@ import java.util.logging.Logger;
|
||||
import net.minecraft.server.AdvancementDataWorld;
|
||||
import net.minecraft.server.Block;
|
||||
import net.minecraft.server.ChatDeserializer;
|
||||
import net.minecraft.server.DataConverterRegistry;
|
||||
import net.minecraft.server.DataConverterTypes;
|
||||
import net.minecraft.server.DynamicOpsNBT;
|
||||
import net.minecraft.server.IBlockData;
|
||||
import net.minecraft.server.IRegistry;
|
||||
import net.minecraft.server.Item;
|
||||
import net.minecraft.server.MinecraftKey;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.MojangsonParser;
|
||||
import net.minecraft.server.NBTBase;
|
||||
import net.minecraft.server.NBTTagCompound;
|
||||
import net.minecraft.server.SharedConstants;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
@@ -74,19 +81,22 @@ public final class CraftMagicNumbers implements UnsafeValues {
|
||||
private static final Map<Material, Block> MATERIAL_BLOCK = new HashMap<>();
|
||||
|
||||
static {
|
||||
for (Block block : (Iterable<Block>) IRegistry.BLOCK) { // Eclipse fail
|
||||
for (Block block : IRegistry.BLOCK) {
|
||||
BLOCK_MATERIAL.put(block, Material.getMaterial(IRegistry.BLOCK.getKey(block).getKey().toUpperCase(Locale.ROOT)));
|
||||
}
|
||||
|
||||
for (Item item : (Iterable<Item>) IRegistry.ITEM) { // Eclipse fail
|
||||
for (Item item : IRegistry.ITEM) {
|
||||
ITEM_MATERIAL.put(item, Material.getMaterial(IRegistry.ITEM.getKey(item).getKey().toUpperCase(Locale.ROOT)));
|
||||
}
|
||||
|
||||
for (Material material : Material.values()) {
|
||||
MinecraftKey key = key(material);
|
||||
// TODO: only register if block/item?
|
||||
MATERIAL_ITEM.put(material, IRegistry.ITEM.get(key));
|
||||
MATERIAL_BLOCK.put(material, IRegistry.BLOCK.get(key));
|
||||
IRegistry.ITEM.getOptional(key).ifPresent((item) -> {
|
||||
MATERIAL_ITEM.put(material, item);
|
||||
});
|
||||
IRegistry.BLOCK.getOptional(key).ifPresent((block) -> {
|
||||
MATERIAL_BLOCK.put(material, block);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,6 +154,24 @@ public final class CraftMagicNumbers implements UnsafeValues {
|
||||
return CraftBlockData.fromData(getBlock(material, data));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Material getMaterial(String material, int version) {
|
||||
Preconditions.checkArgument(version <= this.getDataVersion(), "Newer version! Server downgrades are not supported!");
|
||||
|
||||
// Fastpath up to date materials
|
||||
if (version == this.getDataVersion()) {
|
||||
return Material.getMaterial(material);
|
||||
}
|
||||
|
||||
NBTTagCompound stack = new NBTTagCompound();
|
||||
stack.setString("id", "minecraft:" + material.toLowerCase(Locale.ROOT));
|
||||
|
||||
Dynamic<NBTBase> converted = DataConverterRegistry.a().update(DataConverterTypes.ITEM_STACK, new Dynamic<>(DynamicOpsNBT.a, stack), version, this.getDataVersion());
|
||||
String newId = converted.get("id").asString("");
|
||||
|
||||
return Material.matchMaterial(newId);
|
||||
}
|
||||
|
||||
/**
|
||||
* This string should be changed if the NMS mappings do.
|
||||
*
|
||||
@@ -160,12 +188,12 @@ public final class CraftMagicNumbers implements UnsafeValues {
|
||||
* @return string
|
||||
*/
|
||||
public String getMappingsVersion() {
|
||||
return "7dd4b3ec31629620c41553e5c142e454";
|
||||
return "8b7fe9012a93b36df04844a6c990de27";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDataVersion() {
|
||||
return 1631;
|
||||
return SharedConstants.a().getWorldVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -222,9 +250,11 @@ public final class CraftMagicNumbers implements UnsafeValues {
|
||||
@Override
|
||||
public void checkSupported(PluginDescriptionFile pdf) throws InvalidPluginException {
|
||||
if (pdf.getAPIVersion() != null) {
|
||||
if (!pdf.getAPIVersion().equals("1.13")) {
|
||||
if (!pdf.getAPIVersion().equals("1.13") && !pdf.getAPIVersion().equals("1.14")) {
|
||||
throw new InvalidPluginException("Unsupported API version " + pdf.getAPIVersion());
|
||||
}
|
||||
} else {
|
||||
Bukkit.getLogger().log(Level.WARNING, "Plugin " + pdf.getFullName() + " does not specify an api-version.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ public class CraftNBTTagConfigSerializer {
|
||||
} else if (base instanceof NBTTagList) {
|
||||
List<Object> baseList = new ArrayList<>();
|
||||
for (int i = 0; i < ((NBTList) base).size(); i++) {
|
||||
baseList.add(serialize(((NBTList) base).get(i)));
|
||||
baseList.add(serialize((NBTBase) ((NBTList) base).get(i)));
|
||||
}
|
||||
|
||||
return baseList;
|
||||
|
||||
@@ -10,6 +10,8 @@ import org.bukkit.util.Vector;
|
||||
import net.minecraft.server.BlockPosition;
|
||||
import net.minecraft.server.MovingObjectPosition;
|
||||
import net.minecraft.server.MovingObjectPosition.EnumMovingObjectType;
|
||||
import net.minecraft.server.MovingObjectPositionBlock;
|
||||
import net.minecraft.server.MovingObjectPositionEntity;
|
||||
import net.minecraft.server.Vec3D;
|
||||
|
||||
public class CraftRayTraceResult {
|
||||
@@ -17,23 +19,24 @@ public class CraftRayTraceResult {
|
||||
private CraftRayTraceResult() {}
|
||||
|
||||
public static RayTraceResult fromNMS(World world, MovingObjectPosition nmsHitResult) {
|
||||
if (nmsHitResult == null || nmsHitResult.type == EnumMovingObjectType.MISS) return null;
|
||||
if (nmsHitResult == null || nmsHitResult.getType() == EnumMovingObjectType.MISS) return null;
|
||||
|
||||
Vec3D nmsHitPos = nmsHitResult.pos;
|
||||
Vec3D nmsHitPos = nmsHitResult.getPos();
|
||||
Vector hitPosition = new Vector(nmsHitPos.x, nmsHitPos.y, nmsHitPos.z);
|
||||
BlockFace hitBlockFace = null;
|
||||
|
||||
if (nmsHitResult.direction != null) {
|
||||
hitBlockFace = CraftBlock.notchToBlockFace(nmsHitResult.direction);
|
||||
}
|
||||
|
||||
if (nmsHitResult.entity != null) {
|
||||
Entity hitEntity = nmsHitResult.entity.getBukkitEntity();
|
||||
return new RayTraceResult(hitPosition, hitEntity, hitBlockFace);
|
||||
if (nmsHitResult.getType() == EnumMovingObjectType.ENTITY) {
|
||||
Entity hitEntity = ((MovingObjectPositionEntity) nmsHitResult).getEntity().getBukkitEntity();
|
||||
return new RayTraceResult(hitPosition, hitEntity, null);
|
||||
}
|
||||
|
||||
Block hitBlock = null;
|
||||
BlockPosition nmsBlockPos = nmsHitResult.getBlockPosition();
|
||||
BlockPosition nmsBlockPos = null;
|
||||
if (nmsHitResult.getType() == EnumMovingObjectType.BLOCK) {
|
||||
MovingObjectPositionBlock blockHitResult = (MovingObjectPositionBlock) nmsHitResult;
|
||||
hitBlockFace = CraftBlock.notchToBlockFace(blockHitResult.getDirection());
|
||||
nmsBlockPos = blockHitResult.getBlockPosition();
|
||||
}
|
||||
if (nmsBlockPos != null && world != null) {
|
||||
hitBlock = world.getBlockAt(nmsBlockPos.getX(), nmsBlockPos.getY(), nmsBlockPos.getZ());
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package org.bukkit.craftbukkit.util;
|
||||
|
||||
public final class CraftVector {
|
||||
|
||||
private CraftVector() {
|
||||
}
|
||||
|
||||
public static org.bukkit.util.Vector toBukkit(net.minecraft.server.Vec3D nms) {
|
||||
return new org.bukkit.util.Vector(nms.x, nms.y, nms.z);
|
||||
}
|
||||
|
||||
public static net.minecraft.server.Vec3D toNMS(org.bukkit.util.Vector bukkit) {
|
||||
return new net.minecraft.server.Vec3D(bukkit.getX(), bukkit.getY(), bukkit.getZ());
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,13 @@
|
||||
package org.bukkit.craftbukkit.util;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.function.Predicate;
|
||||
import net.minecraft.server.AxisAlignedBB;
|
||||
import net.minecraft.server.BiomeBase;
|
||||
import net.minecraft.server.Block;
|
||||
import net.minecraft.server.BlockPosition;
|
||||
import net.minecraft.server.ChunkStatus;
|
||||
import net.minecraft.server.DifficultyDamageScaler;
|
||||
import net.minecraft.server.Entity;
|
||||
import net.minecraft.server.EntityHuman;
|
||||
@@ -17,19 +20,15 @@ import net.minecraft.server.HeightMap;
|
||||
import net.minecraft.server.IBlockData;
|
||||
import net.minecraft.server.IChunkAccess;
|
||||
import net.minecraft.server.IChunkProvider;
|
||||
import net.minecraft.server.IDataManager;
|
||||
import net.minecraft.server.ParticleParam;
|
||||
import net.minecraft.server.PersistentCollection;
|
||||
import net.minecraft.server.SoundCategory;
|
||||
import net.minecraft.server.SoundEffect;
|
||||
import net.minecraft.server.TickList;
|
||||
import net.minecraft.server.TileEntity;
|
||||
import net.minecraft.server.VoxelShape;
|
||||
import net.minecraft.server.World;
|
||||
import net.minecraft.server.WorldBorder;
|
||||
import net.minecraft.server.WorldData;
|
||||
import net.minecraft.server.WorldProvider;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||
|
||||
public class DummyGeneratorAccess implements GeneratorAccess {
|
||||
|
||||
@@ -53,11 +52,6 @@ public class DummyGeneratorAccess implements GeneratorAccess {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkAccess getChunkAt(int i, int i1) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public World getMinecraftWorld() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
@@ -79,12 +73,7 @@ public class DummyGeneratorAccess implements GeneratorAccess {
|
||||
}
|
||||
|
||||
@Override
|
||||
public IDataManager getDataManager() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Random m() {
|
||||
public Random getRandom() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@@ -93,11 +82,6 @@ public class DummyGeneratorAccess implements GeneratorAccess {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockPosition getSpawn() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void a(EntityHuman eh, BlockPosition bp, SoundEffect se, SoundCategory sc, float f, float f1) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
@@ -109,17 +93,22 @@ public class DummyGeneratorAccess implements GeneratorAccess {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty(BlockPosition bp) {
|
||||
public void a(EntityHuman eh, int i, BlockPosition bp, int i1) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeBase getBiome(BlockPosition bp) {
|
||||
public List<Entity> getEntities(Entity entity, AxisAlignedBB aabb, Predicate<? super Entity> prdct) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBrightness(EnumSkyBlock esb, BlockPosition bp) {
|
||||
public <T extends Entity> List<T> a(Class<? extends T> type, AxisAlignedBB aabb, Predicate<? super T> prdct) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends EntityHuman> getPlayers() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@@ -129,12 +118,12 @@ public class DummyGeneratorAccess implements GeneratorAccess {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChunkLoaded(int i, int i1, boolean bln) {
|
||||
public IChunkAccess getChunkAt(int i, int i1, ChunkStatus cs, boolean bln) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean e(BlockPosition bp) {
|
||||
public BlockPosition getHighestBlockYAt(HeightMap.Type type, BlockPosition bp) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@@ -143,11 +132,6 @@ public class DummyGeneratorAccess implements GeneratorAccess {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityHuman a(double d, double d1, double d2, double d3, Predicate<Entity> prdct) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int c() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
@@ -158,11 +142,6 @@ public class DummyGeneratorAccess implements GeneratorAccess {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean a(Entity entity, VoxelShape vs) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int a(BlockPosition bp, EnumDirection ed) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
@@ -179,7 +158,17 @@ public class DummyGeneratorAccess implements GeneratorAccess {
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorldProvider o() {
|
||||
public WorldProvider getWorldProvider() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeBase getBiome(BlockPosition bp) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBrightness(EnumSkyBlock esb, BlockPosition bp) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@@ -199,7 +188,7 @@ public class DummyGeneratorAccess implements GeneratorAccess {
|
||||
}
|
||||
|
||||
@Override
|
||||
public PersistentCollection h() {
|
||||
public boolean a(BlockPosition bp, Predicate<IBlockData> prdct) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@@ -209,27 +198,12 @@ public class DummyGeneratorAccess implements GeneratorAccess {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addEntity(Entity entity) {
|
||||
public boolean a(BlockPosition blockposition, boolean flag) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addEntity(Entity entity, CreatureSpawnEvent.SpawnReason reason) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setAir(BlockPosition blockposition) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void a(EnumSkyBlock enumskyblock, BlockPosition blockposition, int i) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setAir(BlockPosition blockposition, boolean flag) {
|
||||
public boolean b(BlockPosition blockposition, boolean flag) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
package org.bukkit.craftbukkit.util;
|
||||
|
||||
public class LongHash {
|
||||
public static long toLong(int msw, int lsw) {
|
||||
return ((long) msw << 32) + lsw - Integer.MIN_VALUE;
|
||||
}
|
||||
|
||||
public static int msw(long l) {
|
||||
return (int) (l >> 32);
|
||||
}
|
||||
|
||||
public static int lsw(long l) {
|
||||
return (int) (l & 0xFFFFFFFF) + Integer.MIN_VALUE;
|
||||
}
|
||||
}
|
||||
@@ -1,302 +0,0 @@
|
||||
/*
|
||||
Based on CompactHashSet Copyright 2011 Ontopia Project
|
||||
|
||||
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 org.bukkit.craftbukkit.util;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
public class LongHashSet {
|
||||
private final static int INITIAL_SIZE = 3;
|
||||
private final static double LOAD_FACTOR = 0.75;
|
||||
|
||||
private final static long FREE = 0;
|
||||
private final static long REMOVED = Long.MIN_VALUE;
|
||||
|
||||
private int freeEntries;
|
||||
private int elements;
|
||||
private long[] values;
|
||||
private int modCount;
|
||||
|
||||
public LongHashSet() {
|
||||
this(INITIAL_SIZE);
|
||||
}
|
||||
|
||||
public LongHashSet(int size) {
|
||||
values = new long[(size==0 ? 1 : size)];
|
||||
elements = 0;
|
||||
freeEntries = values.length;
|
||||
modCount = 0;
|
||||
}
|
||||
|
||||
public Iterator iterator() {
|
||||
return new Itr();
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return elements;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return elements == 0;
|
||||
}
|
||||
|
||||
public boolean contains(int msw, int lsw) {
|
||||
return contains(LongHash.toLong(msw, lsw));
|
||||
}
|
||||
|
||||
public boolean contains(long value) {
|
||||
int hash = hash(value);
|
||||
int index = (hash & 0x7FFFFFFF) % values.length;
|
||||
int offset = 1;
|
||||
|
||||
// search for the object (continue while !null and !this object)
|
||||
while(values[index] != FREE && !(hash(values[index]) == hash && values[index] == value)) {
|
||||
index = ((index + offset) & 0x7FFFFFFF) % values.length;
|
||||
offset = offset * 2 + 1;
|
||||
|
||||
if (offset == -1) {
|
||||
offset = 2;
|
||||
}
|
||||
}
|
||||
|
||||
return values[index] != FREE;
|
||||
}
|
||||
|
||||
public boolean add(int msw, int lsw) {
|
||||
return add(LongHash.toLong(msw, lsw));
|
||||
}
|
||||
|
||||
public boolean add(long value) {
|
||||
int hash = hash(value);
|
||||
int index = (hash & 0x7FFFFFFF) % values.length;
|
||||
int offset = 1;
|
||||
int deletedix = -1;
|
||||
|
||||
// search for the object (continue while !null and !this object)
|
||||
while(values[index] != FREE && !(hash(values[index]) == hash && values[index] == value)) {
|
||||
// if there's a deleted object here we can put this object here,
|
||||
// provided it's not in here somewhere else already
|
||||
if (values[index] == REMOVED) {
|
||||
deletedix = index;
|
||||
}
|
||||
|
||||
index = ((index + offset) & 0x7FFFFFFF) % values.length;
|
||||
offset = offset * 2 + 1;
|
||||
|
||||
if (offset == -1) {
|
||||
offset = 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (values[index] == FREE) {
|
||||
if (deletedix != -1) { // reusing a deleted cell
|
||||
index = deletedix;
|
||||
} else {
|
||||
freeEntries--;
|
||||
}
|
||||
|
||||
modCount++;
|
||||
elements++;
|
||||
values[index] = value;
|
||||
|
||||
if (1 - (freeEntries / (double) values.length) > LOAD_FACTOR) {
|
||||
rehash();
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void remove(int msw, int lsw) {
|
||||
remove(LongHash.toLong(msw, lsw));
|
||||
}
|
||||
|
||||
public boolean remove(long value) {
|
||||
int hash = hash(value);
|
||||
int index = (hash & 0x7FFFFFFF) % values.length;
|
||||
int offset = 1;
|
||||
|
||||
// search for the object (continue while !null and !this object)
|
||||
while(values[index] != FREE && !(hash(values[index]) == hash && values[index] == value)) {
|
||||
index = ((index + offset) & 0x7FFFFFFF) % values.length;
|
||||
offset = offset * 2 + 1;
|
||||
|
||||
if (offset == -1) {
|
||||
offset = 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (values[index] != FREE) {
|
||||
values[index] = REMOVED;
|
||||
modCount++;
|
||||
elements--;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
elements = 0;
|
||||
for (int ix = 0; ix < values.length; ix++) {
|
||||
values[ix] = FREE;
|
||||
}
|
||||
|
||||
freeEntries = values.length;
|
||||
modCount++;
|
||||
}
|
||||
|
||||
public long[] toArray() {
|
||||
long[] result = new long[elements];
|
||||
long[] values = Arrays.copyOf(this.values, this.values.length);
|
||||
int pos = 0;
|
||||
|
||||
for (long value : values) {
|
||||
if (value != FREE && value != REMOVED) {
|
||||
result[pos++] = value;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public long popFirst() {
|
||||
for (long value : values) {
|
||||
if (value != FREE && value != REMOVED) {
|
||||
remove(value);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long[] popAll() {
|
||||
long[] ret = toArray();
|
||||
clear();
|
||||
return ret;
|
||||
}
|
||||
|
||||
// This method copied from Murmur3, written by Austin Appleby released under Public Domain
|
||||
private int hash(long value) {
|
||||
value ^= value >>> 33;
|
||||
value *= 0xff51afd7ed558ccdL;
|
||||
value ^= value >>> 33;
|
||||
value *= 0xc4ceb9fe1a85ec53L;
|
||||
value ^= value >>> 33;
|
||||
return (int) value;
|
||||
}
|
||||
|
||||
private void rehash() {
|
||||
int gargagecells = values.length - (elements + freeEntries);
|
||||
if (gargagecells / (double) values.length > 0.05) {
|
||||
rehash(values.length);
|
||||
} else {
|
||||
rehash(values.length * 2 + 1);
|
||||
}
|
||||
}
|
||||
|
||||
private void rehash(int newCapacity) {
|
||||
long[] newValues = new long[newCapacity];
|
||||
|
||||
for (long value : values) {
|
||||
if (value == FREE || value == REMOVED) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int hash = hash(value);
|
||||
int index = (hash & 0x7FFFFFFF) % newCapacity;
|
||||
int offset = 1;
|
||||
|
||||
// search for the object
|
||||
while (newValues[index] != FREE) {
|
||||
index = ((index + offset) & 0x7FFFFFFF) % newCapacity;
|
||||
offset = offset * 2 + 1;
|
||||
|
||||
if (offset == -1) {
|
||||
offset = 2;
|
||||
}
|
||||
}
|
||||
|
||||
newValues[index] = value;
|
||||
}
|
||||
|
||||
values = newValues;
|
||||
freeEntries = values.length - elements;
|
||||
}
|
||||
|
||||
private class Itr implements Iterator {
|
||||
private int index;
|
||||
private int lastReturned = -1;
|
||||
private int expectedModCount;
|
||||
|
||||
public Itr() {
|
||||
for (index = 0; index < values.length && (values[index] == FREE || values[index] == REMOVED); index++) {
|
||||
// This is just to drive the index forward to the first valid entry
|
||||
}
|
||||
expectedModCount = modCount;
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return index != values.length;
|
||||
}
|
||||
|
||||
public Long next() {
|
||||
if (modCount != expectedModCount) {
|
||||
throw new ConcurrentModificationException();
|
||||
}
|
||||
|
||||
int length = values.length;
|
||||
if (index >= length) {
|
||||
lastReturned = -2;
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
lastReturned = index;
|
||||
for (index += 1; index < length && (values[index] == FREE || values[index] == REMOVED); index++) {
|
||||
// This is just to drive the index forward to the next valid entry
|
||||
}
|
||||
|
||||
if (values[lastReturned] == FREE) {
|
||||
return FREE;
|
||||
} else {
|
||||
return values[lastReturned];
|
||||
}
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
if (modCount != expectedModCount) {
|
||||
throw new ConcurrentModificationException();
|
||||
}
|
||||
|
||||
if (lastReturned == -1 || lastReturned == -2) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
if (values[lastReturned] != FREE && values[lastReturned] != REMOVED) {
|
||||
values[lastReturned] = REMOVED;
|
||||
elements--;
|
||||
modCount++;
|
||||
expectedModCount = modCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,422 +0,0 @@
|
||||
package org.bukkit.craftbukkit.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.util.AbstractCollection;
|
||||
import java.util.AbstractSet;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public class LongObjectHashMap<V> implements Cloneable, Serializable {
|
||||
static final long serialVersionUID = 2841537710170573815L;
|
||||
|
||||
private static final long EMPTY_KEY = Long.MIN_VALUE;
|
||||
private static final int BUCKET_SIZE = 4096;
|
||||
|
||||
private transient long[][] keys;
|
||||
private transient V[][] values;
|
||||
private transient int modCount;
|
||||
private transient int size;
|
||||
|
||||
public LongObjectHashMap() {
|
||||
initialize();
|
||||
}
|
||||
|
||||
public LongObjectHashMap(Map<? extends Long, ? extends V> map) {
|
||||
this();
|
||||
putAll(map);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return size == 0;
|
||||
}
|
||||
|
||||
public boolean containsKey(long key) {
|
||||
return get(key) != null;
|
||||
}
|
||||
|
||||
public boolean containsValue(V value) {
|
||||
for (V val : values()) {
|
||||
if (val == value || val.equals(value)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public V get(long key) {
|
||||
int index = (int) (keyIndex(key) & (BUCKET_SIZE - 1));
|
||||
long[] inner = keys[index];
|
||||
if (inner == null) return null;
|
||||
|
||||
for (int i = 0; i < inner.length; i++) {
|
||||
long innerKey = inner[i];
|
||||
if (innerKey == EMPTY_KEY) {
|
||||
return null;
|
||||
} else if (innerKey == key) {
|
||||
return values[index][i];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public V put(long key, V value) {
|
||||
int index = (int) (keyIndex(key) & (BUCKET_SIZE - 1));
|
||||
long[] innerKeys = keys[index];
|
||||
V[] innerValues = values[index];
|
||||
modCount++;
|
||||
|
||||
if (innerKeys == null) {
|
||||
// need to make a new chain
|
||||
keys[index] = innerKeys = new long[8];
|
||||
Arrays.fill(innerKeys, EMPTY_KEY);
|
||||
values[index] = innerValues = (V[]) new Object[8];
|
||||
innerKeys[0] = key;
|
||||
innerValues[0] = value;
|
||||
size++;
|
||||
} else {
|
||||
int i;
|
||||
for (i = 0; i < innerKeys.length; i++) {
|
||||
// found an empty spot in the chain to put this
|
||||
if (innerKeys[i] == EMPTY_KEY) {
|
||||
size++;
|
||||
innerKeys[i] = key;
|
||||
innerValues[i] = value;
|
||||
return null;
|
||||
}
|
||||
|
||||
// found an existing entry in the chain with this key, replace it
|
||||
if (innerKeys[i] == key) {
|
||||
V oldValue = innerValues[i];
|
||||
innerKeys[i] = key;
|
||||
innerValues[i] = value;
|
||||
return oldValue;
|
||||
}
|
||||
}
|
||||
|
||||
// chain is full, resize it and add our new entry
|
||||
keys[index] = innerKeys = Arrays.copyOf(innerKeys, i << 1);
|
||||
Arrays.fill(innerKeys, i, innerKeys.length, EMPTY_KEY);
|
||||
values[index] = innerValues = Arrays.copyOf(innerValues, i << 1);
|
||||
innerKeys[i] = key;
|
||||
innerValues[i] = value;
|
||||
size++;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public V remove(long key) {
|
||||
int index = (int) (keyIndex(key) & (BUCKET_SIZE - 1));
|
||||
long[] inner = keys[index];
|
||||
if (inner == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (int i = 0; i < inner.length; i++) {
|
||||
// hit the end of the chain, didn't find this entry
|
||||
if (inner[i] == EMPTY_KEY) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (inner[i] == key) {
|
||||
V value = values[index][i];
|
||||
|
||||
for (i++; i < inner.length; i++) {
|
||||
if (inner[i] == EMPTY_KEY) {
|
||||
break;
|
||||
}
|
||||
|
||||
inner[i - 1] = inner[i];
|
||||
values[index][i - 1] = values[index][i];
|
||||
}
|
||||
|
||||
inner[i - 1] = EMPTY_KEY;
|
||||
values[index][i - 1] = null;
|
||||
size--;
|
||||
modCount++;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void putAll(Map<? extends Long, ? extends V> map) {
|
||||
for (Map.Entry entry : map.entrySet()) {
|
||||
put((Long) entry.getKey(), (V) entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
if (size == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
modCount++;
|
||||
size = 0;
|
||||
Arrays.fill(keys, null);
|
||||
Arrays.fill(values, null);
|
||||
}
|
||||
|
||||
public Set<Long> keySet() {
|
||||
return new KeySet();
|
||||
}
|
||||
|
||||
public Collection<V> values() {
|
||||
return new ValueCollection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Set of Entry objects for the HashMap. This is not how the internal
|
||||
* implementation is laid out so this constructs the entire Set when called. For
|
||||
* this reason it should be avoided if at all possible.
|
||||
*
|
||||
* @return Set of Entry objects
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public Set<Map.Entry<Long, V>> entrySet() {
|
||||
HashSet<Map.Entry<Long, V>> set = new HashSet<Map.Entry<Long, V>>();
|
||||
for (long key : keySet()) {
|
||||
set.add(new Entry(key, get(key)));
|
||||
}
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
public Object clone() throws CloneNotSupportedException {
|
||||
LongObjectHashMap clone = (LongObjectHashMap) super.clone();
|
||||
// Make sure we clear any existing information from the clone
|
||||
clone.clear();
|
||||
// Make sure the clone is properly setup for new entries
|
||||
clone.initialize();
|
||||
|
||||
// Iterate through the data normally to do a safe clone
|
||||
for (long key : keySet()) {
|
||||
final V value = get(key);
|
||||
clone.put(key, value);
|
||||
}
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
private void initialize() {
|
||||
keys = new long[BUCKET_SIZE][];
|
||||
values = (V[][]) new Object[BUCKET_SIZE][];
|
||||
}
|
||||
|
||||
private long keyIndex(long key) {
|
||||
key ^= key >>> 33;
|
||||
key *= 0xff51afd7ed558ccdL;
|
||||
key ^= key >>> 33;
|
||||
key *= 0xc4ceb9fe1a85ec53L;
|
||||
key ^= key >>> 33;
|
||||
return key;
|
||||
}
|
||||
|
||||
private void writeObject(ObjectOutputStream outputStream) throws IOException {
|
||||
outputStream.defaultWriteObject();
|
||||
|
||||
for (long key : keySet()) {
|
||||
V value = get(key);
|
||||
outputStream.writeLong(key);
|
||||
outputStream.writeObject(value);
|
||||
}
|
||||
|
||||
outputStream.writeLong(EMPTY_KEY);
|
||||
outputStream.writeObject(null);
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream inputStream) throws ClassNotFoundException, IOException {
|
||||
inputStream.defaultReadObject();
|
||||
initialize();
|
||||
|
||||
while (true) {
|
||||
long key = inputStream.readLong();
|
||||
V value = (V) inputStream.readObject();
|
||||
if (key == EMPTY_KEY && value == null) {
|
||||
break;
|
||||
}
|
||||
|
||||
put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class ValueIterator implements Iterator<V> {
|
||||
private int count;
|
||||
private int index;
|
||||
private int innerIndex;
|
||||
private int expectedModCount;
|
||||
private long lastReturned = EMPTY_KEY;
|
||||
|
||||
long prevKey = EMPTY_KEY;
|
||||
V prevValue;
|
||||
|
||||
ValueIterator() {
|
||||
expectedModCount = LongObjectHashMap.this.modCount;
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return count < LongObjectHashMap.this.size;
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
if (LongObjectHashMap.this.modCount != expectedModCount) {
|
||||
throw new ConcurrentModificationException();
|
||||
}
|
||||
|
||||
if (lastReturned == EMPTY_KEY) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
count--;
|
||||
LongObjectHashMap.this.remove(lastReturned);
|
||||
lastReturned = EMPTY_KEY;
|
||||
expectedModCount = LongObjectHashMap.this.modCount;
|
||||
}
|
||||
|
||||
public V next() {
|
||||
if (LongObjectHashMap.this.modCount != expectedModCount) {
|
||||
throw new ConcurrentModificationException();
|
||||
}
|
||||
|
||||
if (!hasNext()) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
long[][] keys = LongObjectHashMap.this.keys;
|
||||
count++;
|
||||
|
||||
if (prevKey != EMPTY_KEY) {
|
||||
innerIndex++;
|
||||
}
|
||||
|
||||
for (; index < keys.length; index++) {
|
||||
if (keys[index] != null) {
|
||||
for (; innerIndex < keys[index].length; innerIndex++) {
|
||||
long key = keys[index][innerIndex];
|
||||
V value = values[index][innerIndex];
|
||||
if (key == EMPTY_KEY) {
|
||||
break;
|
||||
}
|
||||
|
||||
lastReturned = key;
|
||||
prevKey = key;
|
||||
prevValue = value;
|
||||
return prevValue;
|
||||
}
|
||||
innerIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
}
|
||||
|
||||
private class KeyIterator implements Iterator<Long> {
|
||||
final ValueIterator iterator;
|
||||
|
||||
public KeyIterator() {
|
||||
iterator = new ValueIterator();
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
iterator.remove();
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return iterator.hasNext();
|
||||
}
|
||||
|
||||
public Long next() {
|
||||
iterator.next();
|
||||
return iterator.prevKey;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class KeySet extends AbstractSet<Long> {
|
||||
public void clear() {
|
||||
LongObjectHashMap.this.clear();
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return LongObjectHashMap.this.size();
|
||||
}
|
||||
|
||||
public boolean contains(Object key) {
|
||||
return key instanceof Long && LongObjectHashMap.this.containsKey((Long) key);
|
||||
|
||||
}
|
||||
|
||||
public boolean remove(Object key) {
|
||||
return LongObjectHashMap.this.remove((Long) key) != null;
|
||||
}
|
||||
|
||||
public Iterator<Long> iterator() {
|
||||
return new KeyIterator();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class ValueCollection extends AbstractCollection<V> {
|
||||
public void clear() {
|
||||
LongObjectHashMap.this.clear();
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return LongObjectHashMap.this.size();
|
||||
}
|
||||
|
||||
public boolean contains(Object value) {
|
||||
return LongObjectHashMap.this.containsValue((V) value);
|
||||
}
|
||||
|
||||
public Iterator<V> iterator() {
|
||||
return new ValueIterator();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class Entry implements Map.Entry<Long, V> {
|
||||
private final Long key;
|
||||
private V value;
|
||||
|
||||
Entry(long k, V v) {
|
||||
key = k;
|
||||
value = v;
|
||||
}
|
||||
|
||||
public Long getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public V getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public V setValue(V v) {
|
||||
V old = value;
|
||||
value = v;
|
||||
put(key, v);
|
||||
return old;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
package org.bukkit.craftbukkit.util;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.gson.Gson;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.UUID;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
public class MojangNameLookup {
|
||||
private static final Logger logger = LogManager.getFormatterLogger(MojangNameLookup.class);
|
||||
|
||||
public static String lookupName(UUID id) {
|
||||
if (id == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
URL url = new URL("https://sessionserver.mojang.com/session/minecraft/profile/" + id.toString().replace("-", ""));
|
||||
URLConnection connection = url.openConnection();
|
||||
connection.setConnectTimeout(15000);
|
||||
connection.setReadTimeout(15000);
|
||||
connection.setUseCaches(false);
|
||||
inputStream = connection.getInputStream();
|
||||
String result = IOUtils.toString(inputStream, Charsets.UTF_8);
|
||||
Gson gson = new Gson();
|
||||
Response response = gson.fromJson(result, Response.class);
|
||||
if (response == null || response.name == null) {
|
||||
logger.warn("Failed to lookup name from UUID");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (response.cause != null && response.cause.length() > 0) {
|
||||
logger.warn("Failed to lookup name from UUID: %s", response.errorMessage);
|
||||
return null;
|
||||
}
|
||||
|
||||
return response.name;
|
||||
} catch (MalformedURLException ex) {
|
||||
logger.warn("Malformed URL in UUID lookup");
|
||||
return null;
|
||||
} catch (IOException ex) {
|
||||
IOUtils.closeQuietly(inputStream);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(inputStream);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private class Response {
|
||||
String errorMessage;
|
||||
String cause;
|
||||
String name;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
package org.bukkit.craftbukkit.util;
|
||||
|
||||
import net.minecraft.server.ExceptionWorldConflict;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
|
||||
public class ServerShutdownThread extends Thread {
|
||||
@@ -13,9 +12,7 @@ public class ServerShutdownThread extends Thread {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
server.stop();
|
||||
} catch (ExceptionWorldConflict ex) {
|
||||
ex.printStackTrace();
|
||||
server.close();
|
||||
} finally {
|
||||
try {
|
||||
server.reader.getTerminal().restore();
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
package org.bukkit.craftbukkit.util;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.logging.Formatter;
|
||||
import java.util.logging.LogRecord;
|
||||
import joptsimple.OptionException;
|
||||
import joptsimple.OptionSet;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
|
||||
public class ShortConsoleLogFormatter extends Formatter {
|
||||
private final SimpleDateFormat date;
|
||||
|
||||
public ShortConsoleLogFormatter(MinecraftServer server) {
|
||||
OptionSet options = server.options;
|
||||
SimpleDateFormat date = null;
|
||||
|
||||
if (options.has("date-format")) {
|
||||
try {
|
||||
Object object = options.valueOf("date-format");
|
||||
|
||||
if ((object != null) && (object instanceof SimpleDateFormat)) {
|
||||
date = (SimpleDateFormat) object;
|
||||
}
|
||||
} catch (OptionException ex) {
|
||||
System.err.println("Given date format is not valid. Falling back to default.");
|
||||
}
|
||||
} else if (options.has("nojline")) {
|
||||
date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
}
|
||||
|
||||
if (date == null) {
|
||||
date = new SimpleDateFormat("HH:mm:ss");
|
||||
}
|
||||
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String format(LogRecord record) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
Throwable ex = record.getThrown();
|
||||
|
||||
builder.append(date.format(record.getMillis()));
|
||||
builder.append(" [");
|
||||
builder.append(record.getLevel().getLocalizedName().toUpperCase());
|
||||
builder.append("] ");
|
||||
builder.append(formatMessage(record));
|
||||
builder.append('\n');
|
||||
|
||||
if (ex != null) {
|
||||
StringWriter writer = new StringWriter();
|
||||
ex.printStackTrace(new PrintWriter(writer));
|
||||
builder.append(writer);
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -10,13 +10,15 @@ import org.bukkit.craftbukkit.Main;
|
||||
import org.fusesource.jansi.Ansi;
|
||||
import org.fusesource.jansi.Ansi.Erase;
|
||||
|
||||
public class TerminalConsoleWriterThread implements Runnable {
|
||||
public class TerminalConsoleWriterThread extends Thread {
|
||||
final private ConsoleReader reader;
|
||||
final private OutputStream output;
|
||||
|
||||
public TerminalConsoleWriterThread(OutputStream output, ConsoleReader reader) {
|
||||
this.output = output;
|
||||
this.reader = reader;
|
||||
|
||||
this.setDaemon(true);
|
||||
}
|
||||
|
||||
public void run() {
|
||||
|
||||
Reference in New Issue
Block a user