Quantum batteries
This commit is contained in:
parent
2da5219739
commit
69b8115395
@ -191,6 +191,13 @@ private fun misc(provider: MatteryLanguageProvider) {
|
||||
misc("matter_bottler.switch_mode", "Switch work mode")
|
||||
|
||||
misc("container.matter_panel.number_input", "Input replication task count")
|
||||
|
||||
misc("item.quantum_battery.creative", "Fill this to win Minecraft.")
|
||||
misc("item.quantum_battery.creative2", "See ya after millions of stars burn out.")
|
||||
misc("item.quantum_battery.creative_power", "Stored energy: %s / Infinity")
|
||||
|
||||
misc("item.quantum_link_id", "Quantum link ID: %s")
|
||||
misc("item.quantum_description", "This item is sharing it's contents with other similar items using quantum entanglement")
|
||||
}
|
||||
}
|
||||
|
||||
@ -287,6 +294,10 @@ private fun items(provider: MatteryLanguageProvider) {
|
||||
add(MItems.BATTERY_CAPACITOR, "Capacitor Battery")
|
||||
add(MItems.BATTERY_CREATIVE, "Creative Battery")
|
||||
|
||||
add(MItems.QUANTUM_BATTERY, "Quantum Battery")
|
||||
add(MItems.QUANTUM_CAPACITOR, "Quantum Capacitor")
|
||||
add(MItems.QUANTUM_BATTERY_CREATIVE, "Quantum Creative Battery")
|
||||
|
||||
add(MItems.TRITANIUM_SWORD, "Tritanium Sword")
|
||||
add(MItems.TRITANIUM_PICKAXE, "Tritanium Pickaxe")
|
||||
add(MItems.TRITANIUM_SHOVEL, "Tritanium Shovel")
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
package ru.dbotthepony.mc.otm
|
||||
|
||||
import net.minecraft.server.MinecraftServer
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraftforge.event.TickEvent
|
||||
import net.minecraftforge.event.TickEvent.ServerTickEvent
|
||||
@ -26,6 +27,18 @@ private val postWorldTick = WeakHashMap<Level, ArrayList<IConditionalTickable>>(
|
||||
private val preWorldTickOnce = WeakHashMap<Level, ArrayList<ITickable>>()
|
||||
private val postWorldTickOnce = WeakHashMap<Level, ArrayList<ITickable>>()
|
||||
|
||||
private var _server: MinecraftServer? = null
|
||||
private var _serverThread: Thread? = null
|
||||
|
||||
fun isServerThread(): Boolean {
|
||||
return Thread.currentThread() === _serverThread
|
||||
}
|
||||
|
||||
val MINECRAFT_SERVER: MinecraftServer
|
||||
get() {
|
||||
return _server ?: throw NullPointerException("Not running a server!")
|
||||
}
|
||||
|
||||
// Flag whenever is server alive
|
||||
// To avoid baby deadlocks caused by minecraft engine design issues
|
||||
var SERVER_IS_DYING = true
|
||||
@ -216,23 +229,28 @@ private fun clear() {
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGHEST)
|
||||
fun onServerStarting(event: ServerAboutToStartEvent?) {
|
||||
fun onServerStarting(event: ServerAboutToStartEvent) {
|
||||
clear()
|
||||
SERVER_IS_DYING = false
|
||||
_server = event.server
|
||||
_serverThread = Thread.currentThread()
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGHEST)
|
||||
fun onServerStopping(event: ServerStoppingEvent?) {
|
||||
fun onServerStopping(event: ServerStoppingEvent) {
|
||||
clear()
|
||||
SERVER_IS_DYING = true
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGHEST)
|
||||
fun onServerStopped(event: ServerStoppedEvent?) {
|
||||
fun onServerStopped(event: ServerStoppedEvent) {
|
||||
if (!SERVER_IS_DYING) {
|
||||
LOGGER.fatal("ServerStoppingEvent did not fire. If server has crashed this is normal. However, if server finished it's work 'gracefully' this is a bug.")
|
||||
|
||||
clear()
|
||||
SERVER_IS_DYING = true
|
||||
}
|
||||
|
||||
_server = null
|
||||
_serverThread = null
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ import java.util.ArrayList
|
||||
* 3. This data can not be stored inside unshared (server only) nbt tag because, again, mods prone to use and interact with
|
||||
* it wrong, causing loss of stored data or mods exposing full content of a drive inside their own tag (which cause very real "NBT size too large"
|
||||
* network kicks, often locking players out of server/singleplayer worlds
|
||||
* 4. net.minecraft.world.level.saveddata.SaveData is for storing everything inside one dat file, which
|
||||
* 4. [net.minecraft.world.level.saveddata.SavedData] is for storing everything inside one dat file, which
|
||||
* is performance tanking, because we have to write *entire* NBT on each save, not the data of Drives that are dirty
|
||||
* 5. Mods which check items for being stack-able even with stack size of 1 gonna compare nbt tag,
|
||||
* which will be performance tanking due to clause 1.
|
||||
|
193
src/main/kotlin/ru/dbotthepony/mc/otm/item/QuantumBatteryItem.kt
Normal file
193
src/main/kotlin/ru/dbotthepony/mc/otm/item/QuantumBatteryItem.kt
Normal file
@ -0,0 +1,193 @@
|
||||
package ru.dbotthepony.mc.otm.item
|
||||
|
||||
import net.minecraft.ChatFormatting
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.IntTag
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.Rarity
|
||||
import net.minecraft.world.item.TooltipFlag
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraftforge.common.capabilities.Capability
|
||||
import net.minecraftforge.common.capabilities.ForgeCapabilities
|
||||
import net.minecraftforge.common.capabilities.ICapabilityProvider
|
||||
import net.minecraftforge.common.util.INBTSerializable
|
||||
import net.minecraftforge.common.util.LazyOptional
|
||||
import ru.dbotthepony.mc.otm.*
|
||||
import ru.dbotthepony.mc.otm.capability.IMatteryEnergyStorage
|
||||
import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
||||
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
|
||||
import ru.dbotthepony.mc.otm.core.formatPower
|
||||
import ru.dbotthepony.mc.otm.saveddata.SavedCountingMap
|
||||
import ru.dbotthepony.mc.otm.saveddata.SavedMapDelegate
|
||||
|
||||
class QuantumBatteryItem : Item {
|
||||
private inner class Power : IMatteryEnergyStorage, ICapabilityProvider, INBTSerializable<IntTag> {
|
||||
private val resolver = LazyOptional.of { this }
|
||||
var delegate = SavedMapDelegate(ImpreciseFraction.ZERO)
|
||||
|
||||
override fun <T : Any?> getCapability(cap: Capability<T>, side: Direction?): LazyOptional<T> {
|
||||
if (cap == ForgeCapabilities.ENERGY || cap == MatteryCapability.ENERGY) {
|
||||
return resolver.cast()
|
||||
}
|
||||
|
||||
return LazyOptional.empty()
|
||||
}
|
||||
|
||||
override fun extractEnergyOuter(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction {
|
||||
return extractEnergyInner(howMuch, simulate)
|
||||
}
|
||||
|
||||
override fun extractEnergyInner(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction {
|
||||
if (howMuch.isNegative) {
|
||||
return ImpreciseFraction.ZERO
|
||||
}
|
||||
|
||||
if (isCreative) {
|
||||
val newEnergy = (delegate.value - howMuch).moreThanZero()
|
||||
|
||||
if (!simulate) {
|
||||
delegate.value = newEnergy
|
||||
}
|
||||
|
||||
return delegate.value - newEnergy
|
||||
}
|
||||
|
||||
val newEnergy = (delegate.value - howMuch.coerceAtMost(throughput!!)).moreThanZero()
|
||||
|
||||
if (!simulate) {
|
||||
delegate.value = newEnergy
|
||||
}
|
||||
|
||||
return delegate.value - newEnergy
|
||||
}
|
||||
|
||||
override fun receiveEnergyOuter(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction {
|
||||
return receiveEnergyInner(howMuch, simulate)
|
||||
}
|
||||
|
||||
override fun receiveEnergyInner(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction {
|
||||
if (howMuch.isNegative) {
|
||||
return ImpreciseFraction.ZERO
|
||||
}
|
||||
|
||||
if (isCreative) {
|
||||
if (!simulate) {
|
||||
delegate.value += howMuch
|
||||
}
|
||||
|
||||
return howMuch
|
||||
}
|
||||
|
||||
val newEnergy = (delegate.value + howMuch.coerceAtMost(throughput!!)).coerceAtMost(capacity!!)
|
||||
|
||||
if (!simulate) {
|
||||
delegate.value = newEnergy
|
||||
}
|
||||
|
||||
return newEnergy - delegate.value
|
||||
}
|
||||
|
||||
override val batteryLevel: ImpreciseFraction
|
||||
get() = delegate.value
|
||||
|
||||
override val maxBatteryLevel: ImpreciseFraction
|
||||
get() = capacity ?: (batteryLevel + ImpreciseFraction.LONG_MAX_VALUE)
|
||||
|
||||
override val missingPower: ImpreciseFraction
|
||||
get() = if (isCreative) ImpreciseFraction.LONG_MAX_VALUE else super.missingPower
|
||||
|
||||
override fun canExtract(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun canReceive(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun serializeNBT(): IntTag {
|
||||
if (isServerThread() && delegate.parent == null) {
|
||||
val old = delegate
|
||||
delegate = saveData!!.factorize()
|
||||
delegate.value = old.value
|
||||
}
|
||||
|
||||
return IntTag.valueOf(if (delegate.parent == null) Int.MIN_VALUE else delegate.index)
|
||||
}
|
||||
|
||||
override fun deserializeNBT(nbt: IntTag) {
|
||||
if (nbt.asInt == Int.MIN_VALUE) {
|
||||
delegate = SavedMapDelegate(ImpreciseFraction.ZERO)
|
||||
return
|
||||
}
|
||||
|
||||
delegate = saveData?.computeIfAbsent(nbt.asInt) ?: SavedMapDelegate(null, nbt.asInt, delegate.value)
|
||||
}
|
||||
}
|
||||
|
||||
val isCreative: Boolean
|
||||
val capacity: ImpreciseFraction?
|
||||
val throughput: ImpreciseFraction?
|
||||
|
||||
val saveDataID: String
|
||||
|
||||
val saveData: SavedCountingMap<SavedMapDelegate<ImpreciseFraction>>? get() {
|
||||
if (isServerThread()) {
|
||||
return MINECRAFT_SERVER.overworld().dataStorage.computeIfAbsent({
|
||||
SavedMapDelegate.makeMap(ImpreciseFraction::serializeNBT, ImpreciseFraction.Companion::deserializeNBT, ImpreciseFraction.ZERO).load(it)
|
||||
}, {
|
||||
SavedMapDelegate.makeMap(ImpreciseFraction::serializeNBT, ImpreciseFraction.Companion::deserializeNBT, ImpreciseFraction.ZERO)
|
||||
}, saveDataID) ?: throw NullPointerException("Unable to get save data for $this in ${MINECRAFT_SERVER.overworld()}")
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
constructor(saveDataID: String) : super(Properties().stacksTo(1).rarity(Rarity.EPIC).tab(OverdriveThatMatters.INSTANCE.CREATIVE_TAB)) {
|
||||
isCreative = true
|
||||
capacity = null
|
||||
throughput = null
|
||||
this.saveDataID = "otm_$saveDataID".intern()
|
||||
}
|
||||
|
||||
constructor(saveDataID: String, capacity: ImpreciseFraction, io: ImpreciseFraction) : super(Properties().stacksTo(1).tab(OverdriveThatMatters.INSTANCE.CREATIVE_TAB)) {
|
||||
isCreative = false
|
||||
this.capacity = capacity
|
||||
this.throughput = io
|
||||
this.saveDataID = "otm_$saveDataID".intern()
|
||||
}
|
||||
|
||||
override fun initCapabilities(stack: ItemStack, nbt: CompoundTag?): ICapabilityProvider {
|
||||
return Power()
|
||||
}
|
||||
|
||||
override fun appendHoverText(
|
||||
itemStack: ItemStack,
|
||||
p_41422_: Level?,
|
||||
components: MutableList<Component>,
|
||||
p_41424_: TooltipFlag
|
||||
) {
|
||||
super.appendHoverText(itemStack, p_41422_, components, p_41424_)
|
||||
|
||||
val power = itemStack.getCapability(MatteryCapability.ENERGY).orThrow() as Power
|
||||
|
||||
components.add(TranslatableComponent("otm.item.quantum_description").withStyle(ChatFormatting.DARK_GRAY))
|
||||
|
||||
if (isCreative) {
|
||||
components.add(TranslatableComponent("otm.item.quantum_battery.creative_power", power.batteryLevel.formatPower()).withStyle(ChatFormatting.GRAY))
|
||||
components.add(TranslatableComponent("otm.item.quantum_battery.creative").withStyle(ChatFormatting.DARK_GRAY))
|
||||
components.add(TranslatableComponent("otm.item.quantum_battery.creative2").withStyle(ChatFormatting.DARK_GRAY))
|
||||
} else {
|
||||
components.add(TranslatableComponent("otm.item.power.normal.storage", power.batteryLevel.formatPower(), capacity!!.formatPower()).withStyle(ChatFormatting.GRAY))
|
||||
components.add(TranslatableComponent(
|
||||
"otm.item.power.normal.throughput",
|
||||
throughput!!.formatPower(),
|
||||
throughput.formatPower()
|
||||
).withStyle(ChatFormatting.GRAY))
|
||||
}
|
||||
|
||||
components.add(TranslatableComponent("otm.item.quantum_link_id", power.delegate.index).withStyle(ChatFormatting.DARK_GRAY))
|
||||
}
|
||||
}
|
@ -176,6 +176,10 @@ object MItems {
|
||||
val BATTERY_CAPACITOR: Item by registry.register(MNames.BATTERY_CAPACITOR) { BatteryItem(ImpreciseFraction(150_000), ImpreciseFraction(15000), ImpreciseFraction(15000)) }
|
||||
val BATTERY_CREATIVE: Item by registry.register(MNames.BATTERY_CREATIVE) { BatteryItem() }
|
||||
|
||||
val QUANTUM_BATTERY: Item by registry.register(MNames.QUANTUM_BATTERY) { QuantumBatteryItem(MNames.QUANTUM_BATTERY, ImpreciseFraction(20_000_000), ImpreciseFraction(10_000)) }
|
||||
val QUANTUM_CAPACITOR: Item by registry.register(MNames.QUANTUM_CAPACITOR) { QuantumBatteryItem(MNames.QUANTUM_CAPACITOR, ImpreciseFraction(1_000_000), ImpreciseFraction(200_000)) }
|
||||
val QUANTUM_BATTERY_CREATIVE: Item by registry.register(MNames.QUANTUM_BATTERY_CREATIVE) { QuantumBatteryItem(MNames.QUANTUM_BATTERY_CREATIVE) }
|
||||
|
||||
val BATTERIES = LazyList(
|
||||
{ BATTERY_CRUDE },
|
||||
{ BATTERY_BASIC },
|
||||
|
@ -34,22 +34,6 @@ object MNames {
|
||||
const val GRAVITATION_STABILIZER_LENS = "gravitation_stabilizer_lens"
|
||||
|
||||
const val CARGO_CRATE = "cargo_crate"
|
||||
const val CARGO_CRATE_WHITE = "cargo_crate_white" // нужен рецепт
|
||||
const val CARGO_CRATE_ORANGE = "cargo_crate_orange" // нужен рецепт
|
||||
const val CARGO_CRATE_MAGENTA = "cargo_crate_magenta" // нужен рецепт
|
||||
const val CARGO_CRATE_LIGHT_BLUE = "cargo_crate_light_blue" // нужен рецепт
|
||||
const val CARGO_CRATE_YELLOW = "cargo_crate_yellow" // нужен рецепт
|
||||
const val CARGO_CRATE_LIME = "cargo_crate_lime" // нужен рецепт
|
||||
const val CARGO_CRATE_PINK = "cargo_crate_pink" // нужен рецепт
|
||||
const val CARGO_CRATE_GRAY = "cargo_crate_gray" // нужен рецепт
|
||||
const val CARGO_CRATE_LIGHT_GRAY = "cargo_crate_light_gray" // нужен рецепт
|
||||
const val CARGO_CRATE_CYAN = "cargo_crate_cyan" // нужен рецепт
|
||||
const val CARGO_CRATE_PURPLE = "cargo_crate_purple" // нужен рецепт
|
||||
const val CARGO_CRATE_BLUE = "cargo_crate_blue" // нужен рецепт
|
||||
const val CARGO_CRATE_BROWN = "cargo_crate_brown" // нужен рецепт
|
||||
const val CARGO_CRATE_GREEN = "cargo_crate_green" // нужен рецепт
|
||||
const val CARGO_CRATE_RED = "cargo_crate_red" // нужен рецепт
|
||||
const val CARGO_CRATE_BLACK = "cargo_crate_black" // нужен рецепт
|
||||
|
||||
const val STORAGE_BUS = "storage_bus"
|
||||
const val STORAGE_IMPORTER = "storage_importer"
|
||||
@ -89,6 +73,10 @@ object MNames {
|
||||
const val BATTERY_CAPACITOR = "battery_capacitor"
|
||||
const val BATTERY_CREATIVE = "battery_creative"
|
||||
|
||||
const val QUANTUM_BATTERY = "quantum_battery"
|
||||
const val QUANTUM_CAPACITOR = "quantum_capacitor"
|
||||
const val QUANTUM_BATTERY_CREATIVE = "quantum_battery_creative"
|
||||
|
||||
const val MATTER_CAPACITOR_PARTS = "matter_capacitor_parts"
|
||||
const val MATTER_CAPACITOR_BASIC = "matter_capacitor_basic"
|
||||
const val MATTER_CAPACITOR_NORMAL = "matter_capacitor_normal"
|
||||
|
@ -0,0 +1,411 @@
|
||||
package ru.dbotthepony.mc.otm.saveddata
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectAVLTreeMap
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectFunction
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.IntTag
|
||||
import net.minecraft.nbt.ListTag
|
||||
import net.minecraft.nbt.Tag
|
||||
import net.minecraft.world.level.saveddata.SavedData
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import ru.dbotthepony.mc.otm.set
|
||||
|
||||
class SavedMapDelegate<V>(val parent: SavedCountingMap<SavedMapDelegate<V>>?, val index: Int, value: V) {
|
||||
constructor(value: V) : this(null, -1, value)
|
||||
|
||||
var value: V = value
|
||||
set(value) {
|
||||
if (field != value) {
|
||||
field = value
|
||||
parent?.isDirty = true
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun <V> makeMap(
|
||||
serializer: (value: V) -> Tag,
|
||||
deserializer: (nbt: Tag) -> V,
|
||||
defaultValue: V
|
||||
): SavedCountingMap<SavedMapDelegate<V>> {
|
||||
return SavedCountingMap(
|
||||
serializer = { _, value, _ -> serializer.invoke(value.value) },
|
||||
deserializer = { map, nbt, index -> SavedMapDelegate(map, index, deserializer.invoke(nbt)) },
|
||||
factory = { map, index -> SavedMapDelegate(map, index, defaultValue) }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SavedCountingMap<T>(
|
||||
val serializer: (map: SavedCountingMap<T>, value: T, index: Int) -> Tag,
|
||||
val deserializer: (map: SavedCountingMap<T>, nbt: Tag, index: Int) -> T,
|
||||
val factory: (map: SavedCountingMap<T>, index: Int) -> T
|
||||
) : SavedData(), MutableMap<Int, T> {
|
||||
var nextIndex = 0
|
||||
private set
|
||||
|
||||
fun computeIfAbsent(index: Int): T {
|
||||
return map.computeIfAbsent(index, Int2ObjectFunction {
|
||||
isDirty = true
|
||||
return@Int2ObjectFunction factory.invoke(this, it)
|
||||
})
|
||||
}
|
||||
|
||||
fun factorize(): T {
|
||||
return computeIfAbsent(nextIndex++)
|
||||
}
|
||||
|
||||
private val map = Int2ObjectAVLTreeMap<T>()
|
||||
|
||||
override val size: Int
|
||||
get() = map.size
|
||||
|
||||
override fun containsKey(key: Int): Boolean {
|
||||
return map.containsKey(key)
|
||||
}
|
||||
|
||||
override fun containsValue(value: T): Boolean {
|
||||
return map.containsValue(value)
|
||||
}
|
||||
|
||||
override fun get(key: Int): T? {
|
||||
return map[key]
|
||||
}
|
||||
|
||||
override fun isEmpty(): Boolean {
|
||||
return map.isEmpty()
|
||||
}
|
||||
|
||||
override val entries: MutableSet<MutableMap.MutableEntry<Int, T>> by lazy {
|
||||
object : MutableSet<MutableMap.MutableEntry<Int, T>> {
|
||||
override fun add(element: MutableMap.MutableEntry<Int, T>): Boolean {
|
||||
this@SavedCountingMap[element.key] = element.value
|
||||
return true
|
||||
}
|
||||
|
||||
override fun addAll(elements: Collection<MutableMap.MutableEntry<Int, T>>): Boolean {
|
||||
for (value in elements) {
|
||||
add(value)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun clear() {
|
||||
this@SavedCountingMap.clear()
|
||||
}
|
||||
|
||||
private val setParent = this@SavedCountingMap.map.int2ObjectEntrySet()
|
||||
|
||||
override fun iterator(): MutableIterator<MutableMap.MutableEntry<Int, T>> {
|
||||
return object : MutableIterator<MutableMap.MutableEntry<Int, T>> {
|
||||
private val parent = setParent.iterator()
|
||||
|
||||
override fun hasNext(): Boolean {
|
||||
return parent.hasNext()
|
||||
}
|
||||
|
||||
override fun next(): MutableMap.MutableEntry<Int, T> {
|
||||
return parent.next()
|
||||
}
|
||||
|
||||
override fun remove() {
|
||||
parent.remove()
|
||||
isDirty = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun remove(element: MutableMap.MutableEntry<Int, T>): Boolean {
|
||||
if (setParent.remove(element)) {
|
||||
isDirty = true
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
override fun removeAll(elements: Collection<MutableMap.MutableEntry<Int, T>>): Boolean {
|
||||
if (setParent.removeAll(elements)) {
|
||||
isDirty = true
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
override fun retainAll(elements: Collection<MutableMap.MutableEntry<Int, T>>): Boolean {
|
||||
if (setParent.retainAll(elements)) {
|
||||
isDirty = true
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
override val size: Int
|
||||
get() = setParent.size
|
||||
|
||||
override fun contains(element: MutableMap.MutableEntry<Int, T>): Boolean {
|
||||
return setParent.contains(element)
|
||||
}
|
||||
|
||||
override fun containsAll(elements: Collection<MutableMap.MutableEntry<Int, T>>): Boolean {
|
||||
return setParent.containsAll(elements)
|
||||
}
|
||||
|
||||
override fun isEmpty(): Boolean {
|
||||
return setParent.isEmpty()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override val keys: MutableSet<Int> by lazy {
|
||||
object : MutableSet<Int> {
|
||||
val parent = this@SavedCountingMap.map.keys
|
||||
|
||||
override fun add(element: Int): Boolean {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
override fun addAll(elements: Collection<Int>): Boolean {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
override fun clear() {
|
||||
this@SavedCountingMap.clear()
|
||||
}
|
||||
|
||||
override fun iterator(): MutableIterator<Int> {
|
||||
return object : MutableIterator<Int> {
|
||||
private val parentIterator = parent.iterator()
|
||||
|
||||
override fun hasNext(): Boolean {
|
||||
return parentIterator.hasNext()
|
||||
}
|
||||
|
||||
override fun next(): Int {
|
||||
return parentIterator.nextInt()
|
||||
}
|
||||
|
||||
override fun remove() {
|
||||
parentIterator.remove()
|
||||
isDirty = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun remove(element: Int): Boolean {
|
||||
return this@SavedCountingMap.remove(element) != null
|
||||
}
|
||||
|
||||
override fun removeAll(elements: Collection<Int>): Boolean {
|
||||
var changes = false
|
||||
|
||||
for (element in elements) {
|
||||
changes = remove(element) || changes
|
||||
}
|
||||
|
||||
return changes
|
||||
}
|
||||
|
||||
override fun retainAll(elements: Collection<Int>): Boolean {
|
||||
val iterator = this.iterator()
|
||||
var changes = false
|
||||
|
||||
for (element in iterator) {
|
||||
if (element !in elements) {
|
||||
iterator.remove()
|
||||
changes = true
|
||||
}
|
||||
}
|
||||
|
||||
return changes
|
||||
}
|
||||
|
||||
override val size: Int
|
||||
get() = parent.size
|
||||
|
||||
override fun contains(element: Int): Boolean {
|
||||
return parent.contains(element)
|
||||
}
|
||||
|
||||
override fun containsAll(elements: Collection<Int>): Boolean {
|
||||
return parent.containsAll(elements)
|
||||
}
|
||||
|
||||
override fun isEmpty(): Boolean {
|
||||
return parent.isEmpty()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override val values: MutableCollection<T> by lazy {
|
||||
object : MutableCollection<T> {
|
||||
private val parent = this@SavedCountingMap.map.values
|
||||
|
||||
override val size: Int
|
||||
get() = parent.size
|
||||
|
||||
override fun contains(element: T): Boolean {
|
||||
return parent.contains(element)
|
||||
}
|
||||
|
||||
override fun containsAll(elements: Collection<T>): Boolean {
|
||||
return parent.containsAll(elements)
|
||||
}
|
||||
|
||||
override fun isEmpty(): Boolean {
|
||||
return parent.isEmpty()
|
||||
}
|
||||
|
||||
override fun add(element: T): Boolean {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
override fun addAll(elements: Collection<T>): Boolean {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
override fun clear() {
|
||||
this@SavedCountingMap.clear()
|
||||
}
|
||||
|
||||
override fun iterator(): MutableIterator<T> {
|
||||
return object : MutableIterator<T> {
|
||||
private val parentIterator = parent.iterator()
|
||||
|
||||
override fun hasNext(): Boolean {
|
||||
return parentIterator.hasNext()
|
||||
}
|
||||
|
||||
override fun next(): T {
|
||||
return parentIterator.next()
|
||||
}
|
||||
|
||||
override fun remove() {
|
||||
parentIterator.remove()
|
||||
isDirty = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun remove(element: T): Boolean {
|
||||
val indexOf = this@SavedCountingMap.map.firstNotNullOfOrNull { if (it.value == element) it.key else null } ?: return false
|
||||
this@SavedCountingMap.remove(indexOf)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun removeAll(elements: Collection<T>): Boolean {
|
||||
var changes = false
|
||||
|
||||
for (element in elements) {
|
||||
changes = remove(element) || changes
|
||||
}
|
||||
|
||||
return changes
|
||||
}
|
||||
|
||||
override fun retainAll(elements: Collection<T>): Boolean {
|
||||
val iterator = this.iterator()
|
||||
var changes = false
|
||||
|
||||
for (element in iterator) {
|
||||
if (element !in elements) {
|
||||
iterator.remove()
|
||||
changes = true
|
||||
}
|
||||
}
|
||||
|
||||
return changes
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun clear() {
|
||||
isDirty = true
|
||||
return map.clear()
|
||||
}
|
||||
|
||||
override fun put(key: Int, value: T): T? {
|
||||
val existing = map.put(key, value)
|
||||
|
||||
if (existing == value) {
|
||||
return existing
|
||||
}
|
||||
|
||||
isDirty = true
|
||||
return existing
|
||||
}
|
||||
|
||||
override fun putAll(from: Map<out Int, T>) {
|
||||
isDirty = true
|
||||
return map.putAll(from)
|
||||
}
|
||||
|
||||
override fun remove(key: Int): T? {
|
||||
val removed = map.remove(key)
|
||||
|
||||
if (removed != null) {
|
||||
isDirty = true
|
||||
}
|
||||
|
||||
return removed
|
||||
}
|
||||
|
||||
override fun save(output: CompoundTag): CompoundTag {
|
||||
output["map"] = ListTag().also {
|
||||
for ((key, value) in this.map) {
|
||||
val compound = CompoundTag()
|
||||
|
||||
try {
|
||||
compound["value"] = this.serializer.invoke(this, value, key)
|
||||
it.add(compound)
|
||||
} catch(err: Exception) {
|
||||
LOGGER.error("Unable to serialize $value at $key", err)
|
||||
continue
|
||||
}
|
||||
|
||||
compound["key"] = key
|
||||
}
|
||||
}
|
||||
|
||||
output["next_index"] = nextIndex
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
fun load(input: CompoundTag): SavedCountingMap<T> {
|
||||
this.map.clear()
|
||||
|
||||
val map = input["map"] as? ListTag ?: ListTag()
|
||||
var maximal = -1
|
||||
|
||||
for (value in map) {
|
||||
if (value !is CompoundTag) {
|
||||
continue
|
||||
}
|
||||
|
||||
val key = (value["key"] as IntTag?)?.asInt ?: continue
|
||||
val nbt = value["value"] ?: continue
|
||||
|
||||
try {
|
||||
val deserialized = this.deserializer.invoke(this, nbt, key)
|
||||
this.map.put(key, deserialized)
|
||||
} catch(err: Exception) {
|
||||
LOGGER.error("Unable to deserialize value in $this at $key", err)
|
||||
}
|
||||
|
||||
maximal = maximal.coerceAtLeast(key)
|
||||
}
|
||||
|
||||
nextIndex = (input["next_index"] as IntTag?)?.asInt ?: (maximal + 1)
|
||||
|
||||
isDirty = false
|
||||
return this
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOGGER = LogManager.getLogger()
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user