Revisit quantum battery code and clean it up
This commit is contained in:
parent
8e2c1f25dc
commit
8e03b4363d
@ -17,18 +17,37 @@ import net.minecraftforge.fml.loading.FMLLoader
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import ru.dbotthepony.mc.otm.capability.AbstractProfiledStorage
|
||||
import ru.dbotthepony.mc.otm.client.minecraft
|
||||
import ru.dbotthepony.mc.otm.core.collect.WeakHashSet
|
||||
import ru.dbotthepony.mc.otm.core.util.AtomicallyInvalidatedLazy
|
||||
import ru.dbotthepony.mc.otm.core.util.IConditionalTickable
|
||||
import ru.dbotthepony.mc.otm.core.util.ITickable
|
||||
import ru.dbotthepony.mc.otm.core.util.TickList
|
||||
import ru.dbotthepony.mc.otm.graph.GraphNodeList
|
||||
import ru.dbotthepony.mc.otm.network.MatteryNetworkChannel
|
||||
import java.util.*
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
private val preServerTick = TickList()
|
||||
private val postServerTick = TickList()
|
||||
private val preWorldTick = WeakHashMap<Level, TickList>()
|
||||
private val postWorldTick = WeakHashMap<Level, TickList>()
|
||||
|
||||
private val clientThreads = WeakHashSet<Thread>()
|
||||
private val serverThreads = WeakHashSet<Thread>()
|
||||
|
||||
private val serverCounter = AtomicInteger()
|
||||
private var _server: MinecraftServer? = null
|
||||
val isClient: Boolean by lazy { FMLLoader.getDist() == Dist.CLIENT }
|
||||
|
||||
fun <V> lazyPerServer(fn: (MinecraftServer) -> V): Lazy<V> {
|
||||
return AtomicallyInvalidatedLazy(serverCounter) {
|
||||
if (!SERVER_IS_LIVE)
|
||||
throw IllegalStateException("No server is running")
|
||||
|
||||
fn.invoke(_server!!)
|
||||
}
|
||||
}
|
||||
|
||||
fun onceServerPre(inTicks: Int, callback: Runnable): TickList.Timer? {
|
||||
if (!SERVER_IS_LIVE) {
|
||||
LOGGER.error("Refusing to add timer $callback in ticks $inTicks while server is dying", IllegalStateException("Server is stopping"))
|
||||
@ -47,12 +66,6 @@ fun onceServer(inTicks: Int, callback: Runnable): TickList.Timer? {
|
||||
return postServerTick.Timer(inTicks, callback)
|
||||
}
|
||||
|
||||
private var _server: MinecraftServer? = null
|
||||
private var _serverThread: Thread? = null
|
||||
private var _clientThread: Thread? = null
|
||||
|
||||
val isClient: Boolean by lazy { FMLLoader.getDist() == Dist.CLIENT }
|
||||
|
||||
private val isPausedImpl: Boolean get() {
|
||||
val server = _server
|
||||
|
||||
@ -64,7 +77,7 @@ private val isPausedImpl: Boolean get() {
|
||||
}
|
||||
|
||||
val isPaused: Boolean get() {
|
||||
if (_clientThread === null) {
|
||||
if (clientThreads.isEmpty()) {
|
||||
return false
|
||||
}
|
||||
|
||||
@ -72,11 +85,7 @@ val isPaused: Boolean get() {
|
||||
}
|
||||
|
||||
fun recordClientThread() {
|
||||
if (_clientThread != null) {
|
||||
throw IllegalStateException("Already have client channel")
|
||||
}
|
||||
|
||||
_clientThread = Thread.currentThread()
|
||||
clientThreads.add(Thread.currentThread())
|
||||
}
|
||||
|
||||
fun runIfClient(lambda: () -> Unit) {
|
||||
@ -119,11 +128,11 @@ fun <V> runOnClient(value: V, lambda: () -> V): V {
|
||||
}
|
||||
|
||||
fun isServerThread(): Boolean {
|
||||
return Thread.currentThread() === _serverThread
|
||||
return Thread.currentThread() in serverThreads
|
||||
}
|
||||
|
||||
fun isClientThread(): Boolean {
|
||||
return Thread.currentThread() === _clientThread
|
||||
return Thread.currentThread() in clientThreads
|
||||
}
|
||||
|
||||
val MINECRAFT_SERVER: MinecraftServer
|
||||
@ -146,6 +155,7 @@ private val LOGGER = LogManager.getLogger()
|
||||
fun onServerTick(event: ServerTickEvent) {
|
||||
if (event.phase === TickEvent.Phase.START) {
|
||||
preServerTick.tick()
|
||||
serverThreads.add(Thread.currentThread())
|
||||
} else {
|
||||
postServerTick.tick()
|
||||
// чтоб не плодить кучу подписчиков, вызовем напрямую отсюда
|
||||
@ -158,6 +168,12 @@ fun onServerTick(event: ServerTickEvent) {
|
||||
fun onWorldTick(event: LevelTickEvent) {
|
||||
if (event.phase === TickEvent.Phase.START) {
|
||||
preWorldTick[event.level]?.tick()
|
||||
|
||||
if (event.side.isClient) {
|
||||
clientThreads.add(Thread.currentThread())
|
||||
} else if (event.side.isServer) {
|
||||
serverThreads.add(Thread.currentThread())
|
||||
}
|
||||
} else {
|
||||
postWorldTick[event.level]?.tick()
|
||||
}
|
||||
@ -254,13 +270,15 @@ fun onServerStarting(event: ServerAboutToStartEvent) {
|
||||
clear()
|
||||
SERVER_IS_LIVE = true
|
||||
_server = event.server
|
||||
_serverThread = Thread.currentThread()
|
||||
serverThreads.add(Thread.currentThread())
|
||||
serverCounter.incrementAndGet()
|
||||
MatteryNetworkChannel.onServerStarting()
|
||||
}
|
||||
|
||||
fun onServerStopping(event: ServerStoppingEvent) {
|
||||
clear()
|
||||
SERVER_IS_LIVE = false
|
||||
serverCounter.incrementAndGet()
|
||||
MatteryNetworkChannel.onServerStopping()
|
||||
}
|
||||
|
||||
@ -273,6 +291,6 @@ fun onServerStopped(event: ServerStoppedEvent) {
|
||||
}
|
||||
|
||||
_server = null
|
||||
_serverThread = null
|
||||
serverCounter.incrementAndGet()
|
||||
MatteryNetworkChannel.onServerStopped()
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package ru.dbotthepony.mc.otm.capability
|
||||
|
||||
import com.google.common.collect.Streams
|
||||
import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet
|
||||
import net.minecraft.ChatFormatting
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.network.chat.Component
|
||||
@ -30,6 +31,9 @@ import ru.dbotthepony.mc.otm.container.iterator
|
||||
import ru.dbotthepony.mc.otm.container.stream
|
||||
import ru.dbotthepony.mc.otm.core.collect.AwareItemStack
|
||||
import ru.dbotthepony.mc.otm.core.collect.ContainerItemStackEntry
|
||||
import ru.dbotthepony.mc.otm.core.collect.concatIterators
|
||||
import ru.dbotthepony.mc.otm.core.collect.filter
|
||||
import ru.dbotthepony.mc.otm.core.collect.map
|
||||
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||
import ru.dbotthepony.mc.otm.core.orNull
|
||||
@ -219,25 +223,25 @@ fun ICapabilityProvider.getMatteryEnergySided(side: Direction? = null): LazyOpti
|
||||
*
|
||||
* Contains all items that player might carry
|
||||
*/
|
||||
fun Player.itemsStream(includeCosmetics: Boolean = true): Stream<out ItemStack> {
|
||||
val streams = ArrayList<Stream<out ItemStack>>()
|
||||
streams.add(inventory.stream())
|
||||
fun Player.items(includeCosmetics: Boolean = true): Iterator<ItemStack> {
|
||||
val iterators = ArrayList<Iterator<ItemStack>>()
|
||||
iterators.add(inventory.iterator())
|
||||
|
||||
matteryPlayer?.let {
|
||||
if (it.hasExopack) {
|
||||
streams.add(it.exopackContainer.stream())
|
||||
iterators.add(it.exopackContainer.iterator())
|
||||
}
|
||||
}
|
||||
|
||||
if (isCuriosLoaded) {
|
||||
streams.add(curiosStream(includeCosmetics))
|
||||
iterators.add(curiosStream(includeCosmetics))
|
||||
}
|
||||
|
||||
if (includeCosmetics && isCosmeticArmorLoaded) {
|
||||
streams.add(cosmeticArmorStream())
|
||||
iterators.add(cosmeticArmorStream())
|
||||
}
|
||||
|
||||
return streams.stream().flatMap { it }
|
||||
return concatIterators(iterators)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -245,20 +249,20 @@ fun Player.itemsStream(includeCosmetics: Boolean = true): Stream<out ItemStack>
|
||||
*
|
||||
* Contains all items that player might see/access ([itemsStream] + open container's items)
|
||||
*/
|
||||
fun Player.allItemsStream(includeCosmetics: Boolean = true): Stream<out ItemStack> {
|
||||
fun Player.allItems(includeCosmetics: Boolean = true): Iterator<ItemStack> {
|
||||
if (containerMenu == inventoryMenu || containerMenu == matteryPlayer?.exoPackMenu) {
|
||||
return itemsStream(includeCosmetics)
|
||||
return items(includeCosmetics)
|
||||
}
|
||||
|
||||
val seen = IdentityHashMap<ItemStack, Unit>(containerMenu.slots.size)
|
||||
val seen = ReferenceOpenHashSet<ItemStack>(containerMenu.slots.size)
|
||||
|
||||
for (slot in containerMenu.slots) {
|
||||
seen[slot.item] = Unit
|
||||
seen.add(slot.item)
|
||||
}
|
||||
|
||||
return Streams.concat(
|
||||
itemsStream(includeCosmetics).filter { it.isEmpty || it !in seen },
|
||||
containerMenu.slots.stream().map { it.item })
|
||||
return concatIterators(
|
||||
items(includeCosmetics).filter { it.isNotEmpty && it !in seen },
|
||||
containerMenu.slots.iterator().map { it.item })
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -24,8 +24,10 @@ import ru.dbotthepony.mc.otm.client.screen.panels.button.RectangleButtonPanel
|
||||
import ru.dbotthepony.mc.otm.compat.cos.CosmeticToggleButton.Companion.BUTTON_ACTIVE
|
||||
import ru.dbotthepony.mc.otm.compat.cos.CosmeticToggleButton.Companion.BUTTON_INACTIVE
|
||||
import ru.dbotthepony.mc.otm.container.awareStream
|
||||
import ru.dbotthepony.mc.otm.container.iterator
|
||||
import ru.dbotthepony.mc.otm.container.stream
|
||||
import ru.dbotthepony.mc.otm.core.collect.AwareItemStack
|
||||
import ru.dbotthepony.mc.otm.core.collect.emptyIterator
|
||||
import ru.dbotthepony.mc.otm.menu.MatterySlot
|
||||
import java.util.stream.Stream
|
||||
|
||||
@ -71,16 +73,16 @@ private class CosmeticSlot(container: Container, private val slot: EquipmentSlot
|
||||
}
|
||||
}
|
||||
|
||||
fun Player.cosmeticArmorStream(): Stream<out ItemStack> {
|
||||
fun Player.cosmeticArmorStream(): Iterator<ItemStack> {
|
||||
if (!isCosmeticArmorLoaded) {
|
||||
return Stream.empty()
|
||||
return emptyIterator()
|
||||
}
|
||||
|
||||
return cosmeticArmorStreamImpl()
|
||||
}
|
||||
|
||||
private fun Player.cosmeticArmorStreamImpl(): Stream<out ItemStack> {
|
||||
val manager = ModObjects.invMan ?: return Stream.empty()
|
||||
private fun Player.cosmeticArmorStreamImpl(): Iterator<ItemStack> {
|
||||
val manager = ModObjects.invMan ?: return emptyIterator()
|
||||
|
||||
val container = if (this !is ServerPlayer) {
|
||||
manager.getCosArmorInventoryClient(uuid)
|
||||
@ -88,7 +90,7 @@ private fun Player.cosmeticArmorStreamImpl(): Stream<out ItemStack> {
|
||||
manager.getCosArmorInventory(uuid)
|
||||
}
|
||||
|
||||
return (container as Container).stream()
|
||||
return (container as Container).iterator()
|
||||
}
|
||||
|
||||
fun Player.cosmeticArmorAwareStream(): Stream<out AwareItemStack> {
|
||||
|
@ -11,8 +11,11 @@ import net.minecraftforge.network.PacketDistributor
|
||||
import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
||||
import ru.dbotthepony.mc.otm.capability.matteryPlayer
|
||||
import ru.dbotthepony.mc.otm.container.awareStream
|
||||
import ru.dbotthepony.mc.otm.container.iterator
|
||||
import ru.dbotthepony.mc.otm.container.stream
|
||||
import ru.dbotthepony.mc.otm.core.collect.AwareItemStack
|
||||
import ru.dbotthepony.mc.otm.core.collect.concatIterators
|
||||
import ru.dbotthepony.mc.otm.core.collect.emptyIterator
|
||||
import ru.dbotthepony.mc.otm.core.orNull
|
||||
import ru.dbotthepony.mc.otm.menu.PlayerSlot
|
||||
import top.theillusivec4.curios.api.CuriosApi
|
||||
@ -85,27 +88,27 @@ val Player.curiosSlots: List<PlayerSlot<Slot, Slot>> get() {
|
||||
return getCuriosSlotsImpl()
|
||||
}
|
||||
|
||||
private fun Player.curiosStreamImpl(includeCosmetics: Boolean): Stream<out ItemStack> {
|
||||
val handler = getCapability(MatteryCapability.CURIOS_INVENTORY).orNull() ?: return Stream.empty()
|
||||
private fun Player.curiosStreamImpl(includeCosmetics: Boolean): Iterator<ItemStack> {
|
||||
val handler = getCapability(MatteryCapability.CURIOS_INVENTORY).orNull() ?: return emptyIterator()
|
||||
|
||||
val result = ArrayList<Stream<out ItemStack>>()
|
||||
val result = ArrayList<Iterator<ItemStack>>()
|
||||
|
||||
for ((identifier, curio) in handler.curios) {
|
||||
result.add(curio.stacks.stream())
|
||||
result.add(curio.stacks.iterator())
|
||||
|
||||
if (includeCosmetics && curio.hasCosmetic()) {
|
||||
result.add(curio.cosmeticStacks.stream())
|
||||
result.add(curio.cosmeticStacks.iterator())
|
||||
}
|
||||
}
|
||||
|
||||
return result.stream().flatMap { it }
|
||||
return concatIterators(result)
|
||||
}
|
||||
|
||||
fun Player.curiosStream(includeCosmetics: Boolean = true): Stream<out ItemStack> {
|
||||
return Stream.empty()
|
||||
fun Player.curiosStream(includeCosmetics: Boolean = true): Iterator<ItemStack> {
|
||||
return emptyIterator()
|
||||
|
||||
if (!isCuriosLoaded) {
|
||||
return Stream.empty()
|
||||
return emptyIterator()
|
||||
}
|
||||
|
||||
return curiosStreamImpl(includeCosmetics)
|
||||
|
@ -6,6 +6,8 @@ import net.minecraft.world.item.ItemStack
|
||||
import net.minecraftforge.items.IItemHandler
|
||||
import ru.dbotthepony.mc.otm.core.collect.AwareItemStack
|
||||
import ru.dbotthepony.mc.otm.core.collect.ItemHandlerItemStackEntry
|
||||
import ru.dbotthepony.mc.otm.core.collect.filter
|
||||
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
||||
import java.util.*
|
||||
import java.util.stream.Stream
|
||||
import java.util.stream.StreamSupport
|
||||
@ -48,7 +50,7 @@ class ItemHandlerAwareSpliterator(private val handler: IItemHandler, offset: Int
|
||||
}
|
||||
}
|
||||
|
||||
fun IItemHandler.iterator(): Iterator<ItemStack> = Spliterators.iterator(spliterator())
|
||||
fun IItemHandler.iterator(): Iterator<ItemStack> = Spliterators.iterator(spliterator()).filter { it.isNotEmpty }
|
||||
fun IItemHandler.spliterator(): Spliterator<out ItemStack> = ItemHandlerSpliterator(this)
|
||||
fun IItemHandler.awareSpliterator(): Spliterator<out AwareItemStack> = ItemHandlerAwareSpliterator(this)
|
||||
fun IItemHandler.stream(): Stream<out ItemStack> = StreamSupport.stream(spliterator(), false)
|
||||
|
@ -0,0 +1,31 @@
|
||||
package ru.dbotthepony.mc.otm.core.collect
|
||||
|
||||
import it.unimi.dsi.fastutil.Hash
|
||||
import java.lang.ref.Reference
|
||||
|
||||
object ReferenceHashStrategy : Hash.Strategy<Any?> {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun equals(a: Any?, b: Any?): Boolean {
|
||||
if (a === b) return true
|
||||
|
||||
if (a is Reference<*>) {
|
||||
if (a.refersTo(null) || b == null) return false
|
||||
|
||||
if (b is Reference<*>) {
|
||||
if (b.refersTo(null)) return false
|
||||
return (b as Reference<Any>).refersTo(a.get() ?: return false)
|
||||
} else {
|
||||
return (a as Reference<Any>).refersTo(b)
|
||||
}
|
||||
} else if (b is Reference<*>) {
|
||||
if (b.refersTo(null) || a == null) return false
|
||||
return (b as Reference<Any>).refersTo(a)
|
||||
}
|
||||
|
||||
return a == b
|
||||
}
|
||||
|
||||
override fun hashCode(o: Any?): Int {
|
||||
return o.hashCode()
|
||||
}
|
||||
}
|
@ -23,6 +23,7 @@ import java.util.stream.Collector
|
||||
*/
|
||||
class FilteringIterator<T>(private val parent: Iterator<T>, private val predicate: Predicate<in T>) : MutableIterator<T> {
|
||||
private var foundValue: Any? = Companion
|
||||
private var returned = false
|
||||
|
||||
override fun hasNext(): Boolean {
|
||||
if (foundValue === Companion) {
|
||||
@ -58,16 +59,14 @@ class FilteringIterator<T>(private val parent: Iterator<T>, private val predicat
|
||||
}
|
||||
|
||||
this.foundValue = Companion
|
||||
returned = true
|
||||
return foundValue as T
|
||||
}
|
||||
|
||||
override fun remove() {
|
||||
if (foundValue === Companion) {
|
||||
throw NoSuchElementException()
|
||||
}
|
||||
|
||||
if (!returned) throw NoSuchElementException()
|
||||
(parent as MutableIterator<T>).remove()
|
||||
foundValue = Companion
|
||||
returned = false
|
||||
}
|
||||
|
||||
private companion object
|
||||
@ -197,6 +196,10 @@ fun <T> concatIterators(a: Iterator<T>): MutableIterator<T> {
|
||||
return a as MutableIterator<T>
|
||||
}
|
||||
|
||||
fun <T> concatIterators(iterators: Iterable<Iterator<T>>): MutableIterator<T> {
|
||||
return iterators.iterator().flatMap { it }
|
||||
}
|
||||
|
||||
fun <T> concatIterators(vararg iterators: Iterator<T>): MutableIterator<T> {
|
||||
return iterators.iterator().flatMap { it }
|
||||
}
|
||||
@ -243,7 +246,7 @@ fun <T> Iterator<T>.reduce(identity: T, reducer: (T, T) -> T): T {
|
||||
}
|
||||
|
||||
fun <T> Iterator<T>.reduce(identity: T, reducer: BinaryOperator<T>): T = reduce(identity, reducer::apply)
|
||||
fun <T> Iterator<T?>.filterNotNull(): Iterator<T> = filter { it != null } as Iterator<T>
|
||||
fun <T> Iterator<T?>.filterNotNull(): MutableIterator<T> = filter { it != null } as MutableIterator<T>
|
||||
|
||||
fun <T> Iterator<T>.any(predicate: Predicate<in T>): Boolean {
|
||||
for (value in this) {
|
||||
@ -363,3 +366,7 @@ fun <T> Iterator<T>.maybe(): T? {
|
||||
else
|
||||
null
|
||||
}
|
||||
|
||||
fun <T> emptyIterator(): MutableIterator<T> {
|
||||
return ObjectIterators.emptyIterator()
|
||||
}
|
||||
|
@ -1,53 +1,76 @@
|
||||
package ru.dbotthepony.mc.otm.core.collect
|
||||
|
||||
import java.util.WeakHashMap
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenCustomHashSet
|
||||
import ru.dbotthepony.mc.otm.core.util.HashedWeakReference
|
||||
import java.lang.ref.ReferenceQueue
|
||||
|
||||
/**
|
||||
* Wrapper around [WeakHashMap] to behave like set
|
||||
*/
|
||||
class WeakHashSet<E : Any> : MutableSet<E> {
|
||||
private val backing = WeakHashMap<E, Unit>()
|
||||
private val queue = ReferenceQueue<E>()
|
||||
private val backing = ObjectOpenCustomHashSet<Any>(ReferenceHashStrategy)
|
||||
|
||||
private fun purge() {
|
||||
var next = queue.poll()
|
||||
|
||||
while (next != null) {
|
||||
backing.remove(next)
|
||||
next = queue.poll()
|
||||
}
|
||||
}
|
||||
|
||||
override fun add(element: E): Boolean {
|
||||
return backing.put(element, Unit) == null
|
||||
purge()
|
||||
if (element in backing) return false
|
||||
return backing.add(HashedWeakReference(element, queue))
|
||||
}
|
||||
|
||||
override fun addAll(elements: Collection<E>): Boolean {
|
||||
return elements.count(::add) > 0
|
||||
var any = false
|
||||
elements.forEach { any = add(it) || any }
|
||||
return any
|
||||
}
|
||||
|
||||
override fun clear() {
|
||||
backing.clear()
|
||||
while (queue.poll() != null) {}
|
||||
}
|
||||
|
||||
override fun iterator(): MutableIterator<E> {
|
||||
return backing.keys.iterator()
|
||||
purge()
|
||||
return backing.iterator().map { (it as HashedWeakReference<E>).get() }.filterNotNull()
|
||||
}
|
||||
|
||||
override fun remove(element: E): Boolean {
|
||||
return backing.remove(element) != null
|
||||
purge()
|
||||
return backing.remove(element)
|
||||
}
|
||||
|
||||
override fun removeAll(elements: Collection<E>): Boolean {
|
||||
return backing.keys.removeAll(elements)
|
||||
purge()
|
||||
return backing.removeAll(elements)
|
||||
}
|
||||
|
||||
override fun retainAll(elements: Collection<E>): Boolean {
|
||||
return backing.keys.retainAll(elements)
|
||||
purge()
|
||||
return backing.retainAll(elements)
|
||||
}
|
||||
|
||||
override val size: Int
|
||||
get() = backing.size
|
||||
override val size: Int get() {
|
||||
purge()
|
||||
return backing.size
|
||||
}
|
||||
|
||||
override fun contains(element: E): Boolean {
|
||||
return backing.get(element) === Unit
|
||||
purge()
|
||||
return backing.contains(element)
|
||||
}
|
||||
|
||||
override fun containsAll(elements: Collection<E>): Boolean {
|
||||
return elements.all(::contains)
|
||||
purge()
|
||||
return backing.containsAll(elements)
|
||||
}
|
||||
|
||||
override fun isEmpty(): Boolean {
|
||||
purge()
|
||||
return backing.isEmpty()
|
||||
}
|
||||
}
|
||||
|
@ -665,7 +665,7 @@ class Decimal private constructor(val mag: BigInteger, marker: Nothing?) : Numbe
|
||||
|
||||
@JvmStatic
|
||||
fun read(buff: FriendlyByteBuf): Decimal {
|
||||
return Decimal(BigInteger(buff.readByteArray()))
|
||||
return Decimal(BigInteger(buff.readByteArray()), null)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,42 @@
|
||||
package ru.dbotthepony.mc.otm.core.util
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
|
||||
class AtomicallyInvalidatedLazy<V>(private val invalidator: AtomicInteger, private val initializer: () -> V) : Lazy<V> {
|
||||
@Volatile
|
||||
private var thisCounter = -1
|
||||
@Volatile
|
||||
private var stored: Any? = Companion
|
||||
private val lock = ReentrantLock()
|
||||
|
||||
override val value: V get() {
|
||||
if (thisCounter != invalidator.get()) {
|
||||
lock.lock()
|
||||
this.stored = Companion
|
||||
thisCounter = invalidator.get()
|
||||
lock.unlock()
|
||||
}
|
||||
|
||||
var stored = stored
|
||||
|
||||
if (stored !== Companion)
|
||||
return stored as V
|
||||
|
||||
lock.lock()
|
||||
|
||||
try {
|
||||
stored = initializer.invoke()
|
||||
this.stored = stored
|
||||
return stored
|
||||
} finally {
|
||||
lock.unlock()
|
||||
}
|
||||
}
|
||||
|
||||
override fun isInitialized(): Boolean {
|
||||
return stored !== Companion && thisCounter == invalidator.get()
|
||||
}
|
||||
|
||||
private companion object
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package ru.dbotthepony.mc.otm.core.util
|
||||
|
||||
import java.lang.ref.ReferenceQueue
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
/**
|
||||
* [WeakReference], but with [hashCode] overridden with hash of referent object
|
||||
*/
|
||||
@Suppress("EqualsOrHashCode")
|
||||
class HashedWeakReference<T : Any> : WeakReference<T> {
|
||||
constructor(value: T) : super(value) {
|
||||
hash = value.hashCode()
|
||||
}
|
||||
|
||||
constructor(value: T, queue: ReferenceQueue<T>) : super(value, queue) {
|
||||
hash = value.hashCode()
|
||||
}
|
||||
|
||||
private val hash: Int
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return hash
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "HashedWeakReference[hash=$hash]"
|
||||
}
|
||||
}
|
@ -7,7 +7,8 @@ import net.minecraft.world.level.storage.loot.LootContext
|
||||
import net.minecraft.world.level.storage.loot.parameters.LootContextParams
|
||||
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition
|
||||
import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType
|
||||
import ru.dbotthepony.mc.otm.capability.itemsStream
|
||||
import ru.dbotthepony.mc.otm.capability.items
|
||||
import ru.dbotthepony.mc.otm.core.collect.filter
|
||||
import ru.dbotthepony.mc.otm.data.Codec2Serializer
|
||||
import ru.dbotthepony.mc.otm.data.get
|
||||
import ru.dbotthepony.mc.otm.registry.MLootItemConditions
|
||||
@ -19,7 +20,7 @@ data class ItemInInventoryCondition(
|
||||
val matchCosmetics: Boolean = true,
|
||||
) : LootItemCondition, LootItemCondition.Builder {
|
||||
override fun test(t: LootContext): Boolean {
|
||||
val matches = t[LootContextParams.LAST_DAMAGE_PLAYER]?.itemsStream(matchCosmetics)?.filter {
|
||||
val matches = t[LootContextParams.LAST_DAMAGE_PLAYER]?.items(matchCosmetics)?.filter {
|
||||
if (it.isEmpty) {
|
||||
return@filter false
|
||||
}
|
||||
|
@ -1,17 +1,18 @@
|
||||
package ru.dbotthepony.mc.otm.item
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectFunction
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
|
||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet
|
||||
import net.minecraft.ChatFormatting
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.nbt.ByteArrayTag
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.Tag
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.world.item.*
|
||||
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.minecraft.world.level.saveddata.SavedData
|
||||
import net.minecraftforge.client.event.ClientPlayerNetworkEvent
|
||||
import net.minecraftforge.common.capabilities.Capability
|
||||
import net.minecraftforge.common.capabilities.ForgeCapabilities
|
||||
@ -21,63 +22,140 @@ import net.minecraftforge.event.TickEvent
|
||||
import net.minecraftforge.event.TickEvent.ServerTickEvent
|
||||
import net.minecraftforge.network.NetworkEvent
|
||||
import net.minecraftforge.registries.ForgeRegistries
|
||||
import net.minecraftforge.registries.ForgeRegistry
|
||||
import ru.dbotthepony.mc.otm.*
|
||||
import ru.dbotthepony.mc.otm.capability.*
|
||||
import ru.dbotthepony.mc.otm.capability.FlowDirection
|
||||
import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
||||
import ru.dbotthepony.mc.otm.capability.allItems
|
||||
import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage
|
||||
import ru.dbotthepony.mc.otm.capability.energy.getBarColor
|
||||
import ru.dbotthepony.mc.otm.capability.energy.getBarWidth
|
||||
import ru.dbotthepony.mc.otm.capability.isMekanismLoaded
|
||||
import ru.dbotthepony.mc.otm.capability.matteryEnergy
|
||||
import ru.dbotthepony.mc.otm.compat.mekanism.Mattery2MekanismEnergyWrapper
|
||||
import ru.dbotthepony.mc.otm.config.EnergyBalanceValues
|
||||
import ru.dbotthepony.mc.otm.core.*
|
||||
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||
import ru.dbotthepony.mc.otm.core.collect.filter
|
||||
import ru.dbotthepony.mc.otm.core.getID
|
||||
import ru.dbotthepony.mc.otm.core.getValue
|
||||
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||
import ru.dbotthepony.mc.otm.core.math.getDecimal
|
||||
import ru.dbotthepony.mc.otm.core.math.readDecimal
|
||||
import ru.dbotthepony.mc.otm.core.math.set
|
||||
import ru.dbotthepony.mc.otm.core.math.writeDecimal
|
||||
import ru.dbotthepony.mc.otm.core.nbt.getUUIDSafe
|
||||
import ru.dbotthepony.mc.otm.core.nbt.set
|
||||
import ru.dbotthepony.mc.otm.core.orThrow
|
||||
import ru.dbotthepony.mc.otm.core.tagNotNull
|
||||
import ru.dbotthepony.mc.otm.core.util.formatPower
|
||||
import ru.dbotthepony.mc.otm.isClientThread
|
||||
import ru.dbotthepony.mc.otm.isServerThread
|
||||
import ru.dbotthepony.mc.otm.lazyPerServer
|
||||
import ru.dbotthepony.mc.otm.network.GenericNetworkChannel
|
||||
import ru.dbotthepony.mc.otm.network.MatteryPacket
|
||||
import ru.dbotthepony.mc.otm.network.packetHandled
|
||||
import ru.dbotthepony.mc.otm.saveddata.SavedCountingMap
|
||||
import java.util.*
|
||||
import java.util.function.Function
|
||||
import java.util.function.Supplier
|
||||
import kotlin.collections.MutableList
|
||||
import kotlin.collections.component1
|
||||
import kotlin.collections.component2
|
||||
import kotlin.collections.forEach
|
||||
import kotlin.collections.iterator
|
||||
import kotlin.collections.set
|
||||
|
||||
class QuantumBatteryItem : Item {
|
||||
class Data(
|
||||
val parent: SavedCountingMap<Data>?,
|
||||
val index: Int = -1,
|
||||
energy: Decimal = Decimal.ZERO,
|
||||
passed: Decimal = Decimal.ZERO,
|
||||
received: Decimal = Decimal.ZERO,
|
||||
) {
|
||||
constructor(
|
||||
energy: Decimal = Decimal.ZERO,
|
||||
passed: Decimal = Decimal.ZERO,
|
||||
received: Decimal = Decimal.ZERO,
|
||||
) : this(null, -1, energy, passed, received)
|
||||
class QuantumBatteryItem(val savedataID: String, val balanceValues: EnergyBalanceValues?) : Item(Properties().stacksTo(1).rarity(if (balanceValues == null) Rarity.EPIC else Rarity.UNCOMMON)) {
|
||||
val isCreative = balanceValues == null
|
||||
|
||||
var energy: Decimal = energy
|
||||
interface IValues {
|
||||
val uuid: UUID
|
||||
var energy: Decimal
|
||||
var passed: Decimal
|
||||
var received: Decimal
|
||||
val isServer: Boolean
|
||||
|
||||
fun serialize(): CompoundTag {
|
||||
return CompoundTag().also {
|
||||
it["energy"] = energy
|
||||
it["passed"] = passed
|
||||
it["received"] = received
|
||||
}
|
||||
}
|
||||
|
||||
fun deserialize(nbt: CompoundTag) {
|
||||
energy = nbt.getDecimal("energy")
|
||||
passed = nbt.getDecimal("passed")
|
||||
received = nbt.getDecimal("received")
|
||||
}
|
||||
}
|
||||
|
||||
class UnboundValues(override val uuid: UUID = UUID.randomUUID()) : IValues {
|
||||
override var energy: Decimal = Decimal.ZERO
|
||||
override var passed: Decimal = Decimal.ZERO
|
||||
override var received: Decimal = Decimal.ZERO
|
||||
override val isServer: Boolean
|
||||
get() = false
|
||||
}
|
||||
|
||||
class Data() : SavedData() {
|
||||
constructor(nbt: CompoundTag) : this() {
|
||||
load(nbt)
|
||||
}
|
||||
|
||||
inner class Values(override val uuid: UUID) : IValues {
|
||||
override var energy = Decimal.ZERO
|
||||
set(value) {
|
||||
if (field != value) {
|
||||
field = value
|
||||
parent?.isDirty = true
|
||||
isDirty = true
|
||||
}
|
||||
|
||||
override var passed = Decimal.ZERO
|
||||
set(value) {
|
||||
field = value
|
||||
isDirty = true
|
||||
}
|
||||
|
||||
override var received = Decimal.ZERO
|
||||
set(value) {
|
||||
field = value
|
||||
isDirty = true
|
||||
}
|
||||
|
||||
override val isServer: Boolean
|
||||
get() = true
|
||||
}
|
||||
|
||||
private val data = Object2ObjectOpenHashMap<UUID, Values>()
|
||||
|
||||
fun values(uuid: UUID): Values {
|
||||
return data.computeIfAbsent(uuid, Function { Values(uuid) })
|
||||
}
|
||||
|
||||
fun values(): Values {
|
||||
return values(UUID.randomUUID())
|
||||
}
|
||||
|
||||
override fun save(nbt: CompoundTag): CompoundTag {
|
||||
for ((key, values) in data) {
|
||||
nbt[key.toString()] = values.serialize()
|
||||
}
|
||||
|
||||
return nbt
|
||||
}
|
||||
|
||||
fun load(nbt: CompoundTag) {
|
||||
data.clear()
|
||||
|
||||
for (key in nbt.allKeys) {
|
||||
val id = UUID.fromString(key)
|
||||
data[id] = Values(id).also { it.deserialize(nbt.getCompound(key)) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var passed: Decimal = passed
|
||||
set(value) {
|
||||
if (field != value) {
|
||||
field = value
|
||||
parent?.isDirty = true
|
||||
}
|
||||
}
|
||||
val clientData = Object2ObjectOpenHashMap<UUID, IValues>()
|
||||
|
||||
var received: Decimal = received
|
||||
set(value) {
|
||||
if (field != value) {
|
||||
field = value
|
||||
parent?.isDirty = true
|
||||
}
|
||||
}
|
||||
val serverData: Data by lazyPerServer {
|
||||
it.overworld().dataStorage.computeIfAbsent(::Data, ::Data, "otm_$savedataID")
|
||||
}
|
||||
|
||||
private inner class Power(private val stack: ItemStack) : IMatteryEnergyStorage, ICapabilityProvider {
|
||||
@ -87,7 +165,18 @@ class QuantumBatteryItem : Item {
|
||||
override val energyFlow: FlowDirection
|
||||
get() = FlowDirection.BI_DIRECTIONAL
|
||||
|
||||
var data = Data()
|
||||
var values: IValues = UnboundValues()
|
||||
|
||||
fun updateValues() {
|
||||
if (!values.isServer && isServerThread()) {
|
||||
values = serverData.values(stack.tag?.getUUIDSafe("id") ?: UUID.randomUUID().also { stack.tagNotNull["id"] = it })
|
||||
} else if (isClientThread()) {
|
||||
val id = stack.tag?.getUUIDSafe("id") ?: return
|
||||
|
||||
if (values.uuid != id)
|
||||
values = clientData.computeIfAbsent(id, Function { UnboundValues(it) })
|
||||
}
|
||||
}
|
||||
|
||||
override fun <T : Any?> getCapability(cap: Capability<T>, side: Direction?): LazyOptional<T> {
|
||||
if (cap == ForgeCapabilities.ENERGY || cap == MatteryCapability.ENERGY) {
|
||||
@ -100,253 +189,107 @@ class QuantumBatteryItem : Item {
|
||||
}
|
||||
|
||||
override fun extractEnergy(howMuch: Decimal, simulate: Boolean): Decimal {
|
||||
if (howMuch.isNegative) {
|
||||
if (!howMuch.isPositive)
|
||||
return Decimal.ZERO
|
||||
}
|
||||
|
||||
if (data.parent == null && isServerThread()) {
|
||||
determineQuantumLink()
|
||||
updateValues()
|
||||
|
||||
if (data.parent == null) {
|
||||
if (!values.isServer && !simulate)
|
||||
return Decimal.ZERO
|
||||
}
|
||||
}
|
||||
|
||||
if (isCreative) {
|
||||
val newEnergy = (data.energy - howMuch).moreThanZero()
|
||||
val diff = data.energy - newEnergy
|
||||
if (balanceValues == null) {
|
||||
val newEnergy = (values.energy - howMuch).moreThanZero()
|
||||
val diff = values.energy - newEnergy
|
||||
|
||||
if (!simulate) {
|
||||
data.energy = newEnergy
|
||||
data.passed += diff
|
||||
values.energy = newEnergy
|
||||
values.passed += diff
|
||||
}
|
||||
|
||||
return diff
|
||||
} else {
|
||||
val newEnergy = (values.energy - howMuch.coerceAtMost(balanceValues.energyThroughput)).moreThanZero()
|
||||
val diff = values.energy - newEnergy
|
||||
|
||||
if (!simulate) {
|
||||
values.energy = newEnergy
|
||||
values.passed += diff
|
||||
}
|
||||
|
||||
return diff
|
||||
}
|
||||
|
||||
val newEnergy = (data.energy - howMuch.coerceAtMost(throughput!!)).moreThanZero()
|
||||
val diff = data.energy - newEnergy
|
||||
|
||||
if (!simulate) {
|
||||
data.energy = newEnergy
|
||||
data.passed += diff
|
||||
}
|
||||
|
||||
return diff
|
||||
}
|
||||
|
||||
override fun receiveEnergy(howMuch: Decimal, simulate: Boolean): Decimal {
|
||||
if (howMuch.isNegative) {
|
||||
if (!howMuch.isPositive)
|
||||
return Decimal.ZERO
|
||||
}
|
||||
|
||||
if (data.parent == null && isServerThread()) {
|
||||
determineQuantumLink()
|
||||
updateValues()
|
||||
|
||||
if (data.parent == null) {
|
||||
if (!values.isServer && !simulate)
|
||||
return Decimal.ZERO
|
||||
}
|
||||
}
|
||||
|
||||
if (isCreative) {
|
||||
if (balanceValues == null) {
|
||||
if (!simulate) {
|
||||
data.energy += howMuch
|
||||
data.received += howMuch
|
||||
values.energy += howMuch
|
||||
values.received += howMuch
|
||||
}
|
||||
|
||||
return howMuch
|
||||
}
|
||||
|
||||
if (data.energy >= capacity!!) {
|
||||
} else if (values.energy >= balanceValues.energyCapacity) {
|
||||
return Decimal.ZERO
|
||||
}
|
||||
|
||||
val newEnergy = (data.energy + howMuch.coerceAtMost(throughput!!)).coerceAtMost(capacity!!)
|
||||
val diff = newEnergy - data.energy
|
||||
} else {
|
||||
val newEnergy = (values.energy + howMuch.coerceAtMost(balanceValues.energyThroughput)).coerceAtMost(balanceValues.energyCapacity)
|
||||
val diff = newEnergy - values.energy
|
||||
|
||||
if (!simulate) {
|
||||
data.energy = newEnergy
|
||||
data.received += diff
|
||||
values.energy = newEnergy
|
||||
values.received += diff
|
||||
}
|
||||
|
||||
return diff
|
||||
}
|
||||
}
|
||||
|
||||
override var batteryLevel: Decimal
|
||||
get() {
|
||||
if (data.parent == null) {
|
||||
determineQuantumLink()
|
||||
}
|
||||
|
||||
if (isClientThread()) {
|
||||
return clientPowerMap[data.index]?.energy ?: data.energy
|
||||
}
|
||||
|
||||
return data.energy
|
||||
updateValues()
|
||||
return values.energy
|
||||
}
|
||||
set(value) {
|
||||
if (data.parent == null) {
|
||||
determineQuantumLink()
|
||||
updateValues()
|
||||
values.energy = value
|
||||
}
|
||||
|
||||
if (isClientThread()) {
|
||||
val energy1 = clientPowerMap[data.index]
|
||||
|
||||
if (energy1 != null) {
|
||||
energy1.energy = value
|
||||
} else {
|
||||
data.energy = value
|
||||
val passed: Decimal get() {
|
||||
updateValues()
|
||||
return values.passed
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
data.energy = value
|
||||
}
|
||||
|
||||
val passed: Decimal
|
||||
get() {
|
||||
if (data.parent == null) {
|
||||
determineQuantumLink()
|
||||
}
|
||||
|
||||
if (isClientThread()) {
|
||||
return clientPowerMap[data.index]?.passed ?: data.passed
|
||||
}
|
||||
|
||||
return data.passed
|
||||
}
|
||||
|
||||
val received: Decimal
|
||||
get() {
|
||||
if (data.parent == null) {
|
||||
determineQuantumLink()
|
||||
}
|
||||
|
||||
if (isClientThread()) {
|
||||
return clientPowerMap[data.index]?.received ?: data.received
|
||||
}
|
||||
|
||||
return data.received
|
||||
val received: Decimal get() {
|
||||
updateValues()
|
||||
return values.received
|
||||
}
|
||||
|
||||
override val maxBatteryLevel: Decimal
|
||||
get() = capacity ?: (batteryLevel + Decimal.LONG_MAX_VALUE)
|
||||
get() = balanceValues?.energyCapacity ?: (batteryLevel + Decimal.LONG_MAX_VALUE)
|
||||
|
||||
override val missingPower: Decimal
|
||||
get() = if (isCreative) Decimal.LONG_MAX_VALUE else super.missingPower
|
||||
|
||||
private fun determineQuantumLink() {
|
||||
if (data.parent == null && isServerThread()) {
|
||||
val existing = stack.tag?.getInt("link_id")
|
||||
|
||||
if (existing == null) {
|
||||
val old = data
|
||||
data = saveData!!.factorize()
|
||||
data.energy = old.energy
|
||||
stack.tagNotNull["link_id"] = data.index
|
||||
} else {
|
||||
data = saveData?.computeIfAbsent(existing) ?: Data(null, existing, data.energy, data.passed, data.received)
|
||||
}
|
||||
} else if (!isServerThread()) {
|
||||
// client ?
|
||||
val existing = stack.tag?.getInt("link_id") ?: return
|
||||
|
||||
if (existing != data.index) {
|
||||
data = Data(data.parent, existing, data.energy, data.passed, data.received)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun determineQuantumLinkWeak() {
|
||||
if (data.parent == null && isServerThread()) {
|
||||
val existing = stack.tag?.getInt("link_id")
|
||||
|
||||
if (existing != null) {
|
||||
data = saveData?.computeIfAbsent(existing) ?: Data(null, existing, data.energy, data.passed, data.received)
|
||||
}
|
||||
} else if (!isServerThread()) {
|
||||
val existing = stack.tag?.getInt("link_id") ?: return
|
||||
|
||||
if (existing != data.index) {
|
||||
data = Data(data.parent, existing, data.energy, data.passed, data.received)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val isCreative: Boolean
|
||||
|
||||
private val _capacity: () -> Decimal?
|
||||
private val _throughput: () -> Decimal?
|
||||
|
||||
val capacity get() = _capacity.invoke()
|
||||
val throughput get() = _throughput.invoke()
|
||||
|
||||
val saveDataID: String
|
||||
|
||||
val saveData: SavedCountingMap<Data>? get() {
|
||||
if (isServerThread()) {
|
||||
return MINECRAFT_SERVER.overworld().dataStorage.computeIfAbsent({
|
||||
SavedCountingMap(Companion::storeValue, Companion::loadValue, ::Data).load(it)
|
||||
}, {
|
||||
SavedCountingMap(Companion::storeValue, Companion::loadValue, ::Data)
|
||||
}, saveDataID) ?: throw NullPointerException("Unable to get save data for $this in ${MINECRAFT_SERVER.overworld()}")
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
data class ClientData(
|
||||
var energy: Decimal = Decimal.ZERO,
|
||||
var passed: Decimal = Decimal.ZERO,
|
||||
var received: Decimal = Decimal.ZERO,
|
||||
)
|
||||
|
||||
val clientPowerMap: Int2ObjectOpenHashMap<ClientData> by lazy {
|
||||
check(isClient) { "Invalid side" }
|
||||
Int2ObjectOpenHashMap()
|
||||
}
|
||||
|
||||
constructor(saveDataID: String) : super(Properties().stacksTo(1).rarity(Rarity.EPIC)) {
|
||||
isCreative = true
|
||||
_capacity = { null }
|
||||
_throughput = { null }
|
||||
this.saveDataID = "otm_$saveDataID".intern()
|
||||
}
|
||||
|
||||
constructor(saveDataID: String, capacity: Decimal, io: Decimal) : super(Properties().stacksTo(1)) {
|
||||
isCreative = false
|
||||
_capacity = { capacity }
|
||||
_throughput = { io }
|
||||
this.saveDataID = "otm_$saveDataID".intern()
|
||||
}
|
||||
|
||||
constructor(saveDataID: String, values: EnergyBalanceValues) : super(Properties().stacksTo(1)) {
|
||||
isCreative = false
|
||||
_capacity = values::energyCapacity
|
||||
_throughput = values::energyThroughput
|
||||
this.saveDataID = "otm_$saveDataID".intern()
|
||||
}
|
||||
|
||||
override fun isBarVisible(p_150899_: ItemStack): Boolean {
|
||||
if (isCreative)
|
||||
return false
|
||||
|
||||
if (isCreative) return false
|
||||
return p_150899_.matteryEnergy != null
|
||||
}
|
||||
|
||||
override fun getBarWidth(p_150900_: ItemStack): Int {
|
||||
if (isCreative)
|
||||
return 13
|
||||
|
||||
if (isCreative) return 13
|
||||
return p_150900_.matteryEnergy?.getBarWidth() ?: super.getBarWidth(p_150900_)
|
||||
}
|
||||
|
||||
override fun getBarColor(p_150901_: ItemStack): Int {
|
||||
if (isCreative)
|
||||
return 0
|
||||
|
||||
if (isCreative) return 0
|
||||
return p_150901_.matteryEnergy?.getBarColor() ?: super.getBarColor(p_150901_)
|
||||
}
|
||||
|
||||
@ -354,29 +297,19 @@ class QuantumBatteryItem : Item {
|
||||
return Power(stack)
|
||||
}
|
||||
|
||||
override fun appendHoverText(
|
||||
itemStack: ItemStack,
|
||||
p_41422_: Level?,
|
||||
components: MutableList<Component>,
|
||||
p_41424_: TooltipFlag
|
||||
) {
|
||||
super.appendHoverText(itemStack, p_41422_, components, p_41424_)
|
||||
override fun appendHoverText(itemStack: ItemStack, level: Level?, components: MutableList<Component>, flags: TooltipFlag) {
|
||||
super.appendHoverText(itemStack, level, components, flags)
|
||||
|
||||
val power = itemStack.getCapability(MatteryCapability.ENERGY).orThrow() as Power
|
||||
power.updateValues()
|
||||
|
||||
components.add(TranslatableComponent("otm.item.quantum_description").withStyle(ChatFormatting.DARK_GRAY))
|
||||
|
||||
if (isCreative) {
|
||||
if (balanceValues == null) {
|
||||
components.add(TranslatableComponent("otm.item.quantum_battery.creative_power", power.batteryLevel.formatPower()).withStyle(ChatFormatting.GRAY))
|
||||
} else {
|
||||
components.add(TranslatableComponent("otm.item.power.storage", power.batteryLevel.formatPower(), capacity!!.formatPower()).withStyle(ChatFormatting.GRAY))
|
||||
|
||||
components.add(
|
||||
TranslatableComponent(
|
||||
"otm.item.power.throughput",
|
||||
throughput!!.formatPower(),
|
||||
throughput!!.formatPower()
|
||||
).withStyle(ChatFormatting.GRAY))
|
||||
components.add(TranslatableComponent("otm.item.power.storage", power.batteryLevel.formatPower(), balanceValues.energyCapacity.formatPower()).withStyle(ChatFormatting.GRAY))
|
||||
components.add(TranslatableComponent("otm.item.power.throughput_mono", balanceValues.energyThroughput.formatPower()).withStyle(ChatFormatting.GRAY))
|
||||
}
|
||||
|
||||
components.add(TranslatableComponent("otm.item.power.passed", power.passed.formatPower()).withStyle(ChatFormatting.GRAY))
|
||||
@ -387,18 +320,18 @@ class QuantumBatteryItem : Item {
|
||||
components.add(TranslatableComponent("otm.item.quantum_battery.creative2").withStyle(ChatFormatting.DARK_GRAY))
|
||||
}
|
||||
|
||||
components.add(TranslatableComponent("otm.item.quantum_link_id", power.data.index).withStyle(ChatFormatting.DARK_GRAY))
|
||||
components.add(TranslatableComponent("otm.item.quantum_link_id", power.values.uuid).withStyle(ChatFormatting.DARK_GRAY))
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun clientDisconnect(event: ClientPlayerNetworkEvent.LoggingOut) {
|
||||
ForgeRegistries.ITEMS.values.stream().forEach { if (it is QuantumBatteryItem) it.clientPowerMap.clear() }
|
||||
ForgeRegistries.ITEMS.values.forEach { if (it is QuantumBatteryItem) it.clientData.clear() }
|
||||
}
|
||||
|
||||
fun readPacket(buff: FriendlyByteBuf): ChargePacket {
|
||||
return ChargePacket(
|
||||
(ForgeRegistries.ITEMS as ForgeRegistry<Item>).getValue(buff.readInt()) as QuantumBatteryItem,
|
||||
buff.readInt(),
|
||||
ForgeRegistries.ITEMS.getValue(buff.readInt()) as QuantumBatteryItem,
|
||||
buff.readUUID(),
|
||||
buff.readDecimal(),
|
||||
buff.readDecimal(),
|
||||
buff.readDecimal(),
|
||||
@ -408,54 +341,33 @@ class QuantumBatteryItem : Item {
|
||||
fun tick(event: ServerTickEvent) {
|
||||
if (event.phase == TickEvent.Phase.END) {
|
||||
for (ply in event.server.playerList.players) {
|
||||
val networkedChannels = IntOpenHashSet(0)
|
||||
val networkedChannels = ObjectOpenHashSet<UUID>(0)
|
||||
|
||||
for (item in ply.allItemsStream().filter { !it.isEmpty && it.item is QuantumBatteryItem }) {
|
||||
for (item in ply.allItems().filter { it.isNotEmpty && it.item is QuantumBatteryItem }) {
|
||||
val power = item.getCapability(MatteryCapability.ENERGY).orThrow() as Power
|
||||
|
||||
power.determineQuantumLinkWeak()
|
||||
|
||||
if (power.data.index < 0) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (networkedChannels.add(power.data.index)) {
|
||||
GenericNetworkChannel.send(ply, ChargePacket(item.item as QuantumBatteryItem, power.data.index, power.batteryLevel, power.data.passed, power.data.received))
|
||||
power.updateValues()
|
||||
if (power.values.isServer && networkedChannels.add(power.values.uuid)) {
|
||||
GenericNetworkChannel.send(ply, ChargePacket(item.item as QuantumBatteryItem, power.values.uuid, power.batteryLevel, power.passed, power.received))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadValue(parent: SavedCountingMap<Data>, tag: Tag, index: Int): Data {
|
||||
if (tag is ByteArrayTag) {
|
||||
return Data(parent, index, Decimal.deserializeNBT(tag))
|
||||
} else if (tag is CompoundTag) {
|
||||
return Data(parent, index, Decimal.deserializeNBT(tag["energy"]), Decimal.deserializeNBT(tag["passed"]), Decimal.deserializeNBT(tag["received"]))
|
||||
} else {
|
||||
return Data(parent, index)
|
||||
}
|
||||
}
|
||||
|
||||
private fun storeValue(parent: SavedCountingMap<Data>, value: Data, index: Int): CompoundTag {
|
||||
return CompoundTag().also {
|
||||
it["energy"] = value.energy.serializeNBT()
|
||||
it["passed"] = value.passed.serializeNBT()
|
||||
it["received"] = value.received.serializeNBT()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ChargePacket(
|
||||
val type: QuantumBatteryItem,
|
||||
val channel: Int,
|
||||
val energy: Decimal,
|
||||
val passed: Decimal,
|
||||
val received: Decimal,
|
||||
) : MatteryPacket {
|
||||
override val uuid: UUID,
|
||||
override var energy: Decimal,
|
||||
override var passed: Decimal,
|
||||
override var received: Decimal,
|
||||
) : MatteryPacket, IValues {
|
||||
override val isServer: Boolean
|
||||
get() = false
|
||||
|
||||
override fun write(buff: FriendlyByteBuf) {
|
||||
buff.writeInt((ForgeRegistries.ITEMS as ForgeRegistry<Item>).getID(type))
|
||||
buff.writeInt(channel)
|
||||
buff.writeInt(ForgeRegistries.ITEMS.getID(type))
|
||||
buff.writeUUID(uuid)
|
||||
buff.writeDecimal(energy)
|
||||
buff.writeDecimal(passed)
|
||||
buff.writeDecimal(received)
|
||||
@ -463,7 +375,7 @@ class QuantumBatteryItem : Item {
|
||||
|
||||
override fun play(context: Supplier<NetworkEvent.Context>) {
|
||||
context.packetHandled = true
|
||||
val data = type.clientPowerMap.computeIfAbsent(channel, Int2ObjectFunction { ClientData() })
|
||||
val data = type.clientData.computeIfAbsent(uuid, Function { UnboundValues(it) })
|
||||
data.energy = energy
|
||||
data.passed = passed
|
||||
data.received = received
|
||||
|
@ -351,7 +351,7 @@ object MItems {
|
||||
|
||||
val QUANTUM_BATTERY: QuantumBatteryItem by registry.register(MNames.QUANTUM_BATTERY) { QuantumBatteryItem(MNames.QUANTUM_BATTERY, ItemsConfig.Batteries.QUANTUM_BATTERY) }
|
||||
val QUANTUM_CAPACITOR: QuantumBatteryItem by registry.register(MNames.QUANTUM_CAPACITOR) { QuantumBatteryItem(MNames.QUANTUM_CAPACITOR, ItemsConfig.Batteries.QUANTUM_CAPACITOR) }
|
||||
val QUANTUM_BATTERY_CREATIVE: QuantumBatteryItem by registry.register(MNames.QUANTUM_BATTERY_CREATIVE) { QuantumBatteryItem(MNames.QUANTUM_BATTERY_CREATIVE) }
|
||||
val QUANTUM_BATTERY_CREATIVE: QuantumBatteryItem by registry.register(MNames.QUANTUM_BATTERY_CREATIVE) { QuantumBatteryItem(MNames.QUANTUM_BATTERY_CREATIVE, null) }
|
||||
val ZPM_BATTERY: ZPMItem by registry.register(MNames.ZPM_BATTERY) { ZPMItem() }
|
||||
val PROCEDURAL_BATTERY: ProceduralBatteryItem by registry.register(MNames.PROCEDURAL_BATTERY) { ProceduralBatteryItem() }
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user