1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
|
package moe.nea.firmament.features.macros
import org.joml.Vector2f
import util.render.CustomRenderLayers
import kotlin.math.atan2
import kotlin.math.cos
import kotlin.math.sin
import kotlin.math.sqrt
import net.minecraft.client.gui.DrawContext
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.HudRenderEvent
import moe.nea.firmament.events.TickEvent
import moe.nea.firmament.events.WorldKeyboardEvent
import moe.nea.firmament.events.WorldMouseMoveEvent
import moe.nea.firmament.features.macros.RadialMenuViewer.RadialMenu
import moe.nea.firmament.features.macros.RadialMenuViewer.RadialMenuOption
import moe.nea.firmament.keybindings.SavedKeyBinding
import moe.nea.firmament.util.MC
import moe.nea.firmament.util.render.RenderCircleProgress
import moe.nea.firmament.util.render.drawLine
import moe.nea.firmament.util.render.lerpAngle
import moe.nea.firmament.util.render.wrapAngle
import moe.nea.firmament.util.render.τ
object RadialMenuViewer {
interface RadialMenu {
val key: SavedKeyBinding
val options: List<RadialMenuOption>
}
interface RadialMenuOption {
val isEnabled: Boolean
fun resolve()
fun renderSlice(drawContext: DrawContext)
}
var activeMenu: RadialMenu? = null
set(value) {
field = value
delta = Vector2f(0F, 0F)
}
var delta = Vector2f(0F, 0F)
val maxSelectionSize = 100F
@Subscribe
fun onMouseMotion(event: WorldMouseMoveEvent) {
val menu = activeMenu ?: return
event.cancel()
delta.add(event.deltaX.toFloat(), event.deltaY.toFloat())
val m = delta.lengthSquared()
if (m > maxSelectionSize * maxSelectionSize) {
delta.mul(maxSelectionSize / sqrt(m))
}
}
val INNER_CIRCLE_RADIUS = 16
@Subscribe
fun onRender(event: HudRenderEvent) {
val menu = activeMenu ?: return
val mat = event.context.matrices
mat.push()
mat.translate(
(MC.window.scaledWidth) / 2F,
(MC.window.scaledHeight) / 2F,
0F
)
val sliceWidth = (τ / menu.options.size).toFloat()
var selectedAngle = wrapAngle(atan2(delta.y, delta.x))
if (delta.lengthSquared() < INNER_CIRCLE_RADIUS * INNER_CIRCLE_RADIUS)
selectedAngle = Float.NaN
for ((idx, option) in menu.options.withIndex()) {
val range = (sliceWidth * idx)..(sliceWidth * (idx + 1))
mat.push()
mat.scale(64F, 64F, 1F)
val cutout = INNER_CIRCLE_RADIUS / 64F / 2
RenderCircleProgress.renderCircularSlice(
event.context,
CustomRenderLayers.TRANSLUCENT_CIRCLE_GUI,
0F, 1F, 0F, 1F,
range,
color = if (selectedAngle in range) 0x70A0A0A0 else 0x70FFFFFF,
innerCutoutRadius = cutout
)
mat.pop()
mat.push()
val centreAngle = lerpAngle(range.start, range.endInclusive, 0.5F)
val vec = Vector2f(cos(centreAngle), sin(centreAngle)).mul(40F)
mat.translate(vec.x, vec.y, 0F)
option.renderSlice(event.context)
mat.pop()
}
event.context.drawLine(1, 1, delta.x.toInt(), delta.y.toInt(), me.shedaniel.math.Color.ofOpaque(0x00FF00))
mat.pop()
}
@Subscribe
fun onTick(event: TickEvent) {
val menu = activeMenu ?: return
if (!menu.key.isPressed(true)) {
val angle = atan2(delta.y, delta.x)
val choiceIndex = (wrapAngle(angle) * menu.options.size / τ).toInt()
val choice = menu.options[choiceIndex]
val selectedAny = delta.lengthSquared() > INNER_CIRCLE_RADIUS * INNER_CIRCLE_RADIUS
activeMenu = null
if (selectedAny)
choice.resolve()
}
}
}
object RadialMacros {
var wheels = MacroData.DConfig.data.wheels
private set
fun setWheels(wheels: List<MacroWheel>) {
this.wheels = wheels
RadialMenuViewer.activeMenu = null
}
@Subscribe
fun onOpen(event: WorldKeyboardEvent) {
if (RadialMenuViewer.activeMenu != null) return
wheels.forEach { wheel ->
if (event.matches(wheel.key, atLeast = true)) {
class R(val action: HotkeyAction) : RadialMenuOption {
override val isEnabled: Boolean
get() = true
override fun resolve() {
action.execute()
}
override fun renderSlice(drawContext: DrawContext) {
drawContext.drawCenteredTextWithShadow(MC.font, action.label, 0, 0, -1)
}
}
RadialMenuViewer.activeMenu = object : RadialMenu {
override val key: SavedKeyBinding
get() = wheel.key
override val options: List<RadialMenuOption> =
wheel.options.map { R(it) }
}
}
}
}
}
|