Skip to content

Commit

Permalink
Use Bukkit types for fake-entity metadata
Browse files Browse the repository at this point in the history
  • Loading branch information
NichtStudioCode committed Mar 26, 2024
1 parent 2504972 commit 2bae6f2
Show file tree
Hide file tree
Showing 19 changed files with 178 additions and 134 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import org.joml.Vector3f
import org.joml.Vector3fc
import xyz.xenondevs.commons.collections.mapToIntArray
import xyz.xenondevs.nmsutils.network.ClientboundSetPassengersPacket
import xyz.xenondevs.nova.util.nmsCopy
import xyz.xenondevs.nova.util.runTaskLater
import xyz.xenondevs.nova.util.send
import xyz.xenondevs.nova.world.fakeentity.impl.FakeItemDisplay
Expand Down Expand Up @@ -49,7 +48,7 @@ open class ItemAttachment(
}
}

data.itemStack = itemStack.nmsCopy
data.itemStack = itemStack
}
}

Expand Down
46 changes: 46 additions & 0 deletions nova/src/main/kotlin/xyz/xenondevs/nova/util/NMSUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import org.bukkit.craftbukkit.v1_20_R3.inventory.CraftItemStack
import org.bukkit.craftbukkit.v1_20_R3.util.CraftMagicNumbers
import org.bukkit.entity.Entity
import org.bukkit.entity.Player
import org.bukkit.entity.Pose
import org.bukkit.inventory.EquipmentSlot
import org.bukkit.inventory.ItemStack
import org.bukkit.util.Vector
Expand All @@ -69,6 +70,7 @@ import kotlin.jvm.optionals.getOrNull
import net.minecraft.core.BlockPos as MojangBlockPos
import net.minecraft.world.entity.Entity as MojangEntity
import net.minecraft.world.entity.EquipmentSlot as MojangEquipmentSlot
import net.minecraft.world.entity.Pose as MojangPose
import net.minecraft.world.entity.ai.attributes.Attribute as MojangAttribute
import net.minecraft.world.entity.ai.attributes.AttributeModifier as MojangAttributeModifier
import net.minecraft.world.entity.player.Player as MojangPlayer
Expand Down Expand Up @@ -236,6 +238,50 @@ val AttributeModifier.Operation.nmsOperation: MojangAttributeModifier.Operation
AttributeModifier.Operation.MULTIPLY_SCALAR_1 -> MojangAttributeModifier.Operation.MULTIPLY_TOTAL
}

val MojangPose.bukkitPose: Pose
get() = when(this) {
MojangPose.STANDING -> Pose.STANDING
MojangPose.FALL_FLYING -> Pose.FALL_FLYING
MojangPose.SLEEPING -> Pose.SLEEPING
MojangPose.SWIMMING -> Pose.SWIMMING
MojangPose.SPIN_ATTACK -> Pose.SPIN_ATTACK
MojangPose.CROUCHING -> Pose.SNEAKING
MojangPose.LONG_JUMPING -> Pose.LONG_JUMPING
MojangPose.DYING -> Pose.DYING
MojangPose.CROAKING -> Pose.CROAKING
MojangPose.USING_TONGUE -> Pose.USING_TONGUE
MojangPose.SITTING -> Pose.SITTING
MojangPose.ROARING -> Pose.ROARING
MojangPose.SNIFFING -> Pose.SNIFFING
MojangPose.EMERGING -> Pose.EMERGING
MojangPose.DIGGING -> Pose.DIGGING
MojangPose.SLIDING -> Pose.SLIDING
MojangPose.SHOOTING -> Pose.SHOOTING
MojangPose.INHALING -> Pose.INHALING
}

