Skip to content

Commit

Permalink
Merge pull request #142 from Y2Kwastaken/nms-additions
Browse files Browse the repository at this point in the history
Adds NMS for workbenches
  • Loading branch information
mfnalex authored Feb 17, 2024
2 parents b09d341 + 7ee614b commit c3e3789
Show file tree
Hide file tree
Showing 9 changed files with 187 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
package com.github.spigotbasics.nms

import org.bukkit.entity.HumanEntity
import org.bukkit.event.inventory.InventoryType
import org.bukkit.inventory.InventoryView
import kotlin.jvm.Throws

interface NMSFacade {
fun getTps(): DoubleArray

/**
* Opens a workbench of the provided type, if supported and returns the InventoryView
*
* @param entity the human entity opening the workbench
* @param type the type of workbench being open
* @return the InventoryView
* @throws IllegalArgumentException if the given type is not supported
* @throws IllegalStateException if the given entity is not a player with a connection
*/
@Throws(IllegalArgumentException::class, IllegalStateException::class)
fun openWorkbench(
entity: HumanEntity,
type: InventoryType,
): InventoryView?
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
package com.github.spigotbasics.nms

import org.bukkit.entity.HumanEntity
import org.bukkit.event.inventory.InventoryType
import org.bukkit.inventory.InventoryView

class UnsupportedNMSFacade : NMSFacade {
override fun getTps(): DoubleArray {
throw NMSNotSupportedException()
}

override fun openWorkbench(
entity: HumanEntity,
type: InventoryType,
): InventoryView {
throw NMSNotSupportedException()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package com.github.spigotbasics.nms.v1_20_4

import com.github.spigotbasics.nms.v1_20_4.MenuBuilderImpl.ContainerProvider
import net.minecraft.core.BlockPos
import net.minecraft.network.chat.Component
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.inventory.AnvilMenu
import net.minecraft.world.inventory.CartographyTableMenu
import net.minecraft.world.inventory.ContainerLevelAccess
import net.minecraft.world.inventory.EnchantmentMenu
import net.minecraft.world.inventory.GrindstoneMenu
import net.minecraft.world.inventory.LoomMenu
import net.minecraft.world.inventory.MenuConstructor
import net.minecraft.world.inventory.SmithingMenu
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.state.BlockState
import org.bukkit.event.inventory.InventoryType

object MenuBuilderImpl {
private val builder = mutableMapOf<InventoryType, ContainerProvider>()
private val titles = mutableMapOf<InventoryType, Component>()

init {
builder[InventoryType.ANVIL] = worldAccess(::AnvilMenu)
builder[InventoryType.ENCHANTING] = worldAccess(::EnchantmentMenu)
builder[InventoryType.LOOM] = worldAccess(::LoomMenu)
builder[InventoryType.CARTOGRAPHY] = worldAccess(::CartographyTableMenu)
builder[InventoryType.GRINDSTONE] = worldAccess(::GrindstoneMenu)
builder[InventoryType.SMITHING] = worldAccess(::SmithingMenu)
}

init {
titles[InventoryType.ANVIL] = Component.translatable("container.repair")
titles[InventoryType.ENCHANTING] = Component.translatable("container.enchant")
titles[InventoryType.LOOM] = Component.translatable("container.loom")
titles[InventoryType.CARTOGRAPHY] = Component.translatable("container.cartography_table")
titles[InventoryType.GRINDSTONE] = Component.translatable("container.grindstone_title")
titles[InventoryType.SMITHING] = Component.translatable("container.upgrade")
}

fun build(
serverPlayer: ServerPlayer,
inventoryType: InventoryType,
): AbstractContainerMenu? {
return (builder[inventoryType] ?: return null).supply(serverPlayer, serverPlayer.inventory)
}

fun title(inventoryType: InventoryType): Component? {
return titles[inventoryType]
}

private fun interface ContainerProvider {
fun supply(
player: ServerPlayer,
playerInventory: Inventory,
): AbstractContainerMenu
}

private fun tile(
block: Block,
entity: (BlockPos, BlockState) -> MenuConstructor,
): ContainerProvider {
return ContainerProvider { player, inventory ->
return@ContainerProvider entity.invoke(BlockPos.ZERO, block.defaultBlockState())
.createMenu(player.nextContainerCounter(), inventory, player)!!
}
}

private fun worldAccess(accessor: (Int, Inventory, ContainerLevelAccess) -> AbstractContainerMenu): ContainerProvider {
return ContainerProvider { player, inventory ->
return@ContainerProvider accessor.invoke(
player.nextContainerCounter(),
inventory,
ContainerLevelAccess.create(player.level(), player.blockPosition()),
)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,51 @@
package com.github.spigotbasics.nms.v1_20_4

import com.github.spigotbasics.nms.NMSFacade
import net.minecraft.network.protocol.game.ClientboundOpenScreenPacket
import org.bukkit.Bukkit
import org.bukkit.craftbukkit.v1_20_R3.CraftServer
import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer
import org.bukkit.entity.HumanEntity
import org.bukkit.entity.Player
import org.bukkit.event.inventory.InventoryOpenEvent
import org.bukkit.event.inventory.InventoryType
import org.bukkit.inventory.InventoryView
import java.lang.IllegalStateException

class NMSImpl_v1_20_4 : NMSFacade {
override fun getTps(): DoubleArray {
@Suppress("DEPRECATION")
return (Bukkit.getServer() as CraftServer).handle.server.recentTps
}

override fun openWorkbench(
entity: HumanEntity,
type: InventoryType,
): InventoryView? {
if (entity !is Player) {
throw IllegalStateException("this player does not have a connection so no packets could be sent")
}

val serverPlayer = (entity as CraftPlayer).handle

val resultMenu =
MenuBuilderImpl.build(serverPlayer, type)
?: throw IllegalArgumentException("The given inventory type can not be used to create a workbench")
resultMenu.title = MenuBuilderImpl.title(type)
?: throw IllegalArgumentException("the given inventory title was not found with the specified workbench")
resultMenu.checkReachable = false

// Now that menu setup is done we will call the intended event in a much less naive manner as to support components
val event = InventoryOpenEvent(resultMenu.bukkitView)
Bukkit.getPluginManager().callEvent(event)
if (event.isCancelled) {
return null
}

val menuType = resultMenu.type
serverPlayer.connection.send(ClientboundOpenScreenPacket(resultMenu.containerId, menuType, resultMenu.title))
serverPlayer.containerMenu = resultMenu
serverPlayer.initMenu(resultMenu)
return resultMenu.bukkitView
}
}
1 change: 1 addition & 0 deletions pipe/spigot/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ plugins {

dependencies {
implementation(project(":pipe:facade"))
compileOnly(project(":nms:facade"))
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.github.spigotbasics.pipe.spigot

import com.github.spigotbasics.common.Either
import com.github.spigotbasics.nms.NMSFacade
import com.github.spigotbasics.pipe.OpenInventoryFacade
import com.github.spigotbasics.pipe.SerializedMiniMessage
import com.github.spigotbasics.pipe.SpigotPaperFacade
Expand All @@ -11,7 +12,9 @@ import org.bukkit.event.player.PlayerQuitEvent
import org.bukkit.plugin.PluginManager
import org.bukkit.plugin.SimplePluginManager

class SpigotFacade : SpigotPaperFacade {
class SpigotFacade(nms: NMSFacade) : SpigotPaperFacade {
private val inventoryFacade = SpigotOpenInventoryFacade(nms)

override fun setJoinMessage(
event: PlayerJoinEvent,
legacy: String,
Expand Down Expand Up @@ -39,5 +42,5 @@ class SpigotFacade : SpigotPaperFacade {
return field.get(spm) as SimpleCommandMap
}

override val openInventoryFacade: OpenInventoryFacade = SpigotOpenInventoryFacade
override val openInventoryFacade: OpenInventoryFacade = inventoryFacade
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,32 @@
package com.github.spigotbasics.pipe.spigot

import com.github.spigotbasics.nms.NMSFacade
import com.github.spigotbasics.pipe.OpenInventoryFacade
import org.bukkit.entity.Player
import org.bukkit.event.inventory.InventoryType

object SpigotOpenInventoryFacade : OpenInventoryFacade
class SpigotOpenInventoryFacade(private val nms: NMSFacade) : OpenInventoryFacade {
override fun openAnvil(player: Player) {
nms.openWorkbench(player, InventoryType.ANVIL)
}

override fun openCartographyTable(player: Player) {
nms.openWorkbench(player, InventoryType.CARTOGRAPHY)
}

override fun openGrindstone(player: Player) {
nms.openWorkbench(player, InventoryType.GRINDSTONE)
}

override fun openLoom(player: Player) {
nms.openWorkbench(player, InventoryType.LOOM)
}

override fun openSmithingTable(player: Player) {
nms.openWorkbench(player, InventoryType.SMITHING)
}

override fun openStonecutter(player: Player) {
nms.openWorkbench(player, InventoryType.STONECUTTER)
}
}
2 changes: 1 addition & 1 deletion plugin/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ dependencies {
implementation(project(":pipe:facade"))
implementation(project(":pipe:spigot"))
implementation(project(":pipe:paper"))
// implementation(project(":nms:facade"))
compileOnly(project(":nms:facade"))
implementation(project(":nms:aggregator", "shadow"))
// implementation(project(":common"))
// implementation(kotlin("reflect"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@ class BasicsPluginImpl : JavaPlugin(), BasicsPlugin {
)

override val audienceProvider: AudienceProvider = AudienceProvider(this)

override val nms: NMSFacade = NMSAggregator.getNmsFacade(CURRENT_MINECRAFT_VERSION)
override val facade: SpigotPaperFacade =
if (Spiper.isPaper) {
PaperFacade()
} else {
SpigotFacade()
SpigotFacade(nms)
}

private val logger = BasicsLoggerFactory.getCoreLogger(this::class)
Expand Down Expand Up @@ -75,7 +75,6 @@ class BasicsPluginImpl : JavaPlugin(), BasicsPlugin {
override val storageManager: StorageManager by lazy { StorageManager(coreConfigManager) }
override val corePlayerData: CorePlayerData by lazy { CorePlayerData(storageManager) }
override val chunkTicketManager: ChunkTicketManager = ChunkTicketManager()
override val nms: NMSFacade = NMSAggregator.getNmsFacade(CURRENT_MINECRAFT_VERSION)

internal val modulePlayerDataLoader by lazy {
ModulePlayerDataLoader(
Expand Down

0 comments on commit c3e3789

Please sign in to comment.