geforkt von Mirrors/Paper
Players directory
Dieser Commit ist enthalten in:
Ursprung
a68b56a864
Commit
83b7370131
@ -1,17 +1,17 @@
|
|||||||
--- a/net/minecraft/server/players/BanListEntry.java
|
--- a/net/minecraft/server/players/BanListEntry.java
|
||||||
+++ b/net/minecraft/server/players/BanListEntry.java
|
+++ b/net/minecraft/server/players/BanListEntry.java
|
||||||
@@ -27,7 +27,7 @@
|
@@ -26,7 +_,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
protected BanListEntry(@Nullable T key, JsonObject json) {
|
protected BanListEntry(@Nullable T user, JsonObject entryData) {
|
||||||
- super(key);
|
- super(user);
|
||||||
+ super(BanListEntry.checkExpiry(key, json)); // CraftBukkit
|
+ super(BanListEntry.checkExpiry(user, entryData)); // CraftBukkit
|
||||||
|
|
||||||
Date date;
|
Date date;
|
||||||
|
try {
|
||||||
@@ -83,4 +83,22 @@
|
@@ -80,4 +_,22 @@
|
||||||
json.addProperty("expires", this.expires == null ? "forever" : BanListEntry.DATE_FORMAT.format(this.expires));
|
data.addProperty("expires", this.expires == null ? "forever" : DATE_FORMAT.format(this.expires));
|
||||||
json.addProperty("reason", this.reason);
|
data.addProperty("reason", this.reason);
|
||||||
}
|
}
|
||||||
+
|
+
|
||||||
+ // CraftBukkit start
|
+ // CraftBukkit start
|
@ -0,0 +1,212 @@
|
|||||||
|
--- a/net/minecraft/server/players/GameProfileCache.java
|
||||||
|
+++ b/net/minecraft/server/players/GameProfileCache.java
|
||||||
|
@@ -17,8 +_,6 @@
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
-import java.io.Reader;
|
||||||
|
-import java.io.Writer;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.ParseException;
|
||||||
|
@@ -56,6 +_,10 @@
|
||||||
|
private final AtomicLong operationCount = new AtomicLong();
|
||||||
|
@Nullable
|
||||||
|
private Executor executor;
|
||||||
|
+ // Paper start - Fix GameProfileCache concurrency
|
||||||
|
+ protected final java.util.concurrent.locks.ReentrantLock stateLock = new java.util.concurrent.locks.ReentrantLock();
|
||||||
|
+ protected final java.util.concurrent.locks.ReentrantLock lookupLock = new java.util.concurrent.locks.ReentrantLock();
|
||||||
|
+ // Paper end - Fix GameProfileCache concurrency
|
||||||
|
|
||||||
|
public GameProfileCache(GameProfileRepository profileRepository, File file) {
|
||||||
|
this.profileRepository = profileRepository;
|
||||||
|
@@ -64,10 +_,12 @@
|
||||||
|
}
|
||||||
|
|
||||||
|
private void safeAdd(GameProfileCache.GameProfileInfo profile) {
|
||||||
|
+ try { this.stateLock.lock(); // Paper - Fix GameProfileCache concurrency
|
||||||
|
GameProfile profile1 = profile.getProfile();
|
||||||
|
profile.setLastAccess(this.getNextOperation());
|
||||||
|
this.profilesByName.put(profile1.getName().toLowerCase(Locale.ROOT), profile);
|
||||||
|
this.profilesByUUID.put(profile1.getId(), profile);
|
||||||
|
+ } finally { this.stateLock.unlock(); } // Paper - Fix GameProfileCache concurrency
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Optional<GameProfile> lookupGameProfile(GameProfileRepository profileRepo, String name) {
|
||||||
|
@@ -86,6 +_,8 @@
|
||||||
|
atomicReference.set(null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
+ if (!org.apache.commons.lang3.StringUtils.isBlank(name) // Paper - Don't lookup a profile with a blank name
|
||||||
|
+ && io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode()) // Paper - Add setting for proxy online mode status
|
||||||
|
profileRepo.findProfilesByNames(new String[]{name}, profileLookupCallback);
|
||||||
|
GameProfile gameProfile = atomicReference.get();
|
||||||
|
return gameProfile != null ? Optional.of(gameProfile) : createUnknownProfile(name);
|
||||||
|
@@ -101,7 +_,7 @@
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean usesAuthentication() {
|
||||||
|
- return usesAuthentication;
|
||||||
|
+ return io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode(); // Paper - Add setting for proxy online mode status
|
||||||
|
}
|
||||||
|
|
||||||
|
public void add(GameProfile gameProfile) {
|
||||||
|
@@ -111,15 +_,29 @@
|
||||||
|
Date time = instance.getTime();
|
||||||
|
GameProfileCache.GameProfileInfo gameProfileInfo = new GameProfileCache.GameProfileInfo(gameProfile, time);
|
||||||
|
this.safeAdd(gameProfileInfo);
|
||||||
|
- this.save();
|
||||||
|
+ if(!org.spigotmc.SpigotConfig.saveUserCacheOnStopOnly) this.save(true); // Spigot - skip saving if disabled // Paper - Perf: Async GameProfileCache saving
|
||||||
|
}
|
||||||
|
|
||||||
|
private long getNextOperation() {
|
||||||
|
return this.operationCount.incrementAndGet();
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Paper start
|
||||||
|
+ public @Nullable GameProfile getProfileIfCached(String name) {
|
||||||
|
+ try { this.stateLock.lock(); // Paper - Fix GameProfileCache concurrency
|
||||||
|
+ GameProfileCache.GameProfileInfo entry = this.profilesByName.get(name.toLowerCase(Locale.ROOT));
|
||||||
|
+ if (entry == null) {
|
||||||
|
+ return null;
|
||||||
|
+ }
|
||||||
|
+ entry.setLastAccess(this.getNextOperation());
|
||||||
|
+ return entry.getProfile();
|
||||||
|
+ } finally { this.stateLock.unlock(); } // Paper - Fix GameProfileCache concurrency
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
+
|
||||||
|
public Optional<GameProfile> get(String name) {
|
||||||
|
String string = name.toLowerCase(Locale.ROOT);
|
||||||
|
+ boolean stateLocked = true; try { this.stateLock.lock(); // Paper - Fix GameProfileCache concurrency
|
||||||
|
GameProfileCache.GameProfileInfo gameProfileInfo = this.profilesByName.get(string);
|
||||||
|
boolean flag = false;
|
||||||
|
if (gameProfileInfo != null && new Date().getTime() >= gameProfileInfo.expirationDate.getTime()) {
|
||||||
|
@@ -133,19 +_,24 @@
|
||||||
|
if (gameProfileInfo != null) {
|
||||||
|
gameProfileInfo.setLastAccess(this.getNextOperation());
|
||||||
|
optional = Optional.of(gameProfileInfo.getProfile());
|
||||||
|
+ stateLocked = false; this.stateLock.unlock(); // Paper - Fix GameProfileCache concurrency
|
||||||
|
} else {
|
||||||
|
- optional = lookupGameProfile(this.profileRepository, string);
|
||||||
|
+ stateLocked = false; this.stateLock.unlock(); // Paper - Fix GameProfileCache concurrency
|
||||||
|
+ try { this.lookupLock.lock(); // Paper - Fix GameProfileCache concurrency
|
||||||
|
+ optional = lookupGameProfile(this.profileRepository, name); // CraftBukkit - use correct case for offline players
|
||||||
|
+ } finally { this.lookupLock.unlock(); } // Paper - Fix GameProfileCache concurrency
|
||||||
|
if (optional.isPresent()) {
|
||||||
|
this.add(optional.get());
|
||||||
|
flag = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- if (flag) {
|
||||||
|
- this.save();
|
||||||
|
+ if (flag && !org.spigotmc.SpigotConfig.saveUserCacheOnStopOnly) { // Spigot - skip saving if disabled
|
||||||
|
+ this.save(true); // Paper - Perf: Async GameProfileCache saving
|
||||||
|
}
|
||||||
|
|
||||||
|
return optional;
|
||||||
|
+ } finally { if (stateLocked) { this.stateLock.unlock(); } } // Paper - Fix GameProfileCache concurrency
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<Optional<GameProfile>> getAsync(String name) {
|
||||||
|
@@ -157,7 +_,7 @@
|
||||||
|
return completableFuture;
|
||||||
|
} else {
|
||||||
|
CompletableFuture<Optional<GameProfile>> completableFuture1 = CompletableFuture.<Optional<GameProfile>>supplyAsync(
|
||||||
|
- () -> this.get(name), Util.backgroundExecutor().forName("getProfile")
|
||||||
|
+ () -> this.get(name), Util.PROFILE_EXECUTOR // Paper - don't submit BLOCKING PROFILE LOOKUPS to the world gen thread
|
||||||
|
)
|
||||||
|
.whenCompleteAsync((gameProfile, exception) -> this.requests.remove(name), this.executor);
|
||||||
|
this.requests.put(name, completableFuture1);
|
||||||
|
@@ -167,6 +_,7 @@
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<GameProfile> get(UUID uuid) {
|
||||||
|
+ try { this.stateLock.lock(); // Paper - Fix GameProfileCache concurrency
|
||||||
|
GameProfileCache.GameProfileInfo gameProfileInfo = this.profilesByUUID.get(uuid);
|
||||||
|
if (gameProfileInfo == null) {
|
||||||
|
return Optional.empty();
|
||||||
|
@@ -174,6 +_,7 @@
|
||||||
|
gameProfileInfo.setLastAccess(this.getNextOperation());
|
||||||
|
return Optional.of(gameProfileInfo.getProfile());
|
||||||
|
}
|
||||||
|
+ } finally { this.stateLock.unlock(); } // Paper - Fix GameProfileCache concurrency
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExecutor(Executor exectutor) {
|
||||||
|
@@ -193,7 +_,7 @@
|
||||||
|
|
||||||
|
try {
|
||||||
|
Object var9;
|
||||||
|
- try (Reader reader = Files.newReader(this.file, StandardCharsets.UTF_8)) {
|
||||||
|
+ try (java.io.Reader reader = Files.newReader(this.file, StandardCharsets.UTF_8)) {
|
||||||
|
JsonArray jsonArray = this.gson.fromJson(reader, JsonArray.class);
|
||||||
|
if (jsonArray != null) {
|
||||||
|
DateFormat dateFormat = createDateFormat();
|
||||||
|
@@ -206,6 +_,11 @@
|
||||||
|
|
||||||
|
return (List<GameProfileCache.GameProfileInfo>)var9;
|
||||||
|
} catch (FileNotFoundException var7) {
|
||||||
|
+ // Spigot Start
|
||||||
|
+ } catch (com.google.gson.JsonSyntaxException | NullPointerException ex) {
|
||||||
|
+ GameProfileCache.LOGGER.warn( "Usercache.json is corrupted or has bad formatting. Deleting it to prevent further issues." );
|
||||||
|
+ this.file.delete();
|
||||||
|
+ // Spigot End
|
||||||
|
} catch (JsonParseException | IOException var8) {
|
||||||
|
LOGGER.warn("Failed to load profile cache {}", this.file, var8);
|
||||||
|
}
|
||||||
|
@@ -213,24 +_,45 @@
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
- public void save() {
|
||||||
|
+ public void save(boolean asyncSave) { // Paper - Perf: Async GameProfileCache saving
|
||||||
|
JsonArray jsonArray = new JsonArray();
|
||||||
|
DateFormat dateFormat = createDateFormat();
|
||||||
|
- this.getTopMRUProfiles(1000).forEach(info -> jsonArray.add(writeGameProfile(info, dateFormat)));
|
||||||
|
+ this.listTopMRUProfiles(org.spigotmc.SpigotConfig.userCacheCap).forEach((info) -> jsonArray.add(writeGameProfile(info, dateFormat))); // Spigot // Paper - Fix GameProfileCache concurrency
|
||||||
|
String string = this.gson.toJson((JsonElement)jsonArray);
|
||||||
|
+ Runnable save = () -> { // Paper - Perf: Async GameProfileCache saving
|
||||||
|
|
||||||
|
- try (Writer writer = Files.newWriter(this.file, StandardCharsets.UTF_8)) {
|
||||||
|
+ try (java.io.Writer writer = Files.newWriter(this.file, StandardCharsets.UTF_8)) {
|
||||||
|
writer.write(string);
|
||||||
|
} catch (IOException var9) {
|
||||||
|
}
|
||||||
|
+ // Paper start - Perf: Async GameProfileCache saving
|
||||||
|
+ };
|
||||||
|
+ if (asyncSave) {
|
||||||
|
+ io.papermc.paper.util.MCUtil.scheduleAsyncTask(save);
|
||||||
|
+ } else {
|
||||||
|
+ save.run();
|
||||||
|
+ }
|
||||||
|
+ // Paper end - Perf: Async GameProfileCache saving
|
||||||
|
}
|
||||||
|
|
||||||
|
private Stream<GameProfileCache.GameProfileInfo> getTopMRUProfiles(int limit) {
|
||||||
|
- return ImmutableList.copyOf(this.profilesByUUID.values())
|
||||||
|
- .stream()
|
||||||
|
- .sorted(Comparator.comparing(GameProfileCache.GameProfileInfo::getLastAccess).reversed())
|
||||||
|
- .limit(limit);
|
||||||
|
- }
|
||||||
|
+ // Paper start - Fix GameProfileCache concurrency
|
||||||
|
+ return this.listTopMRUProfiles(limit).stream();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private List<GameProfileCache.GameProfileInfo> listTopMRUProfiles(int limit) {
|
||||||
|
+ try {
|
||||||
|
+ this.stateLock.lock();
|
||||||
|
+ return this.profilesByUUID.values()
|
||||||
|
+ .stream()
|
||||||
|
+ .sorted(Comparator.comparing(GameProfileCache.GameProfileInfo::getLastAccess).reversed())
|
||||||
|
+ .limit(limit)
|
||||||
|
+ .toList();
|
||||||
|
+ } finally {
|
||||||
|
+ this.stateLock.unlock();
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ // Paper end - Fix GameProfileCache concurrency
|
||||||
|
|
||||||
|
private static JsonElement writeGameProfile(GameProfileCache.GameProfileInfo profileInfo, DateFormat dateFormat) {
|
||||||
|
JsonObject jsonObject = new JsonObject();
|
@ -1,6 +1,6 @@
|
|||||||
--- a/net/minecraft/server/players/OldUsersConverter.java
|
--- a/net/minecraft/server/players/OldUsersConverter.java
|
||||||
+++ b/net/minecraft/server/players/OldUsersConverter.java
|
+++ b/net/minecraft/server/players/OldUsersConverter.java
|
||||||
@@ -21,6 +21,9 @@
|
@@ -20,6 +_,9 @@
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import net.minecraft.core.UUIDUtil;
|
import net.minecraft.core.UUIDUtil;
|
||||||
@ -10,62 +10,61 @@
|
|||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.server.dedicated.DedicatedServer;
|
import net.minecraft.server.dedicated.DedicatedServer;
|
||||||
import net.minecraft.util.StringUtil;
|
import net.minecraft.util.StringUtil;
|
||||||
@@ -62,7 +65,8 @@
|
@@ -49,7 +_,8 @@
|
||||||
return new String[i];
|
|
||||||
});
|
|
||||||
|
|
||||||
|
private static void lookupPlayers(MinecraftServer server, Collection<String> names, ProfileLookupCallback callback) {
|
||||||
|
String[] strings = names.stream().filter(name -> !StringUtil.isNullOrEmpty(name)).toArray(String[]::new);
|
||||||
- if (server.usesAuthentication()) {
|
- if (server.usesAuthentication()) {
|
||||||
+ if (server.usesAuthentication() ||
|
+ if (server.usesAuthentication() ||
|
||||||
+ (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode())) { // Spigot: bungee = online mode, for now. // Paper - Add setting for proxy online mode status
|
+ (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode())) { // Spigot: bungee = online mode, for now. // Paper - Add setting for proxy online mode status
|
||||||
server.getProfileRepository().findProfilesByNames(astring, callback);
|
server.getProfileRepository().findProfilesByNames(strings, callback);
|
||||||
} else {
|
} else {
|
||||||
String[] astring1 = astring;
|
for (String string : strings) {
|
||||||
@@ -85,7 +89,7 @@
|
@@ -65,7 +_,7 @@
|
||||||
try {
|
try {
|
||||||
gameprofilebanlist.load();
|
userBanList.load();
|
||||||
} catch (IOException ioexception) {
|
} catch (IOException var6) {
|
||||||
- OldUsersConverter.LOGGER.warn("Could not load existing file {}", gameprofilebanlist.getFile().getName(), ioexception);
|
- LOGGER.warn("Could not load existing file {}", userBanList.getFile().getName(), var6);
|
||||||
+ OldUsersConverter.LOGGER.warn("Could not load existing file {}", gameprofilebanlist.getFile().getName()); // CraftBukkit - don't print stacktrace
|
+ LOGGER.warn("Could not load existing file {}", userBanList.getFile().getName()); // CraftBukkit - don't print stacktrace
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,7 +147,7 @@
|
@@ -120,7 +_,7 @@
|
||||||
try {
|
try {
|
||||||
ipbanlist.load();
|
ipBanList.load();
|
||||||
} catch (IOException ioexception) {
|
} catch (IOException var11) {
|
||||||
- OldUsersConverter.LOGGER.warn("Could not load existing file {}", ipbanlist.getFile().getName(), ioexception);
|
- LOGGER.warn("Could not load existing file {}", ipBanList.getFile().getName(), var11);
|
||||||
+ OldUsersConverter.LOGGER.warn("Could not load existing file {}", ipbanlist.getFile().getName()); // CraftBukkit - don't print stacktrace
|
+ LOGGER.warn("Could not load existing file {}", ipBanList.getFile().getName()); // CraftBukkit - don't print stacktrace
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,7 +188,7 @@
|
@@ -156,7 +_,7 @@
|
||||||
try {
|
try {
|
||||||
oplist.load();
|
serverOpList.load();
|
||||||
} catch (IOException ioexception) {
|
} catch (IOException var6) {
|
||||||
- OldUsersConverter.LOGGER.warn("Could not load existing file {}", oplist.getFile().getName(), ioexception);
|
- LOGGER.warn("Could not load existing file {}", serverOpList.getFile().getName(), var6);
|
||||||
+ OldUsersConverter.LOGGER.warn("Could not load existing file {}", oplist.getFile().getName()); // CraftBukkit - don't print stacktrace
|
+ LOGGER.warn("Could not load existing file {}", serverOpList.getFile().getName()); // CraftBukkit - don't print stacktrace
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,7 +232,7 @@
|
@@ -200,7 +_,7 @@
|
||||||
try {
|
try {
|
||||||
whitelist.load();
|
userWhiteList.load();
|
||||||
} catch (IOException ioexception) {
|
} catch (IOException var6) {
|
||||||
- OldUsersConverter.LOGGER.warn("Could not load existing file {}", whitelist.getFile().getName(), ioexception);
|
- LOGGER.warn("Could not load existing file {}", userWhiteList.getFile().getName(), var6);
|
||||||
+ OldUsersConverter.LOGGER.warn("Could not load existing file {}", whitelist.getFile().getName()); // CraftBukkit - don't print stacktrace
|
+ LOGGER.warn("Could not load existing file {}", userWhiteList.getFile().getName()); // CraftBukkit - don't print stacktrace
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -346,7 +350,39 @@
|
@@ -313,6 +_,37 @@
|
||||||
private void movePlayerFile(File playerDataFolder, String fileName, String uuid) {
|
private void movePlayerFile(File file3, String oldFileName, String newFileName) {
|
||||||
File file5 = new File(file, fileName + ".dat");
|
File file4 = new File(worldPlayersDirectory, oldFileName + ".dat");
|
||||||
File file6 = new File(playerDataFolder, uuid + ".dat");
|
File file5 = new File(file3, newFileName + ".dat");
|
||||||
+
|
|
||||||
+ // CraftBukkit start - Use old file name to seed lastKnownName
|
+ // CraftBukkit start - Use old file name to seed lastKnownName
|
||||||
+ CompoundTag root = null;
|
+ CompoundTag root = null;
|
||||||
+
|
+
|
||||||
+ try {
|
+ try {
|
||||||
+ root = NbtIo.readCompressed(new java.io.FileInputStream(file5), NbtAccounter.unlimitedHeap());
|
+ root = NbtIo.readCompressed(new java.io.FileInputStream(file4), NbtAccounter.unlimitedHeap());
|
||||||
+ } catch (Exception exception) {
|
+ } catch (Exception exception) {
|
||||||
+ // Paper start
|
+ // Paper start
|
||||||
+ io.papermc.paper.util.StacktraceDeobfuscator.INSTANCE.deobfuscateThrowable(exception);
|
+ io.papermc.paper.util.StacktraceDeobfuscator.INSTANCE.deobfuscateThrowable(exception);
|
||||||
@ -73,16 +72,16 @@
|
|||||||
+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(exception);
|
+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(exception);
|
||||||
+ // Paper end
|
+ // Paper end
|
||||||
+ }
|
+ }
|
||||||
|
+
|
||||||
+ if (root != null) {
|
+ if (root != null) {
|
||||||
+ if (!root.contains("bukkit")) {
|
+ if (!root.contains("bukkit")) {
|
||||||
+ root.put("bukkit", new CompoundTag());
|
+ root.put("bukkit", new CompoundTag());
|
||||||
+ }
|
+ }
|
||||||
+ CompoundTag data = root.getCompound("bukkit");
|
+ CompoundTag data = root.getCompound("bukkit");
|
||||||
+ data.putString("lastKnownName", fileName);
|
+ data.putString("lastKnownName", oldFileName);
|
||||||
+
|
+
|
||||||
+ try {
|
+ try {
|
||||||
+ NbtIo.writeCompressed(root, new java.io.FileOutputStream(file2));
|
+ NbtIo.writeCompressed(root, new java.io.FileOutputStream(file1));
|
||||||
+ } catch (Exception exception) {
|
+ } catch (Exception exception) {
|
||||||
+ // Paper start
|
+ // Paper start
|
||||||
+ io.papermc.paper.util.StacktraceDeobfuscator.INSTANCE.deobfuscateThrowable(exception);
|
+ io.papermc.paper.util.StacktraceDeobfuscator.INSTANCE.deobfuscateThrowable(exception);
|
||||||
@ -92,7 +91,6 @@
|
|||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+ // CraftBukkit end
|
+ // CraftBukkit end
|
||||||
+
|
OldUsersConverter.ensureDirectoryExists(file3);
|
||||||
OldUsersConverter.ensureDirectoryExists(playerDataFolder);
|
if (!file4.renameTo(file5)) {
|
||||||
if (!file5.renameTo(file6)) {
|
throw new OldUsersConverter.ConversionError("Could not convert file for " + oldFileName);
|
||||||
throw new OldUsersConverter.ConversionError("Could not convert file for " + fileName);
|
|
@ -0,0 +1,41 @@
|
|||||||
|
--- a/net/minecraft/server/players/SleepStatus.java
|
||||||
|
+++ b/net/minecraft/server/players/SleepStatus.java
|
||||||
|
@@ -14,8 +_,11 @@
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean areEnoughDeepSleeping(int requiredSleepPercentage, List<ServerPlayer> sleepingPlayers) {
|
||||||
|
- int i = (int)sleepingPlayers.stream().filter(Player::isSleepingLongEnough).count();
|
||||||
|
- return i >= this.sleepersNeeded(requiredSleepPercentage);
|
||||||
|
+ // CraftBukkit start
|
||||||
|
+ int i = (int) sleepingPlayers.stream().filter(player -> player.isSleepingLongEnough() || player.fauxSleeping).count();
|
||||||
|
+ boolean anyDeepSleep = sleepingPlayers.stream().anyMatch(Player::isSleepingLongEnough);
|
||||||
|
+ return anyDeepSleep && i >= this.sleepersNeeded(requiredSleepPercentage);
|
||||||
|
+ // CraftBukkit end
|
||||||
|
}
|
||||||
|
|
||||||
|
public int sleepersNeeded(int requiredSleepPercentage) {
|
||||||
|
@@ -35,16 +_,22 @@
|
||||||
|
int i1 = this.sleepingPlayers;
|
||||||
|
this.activePlayers = 0;
|
||||||
|
this.sleepingPlayers = 0;
|
||||||
|
+ boolean anySleep = false; // CraftBukkit
|
||||||
|
|
||||||
|
for (ServerPlayer serverPlayer : players) {
|
||||||
|
if (!serverPlayer.isSpectator()) {
|
||||||
|
this.activePlayers++;
|
||||||
|
- if (serverPlayer.isSleeping()) {
|
||||||
|
+ if (serverPlayer.isSleeping() || serverPlayer.fauxSleeping) { // CraftBukkit
|
||||||
|
this.sleepingPlayers++;
|
||||||
|
}
|
||||||
|
+ // CraftBukkit start
|
||||||
|
+ if (serverPlayer.isSleeping()) {
|
||||||
|
+ anySleep = true;
|
||||||
|
+ }
|
||||||
|
+ // CraftBukkit end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- return (i1 > 0 || this.sleepingPlayers > 0) && (i != this.activePlayers || i1 != this.sleepingPlayers);
|
||||||
|
+ return anySleep && (i1 > 0 || this.sleepingPlayers > 0) && (i != this.activePlayers || i1 != this.sleepingPlayers); // CraftBukkit
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,81 @@
|
|||||||
|
--- a/net/minecraft/server/players/StoredUserList.java
|
||||||
|
+++ b/net/minecraft/server/players/StoredUserList.java
|
||||||
|
@@ -26,7 +_,7 @@
|
||||||
|
private static final Logger LOGGER = LogUtils.getLogger();
|
||||||
|
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
|
||||||
|
private final File file;
|
||||||
|
- private final Map<String, V> map = Maps.newHashMap();
|
||||||
|
+ private final Map<String, V> map = Maps.newConcurrentMap(); // Paper - Use ConcurrentHashMap in JsonList
|
||||||
|
|
||||||
|
public StoredUserList(File file) {
|
||||||
|
this.file = file;
|
||||||
|
@@ -48,8 +_,11 @@
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public V get(K obj) {
|
||||||
|
- this.removeExpired();
|
||||||
|
- return this.map.get(this.getKeyForUser(obj));
|
||||||
|
+ // Paper start - Use ConcurrentHashMap in JsonList
|
||||||
|
+ return this.map.computeIfPresent(this.getKeyForUser(obj), (k, v) -> {
|
||||||
|
+ return v.hasExpired() ? null : v;
|
||||||
|
+ });
|
||||||
|
+ // Paper end - Use ConcurrentHashMap in JsonList
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove(K user) {
|
||||||
|
@@ -71,7 +_,7 @@
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty() {
|
||||||
|
- return this.map.size() < 1;
|
||||||
|
+ return this.map.isEmpty(); // Paper - Use ConcurrentHashMap in JsonList
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getKeyForUser(K obj) {
|
||||||
|
@@ -79,21 +_,12 @@
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean contains(K entry) {
|
||||||
|
+ this.removeExpired(); // CraftBukkit - SPIGOT-7589: Consistently remove expired entries to mirror .get(...)
|
||||||
|
return this.map.containsKey(this.getKeyForUser(entry));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeExpired() {
|
||||||
|
- List<K> list = Lists.newArrayList();
|
||||||
|
-
|
||||||
|
- for (V storedUserEntry : this.map.values()) {
|
||||||
|
- if (storedUserEntry.hasExpired()) {
|
||||||
|
- list.add(storedUserEntry.getUser());
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- for (K object : list) {
|
||||||
|
- this.map.remove(this.getKeyForUser(object));
|
||||||
|
- }
|
||||||
|
+ this.map.values().removeIf(StoredUserEntry::hasExpired); // Paper - Use ConcurrentHashMap in JsonList
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract StoredUserEntry<K> createEntry(JsonObject entryData);
|
||||||
|
@@ -103,6 +_,7 @@
|
||||||
|
}
|
||||||
|
|
||||||
|
public void save() throws IOException {
|
||||||
|
+ this.removeExpired(); // Paper - remove expired values before saving
|
||||||
|
JsonArray jsonArray = new JsonArray();
|
||||||
|
this.map.values().stream().map(storedEntry -> Util.make(new JsonObject(), storedEntry::serialize)).forEach(jsonArray::add);
|
||||||
|
|
||||||
|
@@ -127,7 +_,14 @@
|
||||||
|
this.map.put(this.getKeyForUser(storedUserEntry.getUser()), (V)storedUserEntry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+ // Spigot Start
|
||||||
|
+ } catch (com.google.gson.JsonParseException | NullPointerException ex) {
|
||||||
|
+ org.bukkit.Bukkit.getLogger().log(java.util.logging.Level.WARNING, "Unable to read file " + this.file + ", backing it up to {0}.backup and creating new copy.", ex);
|
||||||
|
+ File backup = new File(this.file + ".backup");
|
||||||
|
+ this.file.renameTo(backup);
|
||||||
|
+ this.file.delete();
|
||||||
|
}
|
||||||
|
+ // Spigot End
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,11 +1,11 @@
|
|||||||
--- a/net/minecraft/server/players/UserBanListEntry.java
|
--- a/net/minecraft/server/players/UserBanListEntry.java
|
||||||
+++ b/net/minecraft/server/players/UserBanListEntry.java
|
+++ b/net/minecraft/server/players/UserBanListEntry.java
|
||||||
@@ -1,3 +1,4 @@
|
@@ -1,3 +_,4 @@
|
||||||
+// mc-dev import
|
+// mc-dev import
|
||||||
package net.minecraft.server.players;
|
package net.minecraft.server.players;
|
||||||
|
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
@@ -39,20 +40,29 @@
|
@@ -37,19 +_,29 @@
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private static GameProfile createGameProfile(JsonObject json) {
|
private static GameProfile createGameProfile(JsonObject json) {
|
||||||
@ -15,13 +15,12 @@
|
|||||||
+ UUID uuid = null;
|
+ UUID uuid = null;
|
||||||
+ String name = null;
|
+ String name = null;
|
||||||
+ if (json.has("uuid")) {
|
+ if (json.has("uuid")) {
|
||||||
String s = json.get("uuid").getAsString();
|
String asString = json.get("uuid").getAsString();
|
||||||
|
|
||||||
- UUID uuid;
|
- UUID uuid;
|
||||||
-
|
|
||||||
try {
|
try {
|
||||||
uuid = UUID.fromString(s);
|
uuid = UUID.fromString(asString);
|
||||||
} catch (Throwable throwable) {
|
} catch (Throwable var4) {
|
||||||
- return null;
|
- return null;
|
||||||
}
|
}
|
||||||
|
|
@ -1,8 +1,8 @@
|
|||||||
--- a/net/minecraft/server/players/UserWhiteList.java
|
--- a/net/minecraft/server/players/UserWhiteList.java
|
||||||
+++ b/net/minecraft/server/players/UserWhiteList.java
|
+++ b/net/minecraft/server/players/UserWhiteList.java
|
||||||
@@ -28,4 +28,23 @@
|
@@ -28,4 +_,23 @@
|
||||||
protected String getKeyForUser(GameProfile gameProfile) {
|
protected String getKeyForUser(GameProfile obj) {
|
||||||
return gameProfile.getId().toString();
|
return obj.getId().toString();
|
||||||
}
|
}
|
||||||
+ // Paper start - Add whitelist events
|
+ // Paper start - Add whitelist events
|
||||||
+ @Override
|
+ @Override
|
@ -1,217 +0,0 @@
|
|||||||
--- a/net/minecraft/server/players/GameProfileCache.java
|
|
||||||
+++ b/net/minecraft/server/players/GameProfileCache.java
|
|
||||||
@@ -60,6 +60,11 @@
|
|
||||||
@Nullable
|
|
||||||
private Executor executor;
|
|
||||||
|
|
||||||
+ // Paper start - Fix GameProfileCache concurrency
|
|
||||||
+ protected final java.util.concurrent.locks.ReentrantLock stateLock = new java.util.concurrent.locks.ReentrantLock();
|
|
||||||
+ protected final java.util.concurrent.locks.ReentrantLock lookupLock = new java.util.concurrent.locks.ReentrantLock();
|
|
||||||
+ // Paper end - Fix GameProfileCache concurrency
|
|
||||||
+
|
|
||||||
public GameProfileCache(GameProfileRepository profileRepository, File cacheFile) {
|
|
||||||
this.profileRepository = profileRepository;
|
|
||||||
this.file = cacheFile;
|
|
||||||
@@ -67,11 +72,13 @@
|
|
||||||
}
|
|
||||||
|
|
||||||
private void safeAdd(GameProfileCache.GameProfileInfo entry) {
|
|
||||||
+ try { this.stateLock.lock(); // Paper - Fix GameProfileCache concurrency
|
|
||||||
GameProfile gameprofile = entry.getProfile();
|
|
||||||
|
|
||||||
entry.setLastAccess(this.getNextOperation());
|
|
||||||
this.profilesByName.put(gameprofile.getName().toLowerCase(Locale.ROOT), entry);
|
|
||||||
this.profilesByUUID.put(gameprofile.getId(), entry);
|
|
||||||
+ } finally { this.stateLock.unlock(); } // Paper - Fix GameProfileCache concurrency
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Optional<GameProfile> lookupGameProfile(GameProfileRepository repository, String name) {
|
|
||||||
@@ -85,10 +92,12 @@
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onProfileLookupFailed(String s1, Exception exception) {
|
|
||||||
- atomicreference.set((Object) null);
|
|
||||||
+ atomicreference.set(null); // CraftBukkit - decompile error
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
+ if (!org.apache.commons.lang3.StringUtils.isBlank(name) // Paper - Don't lookup a profile with a blank name
|
|
||||||
+ && io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode()) // Paper - Add setting for proxy online mode status
|
|
||||||
repository.findProfilesByNames(new String[]{name}, profilelookupcallback);
|
|
||||||
GameProfile gameprofile = (GameProfile) atomicreference.get();
|
|
||||||
|
|
||||||
@@ -105,7 +114,7 @@
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean usesAuthentication() {
|
|
||||||
- return GameProfileCache.usesAuthentication;
|
|
||||||
+ return io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode(); // Paper - Add setting for proxy online mode status
|
|
||||||
}
|
|
||||||
|
|
||||||
public void add(GameProfile profile) {
|
|
||||||
@@ -117,15 +126,29 @@
|
|
||||||
GameProfileCache.GameProfileInfo usercache_usercacheentry = new GameProfileCache.GameProfileInfo(profile, date);
|
|
||||||
|
|
||||||
this.safeAdd(usercache_usercacheentry);
|
|
||||||
- this.save();
|
|
||||||
+ if( !org.spigotmc.SpigotConfig.saveUserCacheOnStopOnly ) this.save(true); // Spigot - skip saving if disabled // Paper - Perf: Async GameProfileCache saving
|
|
||||||
}
|
|
||||||
|
|
||||||
private long getNextOperation() {
|
|
||||||
return this.operationCount.incrementAndGet();
|
|
||||||
}
|
|
||||||
|
|
||||||
+ // Paper start
|
|
||||||
+ public @Nullable GameProfile getProfileIfCached(String name) {
|
|
||||||
+ try { this.stateLock.lock(); // Paper - Fix GameProfileCache concurrency
|
|
||||||
+ GameProfileCache.GameProfileInfo entry = this.profilesByName.get(name.toLowerCase(Locale.ROOT));
|
|
||||||
+ if (entry == null) {
|
|
||||||
+ return null;
|
|
||||||
+ }
|
|
||||||
+ entry.setLastAccess(this.getNextOperation());
|
|
||||||
+ return entry.getProfile();
|
|
||||||
+ } finally { this.stateLock.unlock(); } // Paper - Fix GameProfileCache concurrency
|
|
||||||
+ }
|
|
||||||
+ // Paper end
|
|
||||||
+
|
|
||||||
public Optional<GameProfile> get(String name) {
|
|
||||||
String s1 = name.toLowerCase(Locale.ROOT);
|
|
||||||
+ boolean stateLocked = true; try { this.stateLock.lock(); // Paper - Fix GameProfileCache concurrency
|
|
||||||
GameProfileCache.GameProfileInfo usercache_usercacheentry = (GameProfileCache.GameProfileInfo) this.profilesByName.get(s1);
|
|
||||||
boolean flag = false;
|
|
||||||
|
|
||||||
@@ -141,19 +164,24 @@
|
|
||||||
if (usercache_usercacheentry != null) {
|
|
||||||
usercache_usercacheentry.setLastAccess(this.getNextOperation());
|
|
||||||
optional = Optional.of(usercache_usercacheentry.getProfile());
|
|
||||||
+ stateLocked = false; this.stateLock.unlock(); // Paper - Fix GameProfileCache concurrency
|
|
||||||
} else {
|
|
||||||
- optional = GameProfileCache.lookupGameProfile(this.profileRepository, s1);
|
|
||||||
+ stateLocked = false; this.stateLock.unlock(); // Paper - Fix GameProfileCache concurrency
|
|
||||||
+ try { this.lookupLock.lock(); // Paper - Fix GameProfileCache concurrency
|
|
||||||
+ optional = GameProfileCache.lookupGameProfile(this.profileRepository, name); // CraftBukkit - use correct case for offline players
|
|
||||||
+ } finally { this.lookupLock.unlock(); } // Paper - Fix GameProfileCache concurrency
|
|
||||||
if (optional.isPresent()) {
|
|
||||||
this.add((GameProfile) optional.get());
|
|
||||||
flag = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- if (flag) {
|
|
||||||
- this.save();
|
|
||||||
+ if (flag && !org.spigotmc.SpigotConfig.saveUserCacheOnStopOnly) { // Spigot - skip saving if disabled
|
|
||||||
+ this.save(true); // Paper - Perf: Async GameProfileCache saving
|
|
||||||
}
|
|
||||||
|
|
||||||
return optional;
|
|
||||||
+ } finally { if (stateLocked) { this.stateLock.unlock(); } } // Paper - Fix GameProfileCache concurrency
|
|
||||||
}
|
|
||||||
|
|
||||||
public CompletableFuture<Optional<GameProfile>> getAsync(String username) {
|
|
||||||
@@ -167,7 +195,7 @@
|
|
||||||
} else {
|
|
||||||
CompletableFuture<Optional<GameProfile>> completablefuture1 = CompletableFuture.supplyAsync(() -> {
|
|
||||||
return this.get(username);
|
|
||||||
- }, Util.backgroundExecutor().forName("getProfile")).whenCompleteAsync((optional, throwable) -> {
|
|
||||||
+ }, Util.PROFILE_EXECUTOR).whenCompleteAsync((optional, throwable) -> { // Paper - don't submit BLOCKING PROFILE LOOKUPS to the world gen thread
|
|
||||||
this.requests.remove(username);
|
|
||||||
}, this.executor);
|
|
||||||
|
|
||||||
@@ -178,6 +206,7 @@
|
|
||||||
}
|
|
||||||
|
|
||||||
public Optional<GameProfile> get(UUID uuid) {
|
|
||||||
+ try { this.stateLock.lock(); // Paper - Fix GameProfileCache concurrency
|
|
||||||
GameProfileCache.GameProfileInfo usercache_usercacheentry = (GameProfileCache.GameProfileInfo) this.profilesByUUID.get(uuid);
|
|
||||||
|
|
||||||
if (usercache_usercacheentry == null) {
|
|
||||||
@@ -186,6 +215,7 @@
|
|
||||||
usercache_usercacheentry.setLastAccess(this.getNextOperation());
|
|
||||||
return Optional.of(usercache_usercacheentry.getProfile());
|
|
||||||
}
|
|
||||||
+ } finally { this.stateLock.unlock(); } // Paper - Fix GameProfileCache concurrency
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setExecutor(Executor executor) {
|
|
||||||
@@ -208,7 +238,7 @@
|
|
||||||
|
|
||||||
label54:
|
|
||||||
{
|
|
||||||
- ArrayList arraylist;
|
|
||||||
+ List<GameProfileCache.GameProfileInfo> arraylist; // CraftBukkit - decompile error
|
|
||||||
|
|
||||||
try {
|
|
||||||
JsonArray jsonarray = (JsonArray) this.gson.fromJson(bufferedreader, JsonArray.class);
|
|
||||||
@@ -217,7 +247,7 @@
|
|
||||||
DateFormat dateformat = GameProfileCache.createDateFormat();
|
|
||||||
|
|
||||||
jsonarray.forEach((jsonelement) -> {
|
|
||||||
- Optional optional = GameProfileCache.readGameProfile(jsonelement, dateformat);
|
|
||||||
+ Optional<GameProfileCache.GameProfileInfo> optional = GameProfileCache.readGameProfile(jsonelement, dateformat); // CraftBukkit - decompile error
|
|
||||||
|
|
||||||
Objects.requireNonNull(list);
|
|
||||||
optional.ifPresent(list::add);
|
|
||||||
@@ -250,6 +280,11 @@
|
|
||||||
}
|
|
||||||
} catch (FileNotFoundException filenotfoundexception) {
|
|
||||||
;
|
|
||||||
+ // Spigot Start
|
|
||||||
+ } catch (com.google.gson.JsonSyntaxException | NullPointerException ex) {
|
|
||||||
+ GameProfileCache.LOGGER.warn( "Usercache.json is corrupted or has bad formatting. Deleting it to prevent further issues." );
|
|
||||||
+ this.file.delete();
|
|
||||||
+ // Spigot End
|
|
||||||
} catch (JsonParseException | IOException ioexception) {
|
|
||||||
GameProfileCache.LOGGER.warn("Failed to load profile cache {}", this.file, ioexception);
|
|
||||||
}
|
|
||||||
@@ -257,14 +292,15 @@
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
- public void save() {
|
|
||||||
+ public void save(boolean asyncSave) { // Paper - Perf: Async GameProfileCache saving
|
|
||||||
JsonArray jsonarray = new JsonArray();
|
|
||||||
DateFormat dateformat = GameProfileCache.createDateFormat();
|
|
||||||
|
|
||||||
- this.getTopMRUProfiles(1000).forEach((usercache_usercacheentry) -> {
|
|
||||||
+ this.listTopMRUProfiles(org.spigotmc.SpigotConfig.userCacheCap).forEach((usercache_usercacheentry) -> { // Spigot // Paper - Fix GameProfileCache concurrency
|
|
||||||
jsonarray.add(GameProfileCache.writeGameProfile(usercache_usercacheentry, dateformat));
|
|
||||||
});
|
|
||||||
String s = this.gson.toJson(jsonarray);
|
|
||||||
+ Runnable save = () -> { // Paper - Perf: Async GameProfileCache saving
|
|
||||||
|
|
||||||
try {
|
|
||||||
BufferedWriter bufferedwriter = Files.newWriter(this.file, StandardCharsets.UTF_8);
|
|
||||||
@@ -289,13 +325,32 @@
|
|
||||||
} catch (IOException ioexception) {
|
|
||||||
;
|
|
||||||
}
|
|
||||||
+ // Paper start - Perf: Async GameProfileCache saving
|
|
||||||
+ };
|
|
||||||
+ if (asyncSave) {
|
|
||||||
+ io.papermc.paper.util.MCUtil.scheduleAsyncTask(save);
|
|
||||||
+ } else {
|
|
||||||
+ save.run();
|
|
||||||
+ }
|
|
||||||
+ // Paper end - Perf: Async GameProfileCache saving
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private Stream<GameProfileCache.GameProfileInfo> getTopMRUProfiles(int limit) {
|
|
||||||
- return ImmutableList.copyOf(this.profilesByUUID.values()).stream().sorted(Comparator.comparing(GameProfileCache.GameProfileInfo::getLastAccess).reversed()).limit((long) limit);
|
|
||||||
+ // Paper start - Fix GameProfileCache concurrency
|
|
||||||
+ return this.listTopMRUProfiles(limit).stream();
|
|
||||||
}
|
|
||||||
|
|
||||||
+ private List<GameProfileCache.GameProfileInfo> listTopMRUProfiles(int limit) {
|
|
||||||
+ try {
|
|
||||||
+ this.stateLock.lock();
|
|
||||||
+ return this.profilesByUUID.values().stream().sorted(Comparator.comparing(GameProfileCache.GameProfileInfo::getLastAccess).reversed()).limit(limit).toList();
|
|
||||||
+ } finally {
|
|
||||||
+ this.stateLock.unlock();
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ // Paper end - Fix GameProfileCache concurrency
|
|
||||||
+
|
|
||||||
private static JsonElement writeGameProfile(GameProfileCache.GameProfileInfo entry, DateFormat dateFormat) {
|
|
||||||
JsonObject jsonobject = new JsonObject();
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
|||||||
--- a/net/minecraft/server/players/SleepStatus.java
|
|
||||||
+++ b/net/minecraft/server/players/SleepStatus.java
|
|
||||||
@@ -18,9 +18,12 @@
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean areEnoughDeepSleeping(int percentage, List<ServerPlayer> players) {
|
|
||||||
- int j = (int) players.stream().filter(Player::isSleepingLongEnough).count();
|
|
||||||
+ // CraftBukkit start
|
|
||||||
+ int j = (int) players.stream().filter((eh) -> { return eh.isSleepingLongEnough() || eh.fauxSleeping; }).count();
|
|
||||||
+ boolean anyDeepSleep = players.stream().anyMatch(Player::isSleepingLongEnough);
|
|
||||||
|
|
||||||
- return j >= this.sleepersNeeded(percentage);
|
|
||||||
+ return anyDeepSleep && j >= this.sleepersNeeded(percentage);
|
|
||||||
+ // CraftBukkit end
|
|
||||||
}
|
|
||||||
|
|
||||||
public int sleepersNeeded(int percentage) {
|
|
||||||
@@ -42,18 +45,24 @@
|
|
||||||
this.activePlayers = 0;
|
|
||||||
this.sleepingPlayers = 0;
|
|
||||||
Iterator iterator = players.iterator();
|
|
||||||
+ boolean anySleep = false; // CraftBukkit
|
|
||||||
|
|
||||||
while (iterator.hasNext()) {
|
|
||||||
ServerPlayer entityplayer = (ServerPlayer) iterator.next();
|
|
||||||
|
|
||||||
if (!entityplayer.isSpectator()) {
|
|
||||||
++this.activePlayers;
|
|
||||||
- if (entityplayer.isSleeping()) {
|
|
||||||
+ if (entityplayer.isSleeping() || entityplayer.fauxSleeping) { // CraftBukkit
|
|
||||||
++this.sleepingPlayers;
|
|
||||||
}
|
|
||||||
+ // CraftBukkit start
|
|
||||||
+ if (entityplayer.isSleeping()) {
|
|
||||||
+ anySleep = true;
|
|
||||||
+ }
|
|
||||||
+ // CraftBukkit end
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- return (j > 0 || this.sleepingPlayers > 0) && (i != this.activePlayers || j != this.sleepingPlayers);
|
|
||||||
+ return anySleep && (j > 0 || this.sleepingPlayers > 0) && (i != this.activePlayers || j != this.sleepingPlayers); // CraftBukkit
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,96 +0,0 @@
|
|||||||
--- a/net/minecraft/server/players/StoredUserList.java
|
|
||||||
+++ b/net/minecraft/server/players/StoredUserList.java
|
|
||||||
@@ -30,7 +30,7 @@
|
|
||||||
private static final Logger LOGGER = LogUtils.getLogger();
|
|
||||||
private static final Gson GSON = (new GsonBuilder()).setPrettyPrinting().create();
|
|
||||||
private final File file;
|
|
||||||
- private final Map<String, V> map = Maps.newHashMap();
|
|
||||||
+ private final Map<String, V> map = Maps.newConcurrentMap(); // Paper - Use ConcurrentHashMap in JsonList
|
|
||||||
|
|
||||||
public StoredUserList(File file) {
|
|
||||||
this.file = file;
|
|
||||||
@@ -53,8 +53,11 @@
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public V get(K key) {
|
|
||||||
- this.removeExpired();
|
|
||||||
- return (StoredUserEntry) this.map.get(this.getKeyForUser(key));
|
|
||||||
+ // Paper start - Use ConcurrentHashMap in JsonList
|
|
||||||
+ return (V) this.map.computeIfPresent(this.getKeyForUser(key), (k, v) -> {
|
|
||||||
+ return v.hasExpired() ? null : v;
|
|
||||||
+ });
|
|
||||||
+ // Paper end - Use ConcurrentHashMap in JsonList
|
|
||||||
}
|
|
||||||
|
|
||||||
public void remove(K key) {
|
|
||||||
@@ -77,7 +80,7 @@
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isEmpty() {
|
|
||||||
- return this.map.size() < 1;
|
|
||||||
+ return this.map.isEmpty(); // Paper - Use ConcurrentHashMap in JsonList
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String getKeyForUser(K profile) {
|
|
||||||
@@ -85,29 +88,12 @@
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean contains(K k0) {
|
|
||||||
+ this.removeExpired(); // CraftBukkit - SPIGOT-7589: Consistently remove expired entries to mirror .get(...)
|
|
||||||
return this.map.containsKey(this.getKeyForUser(k0));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void removeExpired() {
|
|
||||||
- List<K> list = Lists.newArrayList();
|
|
||||||
- Iterator iterator = this.map.values().iterator();
|
|
||||||
-
|
|
||||||
- while (iterator.hasNext()) {
|
|
||||||
- V v0 = (StoredUserEntry) iterator.next();
|
|
||||||
-
|
|
||||||
- if (v0.hasExpired()) {
|
|
||||||
- list.add(v0.getUser());
|
|
||||||
- }
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- iterator = list.iterator();
|
|
||||||
-
|
|
||||||
- while (iterator.hasNext()) {
|
|
||||||
- K k0 = iterator.next();
|
|
||||||
-
|
|
||||||
- this.map.remove(this.getKeyForUser(k0));
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
+ this.map.values().removeIf(StoredUserEntry::hasExpired); // Paper - Use ConcurrentHashMap in JsonList
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract StoredUserEntry<K> createEntry(JsonObject json);
|
|
||||||
@@ -117,8 +103,9 @@
|
|
||||||
}
|
|
||||||
|
|
||||||
public void save() throws IOException {
|
|
||||||
+ this.removeExpired(); // Paper - remove expired values before saving
|
|
||||||
JsonArray jsonarray = new JsonArray();
|
|
||||||
- Stream stream = this.map.values().stream().map((jsonlistentry) -> {
|
|
||||||
+ Stream<JsonObject> stream = this.map.values().stream().map((jsonlistentry) -> { // CraftBukkit - decompile error
|
|
||||||
JsonObject jsonobject = new JsonObject();
|
|
||||||
|
|
||||||
Objects.requireNonNull(jsonlistentry);
|
|
||||||
@@ -171,9 +158,17 @@
|
|
||||||
StoredUserEntry<K> jsonlistentry = this.createEntry(jsonobject);
|
|
||||||
|
|
||||||
if (jsonlistentry.getUser() != null) {
|
|
||||||
- this.map.put(this.getKeyForUser(jsonlistentry.getUser()), jsonlistentry);
|
|
||||||
+ this.map.put(this.getKeyForUser(jsonlistentry.getUser()), (V) jsonlistentry); // CraftBukkit - decompile error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+ // Spigot Start
|
|
||||||
+ } catch ( com.google.gson.JsonParseException | NullPointerException ex )
|
|
||||||
+ {
|
|
||||||
+ org.bukkit.Bukkit.getLogger().log( java.util.logging.Level.WARNING, "Unable to read file " + this.file + ", backing it up to {0}.backup and creating new copy.", ex );
|
|
||||||
+ File backup = new File( this.file + ".backup" );
|
|
||||||
+ this.file.renameTo( backup );
|
|
||||||
+ this.file.delete();
|
|
||||||
+ // Spigot End
|
|
||||||
} catch (Throwable throwable) {
|
|
||||||
if (bufferedreader != null) {
|
|
||||||
try {
|
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren