Skip to content

Commit

Permalink
Add First Minestiom Prototype
Browse files Browse the repository at this point in the history
  • Loading branch information
Nico Lube committed Feb 3, 2025
1 parent b114785 commit 201042f
Show file tree
Hide file tree
Showing 28 changed files with 2,098 additions and 4 deletions.
8 changes: 7 additions & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ paperSpigot = "1.20.1-R0.1-SNAPSHOT"
junit = "5.10.1"
mockito = "4.11.0"
adventure-api = "4.14.0"
kotlin = "2.0.21"
kotlin = "2.1.0"
plugin-shadowjar = "8.1.1"
plugin-spotless = "6.25.0"
plugin-bukkit = "0.6.0"
minestom = "87f6524aeb"


[libraries.spigot]
module = "org.spigotmc:spigot-api"
Expand Down Expand Up @@ -42,6 +44,10 @@ version.ref = "mockito"
module = "net.kyori:adventure-api"
version.ref = "adventure-api"

[libraries.minestom]
module = "net.minestom:minestom-snapshots"
version.ref = "minestom"

[plugins]
shadowjar = { id = "com.github.johnrengelman.shadow", version.ref = "plugin-shadowjar" }
spotless = { id = "com.diffplug.spotless", version.ref = "plugin-spotless" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import org.jetbrains.annotations.NotNull;

@SuppressWarnings("unchecked")
abstract class DefaultComponentBuilder<S extends ComponentBuilder<S, C>, C extends IFContext>
public abstract class DefaultComponentBuilder<S extends ComponentBuilder<S, C>, C extends IFContext>
implements ComponentBuilder<S, C> {

protected Ref<Component> reference;
Expand Down
36 changes: 36 additions & 0 deletions inventory-framework-platform-minestom/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import org.apache.tools.ant.filters.ReplaceTokens

plugins {
alias(libs.plugins.shadowjar)
alias(libs.plugins.kotlin)
}

apply from: '../library.gradle'
apply from: '../publish.gradle'

dependencies {
api projects.inventoryFrameworkPlatform
runtimeOnly projects.inventoryFrameworkAnvilInput
compileOnly libs.minestom
testCompileOnly libs.minestom
testImplementation projects.inventoryFrameworkApi
testImplementation projects.inventoryFrameworkTest
}

shadowJar {
archiveBaseName.set('inventory-framework')
archiveAppendix.set('bukkit')

dependencies {
include(project(":inventory-framework-platform"))
include(project(":inventory-framework-anvil-input"))
}
}


java {
targetCompatibility = JavaVersion.VERSION_21
toolchain {
languageVersion.set(JavaLanguageVersion.of(21))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package me.devnatan.inventoryframework

import me.devnatan.inventoryframework.context.IFCloseContext
import me.devnatan.inventoryframework.context.IFContext
import me.devnatan.inventoryframework.context.IFRenderContext
import me.devnatan.inventoryframework.context.IFSlotClickContext
import me.devnatan.inventoryframework.pipeline.StandardPipelinePhases
import net.minestom.server.MinecraftServer
import net.minestom.server.entity.Player
import net.minestom.server.event.EventFilter
import net.minestom.server.event.EventNode
import net.minestom.server.event.inventory.InventoryCloseEvent
import net.minestom.server.event.inventory.InventoryPreClickEvent
import net.minestom.server.event.item.ItemDropEvent
import net.minestom.server.event.item.PickupItemEvent
import net.minestom.server.inventory.PlayerInventory

internal class IFInventoryListener(
private val viewFrame: ViewFrame
) {

init {
val handler = MinecraftServer.getGlobalEventHandler()
val inventoryNode = EventNode.type("IF-inventory", EventFilter.INVENTORY)
.setPriority(10)
.addListener(InventoryPreClickEvent::class.java, this::onInventoryClick)
.addListener(InventoryCloseEvent::class.java, this::onInventoryClose)
val playerNode = EventNode.type("IF-player", EventFilter.PLAYER)
{ _, p -> viewFrame.getViewer(p) != null }
.setPriority(10)
.addListener(ItemDropEvent::class.java, this::onItemDrop)
val entityEvent = EventNode.type("IF-entity", EventFilter.ENTITY)
{ _, e -> e is Player && viewFrame.getViewer(e) != null }
.setPriority(10)
.addListener(PickupItemEvent::class.java, this::onItemPickup)
handler.addChild(inventoryNode)
handler.addChild(playerNode)
handler.addChild(entityEvent)
}

fun onInventoryClick(event: InventoryPreClickEvent) {
if (event.isCancelled) return

val player = event.player
val viewer = viewFrame.getViewer(player) ?: return

val context: IFRenderContext = viewer.activeContext
val clickedComponent: me.devnatan.inventoryframework.component.Component =
context.getComponentsAt(event.slot).stream()
.filter { obj: me.devnatan.inventoryframework.component.Component -> obj.isVisible }
.findFirst()
.orElse(null)
val clickedContainer = if (event.inventory is PlayerInventory)
viewer.selfContainer
else
context.getContainer()

val root: RootView = context.getRoot()
val clickContext: IFSlotClickContext = root.elementFactory
.createSlotClickContext(event.slot, viewer, clickedContainer, clickedComponent, event, false)

root.pipeline.execute(StandardPipelinePhases.CLICK, clickContext)
}

fun onInventoryClose(event: InventoryCloseEvent) {
val player: Player = event.player
val viewer = viewFrame.getViewer(player) ?: return

val context: IFRenderContext = viewer.activeContext
val root: RootView = context.getRoot()
val closeContext: IFCloseContext = root.elementFactory.createCloseContext(viewer, context)

root.pipeline.execute(StandardPipelinePhases.CLOSE, closeContext)
}

fun onItemPickup(event: PickupItemEvent) {
val viewer = viewFrame.getViewer(event.entity as Player) ?: return

val context: IFContext = viewer.activeContext
if (!context.getConfig().isOptionSet(ViewConfig.CANCEL_ON_PICKUP)) return

event.isCancelled = context.getConfig().getOptionValue(ViewConfig.CANCEL_ON_PICKUP)
}

fun onItemDrop(event: ItemDropEvent) {
val viewer = viewFrame.getViewer(event.getPlayer()) ?: return

val context: IFContext = viewer.activeContext
if (!context.getConfig().isOptionSet(ViewConfig.CANCEL_ON_DROP)) return

event.isCancelled = context.getConfig().getOptionValue(ViewConfig.CANCEL_ON_DROP)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
package me.devnatan.inventoryframework

import net.kyori.adventure.text.Component
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer
import net.minestom.server.entity.Player
import net.minestom.server.inventory.Inventory
import net.minestom.server.inventory.InventoryType
import net.minestom.server.inventory.PlayerInventory
import net.minestom.server.item.ItemStack
import java.util.*

class MinestomViewContainer(
private val inventory: Inventory, shared: Boolean, private val type: ViewType,
private val proxied: Boolean
) :
ViewContainer {
val isShared: Boolean = shared

fun getInventory(): Inventory {
return inventory
}

override fun isProxied(): Boolean {
return proxied
}

override fun getTitle(): String {
val diffTitle: Boolean = inventory.viewers.stream()
.map { player ->
(player.openInventory as? Inventory)?.title
?.let { PlainTextComponentSerializer.plainText().serialize(it) } ?: ""
}
.distinct()
.findAny()
.isPresent

check(!(diffTitle && isShared)) { "Cannot get unique title of shared inventory" }
val openInventory = inventory.viewers.first().openInventory
return (openInventory as? Inventory)?.title
?.let { PlainTextComponentSerializer.plainText().serialize(it) } ?: ""
}

override fun getTitle(viewer: Viewer): String {
return ((viewer as MinestomViewer).player.openInventory as? Inventory)?.title
?.let { PlainTextComponentSerializer.plainText().serialize(it) } ?: ""
}

override fun getType(): ViewType {
return type
}

override fun getRowsCount(): Int {
return size / columnsCount
}

override fun getColumnsCount(): Int {
return type.columns
}

override fun renderItem(slot: Int, item: Any) {
requireSupportedItem(item)
inventory.setItemStack(slot, item as ItemStack)
}

override fun removeItem(slot: Int) {
inventory.setItemStack(slot, ItemStack.AIR)
}

override fun matchesItem(slot: Int, item: Any?, exactly: Boolean): Boolean {
requireSupportedItem(item)
val target: ItemStack = inventory.getItemStack(slot) ?: return item == null
if (item is ItemStack) return if (exactly) target == item else target.isSimilar(item as ItemStack)

return false
}

override fun isSupportedItem(item: Any?): Boolean {
return item == null || item is ItemStack
}

private fun requireSupportedItem(item: Any?) {
if (isSupportedItem(item)) return

throw IllegalStateException(
"Unsupported item type: " + item!!.javaClass.name
)
}

override fun hasItem(slot: Int): Boolean {
return !inventory.getItemStack(slot).isAir
}

override fun getSize(): Int {
return inventory.size
}

override fun getSlotsCount(): Int {
return size - 1
}

override fun getFirstSlot(): Int {
return 0
}

override fun getLastSlot(): Int {
val resultSlots = getType().resultSlots
var lastSlot = slotsCount
if (resultSlots != null) {
for (resultSlot in resultSlots) {
if (resultSlot == lastSlot) lastSlot--
}
}

return lastSlot
}

override fun changeTitle(title: String?, target: Viewer) {
changeTitle(title?.let { Component.text(it) } ?: Component.empty(), (target as MinestomViewer).player)
}

fun changeTitle(title: Component, target: Player) {
val open: Inventory = target.openInventory as? Inventory ?: return
if (inventory.inventoryType == InventoryType.CRAFTING || inventory.inventoryType == InventoryType.CRAFTER_3X3) return
open.setTitle(title)
}

override fun isEntityContainer(): Boolean {
return inventory is PlayerInventory
}

override fun open(viewer: Viewer) {
viewer.open(this)
}

override fun close() {
inventory.viewers.forEach(Player::closeInventory)
}

override fun close(viewer: Viewer) {
viewer.close()
}

override fun equals(o: Any?): Boolean {
if (this === o) return true
if (o == null || javaClass != o.javaClass) return false
val that = o as MinestomViewContainer
return isShared == that.isShared && inventory == that.inventory
&& getType() == that.getType()
}

override fun hashCode(): Int {
return Objects.hash(inventory, isShared, getType())
}

override fun toString(): String {
return "BukkitViewContainer{" + "inventory=" + inventory + ", shared=" + isShared + ", type=" + type + '}'
}
}
Loading

0 comments on commit 201042f

Please sign in to comment.