diff --git a/divinemc-server/minecraft-patches/features/0006-Multithreaded-Tracker.patch b/divinemc-server/minecraft-patches/features/0006-Multithreaded-Tracker.patch index 2711b65..77fdb97 100644 --- a/divinemc-server/minecraft-patches/features/0006-Multithreaded-Tracker.patch +++ b/divinemc-server/minecraft-patches/features/0006-Multithreaded-Tracker.patch @@ -22,32 +22,10 @@ index dd2509996bfd08e8c3f9f2be042229eac6d7692d..8ef5a1aaac9c27873ce746eb281f77bb private static final byte CHUNK_TICKET_STAGE_NONE = 0; private static final byte CHUNK_TICKET_STAGE_LOADING = 1; diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java -index d3d9926d504fa6b3384be5ae06b2843ebb7f807c..1d73154786e2ad4c1e9b307dfba43dd6ae008e2a 100644 +index d3d9926d504fa6b3384be5ae06b2843ebb7f807c..965899a98223b15bd770378c202873cbf15b714d 100644 --- a/net/minecraft/server/level/ChunkMap.java +++ b/net/minecraft/server/level/ChunkMap.java -@@ -248,9 +248,19 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - } - - final ServerPlayer[] backingSet = inRange.getRawDataUnchecked(); -- for (int i = 0, len = inRange.size(); i < len; i++) { -- ++(backingSet[i].mobCounts[index]); -+ // DivineMC start - Multithreaded tracker -+ if (org.bxteam.divinemc.DivineConfig.multithreadedEnabled) { -+ for (int i = 0, len = inRange.size(); i < len; i++) { -+ final ServerPlayer player = backingSet[i]; -+ if (player == null) continue; -+ ++(player.mobCounts[index]); -+ } -+ } else { -+ for (int i = 0, len = inRange.size(); i < len; i++) { -+ ++(backingSet[i].mobCounts[index]); -+ } - } -+ // DivineMC end - Multithreaded tracker - } - - // Paper start - per player mob count backoff -@@ -951,6 +961,13 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -951,6 +951,13 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider // Paper end - optimise entity tracker protected void tick() { @@ -61,7 +39,7 @@ index d3d9926d504fa6b3384be5ae06b2843ebb7f807c..1d73154786e2ad4c1e9b307dfba43dd6 // Paper start - optimise entity tracker if (true) { this.newTrackerTick(); -@@ -1073,7 +1090,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1073,7 +1080,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider final Entity entity; private final int range; SectionPos lastSectionPos; @@ -74,7 +52,7 @@ index d3d9926d504fa6b3384be5ae06b2843ebb7f807c..1d73154786e2ad4c1e9b307dfba43dd6 // Paper start - optimise entity tracker private long lastChunkUpdate = -1L; -@@ -1100,21 +1121,55 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1100,21 +1111,55 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider this.lastTrackedChunk = chunk; final ServerPlayer[] playersRaw = players.getRawDataUnchecked(); @@ -140,7 +118,7 @@ index d3d9926d504fa6b3384be5ae06b2843ebb7f807c..1d73154786e2ad4c1e9b307dfba43dd6 } @Override -@@ -1176,7 +1231,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1176,7 +1221,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } public void broadcast(Packet packet) { @@ -149,7 +127,7 @@ index d3d9926d504fa6b3384be5ae06b2843ebb7f807c..1d73154786e2ad4c1e9b307dfba43dd6 serverPlayerConnection.send(packet); } } -@@ -1189,21 +1244,20 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1189,21 +1234,20 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } public void broadcastRemoved() { diff --git a/divinemc-server/minecraft-patches/features/0010-Chunk-System-Optimizations.patch b/divinemc-server/minecraft-patches/features/0010-Chunk-System-Optimizations.patch index ed4674d..8d9ffb9 100644 --- a/divinemc-server/minecraft-patches/features/0010-Chunk-System-Optimizations.patch +++ b/divinemc-server/minecraft-patches/features/0010-Chunk-System-Optimizations.patch @@ -964,10 +964,47 @@ index 460bb584db04b582f3297ae419183f430aff1ec0..72c4e1876115745fbeec12fe8a1ad6f4 commands.put(Set.of("fixlight"), new FixLightCommand()); // Paper - rewrite chunk system commands.put(Set.of("debug", "chunkinfo", "holderinfo"), new ChunkDebugCommand()); // Paper - rewrite chunk system diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java -index 1d73154786e2ad4c1e9b307dfba43dd6ae008e2a..683a0296fd8b22a9a4a0268075df4f90759e5e8c 100644 +index 965899a98223b15bd770378c202873cbf15b714d..dccf4d4b1067e1b09e38cabeae82185929494b62 100644 --- a/net/minecraft/server/level/ChunkMap.java +++ b/net/minecraft/server/level/ChunkMap.java -@@ -730,27 +730,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -127,8 +127,8 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + public final AtomicInteger tickingGenerated = new AtomicInteger(); // Paper - public + private final String storageName; + private final PlayerMap playerMap = new PlayerMap(); +- public final Int2ObjectMap entityMap = new Int2ObjectOpenHashMap<>(); +- private final Long2ByteMap chunkTypeCache = new Long2ByteOpenHashMap(); ++ public final Int2ObjectMap entityMap = new org.bxteam.divinemc.util.map.Int2ObjectConcurrentHashMap<>(); // DivineMC - Chunk System Optimizations ++ private final Long2ByteMap chunkTypeCache = it.unimi.dsi.fastutil.longs.Long2ByteMaps.synchronize(new Long2ByteOpenHashMap()); // DivineMC - Chunk System Optimizations + // Paper - rewrite chunk system + public int serverViewDistance; + public final WorldGenContext worldGenContext; // Paper - public +@@ -249,7 +249,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + + final ServerPlayer[] backingSet = inRange.getRawDataUnchecked(); + for (int i = 0, len = inRange.size(); i < len; i++) { +- ++(backingSet[i].mobCounts[index]); ++ // DivineMC start - Chunk System Optimizations ++ ServerPlayer player = backingSet[i]; ++ if (player == null) continue; ++ ++(player.mobCounts[index]); ++ // DivineMC end - Chunk System Optimizations + } + } + +@@ -266,7 +270,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + } + final ServerPlayer[] backingSet = inRange.getRawDataUnchecked(); + for (int i = 0, len = inRange.size(); i < len; i++) { +- ++(backingSet[i].mobBackoffCounts[idx]); ++ // DivineMC start - Chunk System Optimizations ++ ServerPlayer player = backingSet[i]; ++ if (player == null) continue; ++ ++(player.mobBackoffCounts[idx]); ++ // DivineMC end - Chunk System Optimizations + } + } + // Paper end - per player mob count backoff +@@ -720,27 +728,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider return false; } @@ -996,6 +1033,28 @@ index 1d73154786e2ad4c1e9b307dfba43dd6ae008e2a..683a0296fd8b22a9a4a0268075df4f90 // Paper end - chunk tick iteration optimisation } +@@ -758,10 +746,10 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + final ServerPlayer[] raw = players.getRawDataUnchecked(); + final int len = players.size(); + +- Objects.checkFromIndexSize(0, len, raw.length); +- for (int i = 0; i < len; ++i) { ++ for (int i = 0; i < raw.length; ++i) { // DivineMC - Chunk System Optimizations + final ServerPlayer player = raw[i]; +- if (this.playerIsCloseEnoughForSpawning(player, chunkPos, 16384.0D)) { // Spigot ++ if (player == null) continue; // DivineMC - Chunk System Optimizations ++ if (this.playerIsCloseEnoughForSpawning(player, chunkPos, (org.bxteam.divinemc.DivineConfig.playerNearChunkDetectionRange^2))) { // Spigot // DivineMC - Chunk System Optimizations + if (ret == null) { + ret = new ArrayList<>(len - i); + ret.add(player); +@@ -1146,6 +1134,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + } else { + for (int i = 0, len = players.size(); i < len; ++i) { + final ServerPlayer player = playersRaw[i]; ++ if (player == null) continue; // DivineMC - Chunk System Optimizations + this.updatePlayer(player); + } + diff --git a/net/minecraft/server/level/DistanceManager.java b/net/minecraft/server/level/DistanceManager.java index 5eab6179ce3913cb4e4d424f910ba423faf21c85..4b1efd53e423bdfe90d5efd472823869fc87e73b 100644 --- a/net/minecraft/server/level/DistanceManager.java diff --git a/divinemc-server/minecraft-patches/features/0025-Optimize-canSee-checks.patch b/divinemc-server/minecraft-patches/features/0025-Optimize-canSee-checks.patch index b806627..395c9e8 100644 --- a/divinemc-server/minecraft-patches/features/0025-Optimize-canSee-checks.patch +++ b/divinemc-server/minecraft-patches/features/0025-Optimize-canSee-checks.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Optimize canSee checks diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java -index 683a0296fd8b22a9a4a0268075df4f90759e5e8c..65f67bac8ebe2bacd48384675805abb7edd57c6c 100644 +index dccf4d4b1067e1b09e38cabeae82185929494b62..55da7420dc3dfff468529a0f101f864dbefe3c7c 100644 --- a/net/minecraft/server/level/ChunkMap.java +++ b/net/minecraft/server/level/ChunkMap.java -@@ -1259,7 +1259,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1258,7 +1258,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider flag = flag && this.entity.broadcastToPlayer(player) && ChunkMap.this.isChunkTracked(player, this.entity.chunkPosition().x, this.entity.chunkPosition().z); // Paper end - Configurable entity tracking range by Y // CraftBukkit start - respect vanish API diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/util/CollectionWrapperUtil.java b/divinemc-server/src/main/java/org/bxteam/divinemc/util/CollectionWrapperUtil.java new file mode 100644 index 0000000..1edb1f2 --- /dev/null +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/util/CollectionWrapperUtil.java @@ -0,0 +1,744 @@ +package org.bxteam.divinemc.util; + +import it.unimi.dsi.fastutil.bytes.ByteIterator; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.IntCollection; +import it.unimi.dsi.fastutil.ints.IntIterator; +import it.unimi.dsi.fastutil.ints.IntSet; +import it.unimi.dsi.fastutil.longs.LongIterator; +import it.unimi.dsi.fastutil.longs.LongListIterator; +import it.unimi.dsi.fastutil.objects.ObjectCollection; +import it.unimi.dsi.fastutil.objects.ObjectIterator; +import it.unimi.dsi.fastutil.objects.ObjectSet; +import it.unimi.dsi.fastutil.objects.ReferenceSet; +import it.unimi.dsi.fastutil.shorts.ShortIterator; +import org.apache.commons.lang3.ArrayUtils; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; +import java.util.Iterator; +import java.util.ListIterator; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +public final class CollectionWrapperUtil { + private CollectionWrapperUtil() { + throw new IllegalStateException("This class cannot be instantiated"); + } + + private static Int2ObjectMap.@NotNull Entry intEntryForwards(Map.Entry entry) { + return new Int2ObjectMap.Entry<>() { + @Override + public T getValue() { + return entry.getValue(); + } + + @Override + public T setValue(T value) { + return entry.setValue(value); + } + + @Override + public int getIntKey() { + return entry.getKey(); + } + + @Override + public boolean equals(Object obj) { + if (obj == entry) { + return true; + } + return super.equals(obj); + } + + @Override + public int hashCode() { + return entry.hashCode(); + } + }; + } + + private static Map.Entry intEntryBackwards(Int2ObjectMap.Entry entry) { + return entry; + } + + public static ObjectSet> entrySetIntWrap(Map map) { + return new ConvertingObjectSet<>( + map.entrySet(), + CollectionWrapperUtil::intEntryForwards, + CollectionWrapperUtil::intEntryBackwards + ); + } + + public static IntSet wrapIntSet(Set intset) { + return new WrappingIntSet(intset); + } + + public static ByteIterator itrByteWrap(Iterator backing) { + return new WrappingByteIterator(backing); + } + + public static ByteIterator itrByteWrap(Iterable backing) { + return itrByteWrap(backing.iterator()); + } + + public static IntIterator itrIntWrap(Iterator backing) { + return new WrappingIntIterator(backing); + } + + public static IntIterator itrIntWrap(Iterable backing) { + return itrIntWrap(backing.iterator()); + } + + public static LongIterator itrLongWrap(Iterator backing) { + return new WrappingLongIterator(backing); + } + + public static LongIterator itrLongWrap(Iterable backing) { + return itrLongWrap(backing.iterator()); + } + + public static ShortIterator itrShortWrap(Iterator backing) { + return new WrappingShortIterator(backing); + } + + public static ShortIterator itrShortWrap(Iterable backing) { + return itrShortWrap(backing.iterator()); + } + + public static LongListIterator wrap(ListIterator c) { + return new WrappingLongListIterator(c); + } + + public static LongListIterator wrap(Iterator c) { + return new SlimWrappingLongListIterator(c); + } + + public static ObjectCollection wrap(Collection c) { + return new WrappingObjectCollection<>(c); + } + + public static ReferenceSet wrap(Set s) { + return new WrappingRefSet<>(s); + } + + public static ObjectIterator itrWrap(Iterable in) { + return new WrapperObjectIterator<>(in.iterator()); + } + + public static class ConvertingObjectSet implements ObjectSet { + private final Set backing; + private final Function forward; + private final Function back; + + public ConvertingObjectSet(Set backing, Function forward, Function back) { + this.backing = Objects.requireNonNull(backing, "Backing set cannot be null"); + this.forward = Objects.requireNonNull(forward, "Forward function cannot be null"); + this.back = Objects.requireNonNull(back, "Backward function cannot be null"); + } + + @Override + public int size() { + return backing.size(); + } + + @Override + public boolean isEmpty() { + return backing.isEmpty(); + } + + @SuppressWarnings("unchecked") + @Override + public boolean contains(Object o) { + try { + return backing.contains(back.apply((T) o)); + } catch (ClassCastException cce) { + return false; + } + } + + @Override + public Object[] toArray() { + return backing.stream().map(forward).toArray(); + } + + @Override + public R[] toArray(R[] a) { + return backing.stream().map(forward).collect(Collectors.toSet()).toArray(a); + } + + @Override + public boolean add(T e) { + return backing.add(back.apply(e)); + } + + @SuppressWarnings("unchecked") + @Override + public boolean remove(Object o) { + try { + return backing.remove(back.apply((T) o)); + } catch (ClassCastException cce) { + return false; + } + } + + @SuppressWarnings("unchecked") + @Override + public boolean containsAll(Collection c) { + try { + return backing.containsAll(c.stream() + .map(i -> back.apply((T) i)) + .collect(Collectors.toSet())); + } catch (ClassCastException cce) { + return false; + } + } + + @Override + public boolean addAll(Collection c) { + return backing.addAll(c.stream().map(back).collect(Collectors.toSet())); + } + + @SuppressWarnings("unchecked") + @Override + public boolean removeAll(Collection c) { + try { + return backing.removeAll(c.stream() + .map(i -> back.apply((T) i)) + .collect(Collectors.toSet())); + } catch (ClassCastException cce) { + return false; + } + } + + @SuppressWarnings("unchecked") + @Override + public boolean retainAll(Collection c) { + try { + return backing.retainAll(c.stream() + .map(i -> back.apply((T) i)) + .collect(Collectors.toSet())); + } catch (ClassCastException cce) { + return false; + } + } + + @Override + public void clear() { + backing.clear(); + } + + @Override + public ObjectIterator iterator() { + return new ObjectIterator<>() { + private final Iterator backg = backing.iterator(); + + @Override + public boolean hasNext() { + return backg.hasNext(); + } + + @Override + public T next() { + return forward.apply(backg.next()); + } + + @Override + public void remove() { + backg.remove(); + } + }; + } + } + + static class WrappingIntIterator implements IntIterator { + private final Iterator backing; + + WrappingIntIterator(Iterator backing) { + this.backing = Objects.requireNonNull(backing); + } + + @Override + public boolean hasNext() { + return backing.hasNext(); + } + + @Override + public int nextInt() { + return backing.next(); + } + + @Override + public Integer next() { + return backing.next(); + } + + @Override + public void remove() { + backing.remove(); + } + } + + static class WrappingLongIterator implements LongIterator { + private final Iterator backing; + + WrappingLongIterator(Iterator backing) { + this.backing = Objects.requireNonNull(backing); + } + + @Override + public boolean hasNext() { + return backing.hasNext(); + } + + @Override + public long nextLong() { + return backing.next(); + } + + @Override + public Long next() { + return backing.next(); + } + + @Override + public void remove() { + backing.remove(); + } + } + + static class WrappingShortIterator implements ShortIterator { + private final Iterator backing; + + WrappingShortIterator(Iterator backing) { + this.backing = Objects.requireNonNull(backing); + } + + @Override + public boolean hasNext() { + return backing.hasNext(); + } + + @Override + public short nextShort() { + return backing.next(); + } + + @Override + public Short next() { + return backing.next(); + } + + @Override + public void remove() { + backing.remove(); + } + } + + static class WrappingByteIterator implements ByteIterator { + private final Iterator backing; + + WrappingByteIterator(Iterator backing) { + this.backing = Objects.requireNonNull(backing); + } + + @Override + public boolean hasNext() { + return backing.hasNext(); + } + + @Override + public byte nextByte() { + return next(); + } + + @Override + public Byte next() { + return backing.next(); + } + + @Override + public void remove() { + backing.remove(); + } + } + + public static class WrappingIntSet implements IntSet { + private final Set backing; + + public WrappingIntSet(Set backing) { + this.backing = Objects.requireNonNull(backing); + } + + @Override + public boolean add(int key) { + return backing.add(key); + } + + @Override + public boolean contains(int key) { + return backing.contains(key); + } + + @Override + public int[] toIntArray() { + return backing.stream().mapToInt(Integer::intValue).toArray(); + } + + @Override + public int[] toArray(int[] a) { + return ArrayUtils.toPrimitive(backing.toArray(new Integer[0])); + } + + @Override + public boolean addAll(IntCollection c) { + return backing.addAll(c); + } + + @Override + public boolean containsAll(IntCollection c) { + return backing.containsAll(c); + } + + @Override + public boolean removeAll(IntCollection c) { + return backing.removeAll(c); + } + + @Override + public boolean retainAll(IntCollection c) { + return backing.retainAll(c); + } + + @Override + public int size() { + return backing.size(); + } + + @Override + public boolean isEmpty() { + return backing.isEmpty(); + } + + @Override + public Object[] toArray() { + return backing.toArray(); + } + + @Override + public T[] toArray(T[] a) { + return backing.toArray(a); + } + + @Override + public boolean containsAll(Collection c) { + return backing.containsAll(c); + } + + @Override + public boolean addAll(Collection c) { + return backing.addAll(c); + } + + @Override + public boolean removeAll(Collection c) { + return backing.removeAll(c); + } + + @Override + public boolean retainAll(Collection c) { + return backing.retainAll(c); + } + + @Override + public void clear() { + backing.clear(); + } + + @Override + public IntIterator iterator() { + return new WrappingIntIterator(backing.iterator()); + } + + @Override + public boolean remove(int k) { + return backing.remove(k); + } + } + + public static class WrappingRefSet implements ReferenceSet { + private final Set backing; + + public WrappingRefSet(Set backing) { + this.backing = Objects.requireNonNull(backing); + } + + @Override + public boolean add(V key) { + return backing.add(key); + } + + @Override + public boolean remove(final Object o) { + return backing.remove(o); + } + + @Override + public boolean containsAll(@NotNull final Collection c) { + return backing.containsAll(c); + } + + @Override + public boolean addAll(@NotNull final Collection c) { + return backing.addAll(c); + } + + @Override + public boolean removeAll(@NotNull final Collection c) { + return backing.removeAll(c); + } + + @Override + public boolean retainAll(@NotNull final Collection c) { + return backing.retainAll(c); + } + + @Override + public void clear() { + this.backing.clear(); + } + + @Override + public int size() { + return backing.size(); + } + + @Override + public boolean isEmpty() { + return backing.isEmpty(); + } + + @Override + public boolean contains(final Object o) { + return backing.contains(o); + } + + @Override + public ObjectIterator iterator() { + return null; + } + + @Override + public @NotNull Object[] toArray() { + return this.backing.toArray(); + } + + @Override + public @NotNull T[] toArray(@NotNull final T[] a) { + return this.backing.toArray(a); + } + } + + public static class WrappingLongListIterator implements LongListIterator { + private final ListIterator backing; + + WrappingLongListIterator(ListIterator backing) { + this.backing = Objects.requireNonNull(backing); + } + + @Override + public long previousLong() { + return backing.previous(); + } + + @Override + public long nextLong() { + return backing.next(); + } + + @Override + public boolean hasNext() { + return backing.hasNext(); + } + + @Override + public boolean hasPrevious() { + return backing.hasPrevious(); + } + + @Override + public int nextIndex() { + return backing.nextIndex(); + } + + @Override + public int previousIndex() { + return backing.previousIndex(); + } + + @Override + public void add(long k) { + backing.add(k); + } + + @Override + public void remove() { + backing.remove(); + } + + @Override + public void set(long k) { + backing.set(k); + } + } + + public static class SlimWrappingLongListIterator implements LongListIterator { + private final Iterator backing; + + SlimWrappingLongListIterator(Iterator backing) { + this.backing = Objects.requireNonNull(backing); + } + + @Override + public long previousLong() { + throw new UnsupportedOperationException(); + } + + @Override + public long nextLong() { + return backing.next(); + } + + @Override + public boolean hasNext() { + return backing.hasNext(); + } + + @Override + public boolean hasPrevious() { + throw new UnsupportedOperationException(); + } + + @Override + public int nextIndex() { + throw new UnsupportedOperationException(); + } + + @Override + public int previousIndex() { + throw new UnsupportedOperationException(); + } + + @Override + public void add(long k) { + throw new UnsupportedOperationException(); + } + + @Override + public void remove() { + backing.remove(); + } + + @Override + public void set(long k) { + throw new UnsupportedOperationException(); + } + } + + public static class WrappingObjectCollection implements ObjectCollection { + private final Collection backing; + + public WrappingObjectCollection(Collection backing) { + this.backing = Objects.requireNonNull(backing); + } + + @Override + public int size() { + return backing.size(); + } + + @Override + public boolean isEmpty() { + return backing.isEmpty(); + } + + @Override + public boolean contains(Object o) { + return backing.contains(o); + } + + @Override + public Object[] toArray() { + return backing.toArray(); + } + + @Override + public T[] toArray(T[] a) { + return backing.toArray(a); + } + + @Override + public boolean add(V e) { + return backing.add(e); + } + + @Override + public boolean remove(Object o) { + return backing.remove(o); + } + + @Override + public boolean containsAll(Collection c) { + return backing.containsAll(c); + } + + @Override + public boolean addAll(Collection c) { + return backing.addAll(c); + } + + @Override + public boolean removeAll(Collection c) { + return backing.removeAll(c); + } + + @Override + public boolean retainAll(Collection c) { + return backing.retainAll(c); + } + + @Override + public void clear() { + backing.clear(); + } + + @Override + public ObjectIterator iterator() { + return itrWrap(backing); + } + } + + private record WrapperObjectIterator(Iterator parent) implements ObjectIterator { + private WrapperObjectIterator(Iterator parent) { + this.parent = Objects.requireNonNull(parent); + } + + @Override + public boolean hasNext() { + return parent.hasNext(); + } + + @Override + public T next() { + return parent.next(); + } + + @Override + public void remove() { + parent.remove(); + } + } +} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/util/map/Int2ObjectConcurrentHashMap.java b/divinemc-server/src/main/java/org/bxteam/divinemc/util/map/Int2ObjectConcurrentHashMap.java new file mode 100644 index 0000000..cac8e64 --- /dev/null +++ b/divinemc-server/src/main/java/org/bxteam/divinemc/util/map/Int2ObjectConcurrentHashMap.java @@ -0,0 +1,160 @@ +package org.bxteam.divinemc.util.map; + +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.IntSet; +import it.unimi.dsi.fastutil.objects.ObjectCollection; +import it.unimi.dsi.fastutil.objects.ObjectSet; +import org.bxteam.divinemc.util.CollectionWrapperUtil; + +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; + +public final class Int2ObjectConcurrentHashMap implements Int2ObjectMap { + private final ConcurrentHashMap backing; + private V defaultReturnValue; + + public Int2ObjectConcurrentHashMap() { + this(16); + } + + public Int2ObjectConcurrentHashMap(int initialCapacity) { + if (initialCapacity < 0) { + throw new IllegalArgumentException("Initial capacity cannot be negative: " + initialCapacity); + } + + this.backing = new ConcurrentHashMap<>(initialCapacity); + } + + public Int2ObjectConcurrentHashMap(Map map) { + this(Math.max(16, map.size())); + putAll(Objects.requireNonNull(map, "Source map cannot be null")); + } + + @Override + public V get(int key) { + V value = backing.get(key); + return value != null ? value : defaultReturnValue; + } + + @Override + public V get(Object key) { + V value = backing.get(key); + return value != null ? value : defaultReturnValue; + } + + @Override + public boolean isEmpty() { + return backing.isEmpty(); + } + + @Override + public boolean containsValue(Object value) { + return backing.containsValue(value); + } + + @Override + public void putAll(Map m) { + Objects.requireNonNull(m, "Source map cannot be null"); + backing.putAll(m); + } + + @Override + public int size() { + return backing.size(); + } + + @Override + public void defaultReturnValue(V rv) { + this.defaultReturnValue = rv; + } + + @Override + public V defaultReturnValue() { + return defaultReturnValue; + } + + @Override + public ObjectSet> int2ObjectEntrySet() { + return CollectionWrapperUtil.entrySetIntWrap(backing); + } + + @Override + public IntSet keySet() { + return CollectionWrapperUtil.wrapIntSet(backing.keySet()); + } + + @Override + public ObjectCollection values() { + return CollectionWrapperUtil.wrap(backing.values()); + } + + @Override + public boolean containsKey(int key) { + return backing.containsKey(key); + } + + @Override + public V put(int key, V value) { + return backing.put(key, value); + } + + @Override + public V remove(int key) { + return backing.remove(key); + } + + @Override + public void clear() { + backing.clear(); + } + + public V compute(int key, java.util.function.BiFunction remappingFunction) { + Objects.requireNonNull(remappingFunction); + return backing.compute(key, remappingFunction); + } + + public ConcurrentHashMap concurrentView() { + return backing; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Int2ObjectMap that)) return false; + + if (size() != that.size()) return false; + return int2ObjectEntrySet().containsAll(that.int2ObjectEntrySet()); + } + + @Override + public int hashCode() { + return backing.hashCode(); + } + + @Override + public String toString() { + return backing.toString(); + } + + public V getOrDefault(int key, V defaultValue) { + V value = get(key); + return value != null ? value : defaultValue; + } + + public V putIfAbsent(int key, V value) { + return backing.putIfAbsent(key, value); + } + + public boolean remove(int key, Object value) { + return backing.remove(key, value); + } + + public boolean replace(int key, V oldValue, V newValue) { + return backing.replace(key, oldValue, newValue); + } + + public V replace(int key, V value) { + return backing.replace(key, value); + } +}