Skip to content

Commit e5a2d55

Browse files
committed
Add option to restart GTA
1 parent ab6e77f commit e5a2d55

File tree

7 files changed

+91
-41
lines changed

7 files changed

+91
-41
lines changed

client/src/main/kotlin/core/ProcessHandler.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
package dev.schlaubi.mastermind.core
22

3+
import dev.schlaubi.mastermind.core.settings.settings
4+
import dev.schlaubi.mastermind.windows_helper.WindowsAPI
35
import io.github.oshai.kotlinlogging.KotlinLogging
46
import kotlinx.coroutines.channels.Channel
57
import kotlinx.coroutines.flow.MutableSharedFlow
68
import kotlinx.coroutines.flow.asSharedFlow
9+
import kotlin.io.path.absolutePathString
10+
import kotlin.io.path.div
711
import kotlin.jvm.optionals.getOrNull
812

913
private val LOG = KotlinLogging.logger { }
@@ -19,6 +23,12 @@ suspend fun killGta() {
1923
.findFirst()
2024
if (gtaProcess.isPresent) {
2125
gtaProcess.get().destroyForcibly()
26+
27+
if (settings.autostartGta) {
28+
LOG.info { "Restarting GTA5.exe" }
29+
val gtaPath = WindowsAPI.readGtaLocation() / "PlayGTAV.exe"
30+
Runtime.getRuntime().exec(arrayOf(gtaPath.absolutePathString()))
31+
}
2232
} else {
2333
LOG.error { "GTA5.exe not found" }
2434
_events.emit(Unit)

client/src/main/kotlin/core/settings/Settings.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
package dev.schlaubi.mastermind.core.settings
22

3+
import androidx.compose.ui.input.key.Key
4+
import androidx.compose.ui.input.key.nativeKeyCode
35
import io.ktor.http.*
46
import kotlinx.serialization.Serializable
57

6-
const val F3_KEY = 113
8+
val F3_KEY = Key.F3.nativeKeyCode
79

810
@Serializable
911
data class Settings(
1012
val currentUrl: Url?,
1113
val pastUrls: Set<Url>,
1214
val userName: String,
1315
val hotkey: Int = F3_KEY,
16+
val autostartGta: Boolean = true,
1417
val tokens: Map<String, String> = emptyMap()
1518
)
1619

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package dev.schlaubi.mastermind.ui.components.settings
2+
3+
import androidx.compose.runtime.Composable
4+
import androidx.compose.runtime.rememberCoroutineScope
5+
import dev.schlaubi.mastermind.core.settings.settings
6+
import dev.schlaubi.mastermind.core.settings.writeSettings
7+
import kotlinx.coroutines.Dispatchers
8+
import kotlinx.coroutines.launch
9+
10+
@Composable
11+
fun AutoLaunchGtaSetting() {
12+
val scope = rememberCoroutineScope()
13+
14+
CheckboxWithHeading("Auto-Launch GTA", settings.autostartGta, {
15+
scope.launch(Dispatchers.IO) {
16+
writeSettings(settings.copy(autostartGta = it))
17+
}
18+
})
19+
}

client/src/main/kotlin/ui/components/settings/KeyboardInput.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import androidx.compose.material.icons.Icons
55
import androidx.compose.material.icons.filled.Keyboard
66
import androidx.compose.material3.Icon
77
import androidx.compose.runtime.*
8+
import androidx.compose.ui.input.key.nativeKeyCode
89
import dev.schlaubi.mastermind.core.settings.settings
910
import dev.schlaubi.mastermind.core.settings.writeSettings
1011
import dev.schlaubi.mastermind.util.keys
@@ -16,14 +17,14 @@ fun KeyboardInput() {
1617
val scope = rememberCoroutineScope()
1718

1819
Box {
19-
InputWithHeading(
20+
TextInputWithHeading(
2021
{ Icon(Icons.Default.Keyboard, null) }, "HotKey", initialValue = "F3",
2122
isError = isError,
2223
onValueChange = { isError = it !in keys },
2324
onSubmit = {
2425
if (!isError) {
2526
scope.launch {
26-
writeSettings(settings.copy(hotkey = keys[it]!!))
27+
writeSettings(settings.copy(hotkey = keys[it]!!.nativeKeyCode))
2728
}
2829
}
2930
}

client/src/main/kotlin/ui/components/settings/Settings.kt

Lines changed: 52 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,9 @@ package dev.schlaubi.mastermind.ui.components.settings
22

33
import androidx.compose.foundation.layout.Arrangement
44
import androidx.compose.foundation.layout.Column
5+
import androidx.compose.foundation.layout.ColumnScope
56
import androidx.compose.foundation.layout.fillMaxSize
6-
import androidx.compose.material3.MaterialTheme
7-
import androidx.compose.material3.OutlinedTextField
8-
import androidx.compose.material3.Text
9-
import androidx.compose.material3.TextFieldDefaults
7+
import androidx.compose.material3.*
108
import androidx.compose.runtime.*
119
import androidx.compose.ui.Alignment
1210
import androidx.compose.ui.Modifier
@@ -27,12 +25,31 @@ fun Settings(modifier: Modifier = Modifier) {
2725
) {
2826
UsernameInput()
2927
KeyboardInput()
28+
AutoLaunchGtaSetting()
3029
}
3130
}
3231
}
3332

3433
@Composable
3534
fun InputWithHeading(
35+
heading: String,
36+
modifier: Modifier = Modifier,
37+
content: @Composable ColumnScope.() -> Unit
38+
) {
39+
40+
Column(
41+
horizontalAlignment = Alignment.CenterHorizontally,
42+
verticalArrangement = Arrangement.spacedBy(5.dp),
43+
modifier = modifier
44+
) {
45+
Text(heading, style = MaterialTheme.typography.headlineSmall)
46+
47+
content()
48+
}
49+
}
50+
51+
@Composable
52+
fun TextInputWithHeading(
3653
leadingIcon: @Composable () -> Unit,
3754
heading: String,
3855
initialValue: String,
@@ -42,41 +59,40 @@ fun InputWithHeading(
4259
onValueChange: (String) -> Unit = {},
4360
onSubmit: (String) -> Unit = {},
4461
modifier: Modifier = Modifier
45-
) {
46-
var value by remember { mutableStateOf(initialValue) }
62+
) = InputWithHeading(heading, modifier) {
4763
val focusRequester = LocalFocusManager.current
64+
var value by remember { mutableStateOf(initialValue) }
4865

49-
Column(
50-
horizontalAlignment = Alignment.CenterHorizontally,
51-
verticalArrangement = Arrangement.spacedBy(5.dp),
52-
modifier = modifier
53-
) {
54-
Text(heading, style = MaterialTheme.typography.headlineSmall)
55-
56-
OutlinedTextField(
57-
value = value,
58-
{ value = it; onValueChange(it) },
59-
leadingIcon = leadingIcon,
60-
trailingIcon = trailingIcon,
61-
colors = TextFieldDefaults.colors(),
62-
enabled = enabled,
63-
isError = isError,
64-
maxLines = 1,
65-
modifier = Modifier.onKeyEvent {
66-
if (it.type != KeyEventType.KeyDown) return@onKeyEvent true
66+
OutlinedTextField(
67+
value = value,
68+
{ value = it; onValueChange(it) },
69+
leadingIcon = leadingIcon,
70+
trailingIcon = trailingIcon,
71+
colors = TextFieldDefaults.colors(),
72+
enabled = enabled,
73+
isError = isError,
74+
maxLines = 1,
75+
modifier = Modifier.onKeyEvent {
76+
if (it.type != KeyEventType.KeyDown) return@onKeyEvent true
6777

68-
when (it.key) {
69-
Key.Escape -> {
70-
value = initialValue
71-
focusRequester.clearFocus()
72-
}
78+
when (it.key) {
79+
Key.Escape -> {
80+
value = initialValue
81+
focusRequester.clearFocus()
7382
}
83+
}
7484

75-
false
76-
}.onFocusChanged {
77-
if (!it.isFocused && value != initialValue) {
78-
onSubmit(value)
79-
}
80-
})
81-
}
85+
false
86+
}.onFocusChanged {
87+
if (!it.isFocused && value != initialValue) {
88+
onSubmit(value)
89+
}
90+
})
8291
}
92+
93+
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
94+
@Composable
95+
fun CheckboxWithHeading(heading: String, checked: Boolean, onCheckedChange: (Boolean) -> Unit) =
96+
InputWithHeading(heading) {
97+
Checkbox(checked, onCheckedChange)
98+
}

client/src/main/kotlin/ui/components/settings/UserNameInput.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ fun UsernameInput() {
2727
.collect { loading = false }
2828
}
2929

30-
InputWithHeading({
30+
TextInputWithHeading({
3131
if (loading) CircularProgressIndicator(Modifier.size(ButtonDefaults.IconSize)) else Icon(
3232
Icons.Default.AccountBox, "Username"
3333
)

windows_helper/src/main/kotlin/Extensions.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package dev.schlaubi.mastermind.windows_helper
33
import java.lang.foreign.Arena
44
import java.lang.foreign.MemorySegment
55
import java.lang.foreign.SegmentAllocator
6+
import kotlin.io.path.Path
67

78
private fun readString(producer: (SegmentAllocator) -> MemorySegment): String = Arena.ofConfined().use { arena ->
89
val vec = producer(arena)
@@ -21,7 +22,7 @@ private fun readString(producer: (SegmentAllocator) -> MemorySegment): String =
2122

2223

2324
object WindowsAPI : Arena by Arena.ofConfined() {
24-
fun readGtaLocation() = readString(WindowsHelper::read_gta_location)
25+
fun readGtaLocation() = Path(readString(WindowsHelper::read_gta_location))
2526

2627
fun registerKeyboardHook() = WindowsHelper.register_keyboard_hook()
2728

0 commit comments

Comments
 (0)