diff --git a/gateway/EaglercraftXBungee/EaglerXBungee-Latest.jar b/gateway/EaglercraftXBungee/EaglerXBungee-Latest.jar index bdcef2ed..a5d8bef9 100644 Binary files a/gateway/EaglercraftXBungee/EaglerXBungee-Latest.jar and b/gateway/EaglercraftXBungee/EaglerXBungee-Latest.jar differ diff --git a/gateway/EaglercraftXBungee/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/gateway_bungeecord/EaglerXBungee.java b/gateway/EaglercraftXBungee/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/gateway_bungeecord/EaglerXBungee.java index 126d1119..b69cbe8a 100644 --- a/gateway/EaglercraftXBungee/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/gateway_bungeecord/EaglerXBungee.java +++ b/gateway/EaglercraftXBungee/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/gateway_bungeecord/EaglerXBungee.java @@ -64,8 +64,11 @@ import net.md_5.bungee.BungeeCord; */ public class EaglerXBungee extends Plugin { - public static final String NATIVE_BUNGEECORD_BUILD = "1.21-R0.1-SNAPSHOT:20a71b0:1887"; - public static final String NATIVE_WATERFALL_BUILD = "1.21-R0.1-SNAPSHOT:bf1be7e:581"; + public static final String NATIVE_BUNGEECORD_BUILD = "1.21-R0.1-SNAPSHOT:1265a99:1892"; + public static final String NATIVE_BUNGEECORD_BUILD_DL = "https://ci.md-5.net/job/BungeeCord/1892/artifact/bootstrap/target/BungeeCord.jar"; + + public static final String NATIVE_WATERFALL_BUILD = "1.21-R0.1-SNAPSHOT:9ab9e2b:582"; + public static final String NATIVE_WATERFALL_BUILD_DL = "https://api.papermc.io/v2/projects/waterfall/versions/1.21/builds/582/downloads/waterfall-1.21-582.jar"; static { CompatWarning.displayCompatWarning(); diff --git a/gateway/EaglercraftXBungee/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/gateway_bungeecord/auth/AuthLoadingCache.java b/gateway/EaglercraftXBungee/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/gateway_bungeecord/auth/AuthLoadingCache.java index 957942a8..852e9d67 100644 --- a/gateway/EaglercraftXBungee/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/gateway_bungeecord/auth/AuthLoadingCache.java +++ b/gateway/EaglercraftXBungee/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/gateway_bungeecord/auth/AuthLoadingCache.java @@ -4,6 +4,8 @@ import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; import net.lax1dude.eaglercraft.v1_8.plugin.gateway_bungeecord.api.EaglerXBungeeAPIHelper; @@ -44,6 +46,7 @@ public class AuthLoadingCache { boolean shouldEvict(K key, V value); } + private final ReadWriteLock cacheMapLock; private final Map> cacheMap; private final CacheLoader provider; private final long cacheTTL; @@ -51,6 +54,7 @@ public class AuthLoadingCache { private long cacheTimer; public AuthLoadingCache(CacheLoader provider, long cacheTTL) { + this.cacheMapLock = new ReentrantReadWriteLock(); this.cacheMap = new HashMap<>(); this.provider = provider; this.cacheTTL = cacheTTL; @@ -58,13 +62,19 @@ public class AuthLoadingCache { public V get(K key) { CacheEntry etr; - synchronized(cacheMap) { + cacheMapLock.readLock().lock(); + try { etr = cacheMap.get(key); + }finally { + cacheMapLock.readLock().unlock(); } if(etr == null) { + cacheMapLock.writeLock().lock(); V loaded = provider.load(key); - synchronized(cacheMap) { + try { cacheMap.put(key, new CacheEntry<>(loaded)); + }finally { + cacheMapLock.writeLock().unlock(); } return loaded; }else { @@ -74,13 +84,17 @@ public class AuthLoadingCache { } public void evict(K key) { - synchronized(cacheMap) { + cacheMapLock.writeLock().lock(); + try { cacheMap.remove(key); + }finally { + cacheMapLock.writeLock().unlock(); } } public void evictAll(CacheVisitor visitor) { - synchronized(cacheMap) { + cacheMapLock.writeLock().lock(); + try { Iterator>> itr = cacheMap.entrySet().iterator(); while(itr.hasNext()) { Entry> etr = itr.next(); @@ -88,6 +102,8 @@ public class AuthLoadingCache { itr.remove(); } } + }finally { + cacheMapLock.writeLock().unlock(); } } @@ -95,7 +111,8 @@ public class AuthLoadingCache { long millis = EaglerXBungeeAPIHelper.steadyTimeMillis(); if(millis - cacheTimer > (cacheTTL / 2L)) { cacheTimer = millis; - synchronized(cacheMap) { + cacheMapLock.writeLock().lock(); + try { Iterator> mapItr = cacheMap.values().iterator(); while(mapItr.hasNext()) { CacheEntry etr = mapItr.next(); @@ -103,13 +120,18 @@ public class AuthLoadingCache { mapItr.remove(); } } + }finally { + cacheMapLock.writeLock().unlock(); } } } public void flush() { - synchronized(cacheMap) { + cacheMapLock.writeLock().lock(); + try { cacheMap.clear(); + }finally { + cacheMapLock.writeLock().unlock(); } } diff --git a/gateway/EaglercraftXBungee/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/gateway_bungeecord/server/protocol/GameProtocolMessageController.java b/gateway/EaglercraftXBungee/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/gateway_bungeecord/server/protocol/GameProtocolMessageController.java index 1f0d610c..0c8b38db 100644 --- a/gateway/EaglercraftXBungee/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/gateway_bungeecord/server/protocol/GameProtocolMessageController.java +++ b/gateway/EaglercraftXBungee/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/gateway_bungeecord/server/protocol/GameProtocolMessageController.java @@ -1,6 +1,7 @@ package net.lax1dude.eaglercraft.v1_8.plugin.gateway_bungeecord.server.protocol; import java.io.IOException; +import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.concurrent.Callable; @@ -238,10 +239,12 @@ public class GameProtocolMessageController { while(!sendQueueV4.isEmpty()) { sendCount = 0; totalLen = 0; + Iterator itr = sendQueueV4.iterator(); do { - i = sendQueueV4.get(sendCount++).length; + i = itr.next().length; totalLen += GamePacketOutputBuffer.getVarIntSize(i) + i; - }while(totalLen < 32760 && sendCount < sendQueueV4.size()); + ++sendCount; + }while(totalLen < 32760 && itr.hasNext()); if(totalLen >= 32760) { --sendCount; } diff --git a/gateway/EaglercraftXBungee/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/gateway_bungeecord/server/web/HttpWebServer.java b/gateway/EaglercraftXBungee/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/gateway_bungeecord/server/web/HttpWebServer.java index 704fbfd3..63848b29 100644 --- a/gateway/EaglercraftXBungee/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/gateway_bungeecord/server/web/HttpWebServer.java +++ b/gateway/EaglercraftXBungee/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/gateway_bungeecord/server/web/HttpWebServer.java @@ -40,7 +40,6 @@ public class HttpWebServer { private final String page404; private static HttpMemoryCache default404Page; private static HttpMemoryCache default404UpgradePage; - private static final Object cacheClearLock = new Object(); public HttpWebServer(File directory, Map contentTypes, List index, String page404) { this.directory = directory; @@ -52,15 +51,13 @@ public class HttpWebServer { public void flushCache() { long millis = EaglerXBungeeAPIHelper.steadyTimeMillis(); - synchronized(cacheClearLock) { - synchronized(filesCache) { - Iterator itr = filesCache.values().iterator(); - while(itr.hasNext()) { - HttpMemoryCache i = itr.next(); - if(i.contentType.fileBrowserCacheTTL != Long.MAX_VALUE && millis - i.lastCacheHit > 900000l) { - i.fileData.release(); - itr.remove(); - } + synchronized(filesCache) { + Iterator itr = filesCache.values().iterator(); + while(itr.hasNext()) { + HttpMemoryCache i = itr.next(); + if(i.contentType.fileBrowserCacheTTL != Long.MAX_VALUE && millis - i.lastCacheHit > 900000l) { + i.fileData.release(); + itr.remove(); } } } @@ -94,19 +91,16 @@ public class HttpWebServer { String joinedPath = String.join("/", pathList); - synchronized(cacheClearLock) { - synchronized(filesCache) { - cached = filesCache.get(joinedPath); - } + //TODO: Rewrite this to cause less lock contention + synchronized(filesCache) { + cached = filesCache.get(joinedPath); if(cached != null) { cached = validateCache(cached); if(cached != null) { return cached; }else { - synchronized(filesCache) { - filesCache.remove(joinedPath); - } + filesCache.remove(joinedPath); } } @@ -123,19 +117,13 @@ public class HttpWebServer { if(f.isDirectory()) { for(int i = 0, l = index.size(); i < l; ++i) { String p = joinedPath + "/" + index.get(i); - synchronized(filesCache) { - cached = filesCache.get(p); - } + cached = filesCache.get(p); if(cached != null) { cached = validateCache(cached); if(cached != null) { - synchronized(filesCache) { - filesCache.put(joinedPath, cached); - } + filesCache.put(joinedPath, cached); }else { - synchronized(filesCache) { - filesCache.remove(p); - } + filesCache.remove(p); if(page404 == null || path.equals(page404)) { return default404Page; }else { @@ -151,9 +139,7 @@ public class HttpWebServer { if(ff.isFile()) { HttpMemoryCache memCache = retrieveFile(ff, p); if(memCache != null) { - synchronized(filesCache) { - filesCache.put(joinedPath, memCache); - } + filesCache.put(joinedPath, memCache); return memCache; } } @@ -166,9 +152,7 @@ public class HttpWebServer { }else { HttpMemoryCache memCache = retrieveFile(f, joinedPath); if(memCache != null) { - synchronized(filesCache) { - filesCache.put(joinedPath, memCache); - } + filesCache.put(joinedPath, memCache); return memCache; }else { if(page404 == null || path.equals(page404)) { diff --git a/gateway/EaglercraftXBungee/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/gateway_bungeecord/shit/CompatWarning.java b/gateway/EaglercraftXBungee/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/gateway_bungeecord/shit/CompatWarning.java index 2cdff345..de7fb944 100644 --- a/gateway/EaglercraftXBungee/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/gateway_bungeecord/shit/CompatWarning.java +++ b/gateway/EaglercraftXBungee/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/gateway_bungeecord/shit/CompatWarning.java @@ -37,7 +37,10 @@ public class CompatWarning { ":> apart from the versions listed below:", ":> ", ":> - BungeeCord: " + EaglerXBungee.NATIVE_BUNGEECORD_BUILD, + ":> - " + EaglerXBungee.NATIVE_BUNGEECORD_BUILD_DL, + ":> ", ":> - Waterfall: " + EaglerXBungee.NATIVE_WATERFALL_BUILD, + ":> - " + EaglerXBungee.NATIVE_WATERFALL_BUILD_DL, ":> ", ":> This is not a Bukkit/Spigot plugin!", ":> ", diff --git a/gateway/EaglercraftXBungee/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/gateway_bungeecord/skins/CapeServiceOffline.java b/gateway/EaglercraftXBungee/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/gateway_bungeecord/skins/CapeServiceOffline.java index 5430bb85..da01d3f2 100644 --- a/gateway/EaglercraftXBungee/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/gateway_bungeecord/skins/CapeServiceOffline.java +++ b/gateway/EaglercraftXBungee/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/gateway_bungeecord/skins/CapeServiceOffline.java @@ -1,8 +1,8 @@ package net.lax1dude.eaglercraft.v1_8.plugin.gateway_bungeecord.skins; -import java.util.HashMap; -import java.util.Map; import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import net.lax1dude.eaglercraft.v1_8.plugin.gateway_bungeecord.server.EaglerInitialHandler; import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessagePacket; @@ -13,7 +13,7 @@ import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherCape import net.md_5.bungee.UserConnection; /** - * Copyright (c) 2024 lax1dude. All Rights Reserved. + * Copyright (c) 2024-2025 lax1dude. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -31,21 +31,16 @@ public class CapeServiceOffline { public static final int masterRateLimitPerPlayer = 250; - private final Map capesCache = new HashMap<>(); + private final ConcurrentMap capesCache = new ConcurrentHashMap<>(); public void registerEaglercraftPlayer(UUID playerUUID, GameMessagePacket capePacket) { - synchronized(capesCache) { - capesCache.put(playerUUID, capePacket); - } + capesCache.put(playerUUID, capePacket); } public void processGetOtherCape(UUID searchUUID, UserConnection sender) { EaglerInitialHandler initialHandler = (EaglerInitialHandler)sender.getPendingConnection(); if(initialHandler.skinLookupRateLimiter.rateLimit(masterRateLimitPerPlayer)) { - GameMessagePacket maybeCape; - synchronized(capesCache) { - maybeCape = capesCache.get(searchUUID); - } + GameMessagePacket maybeCape = capesCache.get(searchUUID); if(maybeCape != null) { initialHandler.sendEaglerMessage(maybeCape); }else { @@ -56,10 +51,7 @@ public class CapeServiceOffline { } public void processForceCape(UUID clientUUID, EaglerInitialHandler initialHandler) { - GameMessagePacket maybeCape; - synchronized(capesCache) { - maybeCape = capesCache.get(clientUUID); - } + GameMessagePacket maybeCape = capesCache.get(clientUUID); if(maybeCape != null) { if (maybeCape instanceof SPacketOtherCapePresetEAG) { initialHandler.sendEaglerMessage( @@ -72,15 +64,11 @@ public class CapeServiceOffline { } public void unregisterPlayer(UUID playerUUID) { - synchronized(capesCache) { - capesCache.remove(playerUUID); - } + capesCache.remove(playerUUID); } public GameMessagePacket getCape(UUID clientUUID) { - synchronized(capesCache) { - return capesCache.get(clientUUID); - } + return capesCache.get(clientUUID); } public byte[] getCapeHandshakeData(UUID clientUUID) { @@ -109,8 +97,6 @@ public class CapeServiceOffline { } public void shutdown() { - synchronized(capesCache) { - capesCache.clear(); - } + capesCache.clear(); } } diff --git a/gateway/EaglercraftXBungee/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/gateway_bungeecord/skins/SkinService.java b/gateway/EaglercraftXBungee/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/gateway_bungeecord/skins/SkinService.java index 3d4c5331..d5b30c89 100644 --- a/gateway/EaglercraftXBungee/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/gateway_bungeecord/skins/SkinService.java +++ b/gateway/EaglercraftXBungee/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/gateway_bungeecord/skins/SkinService.java @@ -1,6 +1,7 @@ package net.lax1dude.eaglercraft.v1_8.plugin.gateway_bungeecord.skins; import java.net.URI; +import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; @@ -10,6 +11,10 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.function.Consumer; import org.apache.commons.codec.binary.Base64; @@ -38,7 +43,7 @@ import net.md_5.bungee.connection.LoginResult; import net.md_5.bungee.protocol.Property; /** - * Copyright (c) 2022-2024 lax1dude. All Rights Reserved. + * Copyright (c) 2022-2025 lax1dude. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -56,16 +61,20 @@ public class SkinService implements ISkinService { public static final int masterRateLimitPerPlayer = 250; - private final Map onlinePlayersCache = new HashMap<>(); + private final ConcurrentMap onlinePlayersCache = new ConcurrentHashMap<>(); + private final ConcurrentMap onlinePlayersToTexturesMap = new ConcurrentHashMap<>(); + private final ConcurrentMap foreignSkinCache = new ConcurrentHashMap<>(); + + private final ReadWriteLock onlinePlayersFromTexturesMapLock = new ReentrantReadWriteLock(); private final Multimap onlinePlayersFromTexturesMap = MultimapBuilder.hashKeys().hashSetValues().build(); - private final Map onlinePlayersToTexturesMap = new HashMap<>(); - private final Map foreignSkinCache = new HashMap<>(); private final Map pendingTextures = new HashMap<>(); private final Map pendingUUIDs = new HashMap<>(); private final Map pendingNameLookups = new HashMap<>(); + private final ReadWriteLock antagonistsLock = new ReentrantReadWriteLock(); private final TObjectIntMap antagonists = new TObjectIntHashMap<>(); + private long antagonistCooldown = EaglerXBungeeAPIHelper.steadyTimeMillis(); private final Consumer> antagonistLogger = new Consumer>() { @@ -75,7 +84,8 @@ public class SkinService implements ISkinService { if(t.size() == 1) { int limit = EaglerXBungee.getEagler().getConfig().getAntagonistsRateLimit() << 1; UUID offender = t.iterator().next(); - synchronized(antagonists) { + antagonistsLock.writeLock().lock(); + try { int v = antagonists.get(offender); if(v == antagonists.getNoEntryValue()) { antagonists.put(offender, 1); @@ -84,6 +94,8 @@ public class SkinService implements ISkinService { antagonists.put(offender, v + 1); } } + }finally { + antagonistsLock.writeLock().unlock(); } } } @@ -97,7 +109,7 @@ public class SkinService implements ISkinService { protected final UUID uuid; protected final SkinPacketVersionCache data; protected final int modelKnown; - protected long lastHit; + protected volatile long lastHit; protected CachedForeignSkin(UUID uuid, SkinPacketVersionCache data, int modelKnown) { this.uuid = uuid; @@ -132,7 +144,7 @@ public class SkinService implements ISkinService { protected final Consumer> antagonistsCallback; protected final long initializedTime; - protected boolean finalized; + protected volatile boolean finalized; protected PendingTextureDownload(UUID textureUUID, String textureURL, UUID caller, Consumer callback, Consumer> antagonistsCallback) { @@ -174,7 +186,7 @@ public class SkinService implements ISkinService { protected final Consumer> antagonistsCallback; protected final long initializedTime; - protected boolean finalized; + protected volatile boolean finalized; protected PendingProfileUUIDLookup(UUID profileUUID, UUID caller, Consumer callback, Consumer> antagonistsCallback) { @@ -215,7 +227,7 @@ public class SkinService implements ISkinService { protected final Consumer> antagonistsCallback; protected final long initializedTime; - protected boolean finalized; + protected volatile boolean finalized; protected PendingProfileNameLookup(String profileName, UUID caller, Consumer callback, Consumer> antagonistsCallback) { @@ -263,60 +275,46 @@ public class SkinService implements ISkinService { return; } - CachedPlayerSkin maybeCachedPacket; - synchronized(onlinePlayersCache) { - maybeCachedPacket = onlinePlayersCache.get(searchUUID); - } + CachedPlayerSkin maybeCachedPacket = onlinePlayersCache.get(searchUUID); if(maybeCachedPacket != null) { eaglerHandler.sendEaglerMessage(maybeCachedPacket.data.get(eaglerHandler.getEaglerProtocol())); }else { ProxiedPlayer player = BungeeCord.getInstance().getPlayer(searchUUID); - UUID playerTexture; - synchronized(onlinePlayersToTexturesMap) { - playerTexture = onlinePlayersToTexturesMap.get(searchUUID); - } + UUID playerTexture = onlinePlayersToTexturesMap.get(searchUUID); if(playerTexture != null) { Collection possiblePlayers; - synchronized(onlinePlayersFromTexturesMap) { - possiblePlayers = onlinePlayersFromTexturesMap.get(playerTexture); + onlinePlayersFromTexturesMapLock.readLock().lock(); + try { + possiblePlayers = new ArrayList<>(onlinePlayersFromTexturesMap.get(playerTexture)); + }finally { + onlinePlayersFromTexturesMapLock.readLock().unlock(); } boolean playersExist = possiblePlayers.size() > 0; if(playersExist) { for(UUID uuid : possiblePlayers) { - synchronized(onlinePlayersCache) { - maybeCachedPacket = onlinePlayersCache.get(uuid); - } + maybeCachedPacket = onlinePlayersCache.get(uuid); if(maybeCachedPacket != null) { SkinPacketVersionCache rewritten = SkinPacketVersionCache.rewriteUUID( maybeCachedPacket.data, searchUUID.getMostSignificantBits(), searchUUID.getLeastSignificantBits()); if(player != null) { - synchronized(onlinePlayersCache) { - onlinePlayersCache.put(searchUUID, new CachedPlayerSkin(rewritten, - maybeCachedPacket.textureUUID, maybeCachedPacket.modelId)); - } + onlinePlayersCache.put(searchUUID, new CachedPlayerSkin(rewritten, + maybeCachedPacket.textureUUID, maybeCachedPacket.modelId)); } eaglerHandler.sendEaglerMessage(rewritten.get(eaglerHandler.getEaglerProtocol())); return; } } } - CachedForeignSkin foreignSkin; - synchronized(foreignSkinCache) { - foreignSkin = foreignSkinCache.get(playerTexture); - } + CachedForeignSkin foreignSkin = foreignSkinCache.get(playerTexture); if(foreignSkin != null && foreignSkin.modelKnown != -1) { if(player != null) { - synchronized(onlinePlayersCache) { - onlinePlayersCache.put(searchUUID, - new CachedPlayerSkin(SkinPacketVersionCache.rewriteUUID(foreignSkin.data, - searchUUID.getMostSignificantBits(), searchUUID.getLeastSignificantBits()), - playerTexture, foreignSkin.modelKnown)); - } - synchronized(foreignSkinCache) { - foreignSkinCache.remove(playerTexture); - } + onlinePlayersCache.put(searchUUID, + new CachedPlayerSkin(SkinPacketVersionCache.rewriteUUID(foreignSkin.data, + searchUUID.getMostSignificantBits(), searchUUID.getLeastSignificantBits()), + playerTexture, foreignSkin.modelKnown)); + foreignSkinCache.remove(playerTexture); }else { foreignSkin.lastHit = EaglerXBungeeAPIHelper.steadyTimeMillis(); } @@ -339,7 +337,7 @@ public class SkinService implements ISkinService { if(skinObj != null) { JsonElement url = json.get("url"); if(url != null) { - String urlStr = SkinService.sanitizeTextureURL(url.getAsString()); + String urlStr = sanitizeTextureURL(url.getAsString()); if(urlStr == null) { break; } @@ -353,19 +351,14 @@ public class SkinService implements ISkinService { } UUID skinUUID = SkinPackets.createEaglerURLSkinUUID(urlStr); - CachedForeignSkin foreignSkin; - synchronized(foreignSkinCache) { - foreignSkin = foreignSkinCache.remove(skinUUID); - } + CachedForeignSkin foreignSkin = foreignSkinCache.remove(skinUUID); if(foreignSkin != null) { registerTextureToPlayerAssociation(skinUUID, searchUUID); SkinPacketVersionCache rewrite = SkinPacketVersionCache .rewriteUUIDModel(foreignSkin.data, searchUUID.getMostSignificantBits(), searchUUID.getLeastSignificantBits(), model); - synchronized(onlinePlayersCache) { - onlinePlayersCache.put(searchUUID, new CachedPlayerSkin(rewrite, skinUUID, model)); - } + onlinePlayersCache.put(searchUUID, new CachedPlayerSkin(rewrite, skinUUID, model)); eaglerHandler.sendEaglerMessage(rewrite.get(eaglerHandler.getEaglerProtocol())); return; } @@ -398,10 +391,7 @@ public class SkinService implements ISkinService { }); } }else { - CachedForeignSkin foreignSkin; - synchronized(foreignSkinCache) { - foreignSkin = foreignSkinCache.get(searchUUID); - } + CachedForeignSkin foreignSkin = foreignSkinCache.get(searchUUID); if(foreignSkin != null) { foreignSkin.lastHit = EaglerXBungeeAPIHelper.steadyTimeMillis(); eaglerHandler.sendEaglerMessage(foreignSkin.data.get(eaglerHandler.getEaglerProtocol())); @@ -430,25 +420,22 @@ public class SkinService implements ISkinService { if(!eaglerHandler.skinLookupRateLimiter.rateLimit(masterRateLimitPerPlayer)) { return; } - CachedForeignSkin foreignSkin; - synchronized(foreignSkinCache) { - foreignSkin = foreignSkinCache.get(searchUUID); - } + CachedForeignSkin foreignSkin = foreignSkinCache.get(searchUUID); if(foreignSkin != null) { foreignSkin.lastHit = EaglerXBungeeAPIHelper.steadyTimeMillis(); eaglerHandler.sendEaglerMessage(foreignSkin.data.get(eaglerHandler.getEaglerProtocol())); }else { Collection possiblePlayers; - synchronized(onlinePlayersFromTexturesMap) { - possiblePlayers = onlinePlayersFromTexturesMap.get(searchUUID); + onlinePlayersFromTexturesMapLock.readLock().lock(); + try { + possiblePlayers = new ArrayList<>(onlinePlayersFromTexturesMap.get(searchUUID)); + }finally { + onlinePlayersFromTexturesMapLock.readLock().unlock(); } boolean playersExist = possiblePlayers.size() > 0; if(playersExist) { for(UUID uuid : possiblePlayers) { - CachedPlayerSkin maybeCachedPacket; - synchronized(onlinePlayersCache) { - maybeCachedPacket = onlinePlayersCache.get(uuid); - } + CachedPlayerSkin maybeCachedPacket = onlinePlayersCache.get(uuid); if(maybeCachedPacket != null) { eaglerHandler.sendEaglerMessage(maybeCachedPacket.data.get(eaglerHandler.getEaglerProtocol(), searchUUID.getMostSignificantBits(), searchUUID.getLeastSignificantBits())); @@ -461,10 +448,17 @@ public class SkinService implements ISkinService { searchUUID.getLeastSignificantBits(), 0)); return; } - if(eaglerHandler.skinTextureDownloadRateLimiter.rateLimit(config.getSkinRateLimitPlayer()) && !isLimitedAsAntagonist(sender.getUniqueId())) { - doAsync(() -> { - processResolveURLTextureForForeign(sender, searchUUID, searchUUID, skinURL, -1); - }); + skinURL = sanitizeTextureURL(skinURL); + if(skinURL != null) { + final String skinURL_ = skinURL; + if(eaglerHandler.skinTextureDownloadRateLimiter.rateLimit(config.getSkinRateLimitPlayer()) && !isLimitedAsAntagonist(sender.getUniqueId())) { + doAsync(() -> { + processResolveURLTextureForForeign(sender, searchUUID, searchUUID, skinURL_, -1); + }); + } + }else { + eaglerHandler.sendEaglerMessage(new SPacketOtherSkinPresetEAG(searchUUID.getMostSignificantBits(), + searchUUID.getLeastSignificantBits(), 0)); } } } @@ -479,10 +473,7 @@ public class SkinService implements ISkinService { @Override public void accept(byte[] t) { - CachedPlayerSkin skin; - synchronized(onlinePlayersCache) { - skin = onlinePlayersCache.get(onlineCacheUUID); - } + CachedPlayerSkin skin = onlinePlayersCache.get(onlineCacheUUID); if(skin != null) { EaglerInitialHandler initialHandler = (EaglerInitialHandler)initiator.getPendingConnection(); initialHandler.sendEaglerMessage(skin.data.get(initialHandler.getEaglerProtocol())); @@ -510,9 +501,7 @@ public class SkinService implements ISkinService { onlineCacheUUID.getMostSignificantBits(), onlineCacheUUID.getLeastSignificantBits()), null, -1); } - synchronized (onlinePlayersCache) { - onlinePlayersCache.put(onlineCacheUUID, skin); - } + onlinePlayersCache.put(onlineCacheUUID, skin); EaglerInitialHandler initialHandler = (EaglerInitialHandler) initiator.getPendingConnection(); initialHandler.sendEaglerMessage(skin.data.get(initialHandler.getEaglerProtocol())); } @@ -538,10 +527,7 @@ public class SkinService implements ISkinService { @Override public void accept(byte[] t) { - CachedForeignSkin skin; - synchronized(foreignSkinCache) { - skin = foreignSkinCache.get(foreignCacheUUID); - } + CachedForeignSkin skin = foreignSkinCache.get(foreignCacheUUID); if(skin != null) { EaglerInitialHandler initialHandler = (EaglerInitialHandler) initiator.getPendingConnection(); initialHandler.sendEaglerMessage(skin.data.get(initialHandler.getEaglerProtocol())); @@ -570,9 +556,7 @@ public class SkinService implements ISkinService { foreignCacheUUID.getLeastSignificantBits()), -1); } - synchronized (foreignSkinCache) { - foreignSkinCache.put(foreignCacheUUID, skin); - } + foreignSkinCache.put(foreignCacheUUID, skin); EaglerInitialHandler initialHandler = (EaglerInitialHandler) initiator.getPendingConnection(); initialHandler.sendEaglerMessage(skin.data.get(initialHandler.getEaglerProtocol())); } @@ -598,10 +582,7 @@ public class SkinService implements ISkinService { @Override public void accept(CacheFetchedProfile t) { if(t == null || t.texture == null) { - CachedPlayerSkin skin; - synchronized(onlinePlayersCache) { - skin = onlinePlayersCache.get(playerUUID); - } + CachedPlayerSkin skin = onlinePlayersCache.get(playerUUID); if(skin != null) { EaglerInitialHandler initialHandler = (EaglerInitialHandler) initiator.getPendingConnection(); initialHandler.sendEaglerMessage(skin.data.get(initialHandler.getEaglerProtocol())); @@ -634,9 +615,7 @@ public class SkinService implements ISkinService { SkinPackets.getModelId(t.model) == 1 ? 1 : 0), null, -1); } - synchronized(onlinePlayersCache) { - onlinePlayersCache.put(playerUUID, skin); - } + onlinePlayersCache.put(playerUUID, skin); EaglerInitialHandler initialHandler = (EaglerInitialHandler) initiator.getPendingConnection(); initialHandler.sendEaglerMessage(skin.data.get(initialHandler.getEaglerProtocol())); }else { @@ -666,10 +645,7 @@ public class SkinService implements ISkinService { @Override public void accept(CacheFetchedProfile t) { if(t == null || t.texture == null) { - CachedPlayerSkin skin; - synchronized(onlinePlayersCache) { - skin = onlinePlayersCache.get(t.uuid); - } + CachedPlayerSkin skin = onlinePlayersCache.get(t.uuid); if(skin != null) { EaglerInitialHandler initialHandler = (EaglerInitialHandler) initiator.getPendingConnection(); initialHandler.sendEaglerMessage(skin.data.get(initialHandler.getEaglerProtocol())); @@ -700,9 +676,7 @@ public class SkinService implements ISkinService { mapUUID.getMostSignificantBits(), mapUUID.getLeastSignificantBits(), SkinPackets.getModelId(t.model) == 1 ? 1 : 0), null, -1); } - synchronized(onlinePlayersCache) { - onlinePlayersCache.put(mapUUID, skin); - } + onlinePlayersCache.put(mapUUID, skin); EaglerInitialHandler initialHandler = (EaglerInitialHandler) initiator.getPendingConnection(); initialHandler.sendEaglerMessage(skin.data.get(initialHandler.getEaglerProtocol())); }else { @@ -732,10 +706,7 @@ public class SkinService implements ISkinService { @Override public void accept(CacheFetchedProfile t) { if(t == null || t.texture == null) { - CachedForeignSkin skin; - synchronized(foreignSkinCache) { - skin = foreignSkinCache.get(playerUUID); - } + CachedForeignSkin skin = foreignSkinCache.get(playerUUID); if(skin != null) { EaglerInitialHandler initialHandler = (EaglerInitialHandler) initiator.getPendingConnection(); initialHandler.sendEaglerMessage(skin.data.get(initialHandler.getEaglerProtocol())); @@ -768,9 +739,7 @@ public class SkinService implements ISkinService { SkinPackets.getModelId(t.model) == 1 ? 1 : 0), -1); } - synchronized(foreignSkinCache) { - foreignSkinCache.put(playerUUID, skin); - } + foreignSkinCache.put(playerUUID, skin); EaglerInitialHandler initialHandler = (EaglerInitialHandler) initiator.getPendingConnection(); initialHandler.sendEaglerMessage(skin.data.get(initialHandler.getEaglerProtocol())); }else { @@ -791,27 +760,16 @@ public class SkinService implements ISkinService { } public void registerEaglercraftPlayer(UUID clientUUID, SkinPacketVersionCache generatedPacket, int modelId) { - synchronized(foreignSkinCache) { - foreignSkinCache.remove(clientUUID); - } - synchronized(onlinePlayersCache) { - onlinePlayersCache.put(clientUUID, new CachedPlayerSkin(generatedPacket, null, modelId)); - } + foreignSkinCache.remove(clientUUID); + onlinePlayersCache.put(clientUUID, new CachedPlayerSkin(generatedPacket, null, modelId)); } public void unregisterPlayer(UUID clientUUID) { - CachedPlayerSkin data; - synchronized(onlinePlayersCache) { - data = onlinePlayersCache.remove(clientUUID); - } + CachedPlayerSkin data = onlinePlayersCache.remove(clientUUID); if(data != null) { - synchronized(foreignSkinCache) { - foreignSkinCache.put(clientUUID, new CachedForeignSkin(clientUUID, data.data, data.modelId)); - } + foreignSkinCache.put(clientUUID, new CachedForeignSkin(clientUUID, data.data, data.modelId)); if(data.textureUUID != null) { - synchronized(foreignSkinCache) { - foreignSkinCache.put(data.textureUUID, new CachedForeignSkin(data.textureUUID, data.data, data.modelId)); - } + foreignSkinCache.put(data.textureUUID, new CachedForeignSkin(data.textureUUID, data.data, data.modelId)); } deletePlayerTextureAssociation(clientUUID, data.textureUUID); }else { @@ -821,94 +779,77 @@ public class SkinService implements ISkinService { private void deletePlayerTextureAssociation(UUID clientUUID, UUID textureUUID) { if(textureUUID != null) { - synchronized(onlinePlayersToTexturesMap) { - onlinePlayersToTexturesMap.remove(clientUUID); - } - synchronized(onlinePlayersFromTexturesMap) { + onlinePlayersToTexturesMap.remove(clientUUID); + onlinePlayersFromTexturesMapLock.writeLock().lock(); + try { onlinePlayersFromTexturesMap.remove(textureUUID, clientUUID); + }finally { + onlinePlayersFromTexturesMapLock.writeLock().unlock(); } }else { - UUID removedUUID; - synchronized(onlinePlayersToTexturesMap) { - removedUUID = onlinePlayersToTexturesMap.remove(clientUUID); - } + UUID removedUUID = onlinePlayersToTexturesMap.remove(clientUUID); if(removedUUID != null) { - synchronized(onlinePlayersFromTexturesMap) { + onlinePlayersFromTexturesMapLock.writeLock().lock(); + try { onlinePlayersFromTexturesMap.remove(removedUUID, clientUUID); + }finally { + onlinePlayersFromTexturesMapLock.writeLock().unlock(); } } } } public void registerTextureToPlayerAssociation(UUID textureUUID, UUID playerUUID) { - synchronized(onlinePlayersFromTexturesMap) { + onlinePlayersFromTexturesMapLock.writeLock().lock(); + try { onlinePlayersFromTexturesMap.put(textureUUID, playerUUID); + }finally { + onlinePlayersFromTexturesMapLock.writeLock().unlock(); } - synchronized(onlinePlayersToTexturesMap) { - onlinePlayersToTexturesMap.put(playerUUID, textureUUID); - } - CachedForeignSkin foreign; - synchronized(foreignSkinCache) { - foreign = foreignSkinCache.remove(textureUUID); - } + onlinePlayersToTexturesMap.put(playerUUID, textureUUID); + CachedForeignSkin foreign = foreignSkinCache.remove(textureUUID); if(foreign != null) { - synchronized(onlinePlayersCache) { - onlinePlayersCache.put(playerUUID, new CachedPlayerSkin(foreign.data, textureUUID, foreign.modelKnown)); - } + onlinePlayersCache.put(playerUUID, new CachedPlayerSkin(foreign.data, textureUUID, foreign.modelKnown)); } } public void processForceSkin(UUID playerUUID, EaglerInitialHandler eaglerHandler) { - CachedPlayerSkin maybeCachedPacket; - synchronized(onlinePlayersCache) { - maybeCachedPacket = onlinePlayersCache.get(playerUUID); - } + CachedPlayerSkin maybeCachedPacket = onlinePlayersCache.get(playerUUID); if(maybeCachedPacket != null) { eaglerHandler.sendEaglerMessage(maybeCachedPacket.data.getForceClientV4()); }else { - UUID playerTexture; - synchronized(onlinePlayersToTexturesMap) { - playerTexture = onlinePlayersToTexturesMap.get(playerUUID); - } + UUID playerTexture = onlinePlayersToTexturesMap.get(playerUUID); if(playerTexture != null) { Collection possiblePlayers; - synchronized(onlinePlayersFromTexturesMap) { - possiblePlayers = onlinePlayersFromTexturesMap.get(playerTexture); + onlinePlayersFromTexturesMapLock.readLock().lock(); + try { + possiblePlayers = new ArrayList<>(onlinePlayersFromTexturesMap.get(playerTexture)); + }finally { + onlinePlayersFromTexturesMapLock.readLock().unlock(); } boolean playersExist = possiblePlayers.size() > 0; if(playersExist) { for(UUID uuid : possiblePlayers) { - synchronized(onlinePlayersCache) { - maybeCachedPacket = onlinePlayersCache.get(uuid); - } + maybeCachedPacket = onlinePlayersCache.get(uuid); if(maybeCachedPacket != null) { SkinPacketVersionCache rewritten = SkinPacketVersionCache.rewriteUUID( maybeCachedPacket.data, playerUUID.getMostSignificantBits(), playerUUID.getLeastSignificantBits()); - synchronized(onlinePlayersCache) { - onlinePlayersCache.put(playerUUID, new CachedPlayerSkin(rewritten, - maybeCachedPacket.textureUUID, maybeCachedPacket.modelId)); - } + onlinePlayersCache.put(playerUUID, new CachedPlayerSkin(rewritten, + maybeCachedPacket.textureUUID, maybeCachedPacket.modelId)); eaglerHandler.sendEaglerMessage(rewritten.getForceClientV4()); return; } } } - CachedForeignSkin foreignSkin; - synchronized(foreignSkinCache) { - foreignSkin = foreignSkinCache.get(playerTexture); - } + CachedForeignSkin foreignSkin = foreignSkinCache.get(playerTexture); if(foreignSkin != null && foreignSkin.modelKnown != -1) { - synchronized(onlinePlayersCache) { - onlinePlayersCache.put(playerUUID, - new CachedPlayerSkin(SkinPacketVersionCache.rewriteUUID(foreignSkin.data, - playerUUID.getMostSignificantBits(), playerUUID.getLeastSignificantBits()), - playerTexture, foreignSkin.modelKnown)); - } - synchronized(foreignSkinCache) { - foreignSkinCache.remove(playerTexture); - } + onlinePlayersCache.put(playerUUID, + new CachedPlayerSkin(SkinPacketVersionCache.rewriteUUID(foreignSkin.data, + playerUUID.getMostSignificantBits(), playerUUID.getLeastSignificantBits()), + playerTexture, foreignSkin.modelKnown)); + foreignSkinCache.remove(playerTexture); eaglerHandler.sendEaglerMessage(foreignSkin.data.getForceClientV4()); return; } @@ -927,7 +868,7 @@ public class SkinService implements ISkinService { if(skinObj != null) { JsonElement url = json.get("url"); if(url != null) { - String urlStr = SkinService.sanitizeTextureURL(url.getAsString()); + String urlStr = sanitizeTextureURL(url.getAsString()); if(urlStr == null) { break; } @@ -941,19 +882,14 @@ public class SkinService implements ISkinService { } UUID skinUUID = SkinPackets.createEaglerURLSkinUUID(urlStr); - CachedForeignSkin foreignSkin; - synchronized(foreignSkinCache) { - foreignSkin = foreignSkinCache.remove(skinUUID); - } + CachedForeignSkin foreignSkin = foreignSkinCache.remove(skinUUID); if(foreignSkin != null) { registerTextureToPlayerAssociation(skinUUID, playerUUID); SkinPacketVersionCache rewrite = SkinPacketVersionCache .rewriteUUIDModel(foreignSkin.data, playerUUID.getMostSignificantBits(), playerUUID.getLeastSignificantBits(), model); - synchronized(onlinePlayersCache) { - onlinePlayersCache.put(playerUUID, new CachedPlayerSkin(rewrite, skinUUID, model)); - } + onlinePlayersCache.put(playerUUID, new CachedPlayerSkin(rewrite, skinUUID, model)); eaglerHandler.sendEaglerMessage(rewrite.getForceClientV4()); return; } @@ -981,10 +917,7 @@ public class SkinService implements ISkinService { } }); }else { - CachedForeignSkin foreignSkin; - synchronized(foreignSkinCache) { - foreignSkin = foreignSkinCache.get(playerUUID); - } + CachedForeignSkin foreignSkin = foreignSkinCache.get(playerUUID); if(foreignSkin != null) { foreignSkin.lastHit = EaglerXBungeeAPIHelper.steadyTimeMillis(); eaglerHandler.sendEaglerMessage(foreignSkin.data.getForceClientV4()); @@ -1011,10 +944,7 @@ public class SkinService implements ISkinService { @Override public void accept(byte[] t) { - CachedPlayerSkin skin; - synchronized(onlinePlayersCache) { - skin = onlinePlayersCache.get(onlineCacheUUID); - } + CachedPlayerSkin skin = onlinePlayersCache.get(onlineCacheUUID); if(skin != null) { initiator.sendEaglerMessage(skin.data.getForceClientV4()); } @@ -1041,9 +971,7 @@ public class SkinService implements ISkinService { onlineCacheUUID.getMostSignificantBits(), onlineCacheUUID.getLeastSignificantBits()), null, -1); } - synchronized (onlinePlayersCache) { - onlinePlayersCache.put(onlineCacheUUID, skin); - } + onlinePlayersCache.put(onlineCacheUUID, skin); initiator.sendEaglerMessage(skin.data.getForceClientV4()); } @@ -1068,10 +996,7 @@ public class SkinService implements ISkinService { @Override public void accept(byte[] t) { - CachedForeignSkin skin; - synchronized(foreignSkinCache) { - skin = foreignSkinCache.get(foreignCacheUUID); - } + CachedForeignSkin skin = foreignSkinCache.get(foreignCacheUUID); if(skin != null) { initiator.sendEaglerMessage(skin.data.getForceClientV4()); } @@ -1099,9 +1024,7 @@ public class SkinService implements ISkinService { foreignCacheUUID.getLeastSignificantBits()), -1); } - synchronized (foreignSkinCache) { - foreignSkinCache.put(foreignCacheUUID, skin); - } + foreignSkinCache.put(foreignCacheUUID, skin); initiator.sendEaglerMessage(skin.data.getForceClientV4()); } @@ -1126,10 +1049,7 @@ public class SkinService implements ISkinService { @Override public void accept(CacheFetchedProfile t) { if(t == null || t.texture == null) { - CachedPlayerSkin skin; - synchronized(onlinePlayersCache) { - skin = onlinePlayersCache.get(playerUUID); - } + CachedPlayerSkin skin = onlinePlayersCache.get(playerUUID); if(skin != null) { initiator.sendEaglerMessage(skin.data.getForceClientV4()); } @@ -1161,9 +1081,7 @@ public class SkinService implements ISkinService { SkinPackets.getModelId(t.model) == 1 ? 1 : 0), null, -1); } - synchronized(onlinePlayersCache) { - onlinePlayersCache.put(playerUUID, skin); - } + onlinePlayersCache.put(playerUUID, skin); initiator.sendEaglerMessage(skin.data.getForceClientV4()); }else { processResolveURLTextureForOnlineToForce(initiator, playerUUID, t.textureUUID, t.texture, @@ -1192,10 +1110,7 @@ public class SkinService implements ISkinService { @Override public void accept(CacheFetchedProfile t) { if(t == null || t.texture == null) { - CachedPlayerSkin skin; - synchronized(onlinePlayersCache) { - skin = onlinePlayersCache.get(t.uuid); - } + CachedPlayerSkin skin = onlinePlayersCache.get(t.uuid); if(skin != null) { initiator.sendEaglerMessage(skin.data.getForceClientV4()); } @@ -1225,9 +1140,7 @@ public class SkinService implements ISkinService { mapUUID.getMostSignificantBits(), mapUUID.getLeastSignificantBits(), SkinPackets.getModelId(t.model) == 1 ? 1 : 0), null, -1); } - synchronized(onlinePlayersCache) { - onlinePlayersCache.put(mapUUID, skin); - } + onlinePlayersCache.put(mapUUID, skin); initiator.sendEaglerMessage(skin.data.getForceClientV4()); }else { processResolveURLTextureForOnlineToForce(initiator, mapUUID, t.textureUUID, t.texture, @@ -1256,10 +1169,7 @@ public class SkinService implements ISkinService { @Override public void accept(CacheFetchedProfile t) { if(t == null || t.texture == null) { - CachedForeignSkin skin; - synchronized(foreignSkinCache) { - skin = foreignSkinCache.get(playerUUID); - } + CachedForeignSkin skin = foreignSkinCache.get(playerUUID); if(skin != null) { initiator.sendEaglerMessage(skin.data.getForceClientV4()); } @@ -1291,9 +1201,7 @@ public class SkinService implements ISkinService { SkinPackets.getModelId(t.model) == 1 ? 1 : 0), -1); } - synchronized(foreignSkinCache) { - foreignSkinCache.put(playerUUID, skin); - } + foreignSkinCache.put(playerUUID, skin); initiator.sendEaglerMessage(skin.data.getForceClientV4()); }else { processResolveURLTextureForForeignToForce(initiator, playerUUID, t.textureUUID, t.texture, @@ -1315,12 +1223,16 @@ public class SkinService implements ISkinService { public void flush() { long millis = EaglerXBungeeAPIHelper.steadyTimeMillis(); - synchronized(foreignSkinCache) { - Iterator itr = foreignSkinCache.values().iterator(); - while(itr.hasNext()) { - if(millis - itr.next().lastHit > 900000l) { // 15 minutes - itr.remove(); - } + final List foreignSkinCleanup = new ArrayList<>(4); + foreignSkinCache.entrySet().forEach((etr) -> { + if(millis - etr.getValue().lastHit > 900000l) { // 15 minutes + foreignSkinCleanup.add(etr.getKey()); + } + }); + + if(!foreignSkinCleanup.isEmpty()) { + for(UUID uuid : foreignSkinCleanup) { + foreignSkinCache.remove(uuid); } } @@ -1371,7 +1283,8 @@ public class SkinService implements ISkinService { elapsedCooldown /= cooldownPeriod; if(elapsedCooldown > 0) { antagonistCooldown += elapsedCooldown * cooldownPeriod; - synchronized(antagonists) { + antagonistsLock.writeLock().lock(); + try { Iterator itr = antagonists.keySet().iterator(); while(itr.hasNext()) { UUID key = itr.next(); @@ -1382,6 +1295,8 @@ public class SkinService implements ISkinService { antagonists.put(key, i); } } + }finally { + antagonistsLock.writeLock().unlock(); } } @@ -1389,10 +1304,7 @@ public class SkinService implements ISkinService { } public SkinPacketVersionCache getSkin(UUID playerUUID) { - CachedPlayerSkin skin; - synchronized(onlinePlayersCache) { - skin = onlinePlayersCache.get(playerUUID); - } + CachedPlayerSkin skin = onlinePlayersCache.get(playerUUID); return skin != null ? skin.data : null; } @@ -1407,25 +1319,26 @@ public class SkinService implements ISkinService { private boolean isLimitedAsAntagonist(UUID uuid) { int limit = EaglerXBungee.getEagler().getConfig().getAntagonistsRateLimit(); limit += limit >> 1; - synchronized(antagonists) { - int i = antagonists.get(uuid); - return i != antagonists.getNoEntryValue() && i > limit; + int i; + antagonistsLock.readLock().lock(); + try { + i = antagonists.get(uuid); + }finally { + antagonistsLock.readLock().unlock(); } + return i != antagonists.getNoEntryValue() && i > limit; } private void resetMaps() { - synchronized(onlinePlayersCache) { - onlinePlayersCache.clear(); - } - synchronized(onlinePlayersFromTexturesMap) { + onlinePlayersCache.clear(); + onlinePlayersFromTexturesMapLock.writeLock().lock(); + try { onlinePlayersFromTexturesMap.clear(); + }finally { + onlinePlayersFromTexturesMapLock.writeLock().unlock(); } - synchronized(onlinePlayersToTexturesMap) { - onlinePlayersToTexturesMap.clear(); - } - synchronized(foreignSkinCache) { - foreignSkinCache.clear(); - } + onlinePlayersToTexturesMap.clear(); + foreignSkinCache.clear(); synchronized(pendingTextures) { pendingTextures.clear(); } @@ -1435,8 +1348,11 @@ public class SkinService implements ISkinService { synchronized(pendingNameLookups) { pendingNameLookups.clear(); } - synchronized(antagonists) { + antagonistsLock.writeLock().lock(); + try { antagonists.clear(); + }finally { + antagonistsLock.writeLock().unlock(); } } @@ -1453,7 +1369,7 @@ public class SkinService implements ISkinService { return null; } String host = uri.getHost(); - if(host == null) { + if(host == null || !EaglerXBungee.getEagler().getConfig().isValidSkinHost(host)) { return null; } scheme = scheme.toLowerCase(); diff --git a/gateway/EaglercraftXBungee/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/gateway_bungeecord/skins/SkinServiceOffline.java b/gateway/EaglercraftXBungee/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/gateway_bungeecord/skins/SkinServiceOffline.java index 06298908..927acd6f 100644 --- a/gateway/EaglercraftXBungee/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/gateway_bungeecord/skins/SkinServiceOffline.java +++ b/gateway/EaglercraftXBungee/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/gateway_bungeecord/skins/SkinServiceOffline.java @@ -1,13 +1,8 @@ package net.lax1dude.eaglercraft.v1_8.plugin.gateway_bungeecord.skins; -import java.util.Collection; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; import java.util.UUID; - -import com.google.common.collect.Multimap; -import com.google.common.collect.MultimapBuilder; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import net.lax1dude.eaglercraft.v1_8.plugin.gateway_bungeecord.server.EaglerInitialHandler; import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherSkinPresetEAG; @@ -15,7 +10,7 @@ import net.lax1dude.eaglercraft.v1_8.socket.protocol.util.SkinPacketVersionCache import net.md_5.bungee.UserConnection; /** - * Copyright (c) 2022-2023 lax1dude. All Rights Reserved. + * Copyright (c) 2022-2025 lax1dude. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -45,24 +40,17 @@ public class SkinServiceOffline implements ISkinService { } - private final Map skinCache = new HashMap<>(); - - private final Multimap onlinePlayersFromTexturesMap = MultimapBuilder.hashKeys().hashSetValues().build(); + private final ConcurrentMap skinCache = new ConcurrentHashMap<>(); public void init(String uri, String driverClass, String driverPath, int keepObjectsDays, int keepProfilesDays, int maxObjects, int maxProfiles) { - synchronized(skinCache) { - skinCache.clear(); - } + skinCache.clear(); } public void processGetOtherSkin(UUID searchUUID, UserConnection sender) { EaglerInitialHandler initialHandler = (EaglerInitialHandler)sender.getPendingConnection(); if(initialHandler.skinLookupRateLimiter.rateLimit(masterRateLimitPerPlayer)) { - CachedSkin cached; - synchronized(skinCache) { - cached = skinCache.get(searchUUID); - } + CachedSkin cached = skinCache.get(searchUUID); if(cached != null) { initialHandler.sendEaglerMessage(cached.packet.get(initialHandler.getEaglerProtocol())); }else { @@ -74,24 +62,6 @@ public class SkinServiceOffline implements ISkinService { public void processGetOtherSkin(UUID searchUUID, String skinURL, UserConnection sender) { EaglerInitialHandler initialHandler = (EaglerInitialHandler)sender.getPendingConnection(); - Collection uuids; - synchronized(onlinePlayersFromTexturesMap) { - uuids = onlinePlayersFromTexturesMap.get(searchUUID); - } - if(uuids.size() > 0) { - CachedSkin cached; - synchronized(skinCache) { - Iterator uuidItr = uuids.iterator(); - while(uuidItr.hasNext()) { - cached = skinCache.get(uuidItr.next()); - if(cached != null) { - initialHandler.sendEaglerMessage(cached.packet.get(initialHandler.getEaglerProtocol(), - searchUUID.getMostSignificantBits(), searchUUID.getLeastSignificantBits())); - return; - } - } - } - } if(skinURL.startsWith("eagler://")) { // customs skulls from exported singleplayer worlds initialHandler.sendEaglerMessage(new SPacketOtherSkinPresetEAG(searchUUID.getMostSignificantBits(), searchUUID.getLeastSignificantBits(), 0)); @@ -102,28 +72,21 @@ public class SkinServiceOffline implements ISkinService { } public void registerEaglercraftPlayer(UUID clientUUID, SkinPacketVersionCache generatedPacket, int modelId) { - synchronized(skinCache) { - skinCache.put(clientUUID, new CachedSkin(clientUUID, generatedPacket)); - } + skinCache.put(clientUUID, new CachedSkin(clientUUID, generatedPacket)); } public void unregisterPlayer(UUID clientUUID) { - synchronized(skinCache) { - skinCache.remove(clientUUID); - } + skinCache.remove(clientUUID); + } + + public void registerTextureToPlayerAssociation(String textureURL, UUID playerUUID) { } public void registerTextureToPlayerAssociation(UUID textureUUID, UUID playerUUID) { - synchronized(onlinePlayersFromTexturesMap) { - onlinePlayersFromTexturesMap.put(textureUUID, playerUUID); - } } public void processForceSkin(UUID playerUUID, EaglerInitialHandler initialHandler) { - CachedSkin cached; - synchronized(skinCache) { - cached = skinCache.get(playerUUID); - } + CachedSkin cached = skinCache.get(playerUUID); if(cached != null) { initialHandler.sendEaglerMessage(cached.packet.getForceClientV4()); } @@ -134,16 +97,11 @@ public class SkinServiceOffline implements ISkinService { } public void shutdown() { - synchronized(skinCache) { - skinCache.clear(); - } + skinCache.clear(); } public SkinPacketVersionCache getSkin(UUID playerUUID) { - CachedSkin cached; - synchronized(skinCache) { - cached = skinCache.get(playerUUID); - } + CachedSkin cached = skinCache.get(playerUUID); return cached != null ? cached.packet : null; } diff --git a/gateway/EaglercraftXBungee/src/main/resources/plugin.yml b/gateway/EaglercraftXBungee/src/main/resources/plugin.yml index 1b21af08..01d7794b 100644 --- a/gateway/EaglercraftXBungee/src/main/resources/plugin.yml +++ b/gateway/EaglercraftXBungee/src/main/resources/plugin.yml @@ -1,5 +1,5 @@ name: EaglercraftXBungee main: net.lax1dude.eaglercraft.v1_8.plugin.gateway_bungeecord.EaglerXBungee -version: 1.3.4 +version: 1.3.5 description: Plugin to allow EaglercraftX 1.8 players to join your network, or allow EaglercraftX 1.8 players to use your network as a proxy to join other networks author: lax1dude \ No newline at end of file diff --git a/gateway_version b/gateway_version index 8c9698aa..aaf8be71 100644 --- a/gateway_version +++ b/gateway_version @@ -1 +1 @@ -1.3.4 \ No newline at end of file +1.3.5 \ No newline at end of file