diff --git a/CHANGELOG.md b/CHANGELOG.md index 7be3d178..21afed2b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +######1.6 + +* Removed ProtocolLib as required dependency. You can use ProtocolSupport or BungeeCord as alternative + ######1.5.2 * Fixed BungeeCord force logins if there is a lobby server diff --git a/bukkit/pom.xml b/bukkit/pom.xml index 46a51f5d..fe9e1afc 100644 --- a/bukkit/pom.xml +++ b/bukkit/pom.xml @@ -5,7 +5,7 @@ com.github.games647 fastlogin - 1.5.2 + 1.6 ../pom.xml diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/BukkitLoginSession.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/BukkitLoginSession.java index 46f29279..1f81be7e 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/BukkitLoginSession.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/BukkitLoginSession.java @@ -1,6 +1,5 @@ package com.github.games647.fastlogin.bukkit; -import com.comphenix.protocol.wrappers.WrappedSignedProperty; import com.github.games647.fastlogin.core.LoginSession; import com.github.games647.fastlogin.core.PlayerProfile; @@ -19,9 +18,11 @@ public class BukkitLoginSession extends LoginSession { private final byte[] verifyToken; private UUID uuid; - private WrappedSignedProperty skinProperty; private boolean verified; + private String encodedSkinData; + private String skinSignature; + public BukkitLoginSession(String username, String serverId, byte[] verifyToken, boolean registered , PlayerProfile profile) { super(username, registered, profile); @@ -64,22 +65,23 @@ public class BukkitLoginSession extends LoginSession { return ArrayUtils.clone(verifyToken); } - /** - * Gets the premium skin of this player - * - * @return skin property or null if the player has no skin or is a cracked account - */ - public synchronized WrappedSignedProperty getSkin() { - return this.skinProperty; + public synchronized String getEncodedSkinData() { + return encodedSkinData; + } + + public synchronized String getSkinSignature() { + return skinSignature; } /** * Sets the premium skin property which was retrieved by the session server * - * @param skinProperty premium skin property + * @param encodedData + * @param skinSignature */ - public synchronized void setSkin(WrappedSignedProperty skinProperty) { - this.skinProperty = skinProperty; + public synchronized void setSkin(String encodedData, String skinSignature) { + this.encodedSkinData = encodedData; + this.skinSignature = skinSignature; } /** diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/CacheBuilder.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/CacheBuilder.java new file mode 100644 index 00000000..fb07c667 --- /dev/null +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/CacheBuilder.java @@ -0,0 +1,320 @@ +package com.github.games647.fastlogin.bukkit; + +import java.lang.reflect.Method; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.TimeUnit; + +import com.google.common.base.Ticker; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.RemovalListener; + +/** + * Represents a Guava CacheBuilder that is compatible with both Guava 10 and 13 + */ +public class CacheBuilder { + + private CacheBuilder builder; + + private static Method BUILD_METHOD; + private static Method AS_MAP_METHOD; + + @SuppressWarnings("unchecked") + private CacheBuilder() { + builder = (CacheBuilder) CacheBuilder.newBuilder(); + } + + /** + * Construct a new safe cache builder. + * + * @param Key type + * @param Value type + * + * @return A new cache builder. + */ + public static CacheBuilder newBuilder() { + return new CacheBuilder(); + } + + /** + * Guides the allowed concurrency among update operations. Used as a hint for internal sizing. The table is + * internally partitioned to try to permit the indicated number of concurrent updates without contention. Because + * assignment of entries to these partitions is not necessarily uniform, the actual concurrency observed may vary. + * Ideally, you should choose a value to accommodate as many threads as will ever concurrently modify the table. + * Using a significantly higher value than you need can waste space and time, and a significantly lower value can + * lead to thread contention. But overestimates and underestimates within an order of magnitude do not usually have + * much noticeable impact. A value of one permits only one thread to modify the cache at a time, but since read + * operations can proceed concurrently, this still yields higher concurrency than full synchronization. Defaults to + * 4. + * + *

+ * Note:The default may change in the future. If you care about this value, you should always choose it + * explicitly. + * + * @param concurrencyLevel New concurrency level + * @return This for chaining + * + * @throws IllegalArgumentException if {@code concurrencyLevel} is nonpositive + * @throws IllegalStateException if a concurrency level was already set + */ + public CacheBuilder 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 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 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