concurrencyLevel(int concurrencyLevel) {
+ builder.concurrencyLevel(concurrencyLevel);
+ return this;
+ }
+
+ /**
+ * Specifies that each entry should be automatically removed from the cache once a fixed duration has elapsed after
+ * the entry's creation, or last access. Access time is reset by
+ * {@link com.google.common.cache.Cache#get Cache.get()}, but not by operations on the view returned by
+ * {@link com.google.common.cache.Cache#asMap() Cache.asMap()}.
+ *
+ *
+ * When {@code duration} is zero, elements will be evicted immediately after being loaded into the cache. This has
+ * the same effect as invoking {@link #maximumSize maximumSize}{@code (0)}. It can be useful in testing, or to
+ * disable caching temporarily without a code change.
+ *
+ *
+ * Expired entries may be counted by {@link com.google.common.cache.Cache#size Cache.size()}, but will never be
+ * visible to read or write operations. Expired entries are currently cleaned up during write operations, or during
+ * occasional read operations in the absense of writes; though this behavior may change in the future.
+ *
+ * @param duration the length of time after an entry is last accessed that it should be automatically removed
+ * @param unit the unit that {@code duration} is expressed in
+ * @return This for chaining
+ *
+ * @throws IllegalArgumentException if {@code duration} is negative
+ * @throws IllegalStateException if the time to idle or time to live was already set
+ */
+ public CacheBuilder expireAfterAccess(long duration, TimeUnit unit) {
+ builder.expireAfterAccess(duration, unit);
+ return this;
+ }
+
+ /**
+ * Specifies that each entry should be automatically removed from the cache once a fixed duration has elapsed after
+ * the entry's creation, or the most recent replacement of its value.
+ *
+ *
+ * When {@code duration} is zero, elements will be evicted immediately after being loaded into the cache. This has
+ * the same effect as invoking {@link #maximumSize maximumSize}{@code (0)}. It can be useful in testing, or to
+ * disable caching temporarily without a code change.
+ *
+ *
+ * Expired entries may be counted by {@link com.google.common.cache.Cache#size Cache.size()}, but will never be
+ * visible to read or write operations. Expired entries are currently cleaned up during write operations, or during
+ * occasional read operations in the absense of writes; though this behavior may change in the future.
+ *
+ * @param duration the length of time after an entry is created that it should be automatically removed
+ * @param unit the unit that {@code duration} is expressed in
+ * @return This for chaining
+ *
+ * @throws IllegalArgumentException if {@code duration} is negative
+ * @throws IllegalStateException if the time to live or time to idle was already set
+ */
+ public CacheBuilder expireAfterWrite(long duration, TimeUnit unit) {
+ builder.expireAfterWrite(duration, unit);
+ return this;
+ }
+
+ /**
+ * Sets the minimum total size for the internal hash tables. For example, if the initial capacity is {@code 60}, and
+ * the concurrency level is {@code 8}, then eight segments are created, each having a hash table of size eight.
+ * Providing a large enough estimate at construction time avoids the need for expensive resizing operations later,
+ * but setting this value unnecessarily high wastes memory.
+ *
+ * @param initialCapacity - initial capacity
+ * @return This for chaining
+ *
+ * @throws IllegalArgumentException if {@code initialCapacity} is negative
+ * @throws IllegalStateException if an initial capacity was already set
+ */
+ public CacheBuilder initialCapacity(int initialCapacity) {
+ builder.initialCapacity(initialCapacity);
+ return this;
+ }
+
+ /**
+ * Specifies the maximum number of entries the cache may contain. Note that the cache may evict an entry before
+ * this limit is exceeded. As the cache size grows close to the maximum, the cache evicts entries that are less
+ * likely to be used again. For example, the cache may evict an entry because it hasn't been used recently or very
+ * often.
+ *
+ *
+ * When {@code size} is zero, elements will be evicted immediately after being loaded into the cache. This has the
+ * same effect as invoking {@link #expireAfterWrite expireAfterWrite}{@code (0, unit)} or {@link #expireAfterAccess expireAfterAccess}{@code (0,
+ * unit)}. It can be useful in testing, or to disable caching temporarily without a code change.
+ *
+ * @param size the maximum size of the cache
+ * @return This for chaining
+ *
+ * @throws IllegalArgumentException if {@code size} is negative
+ * @throws IllegalStateException if a maximum size was already set
+ */
+ public CacheBuilder maximumSize(int size) {
+ builder.maximumSize(size);
+ return this;
+ }
+
+ /**
+ * Specifies a listener instance, which all caches built using this {@code CacheBuilder} will notify each time an
+ * entry is removed from the cache by any means.
+ *
+ *
+ * Each cache built by this {@code CacheBuilder} after this method is called invokes the supplied listener after
+ * removing an element for any reason (see removal causes in
+ * {@link com.google.common.cache.RemovalCause RemovalCause}). It will invoke the listener during invocations of any
+ * of that cache's public methods (even read-only methods).
+ *
+ *
+ * Important note: Instead of returning this as a {@code CacheBuilder} instance, this method returns
+ * {@code CacheBuilder}. From this point on, either the original reference or the returned reference may be
+ * used to complete configuration and build the cache, but only the "generic" one is type-safe. That is, it will
+ * properly prevent you from building caches whose key or value types are incompatible with the types accepted by
+ * the listener already provided; the {@code CacheBuilder} type cannot do this. For best results, simply use the
+ * standard method-chaining idiom, as illustrated in the documentation at top, configuring a {@code CacheBuilder}
+ * and building your {@link com.google.common.cache.Cache Cache} all in a single statement.
+ *
+ *
+ * Warning: if you ignore the above advice, and use this {@code CacheBuilder} to build a cache whose key or
+ * value type is incompatible with the listener, you will likely experience a {@link ClassCastException} at some
+ * undefined point in the future.
+ *
+ * @param Key type
+ * @param Value type
+ * @param listener - removal listener
+ * @return This for chaining
+ *
+ * @throws IllegalStateException if a removal listener was already set
+ */
+ @SuppressWarnings("unchecked")
+ public CacheBuilder removalListener(RemovalListener super K1, ? super V1> listener) {
+ builder.removalListener(listener);
+ return (CacheBuilder) this;
+ }
+
+ /**
+ * Specifies a nanosecond-precision time source for use in determining when entries should be expired. By default,
+ * {@link System#nanoTime} is used.
+ *
+ *
+ * The primary intent of this method is to facilitate testing of caches which have been configured with
+ * {@link #expireAfterWrite} or {@link #expireAfterAccess}.
+ *
+ * @param ticker - ticker
+ * @return This for chaining
+ *
+ * @throws IllegalStateException if a ticker was already set
+ */
+ public CacheBuilder ticker(Ticker ticker) {
+ builder.ticker(ticker);
+ return this;
+ }
+
+ /**
+ * Specifies that each value (not key) stored in the cache should be wrapped in a
+ * {@link java.lang.ref.SoftReference SoftReference} (by default, strong references are used). Softly-referenced
+ * objects will be garbage-collected in a globally
+ * least-recently-used manner, in response to memory demand.
+ *
+ *
+ * Warning: in most circumstances it is better to set a per-cache {@linkplain #maximumSize maximum size}
+ * instead of using soft references. You should only use this method if you are well familiar with the practical
+ * consequences of soft references.
+ *
+ *
+ * Note: when this method is used, the resulting cache will use identity ({@code ==}) comparison to determine
+ * equality of values.
+ *
+ * @return This for chaining
+ *
+ * @throws IllegalStateException if the value strength was already set
+ */
+ public CacheBuilder softValues() {
+ builder.softValues();
+ return this;
+ }
+
+ /**
+ * Specifies that each key (not value) stored in the cache should be wrapped in a
+ * {@link java.lang.ref.WeakReference WeakReference} (by default, strong references are used).
+ *
+ *
+ * Warning: when this method is used, the resulting cache will use identity ({@code ==}) comparison to
+ * determine equality of keys.
+ *
+ * @return This for chaining
+ *
+ * @throws IllegalStateException if the key strength was already set
+ */
+ public CacheBuilder weakKeys() {
+ builder.weakKeys();
+ return this;
+ }
+
+ /**
+ * Specifies that each value (not key) stored in the cache should be wrapped in a
+ * {@link java.lang.ref.WeakReference WeakReference} (by default, strong references are used).
+ *
+ *
+ * Weak values will be garbage collected once they are weakly reachable. This makes them a poor candidate for
+ * caching; consider {@link #softValues} instead.
+ *
+ *
+ * Note: when this method is used, the resulting cache will use identity ({@code ==}) comparison to determine
+ * equality of values.
+ *
+ * @return This for chaining
+ *
+ * @throws IllegalStateException if the value strength was already set
+ */
+ public CacheBuilder weakValues() {
+ builder.weakValues();
+ return this;
+ }
+
+ /**
+ * Returns the cache wrapped as a ConcurrentMap.
+ *
+ * We can't return the direct Cache instance as it changed in Guava 13.
+ *
+ * @param Key type
+ * @param Value type
+ * @param loader - cache loader
+ * @return The cache as a a map.
+ */
+ @SuppressWarnings("unchecked")
+ public ConcurrentMap build(CacheLoader super K1, V1> loader) {
+ Object cache = null;
+
+ if (BUILD_METHOD == null) {
+ try {
+ BUILD_METHOD = builder.getClass().getDeclaredMethod("build", CacheLoader.class);
+ BUILD_METHOD.setAccessible(true);
+ } catch (Exception e) {
+ throw new IllegalStateException("Unable to find CacheBuilder.build(CacheLoader)", e);
+ }
+ }
+
+ // Attempt to build the Cache
+ try {
+ cache = BUILD_METHOD.invoke(builder, loader);
+ } catch (Exception e) {
+ throw new IllegalStateException("Unable to invoke " + BUILD_METHOD + " on " + builder, e);
+ }
+
+ if (AS_MAP_METHOD == null) {
+ try {
+ AS_MAP_METHOD = cache.getClass().getMethod("asMap");
+ AS_MAP_METHOD.setAccessible(true);
+ } catch (Exception e) {
+ throw new IllegalStateException("Unable to find Cache.asMap() in " + cache, e);
+ }
+ }
+
+ // Retrieve it as a map
+ try {
+ return (ConcurrentMap) AS_MAP_METHOD.invoke(cache);
+ } catch (Exception e) {
+ throw new IllegalStateException("Unable to invoke " + AS_MAP_METHOD + " on " + cache, e);
+ }
+ }
+}
diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/FastLoginBukkit.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/FastLoginBukkit.java
index 9d91d451..e90a1d97 100644
--- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/FastLoginBukkit.java
+++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/FastLoginBukkit.java
@@ -5,7 +5,6 @@ import com.avaje.ebeaninternal.api.ClassUtil;
import com.comphenix.protocol.AsynchronousManager;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.ProtocolManager;
-import com.comphenix.protocol.utility.SafeCacheBuilder;
import com.github.games647.fastlogin.bukkit.commands.CrackedCommand;
import com.github.games647.fastlogin.bukkit.commands.PremiumCommand;
import com.github.games647.fastlogin.bukkit.hooks.BukkitAuthPlugin;
@@ -42,7 +41,7 @@ public class FastLoginBukkit extends JavaPlugin {
//this map is thread-safe for async access (Packet Listener)
//SafeCacheBuilder is used in order to be version independent
- private final ConcurrentMap session = SafeCacheBuilder.newBuilder()
+ private final ConcurrentMap session = CacheBuilder.newBuilder()
//2 minutes should be enough as a timeout for bad internet connection (Server, Client and Mojang)
.expireAfterWrite(1, TimeUnit.MINUTES)
//mapped by ip:port -> PlayerSession
@@ -104,7 +103,7 @@ public class FastLoginBukkit extends JavaPlugin {
if (getServer().getPluginManager().isPluginEnabled("ProtocolSupport")) {
getServer().getPluginManager().registerEvents(new ProtocolSupportListener(this), this);
- } else {
+ } else if (getServer().getPluginManager().isPluginEnabled("ProtocolLib")) {
ProtocolManager protocolManager = ProtocolLibrary.getProtocolManager();
//we are performing HTTP request on these so run it async (seperate from the Netty IO threads)
@@ -116,6 +115,9 @@ public class FastLoginBukkit extends JavaPlugin {
asynchronousManager.registerAsyncHandler(startPacketListener).start(WORKER_THREADS);
asynchronousManager.registerAsyncHandler(encryptionPacketListener).start(WORKER_THREADS);
getServer().getPluginManager().registerEvents(new LoginSkinApplyListener(this), this);
+ } else {
+ getLogger().warning("Either ProtocolLib or ProtocolSupport have to be installed "
+ + "if you don't use BungeeCord");
}
}
diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/MojangApiBukkit.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/MojangApiBukkit.java
index c3a99e12..8bd54754 100644
--- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/MojangApiBukkit.java
+++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/MojangApiBukkit.java
@@ -1,6 +1,5 @@
package com.github.games647.fastlogin.bukkit;
-import com.comphenix.protocol.wrappers.WrappedSignedProperty;
import com.github.games647.fastlogin.core.FastLoginCore;
import com.github.games647.fastlogin.core.MojangApiConnector;
@@ -50,7 +49,7 @@ public class MojangApiBukkit extends MojangApiConnector {
if (propertyName.equals("textures")) {
String skinValue = (String) skinProperty.get("value");
String signature = (String) skinProperty.get("signature");
- playerSession.setSkin(WrappedSignedProperty.fromValues(propertyName, skinValue, signature));
+ playerSession.setSkin(skinValue, signature);
}
return true;
diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hooks/CrazyLoginHook.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hooks/CrazyLoginHook.java
index 6529dcad..e94462ef 100644
--- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hooks/CrazyLoginHook.java
+++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hooks/CrazyLoginHook.java
@@ -1,7 +1,5 @@
package com.github.games647.fastlogin.bukkit.hooks;
-import com.comphenix.protocol.reflect.FuzzyReflection;
-
import de.st_ddt.crazylogin.CrazyLogin;
import de.st_ddt.crazylogin.data.LoginPlayerData;
import de.st_ddt.crazylogin.databases.CrazyLoginDataDatabase;
@@ -13,6 +11,7 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.logging.Level;
+import org.apache.commons.lang.reflect.FieldUtils;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
@@ -108,7 +107,7 @@ public class CrazyLoginHook implements BukkitAuthPlugin {
private PlayerListener getListener() {
PlayerListener listener;
try {
- listener = FuzzyReflection.getFieldValue(crazyLoginPlugin, PlayerListener.class, true);
+ listener = (PlayerListener) FieldUtils.readField(crazyLoginPlugin, "playerListener", true);
} catch (Exception ex) {
crazyLoginPlugin.getLogger().log(Level.SEVERE, "Failed to get the listener instance for auto login", ex);
listener = null;
diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/packet/LoginSkinApplyListener.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/packet/LoginSkinApplyListener.java
index 74df184f..c4803963 100644
--- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/packet/LoginSkinApplyListener.java
+++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/packet/LoginSkinApplyListener.java
@@ -19,15 +19,17 @@ public class LoginSkinApplyListener implements Listener {
this.plugin = plugin;
}
- @EventHandler(priority = EventPriority.HIGHEST)
+ @EventHandler(priority = EventPriority.LOW)
public void onPlayerLogin(PlayerLoginEvent loginEvent) {
Player player = loginEvent.getPlayer();
BukkitLoginSession session = plugin.getSessions().get(player.getAddress().toString());
if (session != null && plugin.getConfig().getBoolean("forwardSkin")) {
WrappedGameProfile gameProfile = WrappedGameProfile.fromPlayer(player);
- WrappedSignedProperty skin = session.getSkin();
- if (skin != null) {
+ String skinData = session.getEncodedSkinData();
+ String signature = session.getSkinSignature();
+ if (skinData != null && signature != null) {
+ WrappedSignedProperty skin = WrappedSignedProperty.fromValues("textures", skinData, signature);
gameProfile.getProperties().put("textures", skin);
}
}
diff --git a/bukkit/src/main/resources/plugin.yml b/bukkit/src/main/resources/plugin.yml
index 0049b822..7f0c3fba 100644
--- a/bukkit/src/main/resources/plugin.yml
+++ b/bukkit/src/main/resources/plugin.yml
@@ -14,12 +14,11 @@ dev-url: ${project.url}
# Load the plugin as early as possible to inject it for all players
load: STARTUP
-# Without Protocollib the plugin does not work at all
-depend: [ProtocolLib]
-
softdepend:
+ # We require either ProtocolLib or ProtocolSupport
- ProtocolSupport
- # Auth plugins
+ - ProtocolLib
+ # Auth plugins - we delay the hook
# - xAuth
# - AuthMe
# - LogIt
diff --git a/bungee/pom.xml b/bungee/pom.xml
index 4e7ca96f..5a626267 100644
--- a/bungee/pom.xml
+++ b/bungee/pom.xml
@@ -5,7 +5,7 @@
com.github.games647
fastlogin
- 1.5.2
+ 1.6
../pom.xml
diff --git a/core/pom.xml b/core/pom.xml
index ec1fed85..2a982962 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -5,7 +5,7 @@
com.github.games647
fastlogin
- 1.5.2
+ 1.6
../pom.xml
diff --git a/pom.xml b/pom.xml
index 58d188da..783f1715 100644
--- a/pom.xml
+++ b/pom.xml
@@ -8,7 +8,7 @@
pom
FastLogin
- 1.5.2
+ 1.6
2015
https://www.spigotmc.org/resources/fastlogin.14153/
diff --git a/universal/pom.xml b/universal/pom.xml
index 8f2f2615..e9e50fdf 100644
--- a/universal/pom.xml
+++ b/universal/pom.xml
@@ -5,7 +5,7 @@
com.github.games647
fastlogin
- 1.5.2
+ 1.6
../pom.xml