val Pose.nmsPose: MojangPose
get() = when(this) {
Pose.STANDING -> MojangPose.STANDING
Pose.FALL_FLYING -> MojangPose.FALL_FLYING
Pose.SLEEPING -> MojangPose.SLEEPING
Pose.SWIMMING -> MojangPose.SWIMMING
Pose.SPIN_ATTACK -> MojangPose.SPIN_ATTACK
Pose.SNEAKING -> MojangPose.CROUCHING
Pose.LONG_JUMPING -> MojangPose.LONG_JUMPING
Pose.DYING -> MojangPose.DYING
Pose.CROAKING -> MojangPose.CROAKING
Pose.USING_TONGUE -> MojangPose.USING_TONGUE
Pose.SITTING -> MojangPose.SITTING
Pose.ROARING -> MojangPose.ROARING
Pose.SNIFFING -> MojangPose.SNIFFING
Pose.EMERGING -> MojangPose.EMERGING
Pose.DIGGING -> MojangPose.DIGGING
Pose.SLIDING -> MojangPose.SLIDING
Pose.SHOOTING -> MojangPose.SHOOTING
Pose.INHALING -> MojangPose.INHALING
}

val Material.nmsBlock: MojangBlock
get() = CraftMagicNumbers.getBlock(this)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package xyz.xenondevs.nova.util.component.adventure

import io.papermc.paper.adventure.AdventureComponent
import net.kyori.adventure.key.Key
import net.kyori.adventure.text.BuildableComponent
import net.kyori.adventure.text.Component
Expand Down Expand Up @@ -33,6 +34,9 @@ fun String.toAdventureComponentOr(createComponent: () -> Component): Component {
}

fun MojangComponent.toAdventureComponent(): Component {
if (this is AdventureComponent)
return this.`adventure$component`()

return GsonComponentSerializer.gson().deserialize(CraftChatMessage.toJSON(this))
}

Expand All @@ -41,7 +45,7 @@ fun MojangComponent.toJson(): String {
}

fun Component.toNMSComponent(): MojangComponent {
return CraftChatMessage.fromJSON(GsonComponentSerializer.gson().serialize(this))
return AdventureComponent(this)
}

