Use more fastutil data structures

This commit is contained in:
FatSaw
2022-07-09 04:00:26 +03:00
parent e066c5e12c
commit 9ad318d4bb
7 changed files with 2280 additions and 2 deletions

View File

@@ -0,0 +1,458 @@
package net.minecraft.server;
import com.destroystokyo.paper.PaperConfig;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectIterator;
import it.unimi.dsi.fastutil.longs.LongArraySet;
import it.unimi.dsi.fastutil.longs.LongIterator;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import javax.annotation.Nullable;
import com.destroystokyo.paper.exception.ServerInternalException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
// CraftBukkit start
import org.bukkit.craftbukkit.chunkio.ChunkIOExecutor;
import org.bukkit.event.world.ChunkUnloadEvent;
// CraftBukkit end
public class ChunkProviderServer implements IChunkProvider {
private static final Logger a = LogManager.getLogger();
public final LongArraySet unloadQueue = new LongArraySet(512); // Dionysus
public final ChunkGenerator chunkGenerator;
private final IChunkLoader chunkLoader;
// Paper start - chunk save stats
private long lastQueuedSaves = 0L; // Paper
private long lastProcessedSaves = 0L; // Paper
private long lastSaveStatPrinted = System.currentTimeMillis();
// Paper end
// Paper start
protected Chunk lastChunkByPos = null;
public Long2ObjectOpenHashMap<Chunk> chunks = new Long2ObjectOpenHashMap<Chunk>(8192) {
@Override
public Chunk get(long key) {
if (lastChunkByPos != null && key == lastChunkByPos.chunkKey) {
return lastChunkByPos;
}
return lastChunkByPos = super.get(key);
}
@Override
public Chunk remove(long key) {
if (lastChunkByPos != null && key == lastChunkByPos.chunkKey) {
lastChunkByPos = null;
}
return super.remove(key);
}
}; // CraftBukkit
// Paper end
public final WorldServer world;
public ChunkProviderServer(WorldServer worldserver, IChunkLoader ichunkloader, ChunkGenerator chunkgenerator) {
this.world = worldserver;
this.chunkLoader = ichunkloader;
this.chunkGenerator = chunkgenerator;
}
public Collection<Chunk> a() {
return this.chunks.values();
}
public void unload(Chunk chunk) {
if (this.world.worldProvider.c(chunk.locX, chunk.locZ)) {
this.unloadQueue.add(Long.valueOf(ChunkCoordIntPair.a(chunk.locX, chunk.locZ)));
chunk.d = true;
}
}
public void b() {
ObjectIterator objectiterator = this.chunks.values().iterator();
while (objectiterator.hasNext()) {
Chunk chunk = (Chunk) objectiterator.next();
this.unload(chunk);
}
}
// Paper start
public boolean isChunkGenerated(int x, int z) {
return this.chunks.containsKey(ChunkCoordIntPair.asLong(x, z)) || this.chunkLoader.chunkExists(x, z);
}
// Paper end
@Nullable
public Chunk getLoadedChunkAt(int i, int j) {
long k = ChunkCoordIntPair.a(i, j);
Chunk chunk = (Chunk) this.chunks.get(k);
if (chunk != null) {
chunk.d = false;
}
return chunk;
}
@Nullable
public Chunk getOrLoadChunkAt(int i, int j) {
Chunk chunk = this.getLoadedChunkAt(i, j);
if (chunk == null) {
// CraftBukkit start
ChunkRegionLoader loader = null;
if (this.chunkLoader instanceof ChunkRegionLoader) {
loader = (ChunkRegionLoader) this.chunkLoader;
}
if (loader != null && loader.chunkExists(i, j)) {
chunk = ChunkIOExecutor.syncChunkLoad(world, loader, this, i, j);
}
}
return chunk;
}
@Nullable
public Chunk originalGetOrLoadChunkAt(int i, int j) {
// CraftBukkit end
Chunk chunk = this.getLoadedChunkAt(i, j);
if (chunk == null) {
chunk = this.loadChunk(i, j);
if (chunk != null) {
this.chunks.put(ChunkCoordIntPair.a(i, j), chunk);
chunk.addEntities();
chunk.loadNearby(this, this.chunkGenerator, false); // CraftBukkit
}
}
return chunk;
}
// CraftBukkit start
public Chunk getChunkIfLoaded(int x, int z) {
return chunks.get(ChunkCoordIntPair.a(x, z));
}
// CraftBukkit end
public Chunk getChunkAt(int i, int j) {
return getChunkAt(i, j, null);
}
public Chunk getChunkAt(int i, int j, Runnable runnable) {
return getChunkAt(i, j, runnable, true);
}
public Chunk getChunkAt(int i, int j, Runnable runnable, boolean generate) {
Chunk chunk = world.paperConfig.allowPermaChunkLoaders ? getLoadedChunkAt(i, j) : getChunkIfLoaded(i, j); // Paper - Configurable perma chunk loaders
ChunkRegionLoader loader = null;
if (this.chunkLoader instanceof ChunkRegionLoader) {
loader = (ChunkRegionLoader) this.chunkLoader;
}
// We can only use the queue for already generated chunks
if (chunk == null && loader != null && loader.chunkExists(i, j)) {
if (runnable != null) {
ChunkIOExecutor.queueChunkLoad(world, loader, this, i, j, runnable);
return null;
} else {
chunk = ChunkIOExecutor.syncChunkLoad(world, loader, this, i, j);
// Paper start - If there was an issue loading the chunk from region, stage1 will fail and stage2 will load it sync
// all we need to do is fetch an instance
if (chunk == null) {
chunk = getChunkIfLoaded(i, j);
}
// Paper end
}
} else if (chunk == null && generate) {
chunk = originalGetChunkAt(i, j);
}
// If we didn't load the chunk async and have a callback run it now
if (runnable != null) {
runnable.run();
}
return chunk;
}
public Chunk originalGetChunkAt(int i, int j) {
Chunk chunk = this.originalGetOrLoadChunkAt(i, j);
// CraftBukkit end
if (chunk == null) {
world.timings.syncChunkLoadTimer.startTiming(); // Spigot
long k = ChunkCoordIntPair.a(i, j);
try {
chunk = this.chunkGenerator.getOrCreateChunk(i, j);
} catch (Throwable throwable) {
CrashReport crashreport = CrashReport.a(throwable, "Exception generating new chunk");
CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Chunk to be generated");
crashreportsystemdetails.a("Location", (Object) String.format("%d,%d", new Object[] { Integer.valueOf(i), Integer.valueOf(j)}));
crashreportsystemdetails.a("Position hash", (Object) Long.valueOf(k));
crashreportsystemdetails.a("Generator", (Object) this.chunkGenerator);
throw new ReportedException(crashreport);
}
this.chunks.put(k, chunk);
chunk.addEntities();
chunk.loadNearby(this, this.chunkGenerator, true); // CraftBukkit
world.timings.syncChunkLoadTimer.stopTiming(); // Spigot
}
return chunk;
}
@Nullable
public Chunk loadChunk(int i, int j) {
try {
Chunk chunk = this.chunkLoader.a(this.world, i, j);
if (chunk != null) {
chunk.setLastSaved(this.world.getTime());
this.chunkGenerator.recreateStructures(chunk, i, j);
}
return chunk;
} catch (Exception exception) {
// Paper start
String msg = "Couldn\'t load chunk";
ChunkProviderServer.a.error(msg, exception);
ServerInternalException.reportInternalException(exception);
// Paper end
return null;
}
}
public void saveChunkNOP(Chunk chunk) {
try {
// this.chunkLoader.b(this.world, chunk); // Spigot
} catch (Exception exception) {
// Paper start
String msg = "Couldn\'t save entities";
ChunkProviderServer.a.error(msg, exception);
ServerInternalException.reportInternalException(exception);
// Paper end
}
}
public void saveChunk(Chunk chunk, boolean unloaded) { // Spigot
try (co.aikar.timings.Timing timed = world.timings.chunkSaveData.startTiming()) {
chunk.setLastSaved(this.world.getTime());
this.chunkLoader.saveChunk(this.world, chunk, unloaded); // Spigot
} catch (IOException ioexception) {
// Paper start
String msg = "Couldn\'t save chunk";
ChunkProviderServer.a.error(msg, ioexception);
ServerInternalException.reportInternalException(ioexception);
} catch (ExceptionWorldConflict exceptionworldconflict) {
String msg = "Couldn\'t save chunk; already in use by another instance of Minecraft?";
ChunkProviderServer.a.error(msg, exceptionworldconflict);
ServerInternalException.reportInternalException(exceptionworldconflict);
}
}
public boolean a(boolean flag) {
int i = 0;
// CraftBukkit start
// Paper start
final ChunkRegionLoader chunkLoader = (ChunkRegionLoader) world.getChunkProviderServer().chunkLoader;
final int queueSize = chunkLoader.getQueueSize();
final long now = System.currentTimeMillis();
final long timeSince = (now - lastSaveStatPrinted) / 1000;
final Integer printRateSecs = Integer.getInteger("printSaveStats");
if (printRateSecs != null && timeSince >= printRateSecs) {
final String timeStr = "/" + timeSince +"s";
final long queuedSaves = chunkLoader.getQueuedSaves();
long queuedDiff = queuedSaves - lastQueuedSaves;
lastQueuedSaves = queuedSaves;
final long processedSaves = chunkLoader.getProcessedSaves();
long processedDiff = processedSaves - lastProcessedSaves;
lastProcessedSaves = processedSaves;
lastSaveStatPrinted = now;
if (processedDiff > 0 || queueSize > 0 || queuedDiff > 0) {
System.out.println("[Chunk Save Stats] " + world.worldData.getName() +
" - Current: " + queueSize +
" - Queued: " + queuedDiff + timeStr +
" - Processed: " +processedDiff + timeStr
);
}
}
if (queueSize > world.paperConfig.queueSizeAutoSaveThreshold){
return false;
}
final int autoSaveLimit = world.paperConfig.maxAutoSaveChunksPerTick;
// Paper end
Iterator iterator = this.chunks.values().iterator();
while (iterator.hasNext()) {
Chunk chunk = (Chunk) iterator.next();
// CraftBukkit end
if (flag) {
this.saveChunkNOP(chunk);
}
if (chunk.a(flag)) {
this.saveChunk(chunk, false); // Spigot
chunk.f(false);
++i;
if (!flag && i >= autoSaveLimit) { // Spigot - // Paper - Incremental Auto Save - cap max per tick
return false;
}
}
}
return true;
}
public void c() {
this.chunkLoader.c();
}
private static final double UNLOAD_QUEUE_RESIZE_FACTOR = 0.96;
public boolean unloadChunks() {
if (!this.world.savingDisabled) {
if (!this.unloadQueue.isEmpty()) {
// Spigot start
org.spigotmc.SlackActivityAccountant activityAccountant = this.world.getMinecraftServer().slackActivityAccountant;
activityAccountant.startActivity(0.5);
int targetSize = Math.min(this.unloadQueue.size() - 100, (int) (this.unloadQueue.size() * UNLOAD_QUEUE_RESIZE_FACTOR)); // Paper - Make more aggressive
// Spigot end
LongIterator iterator = this.unloadQueue.iterator();
while (iterator.hasNext()) { // Spigot
Long chunkKey = iterator.nextLong();
iterator.remove(); // Spigot
Chunk chunk = (Chunk) this.chunks.get(chunkKey);
if (chunk != null && chunk.d) {
// CraftBukkit start - move unload logic to own method
chunk.setShouldUnload(false); // Paper
if (!unloadChunk(chunk, true)) {
continue;
}
// CraftBukkit end
// Spigot start
if (this.unloadQueue.size() <= targetSize && activityAccountant.activityTimeIsExhausted()) {
break;
}
// Spigot end
}
}
activityAccountant.endActivity(); // Spigot
}
// Paper start - delayed chunk unloads
long now = System.currentTimeMillis();
long unloadAfter = world.paperConfig.delayChunkUnloadsBy;
if (unloadAfter > 0) {
//noinspection Convert2streamapi
for (Chunk chunk : chunks.values()) {
if (chunk.scheduledForUnload != null && now - chunk.scheduledForUnload > unloadAfter) {
chunk.scheduledForUnload = null;
unload(chunk);
}
}
}
// Paper end
this.chunkLoader.b();
}
return false;
}
// CraftBukkit start
public boolean unloadChunk(Chunk chunk, boolean save) {
ChunkUnloadEvent event = new ChunkUnloadEvent(chunk.bukkitChunk, save);
this.world.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
return false;
}
save = event.isSaveChunk();
chunk.lightingQueue.processUnload(); // Paper
// Update neighbor counts
for (int x = -2; x < 3; x++) {
for (int z = -2; z < 3; z++) {
if (x == 0 && z == 0) {
continue;
}
Chunk neighbor = this.getChunkIfLoaded(chunk.locX + x, chunk.locZ + z);
if (neighbor != null) {
neighbor.setNeighborUnloaded(-x, -z);
chunk.setNeighborUnloaded(x, z);
}
}
}
// Moved from unloadChunks above
chunk.removeEntities();
if (save) {
this.saveChunk(chunk, true); // Spigot
this.saveChunkNOP(chunk);
}
this.chunks.remove(chunk.chunkKey);
return true;
}
// CraftBukkit end
public boolean e() {
return !this.world.savingDisabled;
}
public String getName() {
return "ServerChunkCache: " + this.chunks.size() + " Drop: " + this.unloadQueue.size();
}
public List<BiomeBase.BiomeMeta> a(EnumCreatureType enumcreaturetype, BlockPosition blockposition) {
return this.chunkGenerator.getMobsFor(enumcreaturetype, blockposition);
}
@Nullable
public BlockPosition a(World world, String s, BlockPosition blockposition, boolean flag) {
return this.chunkGenerator.findNearestMapFeature(world, s, blockposition, flag);
}
public boolean a(World world, String s, BlockPosition blockposition) {
return this.chunkGenerator.a(world, s, blockposition);
}
public int g() {
return this.chunks.size();
}
public boolean isLoaded(int i, int j) {
return this.chunks.containsKey(ChunkCoordIntPair.a(i, j));
}
public boolean e(int i, int j) {
return this.chunks.containsKey(ChunkCoordIntPair.a(i, j)) || this.chunkLoader.chunkExists(i, j);
}
}

