Upstate upstream B/CB
--- work/Bukkit Submodule work/Bukkit 9a793cce8..0c1d258bb: > Make PigZapEvent extend EntityTransformEvent --- work/CraftBukkit Submodule work/CraftBukkit ee6684bba..6a398ac44: > SPIGOT-4511: Trident doesn't lose durability > Tweak outdated windows
This commit is contained in:
243
Spigot-Server-Patches/0365-Optimize-Server-World-Map.patch
Normal file
243
Spigot-Server-Patches/0365-Optimize-Server-World-Map.patch
Normal file
@@ -0,0 +1,243 @@
|
||||
From c40ff8852b2b3975cb6c23b02934953274edff7d Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Mon, 17 Sep 2018 23:37:31 -0400
|
||||
Subject: [PATCH] Optimize Server World Map
|
||||
|
||||
Minecraft moved worlds to a hashmap in 1.13.1.
|
||||
This creates inconsistent order for iteration of the map.
|
||||
|
||||
This patch restores World management to be back as an Array.
|
||||
|
||||
.values() will allow us to iterate as it was pre 1.13.1 by
|
||||
ArrayList, giving consistent ordering and effecient iteration performance.
|
||||
|
||||
KeySet and EntrySet iteration is proxied to the List iterator,
|
||||
and should retain manipulation behavior but nothing should be doing that.
|
||||
|
||||
Getting a World by dimension ID is now back a constant time operation.
|
||||
|
||||
Hopefully no other plugins try to mess with this map, as we are only handling
|
||||
known NMS used methods, but we can add more if naughty plugins are found later.
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldMap.java b/src/main/java/com/destroystokyo/paper/PaperWorldMap.java
|
||||
new file mode 100644
|
||||
index 000000000..af9e4455c
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldMap.java
|
||||
@@ -0,0 +1,191 @@
|
||||
+package com.destroystokyo.paper;
|
||||
+
|
||||
+import net.minecraft.server.DimensionManager;
|
||||
+import net.minecraft.server.WorldServer;
|
||||
+
|
||||
+import javax.annotation.Nonnull;
|
||||
+import java.util.AbstractSet;
|
||||
+import java.util.ArrayList;
|
||||
+import java.util.Collection;
|
||||
+import java.util.HashMap;
|
||||
+import java.util.Iterator;
|
||||
+import java.util.List;
|
||||
+import java.util.Map;
|
||||
+import java.util.Set;
|
||||
+
|
||||
+public class PaperWorldMap extends HashMap<DimensionManager, WorldServer> {
|
||||
+ private final List<WorldServer> worlds = new ArrayList<>();
|
||||
+ private final List<WorldServer> worldsIterable = new ArrayList<WorldServer>() {
|
||||
+ @Override
|
||||
+ public Iterator<WorldServer> iterator() {
|
||||
+ Iterator<WorldServer> iterator = super.iterator();
|
||||
+ return new Iterator<WorldServer>() {
|
||||
+ private WorldServer last;
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean hasNext() {
|
||||
+ return iterator.hasNext();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public WorldServer next() {
|
||||
+ this.last = iterator.next();
|
||||
+ return last;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void remove() {
|
||||
+ worlds.set(last.dimension.getDimensionID()+1, null);
|
||||
+ }
|
||||
+ };
|
||||
+ }
|
||||
+ };
|
||||
+ @Override
|
||||
+ public int size() {
|
||||
+ return worldsIterable.size();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isEmpty() {
|
||||
+ return worldsIterable.isEmpty();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public WorldServer get(Object key) {
|
||||
+ // Will hit the below method
|
||||
+ return key instanceof DimensionManager ? get((DimensionManager) key) : null;
|
||||
+ }
|
||||
+
|
||||
+ public WorldServer get(DimensionManager key) {
|
||||
+ int id = key.getDimensionID()+1;
|
||||
+ return worlds.size() > id ? worlds.get(id) : null;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean containsKey(Object key) {
|
||||
+ // will hit below method
|
||||
+ return key instanceof DimensionManager && containsKey((DimensionManager) key);
|
||||
+ }
|
||||
+ public boolean containsKey(DimensionManager key) {
|
||||
+ return get(key) != null;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public WorldServer put(DimensionManager key, WorldServer value) {
|
||||
+ while (worlds.size() <= key.getDimensionID()+1) {
|
||||
+ worlds.add(null);
|
||||
+ }
|
||||
+ WorldServer old = worlds.set(key.getDimensionID()+1, value);
|
||||
+ if (old != null) {
|
||||
+ worldsIterable.remove(old);
|
||||
+ }
|
||||
+ worldsIterable.add(value);
|
||||
+ return old;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void putAll(Map<? extends DimensionManager, ? extends WorldServer> m) {
|
||||
+ for (Entry<? extends DimensionManager, ? extends WorldServer> e : m.entrySet()) {
|
||||
+ put(e.getKey(), e.getValue());
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public WorldServer remove(Object key) {
|
||||
+ return key instanceof DimensionManager ? remove((DimensionManager) key) : null;
|
||||
+ }
|
||||
+
|
||||
+ public WorldServer remove(DimensionManager key) {
|
||||
+ WorldServer old;
|
||||
+ if (key.getDimensionID()+1 == worlds.size() - 1) {
|
||||
+ old = worlds.remove(key.getDimensionID()+1);
|
||||
+ } else {
|
||||
+ old = worlds.set(key.getDimensionID() + 1, null);
|
||||
+ }
|
||||
+ if (old != null) {
|
||||
+ worldsIterable.remove(old);
|
||||
+ }
|
||||
+ return old;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void clear() {
|
||||
+ throw new RuntimeException("What the hell are you doing?");
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean containsValue(Object value) {
|
||||
+ return value instanceof WorldServer && get(((WorldServer) value).dimension) != null;
|
||||
+ }
|
||||
+
|
||||
+ @Nonnull
|
||||
+ @Override
|
||||
+ public Set<DimensionManager> keySet() {
|
||||
+ return new AbstractSet<DimensionManager>() {
|
||||
+ @Override
|
||||
+ public Iterator<DimensionManager> iterator() {
|
||||
+ Iterator<WorldServer> iterator = worldsIterable.iterator();
|
||||
+ return new Iterator<DimensionManager>() {
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean hasNext() {
|
||||
+ return iterator.hasNext();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public DimensionManager next() {
|
||||
+ return iterator.next().dimension;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void remove() {
|
||||
+ iterator.remove();
|
||||
+ }
|
||||
+ };
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int size() {
|
||||
+ return worlds.size();
|
||||
+ }
|
||||
+ };
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Collection<WorldServer> values() {
|
||||
+ return worldsIterable;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Set<Entry<DimensionManager, WorldServer>> entrySet() {
|
||||
+ return new AbstractSet<Entry<DimensionManager, WorldServer>>() {
|
||||
+ @Override
|
||||
+ public Iterator<Entry<DimensionManager, WorldServer>> iterator() {
|
||||
+ Iterator<WorldServer> iterator = worldsIterable.iterator();
|
||||
+ return new Iterator<Entry<DimensionManager, WorldServer>>() {
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean hasNext() {
|
||||
+ return iterator.hasNext();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Entry<DimensionManager, WorldServer> next() {
|
||||
+ WorldServer entry = iterator.next();
|
||||
+ return new SimpleEntry<>(entry.dimension, entry);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void remove() {
|
||||
+ iterator.remove();
|
||||
+ }
|
||||
+ };
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int size() {
|
||||
+ return worldsIterable.size();
|
||||
+ }
|
||||
+ };
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index 1f9e8a082..292547be3 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -87,7 +87,7 @@ public abstract class MinecraftServer implements IAsyncTaskHandler, IMojangStati
|
||||
public final DataFixer dataConverterManager;
|
||||
private String serverIp;
|
||||
private int q = -1;
|
||||
- public final Map<DimensionManager, WorldServer> worldServer = Maps.newIdentityHashMap();
|
||||
+ public final Map<DimensionManager, WorldServer> worldServer = new com.destroystokyo.paper.PaperWorldMap(); // Paper
|
||||
private PlayerList s;
|
||||
private boolean isRunning = true;
|
||||
private boolean isRestarting = false; // Paper - flag to signify we're attempting to restart
|
||||
@@ -550,7 +550,7 @@ public abstract class MinecraftServer implements IAsyncTaskHandler, IMojangStati
|
||||
}
|
||||
}
|
||||
|
||||
- for (WorldServer world : this.getWorlds()) {
|
||||
+ for (WorldServer world : com.google.common.collect.Lists.newArrayList(this.getWorlds())) { // Paper - avoid como if 1 world triggers another world
|
||||
this.server.getPluginManager().callEvent(new org.bukkit.event.world.WorldLoadEvent(world.getWorld()));
|
||||
}
|
||||
// CraftBukkit end
|
||||
--
|
||||
2.19.1
|
||||
|
||||
Reference in New Issue
Block a user