fun Component.toJson(): String {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
package xyz.xenondevs.nova.world.block.logic.`break`

import net.minecraft.world.item.ItemDisplayContext
import net.minecraft.world.item.ItemStack
import org.bukkit.Material
import org.bukkit.block.Block
import org.bukkit.entity.ItemDisplay.ItemDisplayTransform
import org.bukkit.entity.Player
import xyz.xenondevs.nova.item.DefaultBlockOverlays
import xyz.xenondevs.nova.util.nmsCopy
import xyz.xenondevs.nova.util.broadcastDestructionStage
import xyz.xenondevs.nova.world.BlockPos
import xyz.xenondevs.nova.world.block.NovaBlock
Expand Down Expand Up @@ -82,7 +80,7 @@ internal class PacketBreakMethod(pos: BlockPos, private val entityId: Int = Rand
internal class DisplayEntityBreakMethod(pos: BlockPos) : VisibleBreakMethod(pos) {

private val itemDisplay = FakeItemDisplay(pos.location.add(.5, .5, .5), true) { _, data ->
data.itemDisplay = ItemDisplayContext.HEAD
data.itemDisplay = ItemDisplayTransform.HEAD
}

override var breakStage: Int = -1
Expand All @@ -92,8 +90,8 @@ internal class DisplayEntityBreakMethod(pos: BlockPos) : VisibleBreakMethod(pos)
field = stage
itemDisplay.updateEntityData(true) {
itemStack = if (stage in 0..9)
DefaultBlockOverlays.BREAK_STAGE_OVERLAY.model.unnamedClientsideProviders[stage].get().nmsCopy
else ItemStack.EMPTY
DefaultBlockOverlays.BREAK_STAGE_OVERLAY.model.unnamedClientsideProviders[stage].get()
else null
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
package xyz.xenondevs.nova.world.block.state.model

import net.minecraft.util.Brightness
import net.minecraft.world.item.ItemDisplayContext
import org.bukkit.Material
import org.bukkit.block.data.BlockData
import org.bukkit.entity.Display.Brightness
import org.joml.Matrix4fc
import xyz.xenondevs.invui.item.builder.ItemBuilder
import xyz.xenondevs.nova.util.item.requiresLight
import xyz.xenondevs.nova.util.nmsCopy
import xyz.xenondevs.nova.world.BlockPos
import xyz.xenondevs.nova.world.fakeentity.FakeEntity
import xyz.xenondevs.nova.world.fakeentity.impl.FakeItemDisplay
import xyz.xenondevs.nova.world.fakeentity.metadata.impl.ItemDisplayMetadata
import java.util.concurrent.ConcurrentHashMap
import net.minecraft.world.item.ItemStack as MojangStack

internal data class DisplayEntityBlockModelData(
val models: List<Model>,
Expand All @@ -23,7 +20,7 @@ internal data class DisplayEntityBlockModelData(
internal data class Model(val material: Material, val customModelData: Int, val transform: Matrix4fc) {

@Transient
val itemStack: MojangStack = ItemBuilder(material).setCustomModelData(customModelData).get().nmsCopy
val itemStack = ItemBuilder(material).setCustomModelData(customModelData).get()

}

Expand Down Expand Up @@ -61,7 +58,7 @@ internal data object DisplayEntityBlockModelProvider : BlockModelProvider<Displa
// re-use as many existing entities as possible
val prevEntities = entities[pos]!!
entities[pos] = newInfo.models.mapIndexed { i, model ->
prevEntities.getOrNull(i)
prevEntities.getOrNull(i)
?.also { prevEntity -> prevEntity.updateEntityData(true) { setMetadata(this, newInfo, model) } }
?: FakeItemDisplay(pos.location.add(0.5, 0.5, 0.5)) { _, data -> setMetadata(data, newInfo, model) }
}
Expand All @@ -78,10 +75,10 @@ internal data object DisplayEntityBlockModelProvider : BlockModelProvider<Displa

private fun setMetadata(data: ItemDisplayMetadata, info: DisplayEntityBlockModelData, model: DisplayEntityBlockModelData.Model) {
// TODO: proper light level
if (info.hitboxType.material.requiresLight)
if (info.hitboxType.material.requiresLight) {
data.brightness = Brightness(15, 15)
}

data.itemDisplay = ItemDisplayContext.NONE
data.itemStack = model.itemStack
data.transform = model.transform
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import io.netty.buffer.Unpooled
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.network.syncher.EntityDataSerializer
import net.minecraft.network.syncher.EntityDataSerializers
import net.minecraft.world.item.ItemStack
import xyz.xenondevs.nmsutils.network.PacketIdRegistry
import xyz.xenondevs.nova.item.logic.PacketItems
import xyz.xenondevs.nova.util.nmsCopy
import java.util.*
import net.minecraft.world.item.ItemStack as MojangStack
import org.bukkit.inventory.ItemStack as BukkitStack

abstract class Metadata internal constructor() {

Expand Down Expand Up @@ -51,20 +53,20 @@ abstract class Metadata internal constructor() {
return entry
}

internal fun <T, R> entry(index: Int, serializer: EntityDataSerializer<R>, default: T, toRaw: (T) -> R): MappedNonNullMetadataEntry<T, R>.MappedDelegate {
val entry = MappedNonNullMetadataEntry(index, serializer, toRaw, { throw UnsupportedOperationException() }, default)
internal fun <T, R> entry(index: Int, serializer: EntityDataSerializer<R>, default: T, map: (T) -> R): MappedNonNullMetadataEntry<T, R> {
val entry = MappedNonNullMetadataEntry(index, serializer, map, default)
entries += entry
return entry.mappedDelegate
return entry
}

internal fun <T, R> entry(index: Int, serializer: EntityDataSerializer<R>, default: T, toRaw: (T) -> R, fromRaw: (R) -> T): MappedNonNullMetadataEntry<T, R> {
val entry = MappedNonNullMetadataEntry(index, serializer, toRaw, fromRaw, default)
internal fun <T> optional(index: Int, serializer: EntityDataSerializer<Optional<T & Any>>): NullableMetadataEntry<T> {
val entry = NullableMetadataEntry<T>(index, serializer)
entries += entry
return entry
}

internal fun <T> optional(index: Int, serializer: EntityDataSerializer<Optional<T & Any>>, default: T?): NullableMetadataEntry<T> {
val entry = NullableMetadataEntry(index, serializer, default)
internal fun <T, R> optional(index: Int, serializer: EntityDataSerializer<Optional<R & Any>>, map: (T) -> R): MappedNullableMetadataEntry<T, R> {
val entry = MappedNullableMetadataEntry(index, serializer, map)
entries += entry
return entry
}
Expand All @@ -75,15 +77,14 @@ abstract class Metadata internal constructor() {
return entry
}

internal fun itemStack(index: Int, useName: Boolean, default: ItemStack): MappedNonNullMetadataEntry<ItemStack, ItemStack>.MappedDelegate {
val entry = MappedNonNullMetadataEntry(
internal fun itemStack(index: Int, useName: Boolean, default: BukkitStack? = null): MappedNonNullMetadataEntry<BukkitStack?, MojangStack> {
val entry = MappedNonNullMetadataEntry<BukkitStack?, MojangStack>(
index, EntityDataSerializers.ITEM_STACK,
{ PacketItems.getClientSideStack(null, it, useName)},
{ PacketItems.getServerSideStack(it) },
{ PacketItems.getClientSideStack(null, it.nmsCopy, useName) },
default
)
entries += entry
return entry.mappedDelegate
return entry
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -50,69 +50,46 @@ internal open class NonNullMetadataEntry<T : Any>(
internal class MappedNonNullMetadataEntry<T, R>(
private val index: Int,
private val serializer: EntityDataSerializer<R>,
private val toRaw: (T) -> R,
private val fromRaw: (R) -> T,
private val map: (T) -> R,
private val default: T
) : MetadataEntry<T> {

private val serializerId = EntityDataSerializers.getSerializedId(serializer)

private var mappedValue: T = default
private var rawValue: R = toRaw(default)
private var value: T = default
private var mappedValue: R = map(default)

override var dirty: Boolean = false

val rawDelegate = RawDelegate()
val mappedDelegate = MappedDelegate()

override fun write(buf: FriendlyByteBuf) {
buf.writeByte(index)
buf.writeVarInt(serializerId)
serializer.write(buf, rawValue!!)
serializer.write(buf, mappedValue!!)
}

override fun isNotDefault(): Boolean =
mappedValue != default
value != default

inner class RawDelegate {

operator fun getValue(thisRef: Any, property: KProperty<*>): R {
return rawValue
}

operator fun setValue(thisRef: Any, property: KProperty<*>, value: R) {
rawValue = value
mappedValue = fromRaw(value)
dirty = true
}

operator fun getValue(thisRef: Any, property: KProperty<*>): T {
return value
}

inner class MappedDelegate {

operator fun getValue(thisRef: Any, property: KProperty<*>): T {
return mappedValue
}

operator fun setValue(thisRef: Any, property: KProperty<*>, value: T) {
this@MappedNonNullMetadataEntry.mappedValue = value
rawValue = toRaw(value)
dirty = true
}

operator fun setValue(thisRef: Any, property: KProperty<*>, value: T) {
this.value = value
mappedValue = map(value)
dirty = true
}

}

internal class NullableMetadataEntry<T>(
private val index: Int,
private val serializer: EntityDataSerializer<Optional<T & Any>>,
private val default: T?
) : MetadataEntry<T?> {

private val serializerId = EntityDataSerializers.getSerializedId(serializer)

private var value: T? = default
private var value: T? = null
override var dirty: Boolean = false

operator fun getValue(thisRef: Any, property: KProperty<*>): T? {
Expand All @@ -131,7 +108,41 @@ internal class NullableMetadataEntry<T>(
}

override fun isNotDefault(): Boolean =
value != default
value != null

}

internal class MappedNullableMetadataEntry<T, R>(
private val index: Int,
private val serializer: EntityDataSerializer<Optional<R & Any>>,
private val map: (T) -> R
) : MetadataEntry<T> {

private val serializerId = EntityDataSerializers.getSerializedId(serializer)

private var value: T? = null
private var mappedValue: R? = null

override var dirty: Boolean = false

override fun write(buf: FriendlyByteBuf) {
buf.writeByte(index)
buf.writeVarInt(serializerId)
serializer.write(buf, Optional.ofNullable(mappedValue))
}

override fun isNotDefault(): Boolean =
value != null

operator fun getValue(thisRef: Any, property: KProperty<*>): T? {
return value
}

operator fun setValue(thisRef: Any, property: KProperty<*>, value: T?) {
this.value = value
mappedValue = value?.let(map)
dirty = true
}

}

Expand Down
Loading

0 comments on commit 2bae6f2

Please sign in to comment.