View File

@@ -0,0 +1,138 @@
package net.minecraft.server;
import it.unimi.dsi.fastutil.objects.Object2LongMap;
import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap;
// CraftBukkit start
import java.net.InetAddress;
import java.util.Iterator;
import java.util.Map;
// CraftBukkit end
public class HandshakeListener implements PacketHandshakingInListener {
private static final com.google.gson.Gson gson = new com.google.gson.Gson(); // Spigot
// CraftBukkit start - add fields
private static final Object2LongOpenHashMap<InetAddress> throttleTracker = new Object2LongOpenHashMap<>();
private static int throttleCounter = 0;
// CraftBukkit end
private final MinecraftServer a;
private final NetworkManager b;
private NetworkManager getNetworkManager() { return b; } // Paper - OBFHELPER
public HandshakeListener(MinecraftServer minecraftserver, NetworkManager networkmanager) {
this.a = minecraftserver;
this.b = networkmanager;
}
public void a(PacketHandshakingInSetProtocol packethandshakinginsetprotocol) {
switch (packethandshakinginsetprotocol.a()) {
case LOGIN:
this.b.setProtocol(EnumProtocol.LOGIN);
ChatMessage chatmessage;
// CraftBukkit start - Connection throttle
try {
long currentTime = System.currentTimeMillis();
long connectionThrottle = MinecraftServer.getServer().server.getConnectionThrottle();
InetAddress address = ((java.net.InetSocketAddress) this.b.getSocketAddress()).getAddress();
synchronized (throttleTracker) {
if (throttleTracker.containsKey(address) && !"127.0.0.1".equals(address.getHostAddress()) && currentTime - throttleTracker.getLong(address) < connectionThrottle) {
throttleTracker.put(address, currentTime);
chatmessage = new ChatMessage("Connection throttled! Please wait before reconnecting.");
this.b.sendPacket(new PacketLoginOutDisconnect(chatmessage));
this.b.close(chatmessage);
return;
}
throttleTracker.put(address, currentTime);
throttleCounter++;
if (throttleCounter > 200) {
throttleCounter = 0;
// Cleanup stale entries
throttleTracker.object2LongEntrySet().removeIf(entry -> entry.getLongValue() > connectionThrottle); // Dionysus
}
}
} catch (Throwable t) {
org.apache.logging.log4j.LogManager.getLogger().debug("Failed to check connection throttle", t);
}
// CraftBukkit end
if (packethandshakinginsetprotocol.b() > 340) {
chatmessage = new ChatMessage( java.text.MessageFormat.format( org.spigotmc.SpigotConfig.outdatedServerMessage.replaceAll("'", "''"), "1.12.2" ) ); // Spigot
this.b.sendPacket(new PacketLoginOutDisconnect(chatmessage));
this.b.close(chatmessage);
} else if (packethandshakinginsetprotocol.b() < 340) {
chatmessage = new ChatMessage( java.text.MessageFormat.format( org.spigotmc.SpigotConfig.outdatedClientMessage.replaceAll("'", "''"), "1.12.2" ) ); // Spigot
this.b.sendPacket(new PacketLoginOutDisconnect(chatmessage));
this.b.close(chatmessage);
} else {
this.b.setPacketListener(new LoginListener(this.a, this.b));
// Paper start - handshake event
boolean proxyLogicEnabled = org.spigotmc.SpigotConfig.bungee;
boolean handledByEvent = false;
// Try and handle the handshake through the event
if (com.destroystokyo.paper.event.player.PlayerHandshakeEvent.getHandlerList().getRegisteredListeners().length != 0) { // Hello? Can you hear me?
com.destroystokyo.paper.event.player.PlayerHandshakeEvent event = new com.destroystokyo.paper.event.player.PlayerHandshakeEvent(packethandshakinginsetprotocol.hostname, !proxyLogicEnabled);
if (event.callEvent()) {
// If we've failed somehow, let the client know so and go no further.
if (event.isFailed()) {
chatmessage = new ChatMessage(event.getFailMessage());
this.b.sendPacket(new PacketLoginOutDisconnect(chatmessage));
this.b.close(chatmessage);
return;
}
packethandshakinginsetprotocol.hostname = event.getServerHostname();
this.b.l = new java.net.InetSocketAddress(event.getSocketAddressHostname(), ((java.net.InetSocketAddress) this.b.getSocketAddress()).getPort());
this.b.spoofedUUID = event.getUniqueId();
this.b.spoofedProfile = gson.fromJson(event.getPropertiesJson(), com.mojang.authlib.properties.Property[].class);
handledByEvent = true; // Hooray, we did it!
}
}
// Don't try and handle default logic if it's been handled by the event.
if (!handledByEvent && proxyLogicEnabled) {
// Paper end
// Spigot Start
//if (org.spigotmc.SpigotConfig.bungee) { // Paper - comment out, we check above!
String[] split = packethandshakinginsetprotocol.hostname.split("\00");
if ( split.length == 3 || split.length == 4 ) {
packethandshakinginsetprotocol.hostname = split[0];
b.l = new java.net.InetSocketAddress(split[1], ((java.net.InetSocketAddress) b.getSocketAddress()).getPort());
b.spoofedUUID = com.mojang.util.UUIDTypeAdapter.fromString( split[2] );
} else
{
chatmessage = new ChatMessage("If you wish to use IP forwarding, please enable it in your BungeeCord config as well!");
this.b.sendPacket(new PacketLoginOutDisconnect(chatmessage));
this.b.close(chatmessage);
return;
}
if ( split.length == 4 )
{
b.spoofedProfile = gson.fromJson(split[3], com.mojang.authlib.properties.Property[].class);
}
}
// Spigot End
((LoginListener) this.b.i()).hostname = packethandshakinginsetprotocol.hostname + ":" + packethandshakinginsetprotocol.port; // CraftBukkit - set hostname
}
break;
case STATUS:
this.b.setProtocol(EnumProtocol.STATUS);
this.b.setPacketListener(new PacketStatusListener(this.a, this.b));
break;
default:
throw new UnsupportedOperationException("Invalid intention " + packethandshakinginsetprotocol.a());
}
// Paper start - NetworkClient implementation
this.getNetworkManager().protocolVersion = packethandshakinginsetprotocol.getProtocolVersion();
this.getNetworkManager().virtualHost = com.destroystokyo.paper.network.PaperNetworkClient.prepareVirtualHost(packethandshakinginsetprotocol.hostname, packethandshakinginsetprotocol.port);
// Paper end
}
public void a(IChatBaseComponent ichatbasecomponent) {}
}

