aboutsummaryrefslogtreecommitdiff
path: root/src/main/kotlin/util/mc
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/kotlin/util/mc')
-rw-r--r--src/main/kotlin/util/mc/ArmorUtil.kt8
-rw-r--r--src/main/kotlin/util/mc/CustomRenderPassHelper.kt161
-rw-r--r--src/main/kotlin/util/mc/FakeInventory.kt24
-rw-r--r--src/main/kotlin/util/mc/FakeSlot.kt12
-rw-r--r--src/main/kotlin/util/mc/FirmamentDataComponentTypes.kt28
-rw-r--r--src/main/kotlin/util/mc/InitLevel.kt25
-rw-r--r--src/main/kotlin/util/mc/IntrospectableItemModelManager.kt4
-rw-r--r--src/main/kotlin/util/mc/InventoryUtil.kt14
-rw-r--r--src/main/kotlin/util/mc/ItemUtil.kt38
-rw-r--r--src/main/kotlin/util/mc/MCTabListAPI.kt96
-rw-r--r--src/main/kotlin/util/mc/NbtItemData.kt24
-rw-r--r--src/main/kotlin/util/mc/NbtPrism.kt85
-rw-r--r--src/main/kotlin/util/mc/NbtUtil.kt15
-rw-r--r--src/main/kotlin/util/mc/PlayerUtil.kt7
-rw-r--r--src/main/kotlin/util/mc/Rectangle.kt11
-rw-r--r--src/main/kotlin/util/mc/SNbtFormatter.kt86
-rw-r--r--src/main/kotlin/util/mc/ScreenUtil.kt16
-rw-r--r--src/main/kotlin/util/mc/SkullItemData.kt106
-rw-r--r--src/main/kotlin/util/mc/SlotUtils.kt52
-rw-r--r--src/main/kotlin/util/mc/TolerantRegistriesOps.kt24
-rw-r--r--src/main/kotlin/util/mc/asFakeServer.kt24
21 files changed, 652 insertions, 208 deletions
diff --git a/src/main/kotlin/util/mc/ArmorUtil.kt b/src/main/kotlin/util/mc/ArmorUtil.kt
new file mode 100644
index 0000000..3bb1768
--- /dev/null
+++ b/src/main/kotlin/util/mc/ArmorUtil.kt
@@ -0,0 +1,8 @@
+package moe.nea.firmament.util.mc
+
+import net.minecraft.world.entity.EquipmentSlot
+import net.minecraft.world.entity.LivingEntity
+
+val LivingEntity.iterableArmorItems
+ get() = EquipmentSlot.entries.asSequence()
+ .map { it to getItemBySlot(it) }
diff --git a/src/main/kotlin/util/mc/CustomRenderPassHelper.kt b/src/main/kotlin/util/mc/CustomRenderPassHelper.kt
new file mode 100644
index 0000000..93cd7c1
--- /dev/null
+++ b/src/main/kotlin/util/mc/CustomRenderPassHelper.kt
@@ -0,0 +1,161 @@
+package moe.nea.firmament.util.mc
+
+import com.mojang.blaze3d.buffers.GpuBuffer
+import com.mojang.blaze3d.buffers.GpuBufferSlice
+import com.mojang.blaze3d.buffers.Std140Builder
+import com.mojang.blaze3d.pipeline.RenderPipeline
+import com.mojang.blaze3d.systems.RenderPass
+import com.mojang.blaze3d.systems.RenderSystem
+import com.mojang.blaze3d.vertex.VertexFormat
+import java.nio.ByteBuffer
+import java.nio.ByteOrder
+import java.util.OptionalDouble
+import java.util.OptionalInt
+import org.joml.Vector3f
+import org.joml.Vector4f
+import com.mojang.blaze3d.pipeline.RenderTarget
+import com.mojang.blaze3d.vertex.BufferBuilder
+import com.mojang.blaze3d.vertex.MeshData
+import net.minecraft.client.renderer.texture.AbstractTexture
+import com.mojang.blaze3d.vertex.ByteBufferBuilder
+import net.minecraft.resources.ResourceLocation
+import net.minecraft.util.Mth
+import moe.nea.firmament.util.ErrorUtil
+import moe.nea.firmament.util.MC
+
+
+class CustomRenderPassHelper(
+ val labelSupplier: () -> String,
+ val drawMode: VertexFormat.Mode,
+ val vertexFormat: VertexFormat,
+ val frameBuffer: RenderTarget,
+ val hasDepth: Boolean,
+) : AutoCloseable {
+ private val scope = mutableListOf<AutoCloseable>()
+ private val preparations = mutableListOf<(RenderPass) -> Unit>()
+ val device = RenderSystem.getDevice()
+ private var hasPipelineAction = false
+ private var hasSetDefaultUniforms = false
+ val commandEncoder = device.createCommandEncoder()
+ fun setPipeline(pipeline: RenderPipeline) {
+ ErrorUtil.softCheck("Already has a pipeline", !hasPipelineAction)
+ hasPipelineAction = true
+ queueAction {
+ it.setPipeline(pipeline)
+ }
+ }
+
+ fun bindSampler(name: String, texture: ResourceLocation) {
+ bindSampler(name, MC.textureManager.getTexture(texture))
+ }
+
+ fun bindSampler(name: String, texture: AbstractTexture) {
+ queueAction { it.bindSampler(name, texture.textureView) }
+ }
+
+
+ fun dontSetDefaultUniforms() {
+ hasSetDefaultUniforms = true
+ }
+
+ fun setAllDefaultUniforms() {
+ hasSetDefaultUniforms = true
+ queueAction {
+ RenderSystem.bindDefaultUniforms(it)
+ }
+ setUniform(
+ "DynamicTransforms", RenderSystem.getDynamicUniforms()
+ .writeTransform(
+ RenderSystem.getModelViewMatrix(),
+ Vector4f(1.0F, 1.0F, 1.0F, 1.0F),
+ Vector3f(), // TODO: 1.21.10
+ RenderSystem.getTextureMatrix(),
+ RenderSystem.getShaderLineWidth()
+ )
+ )
+ }
+
+ fun setUniform(name: String, slice: GpuBufferSlice) = queueAction { it.setUniform(name, slice) }
+ fun setUniform(name: String, slice: GpuBuffer) = queueAction { it.setUniform(name, slice) }
+
+ fun setUniform(name: String, size: Int, labelSupplier: () -> String = { name }, init: (Std140Builder) -> Unit) {
+ val buffer = createUniformBuffer(labelSupplier, allocateByteBuf(size, init))
+ setUniform(name, buffer)
+ }
+
+ var vertices: MeshData? = null
+
+ fun uploadVertices(size: Int, init: (BufferBuilder) -> Unit) {
+ uploadVertices(
+ BufferBuilder(queueClose(ByteBufferBuilder(size)), drawMode, vertexFormat)
+ .also(init)
+ .buildOrThrow()
+ )
+ }
+
+ fun uploadVertices(buffer: MeshData) {
+ queueClose(buffer)
+ ErrorUtil.softCheck("Vertices have already been uploaded", vertices == null)
+ vertices = buffer
+ val vertexBuffer = vertexFormat.uploadImmediateVertexBuffer(buffer.vertexBuffer())
+ val indexBufferConstructor = RenderSystem.getSequentialBuffer(drawMode)
+ val indexBuffer = indexBufferConstructor.getBuffer(buffer.drawState().indexCount)
+ queueAction {
+ it.setIndexBuffer(indexBuffer, indexBufferConstructor.type())
+ it.setVertexBuffer(0, vertexBuffer)
+ }
+ }
+
+ fun createUniformBuffer(labelSupplier: () -> String, buffer: ByteBuffer): GpuBuffer {
+ return queueClose(
+ device.createBuffer(
+ labelSupplier::invoke,
+ GpuBuffer.USAGE_UNIFORM or GpuBuffer.USAGE_MAP_READ,
+ buffer
+ )
+ )
+ }
+
+ fun allocateByteBuf(size: Int, init: (Std140Builder) -> Unit): ByteBuffer {
+ return Std140Builder.intoBuffer( // TODO: i really dont know about this 16 align? but it seems to be generally correct.
+ ByteBuffer
+ .allocateDirect(Mth.roundToward(size, 16))
+ .order(ByteOrder.nativeOrder())
+ ).also(init).get()
+ }
+
+ fun queueAction(action: (RenderPass) -> Unit) {
+ preparations.add(action)
+ }
+
+ fun <T : AutoCloseable> queueClose(t: T): T = t.also { scope.add(it) }
+ override fun close() {
+ scope.reversed().forEach { it.close() }
+ }
+
+ object DrawToken
+
+ fun draw(): DrawToken {
+ val vertexData = (ErrorUtil.notNullOr(vertices, "No vertex data uploaded") { return DrawToken })
+ ErrorUtil.softCheck("Missing default uniforms", hasSetDefaultUniforms)
+ ErrorUtil.softCheck("Missing a pipeline", hasPipelineAction)
+ val renderPass = queueClose(
+ commandEncoder.createRenderPass(
+ labelSupplier::invoke,
+ RenderSystem.outputColorTextureOverride ?: frameBuffer.colorTextureView!!,
+ OptionalInt.empty(),
+ (RenderSystem.outputDepthTextureOverride
+ ?: frameBuffer.depthTextureView).takeIf { frameBuffer.useDepth && hasDepth },
+ OptionalDouble.empty()
+ )
+ )
+ preparations.forEach { it(renderPass) }
+ renderPass.drawIndexed(
+ 0,
+ 0,
+ vertexData.drawState().indexCount,
+ 1
+ )
+ return DrawToken
+ }
+}
diff --git a/src/main/kotlin/util/mc/FakeInventory.kt b/src/main/kotlin/util/mc/FakeInventory.kt
index 26c04bc..198ec68 100644
--- a/src/main/kotlin/util/mc/FakeInventory.kt
+++ b/src/main/kotlin/util/mc/FakeInventory.kt
@@ -1,14 +1,14 @@
package util.mc
-import net.minecraft.entity.player.PlayerEntity
-import net.minecraft.inventory.Inventory
-import net.minecraft.item.ItemStack
+import net.minecraft.world.entity.player.Player
+import net.minecraft.world.Container
+import net.minecraft.world.item.ItemStack
-class FakeInventory(val stack: ItemStack) : Inventory {
- override fun clear() {
+class FakeInventory(val stack: ItemStack) : Container {
+ override fun clearContent() {
}
- override fun size(): Int {
+ override fun getContainerSize(): Int {
return 1
}
@@ -16,26 +16,26 @@ class FakeInventory(val stack: ItemStack) : Inventory {
return stack.isEmpty
}
- override fun getStack(slot: Int): ItemStack {
+ override fun getItem(slot: Int): ItemStack {
require(slot == 0)
return stack
}
- override fun removeStack(slot: Int, amount: Int): ItemStack {
+ override fun removeItem(slot: Int, amount: Int): ItemStack {
return ItemStack.EMPTY
}
- override fun removeStack(slot: Int): ItemStack {
+ override fun removeItemNoUpdate(slot: Int): ItemStack {
return ItemStack.EMPTY
}
- override fun setStack(slot: Int, stack: ItemStack?) {
+ override fun setItem(slot: Int, stack: ItemStack?) {
}
- override fun markDirty() {
+ override fun setChanged() {
}
- override fun canPlayerUse(player: PlayerEntity?): Boolean {
+ override fun stillValid(player: Player?): Boolean {
return true
}
}
diff --git a/src/main/kotlin/util/mc/FakeSlot.kt b/src/main/kotlin/util/mc/FakeSlot.kt
index a9be484..9793fdf 100644
--- a/src/main/kotlin/util/mc/FakeSlot.kt
+++ b/src/main/kotlin/util/mc/FakeSlot.kt
@@ -1,15 +1,15 @@
package moe.nea.firmament.util.mc
import util.mc.FakeInventory
-import net.minecraft.item.ItemStack
-import net.minecraft.screen.slot.Slot
+import net.minecraft.world.item.ItemStack
+import net.minecraft.world.inventory.Slot
class FakeSlot(
- stack: ItemStack,
- x: Int,
- y: Int
+ stack: ItemStack,
+ x: Int,
+ y: Int
) : Slot(FakeInventory(stack), 0, x, y) {
init {
- id = 0
+ index = 0
}
}
diff --git a/src/main/kotlin/util/mc/FirmamentDataComponentTypes.kt b/src/main/kotlin/util/mc/FirmamentDataComponentTypes.kt
index 0866665..79536e5 100644
--- a/src/main/kotlin/util/mc/FirmamentDataComponentTypes.kt
+++ b/src/main/kotlin/util/mc/FirmamentDataComponentTypes.kt
@@ -2,10 +2,10 @@ package moe.nea.firmament.util.mc
import com.mojang.serialization.Codec
import io.netty.buffer.ByteBuf
-import net.minecraft.component.ComponentType
-import net.minecraft.network.codec.PacketCodec
-import net.minecraft.registry.Registries
-import net.minecraft.registry.Registry
+import net.minecraft.core.component.DataComponentType
+import net.minecraft.network.codec.StreamCodec
+import net.minecraft.core.registries.BuiltInRegistries
+import net.minecraft.core.Registry
import moe.nea.firmament.Firmament
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.ClientInitEvent
@@ -19,18 +19,18 @@ object FirmamentDataComponentTypes {
private fun <T> register(
id: String,
- builderOperator: (ComponentType.Builder<T>) -> Unit
- ): ComponentType<T> {
+ builderOperator: (DataComponentType.Builder<T>) -> Unit
+ ): DataComponentType<T> {
return Registry.register(
- Registries.DATA_COMPONENT_TYPE,
+ BuiltInRegistries.DATA_COMPONENT_TYPE,
Firmament.identifier(id),
- ComponentType.builder<T>().also(builderOperator)
+ DataComponentType.builder<T>().also(builderOperator)
.build()
)
}
- fun <T> errorCodec(message: String): PacketCodec<in ByteBuf, T> =
- object : PacketCodec<ByteBuf, T> {
+ fun <T> errorCodec(message: String): StreamCodec<in ByteBuf, T> =
+ object : StreamCodec<ByteBuf, T> {
override fun decode(buf: ByteBuf?): T? {
error(message)
}
@@ -40,16 +40,16 @@ object FirmamentDataComponentTypes {
}
}
- fun <T, B : ComponentType.Builder<T>> B.neverEncode(message: String = "This element should never be encoded or decoded"): B {
- packetCodec(errorCodec(message))
- codec(null)
+ fun <T, B : DataComponentType.Builder<T>> B.neverEncode(message: String = "This element should never be encoded or decoded"): B {
+ networkSynchronized(errorCodec(message))
+ persistent(null)
return this
}
val IS_BROKEN = register<Boolean>(
"is_broken"
) {
- it.codec(Codec.BOOL.fieldOf("is_broken").codec())
+ it.persistent(Codec.BOOL.fieldOf("is_broken").codec())
}
val CUSTOM_MINING_BLOCK_DATA = register<MiningRepoData.CustomMiningBlock>("custom_mining_block") {
diff --git a/src/main/kotlin/util/mc/InitLevel.kt b/src/main/kotlin/util/mc/InitLevel.kt
new file mode 100644
index 0000000..2c3eedb
--- /dev/null
+++ b/src/main/kotlin/util/mc/InitLevel.kt
@@ -0,0 +1,25 @@
+package moe.nea.firmament.util.mc
+
+enum class InitLevel {
+ STARTING,
+ MC_INIT,
+ RENDER_INIT,
+ RENDER,
+ MAIN_MENU,
+ ;
+
+ companion object {
+ var initLevel = InitLevel.STARTING
+ private set
+
+ @JvmStatic
+ fun isAtLeast(wantedLevel: InitLevel): Boolean = initLevel >= wantedLevel
+
+ @JvmStatic
+ fun bump(nextLevel: InitLevel) {
+ if (nextLevel.ordinal != initLevel.ordinal + 1)
+ error("Cannot bump initLevel $nextLevel from $initLevel")
+ initLevel = nextLevel
+ }
+ }
+}
diff --git a/src/main/kotlin/util/mc/IntrospectableItemModelManager.kt b/src/main/kotlin/util/mc/IntrospectableItemModelManager.kt
index e546fd3..537ca5b 100644
--- a/src/main/kotlin/util/mc/IntrospectableItemModelManager.kt
+++ b/src/main/kotlin/util/mc/IntrospectableItemModelManager.kt
@@ -1,7 +1,7 @@
package moe.nea.firmament.util.mc
-import net.minecraft.util.Identifier
+import net.minecraft.resources.ResourceLocation
interface IntrospectableItemModelManager {
- fun hasModel_firmament(identifier: Identifier): Boolean
+ fun hasModel_firmament(identifier: ResourceLocation): Boolean
}
diff --git a/src/main/kotlin/util/mc/InventoryUtil.kt b/src/main/kotlin/util/mc/InventoryUtil.kt
index 74f7b9f..0509138 100644
--- a/src/main/kotlin/util/mc/InventoryUtil.kt
+++ b/src/main/kotlin/util/mc/InventoryUtil.kt
@@ -2,26 +2,26 @@ package moe.nea.firmament.util.mc
import java.util.Spliterator
import java.util.Spliterators
-import net.minecraft.inventory.Inventory
-import net.minecraft.item.ItemStack
+import net.minecraft.world.Container
+import net.minecraft.world.item.ItemStack
-val Inventory.indices get() = 0 until size()
-val Inventory.iterableView
+val Container.indices get() = 0 until containerSize
+val Container.iterableView
get() = object : Iterable<ItemStack> {
override fun spliterator(): Spliterator<ItemStack> {
- return Spliterators.spliterator(iterator(), size().toLong(), 0)
+ return Spliterators.spliterator(iterator(), containerSize.toLong(), 0)
}
override fun iterator(): Iterator<ItemStack> {
return object : Iterator<ItemStack> {
var i = 0
override fun hasNext(): Boolean {
- return i < size()
+ return i < containerSize
}
override fun next(): ItemStack {
if (!hasNext()) throw NoSuchElementException()
- return getStack(i++)
+ return getItem(i++)
}
}
}
diff --git a/src/main/kotlin/util/mc/ItemUtil.kt b/src/main/kotlin/util/mc/ItemUtil.kt
index 13519cf..91b6409 100644
--- a/src/main/kotlin/util/mc/ItemUtil.kt
+++ b/src/main/kotlin/util/mc/ItemUtil.kt
@@ -1,20 +1,30 @@
package moe.nea.firmament.util.mc
-import net.minecraft.item.ItemStack
-import net.minecraft.text.Text
+import kotlin.jvm.optionals.getOrNull
+import net.minecraft.world.item.ItemStack
+import net.minecraft.nbt.CompoundTag
+import net.minecraft.nbt.NbtOps
+import net.minecraft.resources.RegistryOps
+import net.minecraft.core.HolderLookup
+import net.minecraft.network.chat.Component
+import moe.nea.firmament.util.MC
-fun ItemStack.appendLore(args: List<Text>) {
- if (args.isEmpty()) return
- modifyLore {
- val loreList = loreAccordingToNbt.toMutableList()
- for (arg in args) {
- loreList.add(arg)
- }
- loreList
- }
+fun ItemStack.appendLore(args: List<Component>) {
+ if (args.isEmpty()) return
+ modifyLore {
+ val loreList = loreAccordingToNbt.toMutableList()
+ for (arg in args) {
+ loreList.add(arg)
+ }
+ loreList
+ }
}
-fun ItemStack.modifyLore(update: (List<Text>) -> List<Text>) {
- val loreList = loreAccordingToNbt
- loreAccordingToNbt = update(loreList)
+fun ItemStack.modifyLore(update: (List<Component>) -> List<Component>) {
+ val loreList = loreAccordingToNbt
+ loreAccordingToNbt = update(loreList)
+}
+
+fun loadItemFromNbt(nbt: CompoundTag, registries: HolderLookup.Provider = MC.defaultRegistries): ItemStack? {
+ return ItemStack.CODEC.decode(RegistryOps.create(NbtOps.INSTANCE, registries), nbt).result().getOrNull()?.first
}
diff --git a/src/main/kotlin/util/mc/MCTabListAPI.kt b/src/main/kotlin/util/mc/MCTabListAPI.kt
new file mode 100644
index 0000000..56933d9
--- /dev/null
+++ b/src/main/kotlin/util/mc/MCTabListAPI.kt
@@ -0,0 +1,96 @@
+package moe.nea.firmament.util.mc
+
+import com.mojang.serialization.Codec
+import com.mojang.serialization.codecs.RecordCodecBuilder
+import java.util.Optional
+import org.jetbrains.annotations.TestOnly
+import net.minecraft.client.gui.components.PlayerTabOverlay
+import net.minecraft.nbt.NbtOps
+import net.minecraft.world.scores.PlayerTeam
+import net.minecraft.network.chat.Component
+import net.minecraft.network.chat.ComponentSerialization
+import moe.nea.firmament.annotations.Subscribe
+import moe.nea.firmament.commands.thenExecute
+import moe.nea.firmament.commands.thenLiteral
+import moe.nea.firmament.events.CommandEvent
+import moe.nea.firmament.events.TickEvent
+import moe.nea.firmament.features.debug.DeveloperFeatures
+import moe.nea.firmament.features.debug.ExportedTestConstantMeta
+import moe.nea.firmament.mixins.accessor.AccessorPlayerListHud
+import moe.nea.firmament.util.ClipboardUtils
+import moe.nea.firmament.util.MC
+import moe.nea.firmament.util.intoOptional
+import moe.nea.firmament.util.mc.SNbtFormatter.Companion.toPrettyString
+
+object MCTabListAPI {
+
+ fun PlayerTabOverlay.cast() = this as AccessorPlayerListHud
+
+ @Subscribe
+ fun onTick(event: TickEvent) {
+ _currentTabList = null
+ }
+
+ @Subscribe
+ fun devCommand(event: CommandEvent.SubCommand) {
+ event.subcommand(DeveloperFeatures.DEVELOPER_SUBCOMMAND) {
+ thenLiteral("copytablist") {
+ thenExecute {
+ currentTabList.body.forEach {
+ MC.sendChat(Component.literal(ComponentSerialization.CODEC.encodeStart(NbtOps.INSTANCE, it).orThrow.toString()))
+ }
+ var compound = CurrentTabList.CODEC.encodeStart(NbtOps.INSTANCE, currentTabList).orThrow
+ compound = ExportedTestConstantMeta.SOURCE_CODEC.encode(
+ ExportedTestConstantMeta.current,
+ NbtOps.INSTANCE,
+ compound
+ ).orThrow
+ ClipboardUtils.setTextContent(
+ compound.toPrettyString()
+ )
+ }
+ }
+ }
+ }
+
+ @get:TestOnly
+ @set:TestOnly
+ var _currentTabList: CurrentTabList? = null
+
+ val currentTabList get() = _currentTabList ?: getTabListNow().also { _currentTabList = it }
+
+ data class CurrentTabList(
+ val header: Optional<Component>,
+ val footer: Optional<Component>,
+ val body: List<Component>,
+ ) {
+ companion object {
+ val CODEC: Codec<CurrentTabList> = RecordCodecBuilder.create {
+ it.group(
+ ComponentSerialization.CODEC.optionalFieldOf("header").forGetter(CurrentTabList::header),
+ ComponentSerialization.CODEC.optionalFieldOf("footer").forGetter(CurrentTabList::footer),
+ ComponentSerialization.CODEC.listOf().fieldOf("body").forGetter(CurrentTabList::body),
+ ).apply(it, ::CurrentTabList)
+ }
+ }
+ }
+
+ private fun getTabListNow(): CurrentTabList {
+ // This is a precondition for PlayerListHud.collectEntries to be valid
+ MC.networkHandler ?: return CurrentTabList(Optional.empty(), Optional.empty(), emptyList())
+ val hud = MC.inGameHud.tabList.cast()
+ val entries = hud.collectPlayerEntries_firmament()
+ .map {
+ it.tabListDisplayName ?: run {
+ val team = it.team
+ val name = it.profile.name
+ PlayerTeam.formatNameForTeam(team, Component.literal(name))
+ }
+ }
+ return CurrentTabList(
+ header = hud.header_firmament.intoOptional(),
+ footer = hud.footer_firmament.intoOptional(),
+ body = entries,
+ )
+ }
+}
diff --git a/src/main/kotlin/util/mc/NbtItemData.kt b/src/main/kotlin/util/mc/NbtItemData.kt
index 0c49862..55bfac3 100644
--- a/src/main/kotlin/util/mc/NbtItemData.kt
+++ b/src/main/kotlin/util/mc/NbtItemData.kt
@@ -1,22 +1,22 @@
package moe.nea.firmament.util.mc
-import net.minecraft.component.DataComponentTypes
-import net.minecraft.component.type.LoreComponent
-import net.minecraft.item.ItemStack
-import net.minecraft.text.Text
+import net.minecraft.core.component.DataComponents
+import net.minecraft.world.item.component.ItemLore
+import net.minecraft.world.item.ItemStack
+import net.minecraft.network.chat.Component
-var ItemStack.loreAccordingToNbt: List<Text>
- get() = get(DataComponentTypes.LORE)?.lines ?: listOf()
+var ItemStack.loreAccordingToNbt: List<Component>
+ get() = get(DataComponents.LORE)?.lines ?: listOf()
set(value) {
- set(DataComponentTypes.LORE, LoreComponent(value))
+ set(DataComponents.LORE, ItemLore(value))
}
-var ItemStack.displayNameAccordingToNbt: Text
- get() = get(DataComponentTypes.CUSTOM_NAME) ?: get(DataComponentTypes.ITEM_NAME) ?: item.name
+var ItemStack.displayNameAccordingToNbt: Component
+ get() = get(DataComponents.CUSTOM_NAME) ?: get(DataComponents.ITEM_NAME) ?: item.name
set(value) {
- set(DataComponentTypes.CUSTOM_NAME, value)
+ set(DataComponents.CUSTOM_NAME, value)
}
-fun ItemStack.setCustomName(text: Text) {
- set(DataComponentTypes.CUSTOM_NAME, text)
+fun ItemStack.setCustomName(text: Component) {
+ set(DataComponents.CUSTOM_NAME, text)
}
diff --git a/src/main/kotlin/util/mc/NbtPrism.kt b/src/main/kotlin/util/mc/NbtPrism.kt
new file mode 100644
index 0000000..6ac7cb2
--- /dev/null
+++ b/src/main/kotlin/util/mc/NbtPrism.kt
@@ -0,0 +1,85 @@
+package moe.nea.firmament.util.mc
+
+import com.google.gson.Gson
+import com.google.gson.JsonArray
+import com.google.gson.JsonElement
+import com.google.gson.JsonPrimitive
+import com.mojang.brigadier.StringReader
+import com.mojang.brigadier.arguments.ArgumentType
+import com.mojang.brigadier.arguments.StringArgumentType
+import com.mojang.serialization.JsonOps
+import kotlin.jvm.optionals.getOrNull
+import net.minecraft.nbt.CompoundTag
+import net.minecraft.nbt.Tag
+import net.minecraft.nbt.ListTag
+import net.minecraft.nbt.NbtOps
+import net.minecraft.nbt.StringTag
+import moe.nea.firmament.util.Base64Util
+
+class NbtPrism(val path: List<String>) {
+ companion object {
+ fun fromElement(path: JsonElement): NbtPrism? {
+ if (path is JsonArray) {
+ return NbtPrism(path.map { (it as JsonPrimitive).asString })
+ } else if (path is JsonPrimitive && path.isString) {
+ return NbtPrism(path.asString.split("."))
+ }
+ return null
+ }
+ }
+
+ object Argument : ArgumentType<NbtPrism> {
+ override fun parse(reader: StringReader): NbtPrism? {
+ return fromElement(JsonPrimitive(StringArgumentType.string().parse(reader)))
+ }
+
+ override fun getExamples(): Collection<String?>? {
+ return listOf("some.nbt.path", "some.other.*", "some.path.*json.in.a.json.string")
+ }
+ }
+
+ override fun toString(): String {
+ return "Prism($path)"
+ }
+
+ fun access(root: Tag): Collection<Tag> {
+ var rootSet = mutableListOf(root)
+ var switch = mutableListOf<Tag>()
+ for (pathSegment in path) {
+ if (pathSegment == ".") continue
+ if (pathSegment != "*" && pathSegment.startsWith("*")) {
+ if (pathSegment == "*json") {
+ for (element in rootSet) {
+ val eString = element.asString().getOrNull() ?: continue
+ val element = Gson().fromJson(eString, JsonElement::class.java)
+ switch.add(JsonOps.INSTANCE.convertTo(NbtOps.INSTANCE, element))
+ }
+ } else if (pathSegment == "*base64") {
+ for (element in rootSet) {
+ val string = element.asString().getOrNull() ?: continue
+ switch.add(StringTag.valueOf(Base64Util.decodeString(string)))
+ }
+ }
+ }
+ for (element in rootSet) {
+ if (element is ListTag) {
+ if (pathSegment == "*")
+ switch.addAll(element)
+ val index = pathSegment.toIntOrNull() ?: continue
+ if (index !in element.indices) continue
+ switch.add(element[index])
+ }
+ if (element is CompoundTag) {
+ if (pathSegment == "*")
+ element.keySet().mapTo(switch) { element.get(it)!! }
+ switch.add(element.get(pathSegment) ?: continue)
+ }
+ }
+ val temp = switch
+ switch = rootSet
+ rootSet = temp
+ switch.clear()
+ }
+ return rootSet
+ }
+}
diff --git a/src/main/kotlin/util/mc/NbtUtil.kt b/src/main/kotlin/util/mc/NbtUtil.kt
new file mode 100644
index 0000000..cfd4184
--- /dev/null
+++ b/src/main/kotlin/util/mc/NbtUtil.kt
@@ -0,0 +1,15 @@
+package moe.nea.firmament.util.mc
+
+import net.minecraft.world.item.component.CustomData
+import net.minecraft.nbt.Tag
+import net.minecraft.nbt.ListTag
+import moe.nea.firmament.mixins.accessor.AccessorNbtComponent
+
+fun Iterable<Tag>.toNbtList() = ListTag().also {
+ for (element in this) {
+ it.add(element)
+ }
+}
+
+@Suppress("CAST_NEVER_SUCCEEDS")
+val CustomData.unsafeNbt get() = (this as AccessorNbtComponent).unsafeNbt_firmament
diff --git a/src/main/kotlin/util/mc/PlayerUtil.kt b/src/main/kotlin/util/mc/PlayerUtil.kt
new file mode 100644
index 0000000..7c21987
--- /dev/null
+++ b/src/main/kotlin/util/mc/PlayerUtil.kt
@@ -0,0 +1,7 @@
+package moe.nea.firmament.util.mc
+
+import net.minecraft.world.entity.EquipmentSlot
+import net.minecraft.world.entity.player.Player
+
+
+val Player.mainHandStack get() = this.getItemBySlot(EquipmentSlot.MAINHAND)
diff --git a/src/main/kotlin/util/mc/Rectangle.kt b/src/main/kotlin/util/mc/Rectangle.kt
new file mode 100644
index 0000000..6495c29
--- /dev/null
+++ b/src/main/kotlin/util/mc/Rectangle.kt
@@ -0,0 +1,11 @@
+package moe.nea.firmament.util.mc
+
+import me.shedaniel.math.Rectangle
+import net.minecraft.client.gui.navigation.ScreenAxis
+import net.minecraft.client.gui.navigation.ScreenRectangle
+
+fun Rectangle.asScreenRectangle() =
+ ScreenRectangle.of(
+ ScreenAxis.HORIZONTAL,
+ x, y, width, height
+ )
diff --git a/src/main/kotlin/util/mc/SNbtFormatter.kt b/src/main/kotlin/util/mc/SNbtFormatter.kt
index e773927..0e630eb 100644
--- a/src/main/kotlin/util/mc/SNbtFormatter.kt
+++ b/src/main/kotlin/util/mc/SNbtFormatter.kt
@@ -1,22 +1,23 @@
package moe.nea.firmament.util.mc
-import net.minecraft.nbt.NbtByte
-import net.minecraft.nbt.NbtByteArray
-import net.minecraft.nbt.NbtCompound
-import net.minecraft.nbt.NbtDouble
-import net.minecraft.nbt.NbtElement
-import net.minecraft.nbt.NbtEnd
-import net.minecraft.nbt.NbtFloat
-import net.minecraft.nbt.NbtInt
-import net.minecraft.nbt.NbtIntArray
-import net.minecraft.nbt.NbtList
-import net.minecraft.nbt.NbtLong
-import net.minecraft.nbt.NbtLongArray
-import net.minecraft.nbt.NbtShort
-import net.minecraft.nbt.NbtString
-import net.minecraft.nbt.visitor.NbtElementVisitor
-
-class SNbtFormatter private constructor() : NbtElementVisitor {
+import net.minecraft.nbt.CollectionTag
+import net.minecraft.nbt.ByteTag
+import net.minecraft.nbt.ByteArrayTag
+import net.minecraft.nbt.CompoundTag
+import net.minecraft.nbt.DoubleTag
+import net.minecraft.nbt.Tag
+import net.minecraft.nbt.EndTag
+import net.minecraft.nbt.FloatTag
+import net.minecraft.nbt.IntTag
+import net.minecraft.nbt.IntArrayTag
+import net.minecraft.nbt.ListTag
+import net.minecraft.nbt.LongTag
+import net.minecraft.nbt.LongArrayTag
+import net.minecraft.nbt.ShortTag
+import net.minecraft.nbt.StringTag
+import net.minecraft.nbt.TagVisitor
+
+class SNbtFormatter private constructor() : TagVisitor {
private val result = StringBuilder()
private var indent = 0
private fun writeIndent() {
@@ -31,52 +32,52 @@ class SNbtFormatter private constructor() : NbtElementVisitor {
indent--
}
- fun apply(element: NbtElement): StringBuilder {
+ fun apply(element: Tag): StringBuilder {
element.accept(this)
return result
}
- override fun visitString(element: NbtString) {
- result.append(NbtString.escape(element.asString()))
+ override fun visitString(element: StringTag) {
+ result.append(StringTag.quoteAndEscape(element.value))
}
- override fun visitByte(element: NbtByte) {
- result.append(element.numberValue()).append("b")
+ override fun visitByte(element: ByteTag) {
+ result.append(element.box()).append("b")
}
- override fun visitShort(element: NbtShort) {
+ override fun visitShort(element: ShortTag) {
result.append(element.shortValue()).append("s")
}
- override fun visitInt(element: NbtInt) {
+ override fun visitInt(element: IntTag) {
result.append(element.intValue())
}
- override fun visitLong(element: NbtLong) {
+ override fun visitLong(element: LongTag) {
result.append(element.longValue()).append("L")
}
- override fun visitFloat(element: NbtFloat) {
+ override fun visitFloat(element: FloatTag) {
result.append(element.floatValue()).append("f")
}
- override fun visitDouble(element: NbtDouble) {
+ override fun visitDouble(element: DoubleTag) {
result.append(element.doubleValue()).append("d")
}
- private fun visitArrayContents(array: List<NbtElement>) {
+ private fun visitArrayContents(array: CollectionTag) {
array.forEachIndexed { index, element ->
writeIndent()
element.accept(this)
- if (array.size != index + 1) {
+ if (array.size() != index + 1) {
result.append(",")
}
result.append("\n")
}
}
- private fun writeArray(arrayTypeTag: String, array: List<NbtElement>) {
+ private fun writeArray(arrayTypeTag: String, array: CollectionTag) {
result.append("[").append(arrayTypeTag).append("\n")
pushIndent()
visitArrayContents(array)
@@ -86,30 +87,30 @@ class SNbtFormatter private constructor() : NbtElementVisitor {
}
- override fun visitByteArray(element: NbtByteArray) {
+ override fun visitByteArray(element: ByteArrayTag) {
writeArray("B;", element)
}
- override fun visitIntArray(element: NbtIntArray) {
+ override fun visitIntArray(element: IntArrayTag) {
writeArray("I;", element)
}
- override fun visitLongArray(element: NbtLongArray) {
+ override fun visitLongArray(element: LongArrayTag) {
writeArray("L;", element)
}
- override fun visitList(element: NbtList) {
+ override fun visitList(element: ListTag) {
writeArray("", element)
}
- override fun visitCompound(compound: NbtCompound) {
+ override fun visitCompound(compound: CompoundTag) {
result.append("{\n")
pushIndent()
- val keys = compound.keys.sorted()
+ val keys = compound.keySet().sorted()
keys.forEachIndexed { index, key ->
writeIndent()
val element = compound[key] ?: error("Key '$key' found but not present in compound: $compound")
- val escapedName = if (key.matches(SIMPLE_NAME)) key else NbtString.escape(key)
+ val escapedName = escapeName(key)
result.append(escapedName).append(": ")
element.accept(this)
if (keys.size != index + 1) {
@@ -122,17 +123,20 @@ class SNbtFormatter private constructor() : NbtElementVisitor {
result.append("}")
}
- override fun visitEnd(element: NbtEnd) {
+ override fun visitEnd(element: EndTag) {
result.append("END")
}
companion object {
- fun prettify(nbt: NbtElement): String {
+ fun prettify(nbt: Tag): String {
return SNbtFormatter().apply(nbt).toString()
}
- fun NbtElement.toPrettyString() = prettify(this)
+ fun Tag.toPrettyString() = prettify(this)
- private val SIMPLE_NAME = "[A-Za-z0-9._+-]+".toRegex()
+ fun escapeName(key: String): String =
+ if (key.matches(SIMPLE_NAME)) key else StringTag.quoteAndEscape(key)
+
+ val SIMPLE_NAME = "[A-Za-z0-9._+-]+".toRegex()
}
}
diff --git a/src/main/kotlin/util/mc/ScreenUtil.kt b/src/main/kotlin/util/mc/ScreenUtil.kt
index 36feb6b..4e3dbf1 100644
--- a/src/main/kotlin/util/mc/ScreenUtil.kt
+++ b/src/main/kotlin/util/mc/ScreenUtil.kt
@@ -1,9 +1,9 @@
package moe.nea.firmament.util.mc
-import net.minecraft.client.gui.screen.Screen
-import net.minecraft.client.gui.screen.ingame.HandledScreen
-import net.minecraft.entity.player.PlayerInventory
-import net.minecraft.screen.slot.Slot
+import net.minecraft.client.gui.screens.Screen
+import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen
+import net.minecraft.world.entity.player.Inventory
+import net.minecraft.world.inventory.Slot
object ScreenUtil {
private var lastScreen: Screen? = null
@@ -12,15 +12,15 @@ object ScreenUtil {
data class SlotIndex(val index: Int, val isPlayerInventory: Boolean)
fun Screen.getSlotsByIndex(): Map<SlotIndex, Slot> {
- if (this !is HandledScreen<*>) return mapOf()
+ if (this !is AbstractContainerScreen<*>) return mapOf()
if (lastScreen === this) return slotsByIndex
lastScreen = this
- slotsByIndex = this.screenHandler.slots.associate {
- SlotIndex(it.index, it.inventory is PlayerInventory) to it
+ slotsByIndex = this.menu.slots.associate {
+ SlotIndex(it.containerSlot, it.container is Inventory) to it
}
return slotsByIndex
}
- fun Screen.getSlotByIndex( index: Int, isPlayerInventory: Boolean): Slot? =
+ fun Screen.getSlotByIndex(index: Int, isPlayerInventory: Boolean): Slot? =
getSlotsByIndex()[SlotIndex(index, isPlayerInventory)]
}
diff --git a/src/main/kotlin/util/mc/SkullItemData.kt b/src/main/kotlin/util/mc/SkullItemData.kt
index 0405b65..80028af 100644
--- a/src/main/kotlin/util/mc/SkullItemData.kt
+++ b/src/main/kotlin/util/mc/SkullItemData.kt
@@ -2,19 +2,20 @@
package moe.nea.firmament.util.mc
+import com.google.common.collect.Multimap
+import com.google.common.collect.Multimaps
import com.mojang.authlib.GameProfile
import com.mojang.authlib.minecraft.MinecraftProfileTexture
import com.mojang.authlib.properties.Property
+import com.mojang.authlib.properties.PropertyMap
+import java.time.Instant
import java.util.UUID
-import kotlinx.datetime.Clock
-import kotlinx.datetime.Instant
import kotlinx.serialization.Serializable
import kotlinx.serialization.UseSerializers
-import kotlinx.serialization.encodeToString
-import net.minecraft.component.DataComponentTypes
-import net.minecraft.component.type.ProfileComponent
-import net.minecraft.item.ItemStack
-import net.minecraft.item.Items
+import net.minecraft.core.component.DataComponents
+import net.minecraft.world.item.component.ResolvableProfile
+import net.minecraft.world.item.ItemStack
+import net.minecraft.world.item.Items
import moe.nea.firmament.Firmament
import moe.nea.firmament.util.Base64Util.padToValidBase64
import moe.nea.firmament.util.assertTrueOr
@@ -23,66 +24,75 @@ import moe.nea.firmament.util.json.InstantAsLongSerializer
@Serializable
data class MinecraftProfileTextureKt(
- val url: String,
- val metadata: Map<String, String> = mapOf(),
+ val url: String,
+ val metadata: Map<String, String> = mapOf(),
)
@Serializable
data class MinecraftTexturesPayloadKt(
- val textures: Map<MinecraftProfileTexture.Type, MinecraftProfileTextureKt> = mapOf(),
- val profileId: UUID? = null,
- val profileName: String? = null,
- val isPublic: Boolean = true,
- val timestamp: Instant = Clock.System.now(),
+ val textures: Map<MinecraftProfileTexture.Type, MinecraftProfileTextureKt> = mapOf(),
+ val profileId: UUID? = null,
+ val profileName: String? = null,
+ val isPublic: Boolean = true,
+ val timestamp: Instant = Instant.now(),
)
-fun GameProfile.setTextures(textures: MinecraftTexturesPayloadKt) {
- val json = Firmament.json.encodeToString(textures)
- val encoded = java.util.Base64.getEncoder().encodeToString(json.encodeToByteArray())
- properties.put(propertyTextures, Property(propertyTextures, encoded))
+fun createSkullTextures(textures: MinecraftTexturesPayloadKt): PropertyMap {
+ val json = Firmament.json.encodeToString(textures)
+ val encoded = java.util.Base64.getEncoder().encodeToString(json.encodeToByteArray())
+ return PropertyMap(
+ Multimaps.forMap(mapOf(propertyTextures to Property(propertyTextures, encoded)))
+ )
}
private val propertyTextures = "textures"
fun ItemStack.setEncodedSkullOwner(uuid: UUID, encodedData: String) {
- assert(this.item == Items.PLAYER_HEAD)
- val gameProfile = GameProfile(uuid, "LameGuy123")
- gameProfile.properties.put(propertyTextures, Property(propertyTextures, encodedData.padToValidBase64()))
- this.set(DataComponentTypes.PROFILE, ProfileComponent(gameProfile))
+ assert(this.item == Items.PLAYER_HEAD)
+ val gameProfile = GameProfile(
+ uuid, "LameGuy123",
+ PropertyMap(
+ Multimaps.forMap(
+ mapOf(propertyTextures to Property(propertyTextures, encodedData.padToValidBase64()))
+ )
+ )
+ )
+ this.set(DataComponents.PROFILE, ResolvableProfile.createResolved(gameProfile))
}
-val zeroUUID = UUID.fromString("d3cb85e2-3075-48a1-b213-a9bfb62360c1")
+val arbitraryUUID = UUID.fromString("d3cb85e2-3075-48a1-b213-a9bfb62360c1")
fun createSkullItem(uuid: UUID, url: String) = ItemStack(Items.PLAYER_HEAD)
- .also { it.setSkullOwner(uuid, url) }
+ .also { it.setSkullOwner(uuid, url) }
fun ItemStack.setSkullOwner(uuid: UUID, url: String) {
- assert(this.item == Items.PLAYER_HEAD)
- val gameProfile = GameProfile(uuid, "nea89")
- gameProfile.setTextures(
- MinecraftTexturesPayloadKt(
- textures = mapOf(MinecraftProfileTexture.Type.SKIN to MinecraftProfileTextureKt(url)),
- profileId = uuid,
- profileName = "nea89",
- )
- )
- this.set(DataComponentTypes.PROFILE, ProfileComponent(gameProfile))
+ assert(this.item == Items.PLAYER_HEAD)
+ val gameProfile = GameProfile(
+ uuid, "nea89", createSkullTextures(
+ MinecraftTexturesPayloadKt(
+ textures = mapOf(MinecraftProfileTexture.Type.SKIN to MinecraftProfileTextureKt(url)),
+ profileId = uuid,
+ profileName = "nea89",
+ )
+ )
+ )
+ this.set(DataComponents.PROFILE, ResolvableProfile.createResolved(gameProfile))
}
fun decodeProfileTextureProperty(property: Property): MinecraftTexturesPayloadKt? {
- assertTrueOr(property.name == propertyTextures) { return null }
- return try {
- var encodedF: String = property.value
- while (encodedF.length % 4 != 0 && encodedF.last() == '=') {
- encodedF = encodedF.substring(0, encodedF.length - 1)
- }
- val json = java.util.Base64.getDecoder().decode(encodedF).decodeToString()
- Firmament.json.decodeFromString<MinecraftTexturesPayloadKt>(json)
- } catch (e: Exception) {
- // Malformed profile data
- if (Firmament.DEBUG)
- e.printStackTrace()
- null
- }
+ assertTrueOr(property.name == propertyTextures) { return null }
+ return try {
+ var encodedF: String = property.value
+ while (encodedF.length % 4 != 0 && encodedF.last() == '=') {
+ encodedF = encodedF.substring(0, encodedF.length - 1)
+ }
+ val json = java.util.Base64.getDecoder().decode(encodedF).decodeToString()
+ Firmament.json.decodeFromString<MinecraftTexturesPayloadKt>(json)
+ } catch (e: Exception) {
+ // Malformed profile data
+ if (Firmament.DEBUG)
+ e.printStackTrace()
+ null
+ }
}
diff --git a/src/main/kotlin/util/mc/SlotUtils.kt b/src/main/kotlin/util/mc/SlotUtils.kt
index 4709dcf..2f5fd49 100644
--- a/src/main/kotlin/util/mc/SlotUtils.kt
+++ b/src/main/kotlin/util/mc/SlotUtils.kt
@@ -1,34 +1,46 @@
package moe.nea.firmament.util.mc
-import net.minecraft.screen.ScreenHandler
-import net.minecraft.screen.slot.Slot
-import net.minecraft.screen.slot.SlotActionType
+import org.lwjgl.glfw.GLFW
+import net.minecraft.world.inventory.AbstractContainerMenu
+import net.minecraft.world.inventory.Slot
+import net.minecraft.world.inventory.ClickType
import moe.nea.firmament.util.MC
object SlotUtils {
- fun Slot.clickMiddleMouseButton(handler: ScreenHandler) {
- MC.interactionManager?.clickSlot(
- handler.syncId,
- this.id,
- 2,
- SlotActionType.CLONE,
+ fun Slot.clickMiddleMouseButton(handler: AbstractContainerMenu) {
+ MC.interactionManager?.handleInventoryMouseClick(
+ handler.containerId,
+ this.index,
+ GLFW.GLFW_MOUSE_BUTTON_MIDDLE,
+ ClickType.CLONE,
MC.player
)
}
- fun Slot.swapWithHotBar(handler: ScreenHandler, hotbarIndex: Int) {
- MC.interactionManager?.clickSlot(
- handler.syncId, this.id,
- hotbarIndex, SlotActionType.SWAP,
- MC.player)
+ fun Slot.swapWithHotBar(handler: AbstractContainerMenu, hotbarIndex: Int) {
+ MC.interactionManager?.handleInventoryMouseClick(
+ handler.containerId, this.index,
+ hotbarIndex, ClickType.SWAP,
+ MC.player
+ )
+ }
+
+ fun Slot.clickRightMouseButton(handler: AbstractContainerMenu) {
+ MC.interactionManager?.handleInventoryMouseClick(
+ handler.containerId,
+ this.index,
+ GLFW.GLFW_MOUSE_BUTTON_RIGHT,
+ ClickType.PICKUP,
+ MC.player
+ )
}
- fun Slot.clickRightMouseButton(handler: ScreenHandler) {
- MC.interactionManager?.clickSlot(
- handler.syncId,
- this.id,
- 1,
- SlotActionType.PICKUP,
+ fun Slot.clickLeftMouseButton(handler: AbstractContainerMenu) {
+ MC.interactionManager?.handleInventoryMouseClick(
+ handler.containerId,
+ this.index,
+ GLFW.GLFW_MOUSE_BUTTON_LEFT,
+ ClickType.PICKUP,
MC.player
)
}
diff --git a/src/main/kotlin/util/mc/TolerantRegistriesOps.kt b/src/main/kotlin/util/mc/TolerantRegistriesOps.kt
index ce596a0..833aca9 100644
--- a/src/main/kotlin/util/mc/TolerantRegistriesOps.kt
+++ b/src/main/kotlin/util/mc/TolerantRegistriesOps.kt
@@ -2,27 +2,27 @@ package moe.nea.firmament.util.mc
import com.mojang.serialization.DynamicOps
import java.util.Optional
-import net.minecraft.registry.Registry
-import net.minecraft.registry.RegistryKey
-import net.minecraft.registry.RegistryOps
-import net.minecraft.registry.RegistryWrapper
-import net.minecraft.registry.entry.RegistryEntryOwner
+import net.minecraft.core.Registry
+import net.minecraft.resources.ResourceKey
+import net.minecraft.resources.RegistryOps
+import net.minecraft.core.HolderLookup
+import net.minecraft.core.HolderOwner
class TolerantRegistriesOps<T>(
delegate: DynamicOps<T>,
- registryInfoGetter: RegistryInfoGetter
+ registryInfoGetter: RegistryInfoLookup
) : RegistryOps<T>(delegate, registryInfoGetter) {
- constructor(delegate: DynamicOps<T>, registry: RegistryWrapper.WrapperLookup) :
- this(delegate, CachedRegistryInfoGetter(registry))
+ constructor(delegate: DynamicOps<T>, registry: HolderLookup.Provider) :
+ this(delegate, HolderLookupAdapter(registry))
- class TolerantOwner<E> : RegistryEntryOwner<E> {
- override fun ownerEquals(other: RegistryEntryOwner<E>?): Boolean {
+ class TolerantOwner<E> : HolderOwner<E> {
+ override fun canSerializeIn(other: HolderOwner<E>?): Boolean {
return true
}
}
- override fun <E : Any?> getOwner(registryRef: RegistryKey<out Registry<out E>>?): Optional<RegistryEntryOwner<E>> {
- return super.getOwner(registryRef).map {
+ override fun <E : Any?> owner(registryRef: ResourceKey<out Registry<out E>>?): Optional<HolderOwner<E>> {
+ return super.owner(registryRef).map {
TolerantOwner()
}
}
diff --git a/src/main/kotlin/util/mc/asFakeServer.kt b/src/main/kotlin/util/mc/asFakeServer.kt
index d3811bd..1075d62 100644
--- a/src/main/kotlin/util/mc/asFakeServer.kt
+++ b/src/main/kotlin/util/mc/asFakeServer.kt
@@ -1,27 +1,27 @@
package moe.nea.firmament.util.mc
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource
-import net.minecraft.server.command.CommandOutput
-import net.minecraft.server.command.ServerCommandSource
-import net.minecraft.text.Text
+import net.minecraft.commands.CommandSource
+import net.minecraft.commands.CommandSourceStack
+import net.minecraft.network.chat.Component
-fun FabricClientCommandSource.asFakeServer(): ServerCommandSource {
+fun FabricClientCommandSource.asFakeServer(): CommandSourceStack {
val source = this
- return ServerCommandSource(
- object : CommandOutput {
- override fun sendMessage(message: Text?) {
- source.player.sendMessage(message, false)
+ return CommandSourceStack(
+ object : CommandSource {
+ override fun sendSystemMessage(message: Component?) {
+ source.player.displayClientMessage(message, false)
}
- override fun shouldReceiveFeedback(): Boolean {
+ override fun acceptsSuccess(): Boolean {
return true
}
- override fun shouldTrackOutput(): Boolean {
+ override fun acceptsFailure(): Boolean {
return true
}
- override fun shouldBroadcastConsoleToOps(): Boolean {
+ override fun shouldInformAdmins(): Boolean {
return true
}
},
@@ -30,7 +30,7 @@ fun FabricClientCommandSource.asFakeServer(): ServerCommandSource {
null,
0,
"FakeServerCommandSource",
- Text.literal("FakeServerCommandSource"),
+ Component.literal("FakeServerCommandSource"),
null,
source.player
)