Signed-off-by: Chaoscaot <max@maxsp.de>
This commit is contained in:
2026-06-10 00:36:18 +02:00
parent a938abde3f
commit 5ce69e6b7a
14 changed files with 501 additions and 1 deletions
@@ -34,6 +34,7 @@ dependencies {
compileOnly(libs.classindex)
annotationProcessor(libs.classindex)
compileOnly(project(":SpigotCore", "default"))
compileOnly(project(":KotlinCore", "default"))
compileOnly(libs.axiom)
compileOnly(libs.authlib)
@@ -0,0 +1,38 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2026 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.bausystem.features;
import de.steamwar.command.SWCommand;
import de.steamwar.kotlin.ui.TestInv;
import de.steamwar.linkage.Linked;
import org.bukkit.entity.Player;
@Linked
public class TestCommand extends SWCommand {
public TestCommand() {
super("supertestcommand");
}
@Register
public void test(Player player) {
TestInv inv = new TestInv(player);
inv.open();
}
}
+2
View File
@@ -37,5 +37,7 @@ tasks.register<DevServer>("DevBau21") {
dependsOn(":SpigotCore:shadowJar")
dependsOn(":BauSystem:shadowJar")
dependsOn(":SchematicSystem:shadowJar")
dependsOn(":KotlinCore:shadowJar")
template = "Bau21"
worldName = "73"
}
+7
View File
@@ -1,3 +1,5 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
/*
* This file is a part of the SteamWar software.
*
@@ -41,3 +43,8 @@ dependencies {
implementation(libs.mysql)
implementation("org.slf4j:slf4j-simple:2.0.17")
}
val compileKotlin: KotlinCompile by tasks
compileKotlin.compilerOptions {
freeCompilerArgs.set(listOf("-XXLanguage:+ContextParameters"))
}
@@ -0,0 +1,63 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2026 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.kotlin.ui
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
class Observer<T>(private var value: T): ReadWriteProperty<Any?, T> {
private val listeners = mutableSetOf<RenderBoundary>()
fun removeListener(render: RenderBoundary) {
listeners.remove(render)
}
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return value
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
this.value = value
notifyListeners()
}
fun set(value: T) {
this.value = value
notifyListeners()
}
fun get() = value
fun update(update: (T) -> T) {
this.value = update(value)
notifyListeners()
}
private fun notifyListeners() {
listeners.forEach { it.update() }
}
context(render: RenderBoundary)
fun listen(): Observer<T> {
listeners.add(render)
render.observers.add(this)
return this
}
}
@@ -0,0 +1,40 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2026 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.kotlin.ui
abstract class RenderBoundary(private val parent: RenderBoundary?) {
val observers = mutableSetOf<Observer<*>>()
fun update() {
render()
updateInv()
}
protected open fun updateInv() {
parent?.updateInv()
}
abstract fun render()
open fun destroy() {
observers.forEach { it.removeListener(this) }
observers.clear()
}
}
@@ -0,0 +1,23 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2026 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.kotlin.ui
@DslMarker
annotation class RenderMarker()
@@ -0,0 +1,49 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2026 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.kotlin.ui
import de.steamwar.kotlin.ui.components.item
import org.bukkit.Material
import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack
class TestInv(player: Player): UIInventory(player) {
override fun render() {
inventory(3, title = "TEST_TITLE") {
group {
item {
var test by Test.test.listen()
x = 1
y = 1
item = ItemStack.of(Material.STONE, test)
onClick {
test++
}
}
}
}
}
}
object Test {
val test = Observer(1)
}
@@ -0,0 +1,53 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2026 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.kotlin.ui
import de.steamwar.kotlin.KotlinCore
import de.steamwar.kotlin.ui.context.WindowContext
import net.kyori.adventure.text.event.ClickEvent
import org.bukkit.Bukkit
import org.bukkit.entity.Player
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener
import org.bukkit.event.inventory.InventoryClickEvent
import org.bukkit.event.inventory.InventoryCloseEvent
import org.bukkit.event.inventory.InventoryType
abstract class UIInventory(val player: Player) {
lateinit var window: UIWindow
abstract fun render()
fun open() {
if (!::window.isInitialized) {
render()
}
window.open()
}
protected fun inventory(size: Int, title: String, init: WindowContext.() -> Unit) {
window = UIWindow(size, title, player, init)
}
protected fun inventory(type: InventoryType, title: String, init: WindowContext.() -> Unit) {
window = UIWindow(type, title, player, init)
}
}
@@ -0,0 +1,83 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2026 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.kotlin.ui
import de.steamwar.kotlin.KotlinCore
import de.steamwar.kotlin.ui.context.WindowContext
import net.kyori.adventure.text.Component
import org.bukkit.Bukkit
import org.bukkit.entity.Player
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener
import org.bukkit.event.inventory.InventoryClickEvent
import org.bukkit.event.inventory.InventoryCloseEvent
import org.bukkit.event.inventory.InventoryType
import org.bukkit.inventory.Inventory
class UIWindow(val bukkitInv: Inventory, val player: Player, val render: WindowContext.() -> Unit): Listener {
val onClicks = mutableMapOf<Int, (event: InventoryClickEvent) -> Unit>()
private var updating = false
constructor(size: Int, title: String, player: Player, render: WindowContext.() -> Unit): this(
Bukkit.createInventory(null, size * 9, Component.translatable(title)), player, render
)
constructor(type: InventoryType, title: String, player: Player, render: WindowContext.() -> Unit): this(
Bukkit.createInventory(null, type, Component.translatable(title)), player, render
)
fun open() {
render(getContext())
openInv()
}
fun openInv() {
updating = true
player.openInventory(bukkitInv)
Bukkit.getPluginManager().registerEvents(this, KotlinCore.plugin)
updating = false
}
@EventHandler
fun onInventoryClick(event: InventoryClickEvent) {
if (event.whoClicked != player) return
event.isCancelled = true
onClicks[event.slot]?.invoke(event)
}
@EventHandler
fun onInventoryClose(event: InventoryCloseEvent) {
if (event.player != player) return
onClose()
InventoryClickEvent.getHandlerList().unregister(this)
InventoryCloseEvent.getHandlerList().unregister(this)
}
fun getContext() = WindowContext(this)
fun onClose() {
if (updating) return
onClicks.clear()
}
}
@@ -0,0 +1,50 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2026 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.kotlin.ui.components
import de.steamwar.kotlin.ui.RenderBoundary
import de.steamwar.kotlin.ui.RenderMarker
import de.steamwar.kotlin.ui.context.GroupContext
import org.bukkit.Material
import org.bukkit.event.inventory.InventoryClickEvent
import org.bukkit.inventory.ItemStack
@RenderMarker
class ItemContext(val parent: GroupContext, val renderFunc: ItemContext.() -> Unit): RenderBoundary(parent) {
override fun render() {
renderFunc(this)
parent.renderItem(x, y, item, onClick)
}
init {
render()
}
var item: ItemStack = ItemStack.of(Material.AIR)
var onClick: (event: InventoryClickEvent) -> Unit = {}
var x: Int = 0
var y: Int = 0
fun onClick(func: (event: InventoryClickEvent) -> Unit) {
onClick = func
}
}
fun GroupContext.item(init: ItemContext.() -> Unit) = children.add(ItemContext(this, init))
@@ -0,0 +1,53 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2026 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.kotlin.ui.context
import de.steamwar.kotlin.ui.RenderBoundary
import de.steamwar.kotlin.ui.RenderMarker
import org.bukkit.event.inventory.InventoryClickEvent
import org.bukkit.inventory.ItemStack
@RenderMarker
open class GroupContext(val parent: GroupContext?, val init: GroupContext.() -> Unit): RenderBoundary(parent) {
val children = mutableListOf<RenderBoundary>()
override fun destroy() {
children.forEach { it.destroy() }
super.destroy()
}
init {
init(this)
}
open fun renderItem(x: Int, y: Int, item: ItemStack, onClick: (event: InventoryClickEvent) -> Unit) {
parent?.renderItem(x, y, item, onClick)
}
fun group(init: GroupContext.() -> Unit) {
children.add(GroupContext(this, init))
}
override fun render() {
children.forEach { it.destroy() }
children.clear()
init(this)
}
}
@@ -0,0 +1,39 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2026 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.kotlin.ui.context
import de.steamwar.kotlin.ui.RenderMarker
import de.steamwar.kotlin.ui.UIWindow
import org.bukkit.event.inventory.InventoryClickEvent
import org.bukkit.inventory.ItemStack
@RenderMarker
class WindowContext(val window: UIWindow): GroupContext(null, {}) {
override fun renderItem(x: Int, y: Int, item: ItemStack, onClick: (event: InventoryClickEvent) -> Unit) {
window.bukkitInv.setItem(x + y * 9, item)
window.onClicks[x + y * 9] = onClick
}
override fun updateInv() = window.openInv()
fun outsideClick(click: (event: InventoryClickEvent) -> Unit) {
window.onClicks[-999] = click
}
}
-1
View File
@@ -27,7 +27,6 @@ plugins {
class DevServer extends DefaultTask {
@Input
@Optional
boolean debug = false
@Input