container objects "functional"
This commit is contained in:
parent
77aa05d9f3
commit
9f52e2314d
src/main/kotlin/ru/dbotthepony/kstarbound
@ -234,7 +234,10 @@ object Starbound : BlockableEventLoop("Universe Thread"), Scheduler, ISBFileLoca
|
||||
throw NoSuchElementException("Script $path does not exist")
|
||||
}
|
||||
|
||||
return loader.compileTextChunk(path, find.readToString())
|
||||
val time = System.nanoTime()
|
||||
val result = loader.compileTextChunk(path, find.readToString())
|
||||
LOGGER.debug("Compiled {} in {} ms", path, (System.nanoTime() - time) / 1_000_000L)
|
||||
return result
|
||||
}
|
||||
|
||||
fun loadScript(path: String): ChunkFactory {
|
||||
|
@ -35,6 +35,7 @@ import ru.dbotthepony.kstarbound.io.readInternedString
|
||||
import ru.dbotthepony.kstarbound.item.ItemStack
|
||||
import ru.dbotthepony.kstarbound.json.readJsonElement
|
||||
import ru.dbotthepony.kstarbound.json.writeJsonElement
|
||||
import ru.dbotthepony.kstarbound.lua.get
|
||||
import ru.dbotthepony.kstarbound.lua.indexNoYield
|
||||
import ru.dbotthepony.kstarbound.lua.toJson
|
||||
import java.io.DataInputStream
|
||||
@ -109,6 +110,24 @@ fun ExecutionContext.ItemDescriptor(data: Table): ItemDescriptor {
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("Does not obey meta methods, need to find replacement where possible")
|
||||
fun ItemDescriptor(data: Table): ItemDescriptor {
|
||||
val name = data[1L] ?: data["name"] ?: data["item"]
|
||||
val count = data[2L] ?: data["count"] ?: 1L
|
||||
val parameters = data[3L] ?: data["parameters"] ?: data["data"]
|
||||
|
||||
if (name !is ByteString) throw LuaRuntimeException("Invalid item descriptor name (${name})")
|
||||
if (count !is Number) throw LuaRuntimeException("Invalid item descriptor count (${count})")
|
||||
|
||||
if (parameters == null) {
|
||||
return ItemDescriptor(name.decode(), count.toLong())
|
||||
} else if (parameters is Table) {
|
||||
return ItemDescriptor(name.decode(), count.toLong(), parameters.toJson(true) as JsonObject)
|
||||
} else {
|
||||
throw LuaRuntimeException("Invalid item descriptor parameters ($parameters)")
|
||||
}
|
||||
}
|
||||
|
||||
fun ItemDescriptor(stream: DataInputStream): ItemDescriptor {
|
||||
val name = stream.readInternedString()
|
||||
val count = stream.readVarLong()
|
||||
@ -135,6 +154,7 @@ data class ItemDescriptor(
|
||||
constructor(ref: Registry.Ref<IItemDefinition>, count: Long, parameters: JsonObject) : this(ref.key.left(), count, parameters)
|
||||
|
||||
val isEmpty get() = count <= 0L || name == "" || ref.isEmpty
|
||||
val isNotEmpty get() = !isEmpty
|
||||
val ref by lazy { if (name == "") Registries.items.emptyRef else Registries.items.ref(name) }
|
||||
|
||||
override fun toString(): String {
|
||||
|
@ -13,6 +13,7 @@ import ru.dbotthepony.kstarbound.Globals
|
||||
import ru.dbotthepony.kstarbound.Registries
|
||||
import ru.dbotthepony.kstarbound.Starbound
|
||||
import ru.dbotthepony.kstarbound.defs.AssetPath
|
||||
import ru.dbotthepony.kstarbound.defs.tile.isNotEmptyLiquid
|
||||
import ru.dbotthepony.kstarbound.io.readColor
|
||||
import ru.dbotthepony.kstarbound.io.writeColor
|
||||
import ru.dbotthepony.kstarbound.json.builder.IStringSerializable
|
||||
@ -178,10 +179,8 @@ data class SkyParameters(
|
||||
// If the planet has water, then draw the corresponding water image as the
|
||||
// base layer, otherwise use the bottom most mask image.
|
||||
|
||||
val surfaceLiquid = visitable.surfaceLiquid.entry?.key
|
||||
|
||||
if (surfaceLiquid != null && liquidImages.isNotBlank()) {
|
||||
layers.add(Layer(liquidImages.replace("<liquid>", surfaceLiquid), imageScale))
|
||||
if (visitable.surfaceLiquid.isNotEmptyLiquid && liquidImages.isNotBlank()) {
|
||||
layers.add(Layer(liquidImages.replace("<liquid>", visitable.surfaceLiquid.entry!!.key), imageScale))
|
||||
} else {
|
||||
if (baseCount > 0) {
|
||||
layers.add(Layer("${baseImages.replace("<biome>", visitable.primaryBiome).replace("<num>", baseCount.toString())}?hueshift=${visitable.hueShift}", imageScale))
|
||||
@ -293,15 +292,13 @@ data class SkyParameters(
|
||||
|
||||
val biomeHueShift = "?hueshift=${visitable.hueShift.toInt()}"
|
||||
|
||||
val surfaceLiquid = visitable.surfaceLiquid.entry?.key
|
||||
|
||||
if (surfaceLiquid != null) {
|
||||
if (visitable.surfaceLiquid.isNotEmptyLiquid) {
|
||||
val random = random(parameters.seed)
|
||||
|
||||
for (i in 0 until 23)
|
||||
random.nextInt()
|
||||
|
||||
images.add(getLR(liquidTextures.replace("<liquid>", surfaceLiquid)))
|
||||
images.add(getLR(liquidTextures.replace("<liquid>", visitable.surfaceLiquid.entry!!.key)))
|
||||
|
||||
val masksL = ArrayList<String>()
|
||||
val masksR = ArrayList<String>()
|
||||
|
@ -1,13 +0,0 @@
|
||||
package ru.dbotthepony.kstarbound.item
|
||||
|
||||
open class Container(final override val size: Int) : IContainer {
|
||||
private val slots = Array(size) { ItemStack.EMPTY }
|
||||
|
||||
override fun get(index: Int): ItemStack {
|
||||
return slots[index]
|
||||
}
|
||||
|
||||
override fun set(index: Int, value: ItemStack) {
|
||||
slots[index] = value
|
||||
}
|
||||
}
|
@ -1,7 +1,152 @@
|
||||
package ru.dbotthepony.kstarbound.item
|
||||
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonElement
|
||||
import ru.dbotthepony.kstarbound.Starbound
|
||||
import ru.dbotthepony.kstarbound.defs.item.ItemDescriptor
|
||||
|
||||
interface IContainer {
|
||||
val size: Int
|
||||
var size: Int
|
||||
operator fun get(index: Int): ItemStack
|
||||
operator fun set(index: Int, value: ItemStack)
|
||||
|
||||
fun ageItems(by: Double): Boolean {
|
||||
var any = false
|
||||
|
||||
for (i in 0 until size) {
|
||||
val (newItem, hasAdvanced) = this[i].advanceAge(by)
|
||||
any = hasAdvanced || any
|
||||
|
||||
if (newItem != null) {
|
||||
this[i] = newItem
|
||||
}
|
||||
}
|
||||
|
||||
return any
|
||||
}
|
||||
|
||||
// puts item into container, returns remaining not put items
|
||||
fun add(item: ItemStack, simulate: Boolean = false): ItemStack {
|
||||
val copy = item.copy()
|
||||
|
||||
// first, try to put into not empty slots first
|
||||
for (i in 0 until size) {
|
||||
val itemThere = this[i]
|
||||
|
||||
if (itemThere.isStackable(copy)) {
|
||||
val newCount = (itemThere.size + copy.size).coerceAtMost(itemThere.maxStackSize)
|
||||
val diff = newCount - itemThere.size
|
||||
|
||||
copy.size -= diff
|
||||
|
||||
if (!simulate)
|
||||
itemThere.size += diff
|
||||
|
||||
if (copy.isEmpty)
|
||||
return ItemStack.EMPTY
|
||||
}
|
||||
}
|
||||
|
||||
// then try to move into empty slots
|
||||
for (i in 0 until size) {
|
||||
val itemThere = this[i]
|
||||
|
||||
if (itemThere.isEmpty) {
|
||||
if (copy.size > copy.maxStackSize) {
|
||||
if (!simulate)
|
||||
this[i] = copy.copy(copy.maxStackSize)
|
||||
|
||||
copy.size -= copy.maxStackSize
|
||||
} else {
|
||||
if (!simulate)
|
||||
this[i] = copy
|
||||
|
||||
return ItemStack.EMPTY
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return copy
|
||||
}
|
||||
|
||||
fun clear()
|
||||
|
||||
fun toJson(store: Boolean = false): JsonArray {
|
||||
val result = JsonArray(size)
|
||||
|
||||
if (store) {
|
||||
Starbound.storeJson {
|
||||
for (i in 0 until size) {
|
||||
result.add(this[i].toJson())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (i in 0 until size) {
|
||||
result.add(this[i].toJson())
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
fun fromJson(json: JsonElement, resize: Boolean = false): List<ItemStack> {
|
||||
clear()
|
||||
|
||||
val read = ArrayList<ItemStack>()
|
||||
val array = json.asJsonArray
|
||||
var nonEmpty = 0
|
||||
|
||||
for (i in 0 until array.size()) {
|
||||
val item = ItemDescriptor(array[i])
|
||||
|
||||
if (item.isNotEmpty)
|
||||
nonEmpty++
|
||||
|
||||
read.add(ItemStack.create(item))
|
||||
}
|
||||
|
||||
if (read.size > size) {
|
||||
// we have a problem
|
||||
|
||||
if (resize) {
|
||||
// no problem
|
||||
size = read.size
|
||||
|
||||
for ((i, item) in read.withIndex()) {
|
||||
this[i] = item
|
||||
}
|
||||
|
||||
return emptyList()
|
||||
} else {
|
||||
// first, put items to their place if they are within container size
|
||||
|
||||
for (i in 0 until size) {
|
||||
this[i] = read[i]
|
||||
}
|
||||
|
||||
// second, try to move remaining item into empty or stackable slots
|
||||
val lost = ArrayList<ItemStack>()
|
||||
|
||||
for (i in size until read.size) {
|
||||
val remaining = add(read[i])
|
||||
|
||||
if (remaining.isNotEmpty) {
|
||||
lost.add(remaining)
|
||||
}
|
||||
}
|
||||
|
||||
// if we weren't capable of putting excess items into container, then what a shame.
|
||||
return lost
|
||||
}
|
||||
} else {
|
||||
if (read.size < size && resize)
|
||||
size = read.size
|
||||
|
||||
for ((i, item) in read.withIndex()) {
|
||||
this[i] = item
|
||||
}
|
||||
|
||||
return emptyList()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ import ru.dbotthepony.kommons.io.writeBinaryString
|
||||
import ru.dbotthepony.kommons.io.writeVarLong
|
||||
import ru.dbotthepony.kstarbound.Registries
|
||||
import ru.dbotthepony.kstarbound.json.writeJsonElement
|
||||
import ru.dbotthepony.kstarbound.lua.LuaEnvironment
|
||||
import ru.dbotthepony.kstarbound.lua.from
|
||||
import java.io.DataOutputStream
|
||||
import java.util.concurrent.atomic.AtomicLong
|
||||
@ -62,7 +63,8 @@ open class ItemStack {
|
||||
}
|
||||
|
||||
val config: Registry.Ref<IItemDefinition>
|
||||
val parameters: JsonObject
|
||||
var parameters: JsonObject
|
||||
protected set
|
||||
|
||||
val isEmpty: Boolean
|
||||
get() = size <= 0 || config.isEmpty
|
||||
@ -81,6 +83,38 @@ open class ItemStack {
|
||||
size -= amount
|
||||
}
|
||||
|
||||
data class AgingResult(val new: ItemStack?, val ageUpdated: Boolean)
|
||||
|
||||
private fun config() = config
|
||||
|
||||
private val agingScripts: LuaEnvironment? by lazy {
|
||||
val config = config().value ?: return@lazy null
|
||||
//if (config.itemTags)
|
||||
null
|
||||
}
|
||||
|
||||
open fun advanceAge(by: Double): AgingResult {
|
||||
val agingScripts = agingScripts ?: return AgingResult(null, false)
|
||||
|
||||
val descriptor = createDescriptor()
|
||||
val updated = ItemDescriptor(agingScripts.invokeGlobal("ageItem", descriptor.toTable(agingScripts), by)[0] as Table)
|
||||
|
||||
if (descriptor != updated) {
|
||||
if (descriptor.name == updated.name) {
|
||||
// only parameters got changed
|
||||
this.parameters = descriptor.parameters
|
||||
this.size = descriptor.count
|
||||
changeset = CHANGESET.incrementAndGet()
|
||||
return AgingResult(null, true)
|
||||
} else {
|
||||
// item got replaced by something else
|
||||
return AgingResult(create(updated), true)
|
||||
}
|
||||
}
|
||||
|
||||
return AgingResult(null, false)
|
||||
}
|
||||
|
||||
fun createDescriptor(): ItemDescriptor {
|
||||
if (isEmpty)
|
||||
return ItemDescriptor.EMPTY
|
||||
@ -151,7 +185,7 @@ open class ItemStack {
|
||||
return "ItemDescriptor[${config.value?.itemName}, count = $size, params = $parameters]"
|
||||
}
|
||||
|
||||
fun copy(): ItemStack {
|
||||
fun copy(size: Long = this.size): ItemStack {
|
||||
if (isEmpty)
|
||||
return this
|
||||
|
||||
@ -206,6 +240,9 @@ open class ItemStack {
|
||||
val EMPTY = ItemStack()
|
||||
|
||||
fun create(descriptor: ItemDescriptor): ItemStack {
|
||||
if (descriptor.isEmpty)
|
||||
return EMPTY
|
||||
|
||||
return ItemStack(descriptor)
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,14 @@ import java.io.DataInputStream
|
||||
import java.io.DataOutputStream
|
||||
|
||||
class PlayerInventory {
|
||||
inner class Bag(override val size: Int) : IContainer {
|
||||
inner class Bag(size: Int) : IContainer {
|
||||
override var size: Int = size
|
||||
set(value) { throw UnsupportedOperationException() }
|
||||
|
||||
override fun clear() {
|
||||
slots.forEach { it.accept(ItemStack.EMPTY) }
|
||||
}
|
||||
|
||||
val slots = immutableList(size) { networkedItem() }
|
||||
|
||||
override fun get(index: Int): ItemStack {
|
||||
|
@ -1,23 +1,259 @@
|
||||
package ru.dbotthepony.kstarbound.world.entities.tile
|
||||
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.JsonPrimitive
|
||||
import it.unimi.dsi.fastutil.io.FastByteArrayInputStream
|
||||
import it.unimi.dsi.fastutil.io.FastByteArrayOutputStream
|
||||
import ru.dbotthepony.kommons.gson.get
|
||||
import ru.dbotthepony.kommons.gson.set
|
||||
import ru.dbotthepony.kommons.io.readByteArray
|
||||
import ru.dbotthepony.kommons.io.readVarInt
|
||||
import ru.dbotthepony.kommons.io.writeByteArray
|
||||
import ru.dbotthepony.kommons.io.writeVarInt
|
||||
import ru.dbotthepony.kommons.util.getValue
|
||||
import ru.dbotthepony.kommons.util.setValue
|
||||
import ru.dbotthepony.kstarbound.Registry
|
||||
import ru.dbotthepony.kstarbound.defs.InteractAction
|
||||
import ru.dbotthepony.kstarbound.defs.InteractRequest
|
||||
import ru.dbotthepony.kstarbound.defs.item.ItemDescriptor
|
||||
import ru.dbotthepony.kstarbound.defs.`object`.ObjectDefinition
|
||||
import ru.dbotthepony.kstarbound.item.IContainer
|
||||
import ru.dbotthepony.kstarbound.item.ItemStack
|
||||
import ru.dbotthepony.kstarbound.math.Interpolator
|
||||
import ru.dbotthepony.kstarbound.network.syncher.NetworkedElement
|
||||
import ru.dbotthepony.kstarbound.network.syncher.networkedBoolean
|
||||
import ru.dbotthepony.kstarbound.network.syncher.networkedBytes
|
||||
import ru.dbotthepony.kstarbound.network.syncher.networkedFloat
|
||||
import ru.dbotthepony.kstarbound.network.syncher.networkedSignedInt
|
||||
import ru.dbotthepony.kstarbound.util.ManualLazy
|
||||
import ru.dbotthepony.kstarbound.util.RelativeClock
|
||||
import ru.dbotthepony.kstarbound.world.entities.ItemDropEntity
|
||||
import java.io.DataInputStream
|
||||
import java.io.DataOutputStream
|
||||
|
||||
class ContainerObject(config: Registry.Entry<ObjectDefinition>) : WorldObject(config) {
|
||||
var opened by networkedSignedInt().also { networkGroup.upstream.add(it) }
|
||||
var isCrafting by networkedBoolean().also { networkGroup.upstream.add(it) }
|
||||
var craftingProgress by networkedFloat().also { networkGroup.upstream.add(it); it.interpolator = Interpolator.Linear }
|
||||
// i have no words.
|
||||
// this field embeds ENTIRE net state of 'ItemBag',
|
||||
// and each time container is updated, its contents are networked fully
|
||||
// each. damn. time.
|
||||
// placeholder data, container size 40, read 0 items
|
||||
var itemsNetState by networkedBytes(byteArrayOf(40, 0)).also { networkGroup.upstream.add(it) }
|
||||
val items = Container(0).also { networkGroup.upstream.add(it) }
|
||||
|
||||
// whenever set loot seed, put initial items, etc.
|
||||
private var isInitialized = false
|
||||
|
||||
private val lostItems = ArrayList<ItemStack>()
|
||||
private val ageItemsTimer = RelativeClock()
|
||||
|
||||
private val ageItemsEvery = ManualLazy {
|
||||
lookupProperty("ageItemsEvery") { JsonPrimitive(10.0) }.asDouble
|
||||
}.also { parametersLazies.add(it) }
|
||||
|
||||
private val itemAgeMultiplier = ManualLazy {
|
||||
lookupProperty("itemAgeMultiplier") { JsonPrimitive(1.0) }.asDouble
|
||||
}.also { parametersLazies.add(it) }
|
||||
|
||||
override fun tick(delta: Double) {
|
||||
super.tick(delta)
|
||||
|
||||
if (world.isServer) {
|
||||
for (item in lostItems) {
|
||||
val entity = ItemDropEntity(item)
|
||||
entity.position = position
|
||||
entity.joinWorld(world)
|
||||
}
|
||||
|
||||
lostItems.clear()
|
||||
ageItemsTimer.update(world.sky.time)
|
||||
|
||||
if (ageItemsTimer.time >= ageItemsEvery.value) {
|
||||
items.ageItems(ageItemsTimer.time * itemAgeMultiplier.value)
|
||||
ageItemsTimer.set(0.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun interact(request: InteractRequest): InteractAction {
|
||||
return InteractAction(InteractAction.Type.OPEN_CONTAINER, entityID)
|
||||
}
|
||||
|
||||
override fun deserialize(data: JsonObject) {
|
||||
super.deserialize(data)
|
||||
|
||||
opened = data.get("opened", 0)
|
||||
isCrafting = data.get("crafting", false)
|
||||
craftingProgress = data.get("craftingProgress", 0.0)
|
||||
isInitialized = data.get("initialized", true)
|
||||
items.fromJson(data.get("items", JsonArray()), resize = true)
|
||||
}
|
||||
|
||||
override fun serialize(): JsonObject {
|
||||
val data = super.serialize()
|
||||
|
||||
// required by original engine
|
||||
data["currentState"] = 0
|
||||
data["opened"] = opened
|
||||
data["crafting"] = isCrafting
|
||||
data["craftingProgress"] = craftingProgress
|
||||
data["initialized"] = isInitialized
|
||||
data["items"] = items.toJson(true)
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
// Networking of this container to legacy clients is incredibly stupid,
|
||||
// and networks entire state each time something has changed.
|
||||
inner class Container(size: Int) : NetworkedElement(), IContainer {
|
||||
private var items = Array(size) { ItemStack.EMPTY }
|
||||
private var itemNetVersions = LongArray(size)
|
||||
private var itemObservedVersion = LongArray(size)
|
||||
private var lastSizeChange = 0L
|
||||
|
||||
private fun observeItems() {
|
||||
for (i in 0 until size) {
|
||||
if (itemObservedVersion[i] != items[i].changeset) {
|
||||
itemObservedVersion[i] = items[i].changeset
|
||||
itemNetVersions[i] = currentVersion()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override var size: Int = size
|
||||
set(value) {
|
||||
if (field == value) return
|
||||
lastSizeChange = currentVersion()
|
||||
|
||||
if (value > field) {
|
||||
items = items.copyOf(value) as Array<ItemStack>
|
||||
|
||||
for (i in field until value)
|
||||
items[i] = ItemStack.EMPTY
|
||||
} else {
|
||||
for (i in value until field) {
|
||||
lostItems.add(items[i])
|
||||
}
|
||||
|
||||
items = items.copyOf(value) as Array<ItemStack>
|
||||
}
|
||||
|
||||
field = value
|
||||
itemObservedVersion = itemObservedVersion.copyOf(value)
|
||||
itemNetVersions = itemNetVersions.copyOf(value)
|
||||
}
|
||||
|
||||
override fun get(index: Int): ItemStack {
|
||||
return items[index]
|
||||
}
|
||||
|
||||
override fun set(index: Int, value: ItemStack) {
|
||||
items[index] = value.copy()
|
||||
}
|
||||
|
||||
override fun clear() {
|
||||
items.fill(ItemStack.EMPTY)
|
||||
}
|
||||
|
||||
override fun readInitial(data: DataInputStream, isLegacy: Boolean) {
|
||||
if (isLegacy) {
|
||||
val stream = DataInputStream(FastByteArrayInputStream(data.readByteArray()))
|
||||
|
||||
size = stream.readVarInt()
|
||||
|
||||
val setItemsSize = stream.readVarInt()
|
||||
items.fill(ItemStack.EMPTY)
|
||||
|
||||
for (i in 0 until setItemsSize) {
|
||||
items[i] = ItemStack(ItemDescriptor(stream))
|
||||
}
|
||||
} else {
|
||||
size = data.readVarInt()
|
||||
items.fill(ItemStack.EMPTY)
|
||||
|
||||
while (true) {
|
||||
val index = data.readVarInt() - 1
|
||||
if (index == -1) break
|
||||
items[index] = ItemStack(ItemDescriptor(data))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun writeInitial(data: DataOutputStream, isLegacy: Boolean) {
|
||||
if (isLegacy) {
|
||||
val wrapper = FastByteArrayOutputStream()
|
||||
val stream = DataOutputStream(wrapper)
|
||||
stream.writeVarInt(size)
|
||||
var setItemsSize = items.indexOfLast { it.isNotEmpty }
|
||||
|
||||
if (setItemsSize == -1)
|
||||
setItemsSize = 0
|
||||
|
||||
stream.writeVarInt(setItemsSize)
|
||||
|
||||
for (i in 0 until setItemsSize) {
|
||||
items[i].write(stream)
|
||||
}
|
||||
|
||||
data.writeByteArray(wrapper.array, 0, wrapper.length)
|
||||
} else {
|
||||
data.writeVarInt(size)
|
||||
|
||||
for (i in 0 until size) {
|
||||
if (items[i].isNotEmpty) {
|
||||
data.writeVarInt(i + 1)
|
||||
items[i].write(data)
|
||||
}
|
||||
}
|
||||
|
||||
data.writeVarInt(0)
|
||||
}
|
||||
}
|
||||
|
||||
override fun readDelta(data: DataInputStream, interpolationDelay: Double, isLegacy: Boolean) {
|
||||
if (isLegacy) {
|
||||
readInitial(data, true)
|
||||
} else {
|
||||
if (data.readBoolean()) {
|
||||
readInitial(data, false)
|
||||
} else {
|
||||
while (true) {
|
||||
val index = data.readVarInt() - 1
|
||||
if (index == -1) break
|
||||
items[index] = ItemStack(ItemDescriptor(data))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun writeDelta(data: DataOutputStream, remoteVersion: Long, isLegacy: Boolean) {
|
||||
if (isLegacy) {
|
||||
writeInitial(data, true)
|
||||
} else {
|
||||
if (lastSizeChange >= remoteVersion) {
|
||||
data.writeBoolean(true)
|
||||
writeInitial(data, false)
|
||||
} else {
|
||||
observeItems()
|
||||
data.writeBoolean(false)
|
||||
|
||||
for (i in 0 until size) {
|
||||
if (itemNetVersions[i] >= remoteVersion) {
|
||||
data.writeVarInt(i + 1)
|
||||
items[i].write(data)
|
||||
}
|
||||
}
|
||||
|
||||
data.writeVarInt(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun hasChangedSince(version: Long): Boolean {
|
||||
observeItems()
|
||||
return lastSizeChange >= version || itemNetVersions.any { it >= version }
|
||||
}
|
||||
|
||||
override fun readBlankDelta(interpolationDelay: Double) {}
|
||||
override fun enableInterpolation(extrapolation: Double) {}
|
||||
override fun disableInterpolation() {}
|
||||
override fun tickInterpolation(delta: Double) {}
|
||||
}
|
||||
}
|
||||
|
@ -504,6 +504,7 @@ open class WorldObject(val config: Registry.Entry<ObjectDefinition>) : TileEntit
|
||||
}
|
||||
|
||||
if (shouldBreak) {
|
||||
callBreak(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user