View File

@@ -0,0 +1,164 @@
package net.minecraft.server;
import com.google.common.collect.Lists;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.function.Supplier;
import it.unimi.dsi.fastutil.longs.LongArrayList;
import it.unimi.dsi.fastutil.objects.Object2LongMap;
import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import it.unimi.dsi.fastutil.objects.ObjectIterator;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class MethodProfiler {
public static final boolean ENABLED = Boolean.getBoolean("enableDebugMethodProfiler"); // CraftBukkit - disable unless specified in JVM arguments
private static final Logger b = LogManager.getLogger();
private final ObjectArrayList<String> c = new ObjectArrayList<>(); // Dionysus
private final LongArrayList d = new LongArrayList(); // Dionysus
public boolean a;
private String e = "";
private final Object2LongOpenHashMap<String> f = new Object2LongOpenHashMap<>();
public MethodProfiler() {}
public void a() {
if (!ENABLED) return; // CraftBukkit
this.f.clear();
this.e = "";
this.c.clear();
}
public void a(String s) {
if (!ENABLED) return; // CraftBukkit
if (this.a) {
if (!this.e.isEmpty()) {
this.e = this.e + ".";
}
this.e = this.e + s;
this.c.add(this.e);
this.d.add(Long.valueOf(System.nanoTime()));
}
}
public void a(Supplier<String> supplier) {
if (!ENABLED) return; // CraftBukkit
if (this.a) {
this.a((String) supplier.get());
}
}
public void b() {
if (!ENABLED) return; // CraftBukkit
if (this.a) {
long i = System.nanoTime();
long j = this.d.removeLong(this.d.size() - 1);
this.c.remove(this.c.size() - 1);
long k = i - j;
if (this.f.containsKey(this.e)) {
this.f.put(this.e, this.f.get(this.e) + k);
} else {
this.f.put(this.e, k);
}
if (k > 100000000L) {
MethodProfiler.b.warn("Something\'s taking too long! \'{}\' took aprox {} ms", this.e, Double.valueOf((double) k / 1000000.0D));
}
this.e = this.c.isEmpty() ? "" : (String) this.c.get(this.c.size() - 1);
}
}
public List<MethodProfiler.ProfilerInfo> b(String s) {
if (!ENABLED || !this.a) { // CraftBukkit
return Collections.emptyList();
} else {
long i = this.f.getOrDefault("root", 0L);
long j = this.f.getOrDefault(s, -1L);
ArrayList<MethodProfiler.ProfilerInfo> arraylist = Lists.newArrayList();
if (!s.isEmpty()) {
s = s + ".";
}
long k = 0L;
for (String s1 : this.f.keySet()) {
if (s1.length() > s.length() && s1.startsWith(s) && s1.indexOf(".", s.length() + 1) < 0) {
k += this.f.getLong(s1);
}
}
float f = (float) k;
if (k < j) {
k = j;
}
if (i < k) {
i = k;
}
for (Object2LongMap.Entry<String> entry : this.f.object2LongEntrySet()) {
String s2 = entry.getKey();
if (s2.length() > s.length() && s2.startsWith(s) && s2.indexOf(".", s.length() + 1) < 0) {
long l = this.f.getLong(s2);
double d0 = (double) l * 100.0D / (double) k;
double d1 = (double) l * 100.0D / (double) i;
String s3 = s2.substring(s.length());
arraylist.add(new MethodProfiler.ProfilerInfo(s3, d0, d1));
}
entry.setValue(entry.getLongValue() * 999L / 1000L);
}
if ((float) k > f) {
arraylist.add(new MethodProfiler.ProfilerInfo("unspecified", (double) ((float) k - f) * 100.0D / (double) k, (double) ((float) k - f) * 100.0D / (double) i));
}
Collections.sort(arraylist);
arraylist.add(0, new MethodProfiler.ProfilerInfo(s, 100.0D, (double) k * 100.0D / (double) i));
return arraylist;
}
}
public void c(String s) {
if (!ENABLED) return; // CraftBukkit
this.b();
this.a(s);
}
public String c() {
if (!ENABLED) return "[DISABLED]"; // CraftBukkit
return this.c.isEmpty() ? "[UNKNOWN]" : (String) this.c.get(this.c.size() - 1);
}
public static final class ProfilerInfo implements Comparable<MethodProfiler.ProfilerInfo> {
public double a;
public double b;
public String c;
public ProfilerInfo(String s, double d0, double d1) {
this.c = s;
this.a = d0;
this.b = d1;
}
public int a(MethodProfiler.ProfilerInfo methodprofiler_profilerinfo) {
return methodprofiler_profilerinfo.a < this.a ? -1 : (methodprofiler_profilerinfo.a > this.a ? 1 : methodprofiler_profilerinfo.c.compareTo(this.c));
}
public int compareTo(MethodProfiler.ProfilerInfo object) { // CraftBukkit: decompile error
return this.a((MethodProfiler.ProfilerInfo) object);
}
}
}

View File

@@ -79,8 +79,20 @@ public abstract class PlayerList {
private int v;
// CraftBukkit start
private CraftServer cserver;
private final Map<String,EntityPlayer> playersByName = new org.spigotmc.CaseInsensitiveMap<EntityPlayer>();
private final CraftServer cserver;
private final Map<String,EntityPlayer> playersByName = new it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap<String, EntityPlayer>(
new it.unimi.dsi.fastutil.Hash.Strategy<String>() {
@Override
public int hashCode(String o) {
return o.toLowerCase().hashCode();
}
@Override
public boolean equals(String a, String b) {
return a.equalsIgnoreCase(b);
}
}
);
@Nullable String collideRuleTeamName; // Paper - Team name used for collideRule
public PlayerList(MinecraftServer minecraftserver) {