From 9c7796d51272214a786510edd261c55eaa3d5868 Mon Sep 17 00:00:00 2001 From: grng <36968271+grngxd@users.noreply.github.com> Date: Thu, 7 Mar 2024 19:45:08 +0000 Subject: [PATCH 1/2] class based state --- .idea/discord.xml | 7 +++ .../com/neptuneclient/voidui/event/Event.kt | 7 +++ .../voidui/event/EventManager.kt | 47 +++++++++++++++++++ .../neptuneclient/voidui/event/Subscribe.kt | 14 ++++++ .../voidui/event/impl/StateChangeEvent.kt | 8 ++++ .../com/neptuneclient/voidui/ui/Component.kt | 1 - .../voidui/ui/ReactiveComponent.kt | 22 +++++++++ .../com/neptuneclient/voidui/ui/State.kt | 26 ++++++++++ .../testmod/mixins/TitleScreenMixin.java | 22 +++++++++ .../voidui/testmod/mixins/void/Label.kt | 23 +++++++++ 10 files changed, 176 insertions(+), 1 deletion(-) create mode 100644 .idea/discord.xml create mode 100644 src/main/kotlin/com/neptuneclient/voidui/event/Event.kt create mode 100644 src/main/kotlin/com/neptuneclient/voidui/event/EventManager.kt create mode 100644 src/main/kotlin/com/neptuneclient/voidui/event/Subscribe.kt create mode 100644 src/main/kotlin/com/neptuneclient/voidui/event/impl/StateChangeEvent.kt create mode 100644 src/main/kotlin/com/neptuneclient/voidui/ui/State.kt create mode 100644 test-mod/src/main/kotlin/com/neptuneclient/voidui/testmod/mixins/TitleScreenMixin.java create mode 100644 test-mod/src/main/kotlin/com/neptuneclient/voidui/testmod/mixins/void/Label.kt diff --git a/.idea/discord.xml b/.idea/discord.xml new file mode 100644 index 0000000..d8e9561 --- /dev/null +++ b/.idea/discord.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/src/main/kotlin/com/neptuneclient/voidui/event/Event.kt b/src/main/kotlin/com/neptuneclient/voidui/event/Event.kt new file mode 100644 index 0000000..fac088e --- /dev/null +++ b/src/main/kotlin/com/neptuneclient/voidui/event/Event.kt @@ -0,0 +1,7 @@ +package com.neptuneclient.voidui.event + +/** + * @author refactoring + * @date 01-09-2023 + */ +open class Event() \ No newline at end of file diff --git a/src/main/kotlin/com/neptuneclient/voidui/event/EventManager.kt b/src/main/kotlin/com/neptuneclient/voidui/event/EventManager.kt new file mode 100644 index 0000000..ac7c6ec --- /dev/null +++ b/src/main/kotlin/com/neptuneclient/voidui/event/EventManager.kt @@ -0,0 +1,47 @@ +package com.neptuneclient.voidui.event + +import java.lang.reflect.InvocationTargetException + + +/** + * @author refactoring + * @date 01-09-2023 + */ +class EventManager { + var targetClasses: MutableMap, Any> = HashMap() + fun register(`object`: Any) { + if (targetClasses.containsKey(`object`.javaClass)) return + targetClasses[`object`.javaClass] = `object` + } + + fun unregister(`object`: Any) { + targetClasses.remove(`object`.javaClass) + } + + fun clearTargets() { + targetClasses.clear() + } + + fun fire(event: Event) { + targetClasses.forEach { (clazz: Class<*>, `object`: Any?) -> + for (method in clazz.getDeclaredMethods()) { + if (method.isAnnotationPresent(Subscribe::class.java) && method.getAnnotation( + Subscribe::class.java + ).target == event.javaClass + ) { + try { + method.invoke(`object`, event) + } catch (e: IllegalAccessException) { + throw RuntimeException(e) + } catch (e: InvocationTargetException) { + throw RuntimeException(e) + } + } + } + } + } + + companion object { + val instance = EventManager() + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/neptuneclient/voidui/event/Subscribe.kt b/src/main/kotlin/com/neptuneclient/voidui/event/Subscribe.kt new file mode 100644 index 0000000..89f3d39 --- /dev/null +++ b/src/main/kotlin/com/neptuneclient/voidui/event/Subscribe.kt @@ -0,0 +1,14 @@ +package com.neptuneclient.voidui.event + +import kotlin.reflect.KClass + + +/** + * @author refactoring + * @date 01-09-2023 + */ +@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER) +@Retention( + AnnotationRetention.RUNTIME +) +annotation class Subscribe(val target: KClass<*>) \ No newline at end of file diff --git a/src/main/kotlin/com/neptuneclient/voidui/event/impl/StateChangeEvent.kt b/src/main/kotlin/com/neptuneclient/voidui/event/impl/StateChangeEvent.kt new file mode 100644 index 0000000..27f82a3 --- /dev/null +++ b/src/main/kotlin/com/neptuneclient/voidui/event/impl/StateChangeEvent.kt @@ -0,0 +1,8 @@ +package com.neptuneclient.voidui.event.impl + +import com.neptuneclient.voidui.event.Event +import com.neptuneclient.voidui.ui.State + +class StateChangeEvent(state: State) : Event() { + var state: State = state +} \ No newline at end of file diff --git a/src/main/kotlin/com/neptuneclient/voidui/ui/Component.kt b/src/main/kotlin/com/neptuneclient/voidui/ui/Component.kt index 5ce6bdf..1bb5a1c 100644 --- a/src/main/kotlin/com/neptuneclient/voidui/ui/Component.kt +++ b/src/main/kotlin/com/neptuneclient/voidui/ui/Component.kt @@ -1,7 +1,6 @@ package com.neptuneclient.voidui.ui sealed class Component { - abstract fun build(): Component } \ No newline at end of file diff --git a/src/main/kotlin/com/neptuneclient/voidui/ui/ReactiveComponent.kt b/src/main/kotlin/com/neptuneclient/voidui/ui/ReactiveComponent.kt index ca9dc64..fee4d22 100644 --- a/src/main/kotlin/com/neptuneclient/voidui/ui/ReactiveComponent.kt +++ b/src/main/kotlin/com/neptuneclient/voidui/ui/ReactiveComponent.kt @@ -1,4 +1,26 @@ package com.neptuneclient.voidui.ui +import com.neptuneclient.voidui.event.EventManager +import com.neptuneclient.voidui.event.Subscribe +import com.neptuneclient.voidui.event.impl.StateChangeEvent + abstract class ReactiveComponent : Component() { + // array of states + var state: HashMap> = hashMapOf() + // call function on state change + open fun init() { + EventManager.instance.register(this) + + for (s in state) { + s.value.init() + } + } + override fun build(): Component { + return this + } + + @Subscribe(target = StateChangeEvent::class) + fun onStateChange(event: StateChangeEvent<*>) { + println("State changed from ${event.state.prev} to ${event.state.value}") + } } \ No newline at end of file diff --git a/src/main/kotlin/com/neptuneclient/voidui/ui/State.kt b/src/main/kotlin/com/neptuneclient/voidui/ui/State.kt new file mode 100644 index 0000000..dd6fe59 --- /dev/null +++ b/src/main/kotlin/com/neptuneclient/voidui/ui/State.kt @@ -0,0 +1,26 @@ +package com.neptuneclient.voidui.ui + +import com.neptuneclient.voidui.event.EventManager +import com.neptuneclient.voidui.event.impl.StateChangeEvent + +class State (initial: T) { + // make the setter like react + var value: T = initial + set(value) { + field = value + changed() + } + + var prev: T = initial + fun init() { + EventManager.instance.register(this) + println("State initialized") + } + + fun changed() { + EventManager.instance.fire( + StateChangeEvent(this) + ) + prev = this.value + } +} \ No newline at end of file diff --git a/test-mod/src/main/kotlin/com/neptuneclient/voidui/testmod/mixins/TitleScreenMixin.java b/test-mod/src/main/kotlin/com/neptuneclient/voidui/testmod/mixins/TitleScreenMixin.java new file mode 100644 index 0000000..826a6a4 --- /dev/null +++ b/test-mod/src/main/kotlin/com/neptuneclient/voidui/testmod/mixins/TitleScreenMixin.java @@ -0,0 +1,22 @@ +package com.neptuneclient.voidui.testmod.mixins; + +import com.neptuneclient.voidui.VoidUI; +import com.neptuneclient.voidui.ui.Screen; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.screen.TitleScreen; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; + +@Mixin(TitleScreen.class) +public class TitleScreenMixin { + VoidUI voidUI = new VoidUI(); + /** + * @author + * @reason + */ + @Overwrite + public void render(DrawContext context, int mouseX, int mouseY, float delta) { + voidUI.setCurrentScreen((Screen) (Object) this); + + } +} diff --git a/test-mod/src/main/kotlin/com/neptuneclient/voidui/testmod/mixins/void/Label.kt b/test-mod/src/main/kotlin/com/neptuneclient/voidui/testmod/mixins/void/Label.kt new file mode 100644 index 0000000..876eb4a --- /dev/null +++ b/test-mod/src/main/kotlin/com/neptuneclient/voidui/testmod/mixins/void/Label.kt @@ -0,0 +1,23 @@ +package com.neptuneclient.voidui.testmod.mixins.void + +import com.neptuneclient.voidui.ui.Component +import com.neptuneclient.voidui.ui.ReactiveComponent +import com.neptuneclient.voidui.ui.State + +class Label: ReactiveComponent() { + override fun init() { + super.init() + + state = hashMapOf( + "number" to State(0) + ) + } + override fun build(): Component { + // wait 4 seconds + Thread(Runnable { + Thread.sleep(4000) + this.state["number"]?.value = 1 + }) + return super.build() + } +} \ No newline at end of file From f8dfc2420f12c906c26a69315a5dd16bb37ce71a Mon Sep 17 00:00:00 2001 From: grng <36968271+grngxd@users.noreply.github.com> Date: Thu, 7 Mar 2024 20:09:17 +0000 Subject: [PATCH 2/2] shitty state --- .../kotlin/com/neptuneclient/voidui/VoidUI.kt | 1 - .../voidui/ui/ReactiveComponent.kt | 28 ++++++++++++++----- .../com/neptuneclient/voidui/ui/State.kt | 10 +++++-- .../voidui/testmod/mixins/void/Label.kt | 25 ++++++++--------- 4 files changed, 40 insertions(+), 24 deletions(-) diff --git a/src/main/kotlin/com/neptuneclient/voidui/VoidUI.kt b/src/main/kotlin/com/neptuneclient/voidui/VoidUI.kt index 135b637..d88eeed 100644 --- a/src/main/kotlin/com/neptuneclient/voidui/VoidUI.kt +++ b/src/main/kotlin/com/neptuneclient/voidui/VoidUI.kt @@ -7,5 +7,4 @@ class VoidUI { var currentScreen: Screen? = null fun complexFunction(x: Int, y: Int) = x + y - } \ No newline at end of file diff --git a/src/main/kotlin/com/neptuneclient/voidui/ui/ReactiveComponent.kt b/src/main/kotlin/com/neptuneclient/voidui/ui/ReactiveComponent.kt index fee4d22..6e3c97c 100644 --- a/src/main/kotlin/com/neptuneclient/voidui/ui/ReactiveComponent.kt +++ b/src/main/kotlin/com/neptuneclient/voidui/ui/ReactiveComponent.kt @@ -5,20 +5,34 @@ import com.neptuneclient.voidui.event.Subscribe import com.neptuneclient.voidui.event.impl.StateChangeEvent abstract class ReactiveComponent : Component() { - // array of states - var state: HashMap> = hashMapOf() - // call function on state change - open fun init() { - EventManager.instance.register(this) + val states = mutableListOf>() - for (s in state) { - s.value.init() + init { + EventManager.instance.register(this) + for (field in this.javaClass.declaredFields) { + if (field.type == State::class.java) { + field.isAccessible = true + val state = field.get(this) as State<*> + state.init() + states.add(state) + state.subscribe { newValue -> + // Here you can react to changes in the state. + // For example, you can rebuild the component. + rebuild() + } + } } } + override fun build(): Component { return this } + open fun rebuild() { + // This method is called when a state changes. + // You can override it to rebuild the component. + } + @Subscribe(target = StateChangeEvent::class) fun onStateChange(event: StateChangeEvent<*>) { println("State changed from ${event.state.prev} to ${event.state.value}") diff --git a/src/main/kotlin/com/neptuneclient/voidui/ui/State.kt b/src/main/kotlin/com/neptuneclient/voidui/ui/State.kt index dd6fe59..cf87647 100644 --- a/src/main/kotlin/com/neptuneclient/voidui/ui/State.kt +++ b/src/main/kotlin/com/neptuneclient/voidui/ui/State.kt @@ -3,8 +3,7 @@ package com.neptuneclient.voidui.ui import com.neptuneclient.voidui.event.EventManager import com.neptuneclient.voidui.event.impl.StateChangeEvent -class State (initial: T) { - // make the setter like react +class State(initial: T) { var value: T = initial set(value) { field = value @@ -12,6 +11,8 @@ class State (initial: T) { } var prev: T = initial + private val listeners = mutableListOf<(T) -> Unit>() + fun init() { EventManager.instance.register(this) println("State initialized") @@ -22,5 +23,10 @@ class State (initial: T) { StateChangeEvent(this) ) prev = this.value + listeners.forEach { it(value) } // Notify all listeners about the change + } + + fun subscribe(listener: (T) -> Unit) { + listeners.add(listener) } } \ No newline at end of file diff --git a/test-mod/src/main/kotlin/com/neptuneclient/voidui/testmod/mixins/void/Label.kt b/test-mod/src/main/kotlin/com/neptuneclient/voidui/testmod/mixins/void/Label.kt index 876eb4a..ca1ba4e 100644 --- a/test-mod/src/main/kotlin/com/neptuneclient/voidui/testmod/mixins/void/Label.kt +++ b/test-mod/src/main/kotlin/com/neptuneclient/voidui/testmod/mixins/void/Label.kt @@ -1,23 +1,20 @@ package com.neptuneclient.voidui.testmod.mixins.void -import com.neptuneclient.voidui.ui.Component import com.neptuneclient.voidui.ui.ReactiveComponent import com.neptuneclient.voidui.ui.State -class Label: ReactiveComponent() { - override fun init() { - super.init() +class Label(initialText: String) : ReactiveComponent() { + val text = State(initialText) - state = hashMapOf( - "number" to State(0) - ) + init { + text.subscribe { + rebuild() + } } - override fun build(): Component { - // wait 4 seconds - Thread(Runnable { - Thread.sleep(4000) - this.state["number"]?.value = 1 - }) - return super.build() + + override fun rebuild() { + // Logic to update the UI goes here. + // This might involve re-rendering the component's UI, updating its data, etc. + println("Current text: ${text.value}") } } \ No newline at end of file