diff --git a/divinemc-server/minecraft-patches/features/0068-Optimize-collections.patch b/divinemc-server/minecraft-patches/features/0068-Optimize-collections.patch index 463a90a..ee67048 100644 --- a/divinemc-server/minecraft-patches/features/0068-Optimize-collections.patch +++ b/divinemc-server/minecraft-patches/features/0068-Optimize-collections.patch @@ -36,6 +36,23 @@ index 7e31c5c8659d24948fd45a2d6ee7bdeca6027d27..95221434fd8eef388f0308b72af3f934 } protected NonNullList(List list, @Nullable E defaultValue) { +diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java +index a6bf257ca93e4b3819b65b4ef4ba71d9e2b40933..038d75aa39a158b65887c81f2687cb3c8140a6e2 100644 +--- a/net/minecraft/server/level/ChunkMap.java ++++ b/net/minecraft/server/level/ChunkMap.java +@@ -132,8 +132,10 @@ 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(); ++ // DivineMC start - Optimize collections ++ public final Int2ObjectMap entityMap = new org.bxteam.divinemc.util.map.Int2ObjectConcurrentHashMap<>(); ++ private final Long2ByteMap chunkTypeCache = it.unimi.dsi.fastutil.longs.Long2ByteMaps.synchronize(new Long2ByteOpenHashMap()); ++ // DivineMC end - Optimize collections + // Paper - rewrite chunk system + public int serverViewDistance; + public final WorldGenContext worldGenContext; // Paper - public diff --git a/net/minecraft/world/entity/ai/sensing/NearestLivingEntitySensor.java b/net/minecraft/world/entity/ai/sensing/NearestLivingEntitySensor.java index b0c5e41fefc7c9adf1a61bd5b52861736657d37e..dfc62772d5617f0dce72b45a1bebf1b2f051efd5 100644 --- a/net/minecraft/world/entity/ai/sensing/NearestLivingEntitySensor.java diff --git a/divinemc-server/minecraft-patches/features/0069-Configurable-player-spawn-tracking-range.patch b/divinemc-server/minecraft-patches/features/0069-Configurable-player-spawn-tracking-range.patch new file mode 100644 index 0000000..078d21b --- /dev/null +++ b/divinemc-server/minecraft-patches/features/0069-Configurable-player-spawn-tracking-range.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> +Date: Mon, 4 Aug 2025 02:38:45 +0300 +Subject: [PATCH] Configurable player spawn tracking range + + +diff --git a/ca/spottedleaf/moonrise/patches/chunk_tick_iteration/ChunkTickConstants.java b/ca/spottedleaf/moonrise/patches/chunk_tick_iteration/ChunkTickConstants.java +index 6d1fe8028739145b11fce98ad62b2f8044299548..9f086ded18d1fc8850877c6be113d88074427526 100644 +--- a/ca/spottedleaf/moonrise/patches/chunk_tick_iteration/ChunkTickConstants.java ++++ b/ca/spottedleaf/moonrise/patches/chunk_tick_iteration/ChunkTickConstants.java +@@ -2,7 +2,7 @@ package ca.spottedleaf.moonrise.patches.chunk_tick_iteration; + + public final class ChunkTickConstants { + +- public static final int PLAYER_SPAWN_TRACK_RANGE = 8; ++ public static final int PLAYER_SPAWN_TRACK_RANGE = (int) Math.round(org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.playerNearChunkDetectionRange / 16.0); // DivineMC - Configurable player spawn tracking range + // the smallest distance on x/z is at 45 degrees, we need to subtract 0.5 since this is calculated from chunk center and not chunk perimeter + // note: vanilla does not subtract 0.5 but the result is (luckily!) the same + public static final int NARROW_SPAWN_TRACK_RANGE = (int)Math.floor(((double)PLAYER_SPAWN_TRACK_RANGE / Math.sqrt(2.0)) - 0.5); +diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java +index 038d75aa39a158b65887c81f2687cb3c8140a6e2..3ca2f56cb31d41e88eb2a3e59c3749fbdef7c85e 100644 +--- a/net/minecraft/server/level/ChunkMap.java ++++ b/net/minecraft/server/level/ChunkMap.java +@@ -824,10 +824,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 - Configurable player spawn tracking range + final ServerPlayer player = raw[i]; +- if (this.playerIsCloseEnoughForSpawning(player, chunkPos, 16384.0D)) { // Spigot ++ if (player == null) continue; // DivineMC - Configurable player spawn tracking range ++ if (this.playerIsCloseEnoughForSpawning(player, chunkPos, (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.playerNearChunkDetectionRange^2))) { // Spigot // DivineMC - Configurable player spawn tracking range + if (ret == null) { + ret = new ArrayList<>(len - i); + ret.add(player); +@@ -1222,6 +1222,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + + for (int i = 0; i < playersLength; ++i) { // DivineMC - Multithreaded tracker + final ServerPlayer player = playersRaw[i]; ++ if (player == null) continue; // DivineMC - Configurable player spawn tracking range + this.updatePlayer(player); + } + diff --git a/divinemc-server/minecraft-patches/sources/ca/spottedleaf/moonrise/patches/chunk_tick_iteration/ChunkTickConstants.java.patch b/divinemc-server/minecraft-patches/sources/ca/spottedleaf/moonrise/patches/chunk_tick_iteration/ChunkTickConstants.java.patch deleted file mode 100644 index 71edb35..0000000 --- a/divinemc-server/minecraft-patches/sources/ca/spottedleaf/moonrise/patches/chunk_tick_iteration/ChunkTickConstants.java.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/ca/spottedleaf/moonrise/patches/chunk_tick_iteration/ChunkTickConstants.java -+++ b/ca/spottedleaf/moonrise/patches/chunk_tick_iteration/ChunkTickConstants.java -@@ -2,7 +_,7 @@ - - public final class ChunkTickConstants { - -- public static final int PLAYER_SPAWN_TRACK_RANGE = 8; -+ public static final int PLAYER_SPAWN_TRACK_RANGE = (int) Math.round(org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.playerNearChunkDetectionRange / 16.0); // DivineMC - Configurable player spawn tracking range - // the smallest distance on x/z is at 45 degrees, we need to subtract 0.5 since this is calculated from chunk center and not chunk perimeter - // note: vanilla does not subtract 0.5 but the result is (luckily!) the same - public static final int NARROW_SPAWN_TRACK_RANGE = (int)Math.floor(((double)PLAYER_SPAWN_TRACK_RANGE / Math.sqrt(2.0)) - 0.5); 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); + } +} diff --git a/gradle.properties b/gradle.properties index 5dcab65..f287e21 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ group = org.bxteam.divinemc version=1.21.8-R0.1-SNAPSHOT mcVersion=1.21.8 -purpurRef=c29e75fe5eca43efd7f348b01b34798995e2c2e1 +purpurRef=254407dad394e331c77590e86f2c055c441bf48f experimental=false #org.gradle.configuration-cache=true