Compare commits
No commits in common. "77443ee801c104a7fc7dada97685fe5f055bf85e" and "8fbf7d4c2c7894ca51c9d0349d8530b59c82f367" have entirely different histories.
77443ee801
...
8fbf7d4c2c
@ -31,7 +31,7 @@ import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot
|
|||||||
import java.util.Collections.emptyIterator
|
import java.util.Collections.emptyIterator
|
||||||
import java.util.stream.Stream
|
import java.util.stream.Stream
|
||||||
|
|
||||||
internal val isCosmeticArmorLoaded by lazy {
|
val isCosmeticArmorLoaded by lazy {
|
||||||
ModList.get().isLoaded("cosmeticarmorreworked")
|
ModList.get().isLoaded("cosmeticarmorreworked")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ import java.util.Collections.emptyIterator
|
|||||||
import java.util.stream.Stream
|
import java.util.stream.Stream
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
internal val isCuriosLoaded by lazy {
|
val isCuriosLoaded by lazy {
|
||||||
ModList.get().isLoaded(CuriosApi.MODID)
|
ModList.get().isLoaded(CuriosApi.MODID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot
|
|||||||
import ru.dbotthepony.mc.otm.menu.makeSlots
|
import ru.dbotthepony.mc.otm.menu.makeSlots
|
||||||
import ru.dbotthepony.mc.otm.registry.MDeferredRegister
|
import ru.dbotthepony.mc.otm.registry.MDeferredRegister
|
||||||
|
|
||||||
internal val isIronChestLoaded by lazy {
|
val isIronChestLoaded by lazy {
|
||||||
ModList.get().isLoaded(IronChests.MODID)
|
ModList.get().isLoaded(IronChests.MODID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ import ru.dbotthepony.mc.otm.menu.makeSlots
|
|||||||
import ru.dbotthepony.mc.otm.registry.MDeferredRegister
|
import ru.dbotthepony.mc.otm.registry.MDeferredRegister
|
||||||
import kotlin.collections.toTypedArray
|
import kotlin.collections.toTypedArray
|
||||||
|
|
||||||
internal val isIronShulkersLoaded by lazy {
|
val isIronShulkersLoaded by lazy {
|
||||||
ModList.get().isLoaded(IronShulkerBoxes.MODID)
|
ModList.get().isLoaded(IronShulkerBoxes.MODID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ import net.minecraft.world.inventory.Slot
|
|||||||
import net.neoforged.fml.ModList
|
import net.neoforged.fml.ModList
|
||||||
import ru.dbotthepony.mc.otm.client.render.MGUIGraphics
|
import ru.dbotthepony.mc.otm.client.render.MGUIGraphics
|
||||||
|
|
||||||
internal val isItemBordersLoaded by lazy {
|
val isItemBordersLoaded by lazy {
|
||||||
ModList.get().isLoaded("itemborders")
|
ModList.get().isLoaded("itemborders")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,19 +1,8 @@
|
|||||||
package ru.dbotthepony.mc.otm.network.syncher
|
package ru.dbotthepony.mc.otm.network.syncher
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ReferenceLinkedOpenHashMap
|
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap
|
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ReferenceOpenHashMap
|
|
||||||
import it.unimi.dsi.fastutil.ints.IntArraySet
|
import it.unimi.dsi.fastutil.ints.IntArraySet
|
||||||
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.objects.ObjectIterator
|
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectSet
|
|
||||||
import it.unimi.dsi.fastutil.objects.Reference2ObjectLinkedOpenHashMap
|
|
||||||
import it.unimi.dsi.fastutil.objects.ReferenceCollection
|
|
||||||
import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet
|
import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet
|
||||||
import it.unimi.dsi.fastutil.objects.ReferenceSet
|
|
||||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||||
import ru.dbotthepony.kommons.util.KOptional
|
import ru.dbotthepony.kommons.util.KOptional
|
||||||
import ru.dbotthepony.mc.otm.util.IDAllocator
|
import ru.dbotthepony.mc.otm.util.IDAllocator
|
||||||
@ -50,7 +39,7 @@ class DynamicSynchableGroup<T : Any>(
|
|||||||
* first-time networking of [T] to remote
|
* first-time networking of [T] to remote
|
||||||
*/
|
*/
|
||||||
private val writer: T.(RegistryFriendlyByteBuf) -> Unit = {},
|
private val writer: T.(RegistryFriendlyByteBuf) -> Unit = {},
|
||||||
) : ISynchable, ReferenceSet<T> {
|
) : ISynchable, MutableSet<T> {
|
||||||
private inner class RemoteState(val listener: Runnable) : IRemoteState {
|
private inner class RemoteState(val listener: Runnable) : IRemoteState {
|
||||||
private inner class RemoteSlot(val slot: Slot<T>, fromConstructor: Boolean) : Runnable, Closeable {
|
private inner class RemoteSlot(val slot: Slot<T>, fromConstructor: Boolean) : Runnable, Closeable {
|
||||||
val remoteState = synchable(slot.value).createRemoteState(this)
|
val remoteState = synchable(slot.value).createRemoteState(this)
|
||||||
@ -199,12 +188,11 @@ class DynamicSynchableGroup<T : Any>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Slot<T : Any>(val value: T, val id: Int)
|
private data class Slot<T : Any>(val value: T, val id: Int)
|
||||||
|
|
||||||
private var defaultReturnValue: T? = null
|
|
||||||
private val remoteStates = ArrayList<RemoteState>()
|
private val remoteStates = ArrayList<RemoteState>()
|
||||||
private val value2slot = Reference2ObjectLinkedOpenHashMap<T, Slot<T>>()
|
private val value2slot = LinkedHashMap<T, Slot<T>>()
|
||||||
private val id2slot = Int2ReferenceLinkedOpenHashMap<Slot<T>>()
|
private val id2slot = Int2ObjectOpenHashMap<Slot<T>>()
|
||||||
private val idAllocator = IDAllocator()
|
private val idAllocator = IDAllocator()
|
||||||
|
|
||||||
override val hasRemotes: Boolean
|
override val hasRemotes: Boolean
|
||||||
@ -222,7 +210,7 @@ class DynamicSynchableGroup<T : Any>(
|
|||||||
REMOVE_ENTRY -> {
|
REMOVE_ENTRY -> {
|
||||||
val id = stream.readVarInt()
|
val id = stream.readVarInt()
|
||||||
val slot = checkNotNull(id2slot.remove(id)) { "No such slot with ID: $id" }
|
val slot = checkNotNull(id2slot.remove(id)) { "No such slot with ID: $id" }
|
||||||
check(value2slot.remove(slot.value) == slot)
|
check(value2slot.remove(slot.value) == value2slot)
|
||||||
remoteStates.forEach { it.remove(slot) }
|
remoteStates.forEach { it.remove(slot) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,7 +223,7 @@ class DynamicSynchableGroup<T : Any>(
|
|||||||
|
|
||||||
if (id2slot.containsKey(id)) {
|
if (id2slot.containsKey(id)) {
|
||||||
val slot = id2slot.remove(id)!!
|
val slot = id2slot.remove(id)!!
|
||||||
check(value2slot.remove(slot.value) == slot)
|
check(value2slot.remove(slot.value) == value2slot)
|
||||||
remoteStates.forEach { it.remove(slot) }
|
remoteStates.forEach { it.remove(slot) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,8 +298,8 @@ class DynamicSynchableGroup<T : Any>(
|
|||||||
return value2slot.isEmpty()
|
return value2slot.isEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun iterator(): ObjectIterator<T> {
|
override fun iterator(): MutableIterator<T> {
|
||||||
return object : ObjectIterator<T> {
|
return object : MutableIterator<T> {
|
||||||
private val parent = value2slot.values.iterator()
|
private val parent = value2slot.values.iterator()
|
||||||
private var last: KOptional<Slot<T>> = KOptional()
|
private var last: KOptional<Slot<T>> = KOptional()
|
||||||
|
|
||||||
@ -335,15 +323,11 @@ class DynamicSynchableGroup<T : Any>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun removeBySlot(slot: Slot<T>) {
|
override fun remove(element: T): Boolean {
|
||||||
value2slot.remove(slot.value)
|
val slot = value2slot.remove(element) ?: return false
|
||||||
id2slot.remove(slot.id)
|
checkNotNull(id2slot.remove(slot.id))
|
||||||
remoteStates.forEach { it.remove(slot) }
|
remoteStates.forEach { it.remove(slot) }
|
||||||
idAllocator.release(slot.id)
|
idAllocator.release(slot.id)
|
||||||
}
|
|
||||||
|
|
||||||
override fun remove(element: T): Boolean {
|
|
||||||
removeBySlot(value2slot.remove(element) ?: return false)
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -367,341 +351,6 @@ class DynamicSynchableGroup<T : Any>(
|
|||||||
return any
|
return any
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Representation of this synchable group as an [Int2ReferenceMap]. Changes made to [DynamicSynchableGroup] are reflected in this map
|
|
||||||
* and vice versa. Entries can be put at arbitrary keys, but negative keys should be avoided, since they are not efficiently
|
|
||||||
* networked, and hence will create a lot of network traffic if synchables with negative keys get frequently updated.
|
|
||||||
*/
|
|
||||||
val asMap: Int2ReferenceMap<T> by lazy {
|
|
||||||
object : Int2ReferenceMap<T> {
|
|
||||||
override fun isEmpty(): Boolean {
|
|
||||||
return this@DynamicSynchableGroup.isEmpty()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun remove(key: Int): T? {
|
|
||||||
val slot = id2slot.remove(key) ?: return null
|
|
||||||
removeBySlot(slot)
|
|
||||||
return slot.value
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getOrDefault(key: Int, defaultValue: T): T {
|
|
||||||
return super.getOrDefault(key, defaultValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
override val size: Int
|
|
||||||
get() = this@DynamicSynchableGroup.size
|
|
||||||
|
|
||||||
override fun put(key: Int, value: T): T? {
|
|
||||||
val slot = Slot(value, key)
|
|
||||||
val oldSlot = id2slot.put(key, slot)
|
|
||||||
|
|
||||||
if (oldSlot?.value === value)
|
|
||||||
return value
|
|
||||||
|
|
||||||
if (oldSlot != null) {
|
|
||||||
remoteStates.forEach { it.remove(oldSlot) }
|
|
||||||
value2slot.remove(oldSlot.value)
|
|
||||||
} else {
|
|
||||||
idAllocator.allocate(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
value2slot[value] = slot
|
|
||||||
remoteStates.forEach { it.add(slot) }
|
|
||||||
|
|
||||||
return oldSlot?.value
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun get(key: Int): T? {
|
|
||||||
return id2slot.get(key)?.value ?: defaultReturnValue
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun containsKey(key: Int): Boolean {
|
|
||||||
return id2slot.containsKey(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun defaultReturnValue(rv: T?) {
|
|
||||||
defaultReturnValue = rv
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun defaultReturnValue(): T? {
|
|
||||||
return defaultReturnValue
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun putAll(from: Map<out Int, T>) {
|
|
||||||
from.forEach { (k, v) ->
|
|
||||||
put(k, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun containsValue(value: T): Boolean {
|
|
||||||
return value2slot.containsKey(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val entrySet: ObjectSet<Int2ReferenceMap.Entry<T>> by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
|
||||||
object : ObjectSet<Int2ReferenceMap.Entry<T>> {
|
|
||||||
inner class Entry(private val ikey: Int) : Int2ReferenceMap.Entry<T> {
|
|
||||||
override val value: T
|
|
||||||
get() = id2slot[ikey]?.value ?: throw NoSuchElementException()
|
|
||||||
|
|
||||||
override fun setValue(newValue: T): T? {
|
|
||||||
return put(ikey, newValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getIntKey(): Int {
|
|
||||||
return ikey
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
|
||||||
return this === other || other is Int2ReferenceMap.Entry<*> && other.intKey == ikey && other.value === id2slot[ikey]?.value
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
|
||||||
return ikey * 31 + (id2slot[ikey] as Slot<T>?).hashCode()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun toString(): String {
|
|
||||||
return "Map.Entry[$ikey, ${id2slot[ikey]?.value}]"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override val size: Int
|
|
||||||
get() = id2slot.size
|
|
||||||
|
|
||||||
override fun add(element: Int2ReferenceMap.Entry<T>): Boolean {
|
|
||||||
return put(element.intKey, element.value) != null
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun addAll(elements: Collection<Int2ReferenceMap.Entry<T>>): Boolean {
|
|
||||||
var any = false
|
|
||||||
elements.forEach { any = add(it) || any }
|
|
||||||
return any
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun clear() {
|
|
||||||
this@DynamicSynchableGroup.clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun iterator(): ObjectIterator<Int2ReferenceMap.Entry<T>> {
|
|
||||||
return object : ObjectIterator<Int2ReferenceMap.Entry<T>> {
|
|
||||||
private val parent = id2slot.int2ReferenceEntrySet().iterator()
|
|
||||||
private var last: Slot<T>? = null
|
|
||||||
|
|
||||||
override fun hasNext(): Boolean {
|
|
||||||
return parent.hasNext()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun remove() {
|
|
||||||
if (last == null)
|
|
||||||
throw NoSuchElementException()
|
|
||||||
|
|
||||||
parent.remove()
|
|
||||||
removeBySlot(last!!)
|
|
||||||
last = null
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun next(): Int2ReferenceMap.Entry<T> {
|
|
||||||
val value = parent.next()
|
|
||||||
last = value.value
|
|
||||||
return Entry(value.intKey)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun remove(element: Int2ReferenceMap.Entry<T>): Boolean {
|
|
||||||
val slot = id2slot.get(element.intKey)
|
|
||||||
|
|
||||||
if (slot?.value === element.value) {
|
|
||||||
this@DynamicSynchableGroup.removeBySlot(slot)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun removeAll(elements: Collection<Int2ReferenceMap.Entry<T>>): Boolean {
|
|
||||||
var any = false
|
|
||||||
elements.forEach { any = remove(it) || any }
|
|
||||||
return any
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun retainAll(elements: Collection<Int2ReferenceMap.Entry<T>>): Boolean {
|
|
||||||
if (elements.isEmpty()) {
|
|
||||||
val isNotEmpty = id2slot.isNotEmpty()
|
|
||||||
this@DynamicSynchableGroup.clear()
|
|
||||||
return isNotEmpty
|
|
||||||
}
|
|
||||||
|
|
||||||
var any = false
|
|
||||||
val itr = id2slot.int2ReferenceEntrySet().iterator()
|
|
||||||
|
|
||||||
for (entry in itr) {
|
|
||||||
if (elements.none { it.intKey == entry.intKey && it.value === entry.value.value }) {
|
|
||||||
any = true
|
|
||||||
itr.remove()
|
|
||||||
removeBySlot(entry.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return any
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun contains(element: Int2ReferenceMap.Entry<T>): Boolean {
|
|
||||||
return id2slot.get(element.intKey)?.value === element.value
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun containsAll(elements: Collection<Int2ReferenceMap.Entry<T>>): Boolean {
|
|
||||||
return elements.all { contains(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun isEmpty(): Boolean {
|
|
||||||
return id2slot.isEmpty()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun int2ReferenceEntrySet(): ObjectSet<Int2ReferenceMap.Entry<T>> {
|
|
||||||
return entrySet
|
|
||||||
}
|
|
||||||
|
|
||||||
override val keys: IntSet by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
|
||||||
object : IntSet {
|
|
||||||
override fun add(key: Int): Boolean {
|
|
||||||
throw UnsupportedOperationException()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun addAll(c: IntCollection): Boolean {
|
|
||||||
throw UnsupportedOperationException()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun addAll(elements: Collection<Int>): Boolean {
|
|
||||||
throw UnsupportedOperationException()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun clear() {
|
|
||||||
this@DynamicSynchableGroup.clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun iterator(): IntIterator {
|
|
||||||
return object : IntIterator {
|
|
||||||
private val parent = id2slot.keys.iterator()
|
|
||||||
private var last = -1
|
|
||||||
private var hasLast = false
|
|
||||||
|
|
||||||
override fun hasNext(): Boolean {
|
|
||||||
return parent.hasNext()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun remove() {
|
|
||||||
if (!hasLast)
|
|
||||||
throw NoSuchElementException()
|
|
||||||
|
|
||||||
hasLast = false
|
|
||||||
val slot = id2slot.get(last)
|
|
||||||
parent.remove()
|
|
||||||
removeBySlot(slot)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun nextInt(): Int {
|
|
||||||
last = parent.nextInt()
|
|
||||||
hasLast = true
|
|
||||||
return last
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun remove(k: Int): Boolean {
|
|
||||||
removeBySlot(id2slot.get(k) ?: return false)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun removeAll(c: IntCollection): Boolean {
|
|
||||||
val itr = c.iterator()
|
|
||||||
var any = false
|
|
||||||
|
|
||||||
while (itr.hasNext()) {
|
|
||||||
any = remove(itr.nextInt()) || any
|
|
||||||
}
|
|
||||||
|
|
||||||
return any
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun removeAll(elements: Collection<Int>): Boolean {
|
|
||||||
val itr = elements.iterator()
|
|
||||||
var any = false
|
|
||||||
|
|
||||||
while (itr.hasNext()) {
|
|
||||||
any = remove(itr.next()) || any
|
|
||||||
}
|
|
||||||
|
|
||||||
return any
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun retainAll(c: IntCollection): Boolean {
|
|
||||||
val itr = id2slot.values.iterator()
|
|
||||||
var any = false
|
|
||||||
|
|
||||||
for (slot in itr) {
|
|
||||||
if (!c.contains(slot.id)) {
|
|
||||||
itr.remove()
|
|
||||||
check(value2slot.remove(slot.value) == slot)
|
|
||||||
remoteStates.forEach { it.remove(slot) }
|
|
||||||
any = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return any
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun retainAll(elements: Collection<Int>): Boolean {
|
|
||||||
val itr = id2slot.values.iterator()
|
|
||||||
var any = false
|
|
||||||
|
|
||||||
for (slot in itr) {
|
|
||||||
if (!elements.contains(slot.id)) {
|
|
||||||
itr.remove()
|
|
||||||
check(value2slot.remove(slot.value) == slot)
|
|
||||||
remoteStates.forEach { it.remove(slot) }
|
|
||||||
any = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return any
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun contains(key: Int): Boolean {
|
|
||||||
return id2slot.containsKey(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun containsAll(c: IntCollection): Boolean {
|
|
||||||
return id2slot.keys.containsAll(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun containsAll(elements: Collection<Int>): Boolean {
|
|
||||||
return id2slot.keys.containsAll(elements)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun isEmpty(): Boolean {
|
|
||||||
return id2slot.isEmpty()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun toArray(a: IntArray?): IntArray {
|
|
||||||
return id2slot.keys.toArray(a)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun toIntArray(): IntArray {
|
|
||||||
return id2slot.keys.toIntArray()
|
|
||||||
}
|
|
||||||
|
|
||||||
override val size: Int
|
|
||||||
get() = id2slot.size
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override val values: ReferenceCollection<T>
|
|
||||||
get() = this@DynamicSynchableGroup
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val END = 0
|
private const val END = 0
|
||||||
private const val ADD_ENTRY = 1
|
private const val ADD_ENTRY = 1
|
||||||
|
@ -1,58 +1,37 @@
|
|||||||
package ru.dbotthepony.mc.otm.util
|
package ru.dbotthepony.mc.otm.util
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.ints.IntRBTreeSet
|
import it.unimi.dsi.fastutil.ints.IntAVLTreeSet
|
||||||
|
|
||||||
class IDAllocator {
|
class IDAllocator {
|
||||||
private var nextID = -1
|
private var highestID = 0
|
||||||
private val gaps = IntRBTreeSet()
|
private val gaps = IntAVLTreeSet()
|
||||||
private val sparseAllocations = IntRBTreeSet()
|
|
||||||
|
|
||||||
private fun increaseHighestID(): Int {
|
|
||||||
while (sparseAllocations.remove(++nextID)) {}
|
|
||||||
return nextID
|
|
||||||
}
|
|
||||||
|
|
||||||
fun allocate(): Int {
|
fun allocate(): Int {
|
||||||
if (gaps.isEmpty()) {
|
if (gaps.isEmpty()) {
|
||||||
return increaseHighestID()
|
return highestID++
|
||||||
} else {
|
} else {
|
||||||
return gaps.removeFirst()
|
return gaps.removeFirst()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun allocate(id: Int): Boolean {
|
|
||||||
if (id < 0) {
|
|
||||||
return true // not handling negative IDs
|
|
||||||
} else if (id > nextID) {
|
|
||||||
sparseAllocations.add(id)
|
|
||||||
return true
|
|
||||||
} else if (id == nextID) {
|
|
||||||
increaseHighestID()
|
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
return gaps.remove(id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun release(id: Int) {
|
fun release(id: Int) {
|
||||||
if (id < 0) {
|
if (id >= 0) {
|
||||||
return // not handling negative IDs
|
throw IllegalArgumentException("Invalid ID: $id")
|
||||||
} else if (sparseAllocations.remove(id)) {
|
} else if (id >= highestID) {
|
||||||
return // was allocated above highest ID
|
throw IllegalArgumentException("Not tracking ID: $id (highest known ID is ${highestID - 1})")
|
||||||
} else if (id > nextID) {
|
|
||||||
throw IllegalArgumentException("Not tracking ID: $id (highest known ID is ${nextID})")
|
|
||||||
} else if (id in gaps) {
|
} else if (id in gaps) {
|
||||||
throw IllegalArgumentException("ID is already free: $id")
|
throw IllegalArgumentException("ID is already free: $id")
|
||||||
} else if (id == nextID) {
|
}
|
||||||
nextID--
|
|
||||||
|
if (id + 1 == highestID) {
|
||||||
|
highestID--
|
||||||
} else {
|
} else {
|
||||||
check(gaps.add(id))
|
gaps.add(id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun reset() {
|
fun reset() {
|
||||||
nextID = -1
|
highestID = 0
|
||||||
gaps.clear()
|
gaps.clear()
|
||||||
sparseAllocations.clear()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user