Skip to content

Commit

Permalink
Add option to restart GTA
Browse files Browse the repository at this point in the history
  • Loading branch information
DRSchlaubi committed Feb 22, 2025
1 parent ab6e77f commit e5a2d55
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 41 deletions.
10 changes: 10 additions & 0 deletions client/src/main/kotlin/core/ProcessHandler.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package dev.schlaubi.mastermind.core

import dev.schlaubi.mastermind.core.settings.settings
import dev.schlaubi.mastermind.windows_helper.WindowsAPI
import io.github.oshai.kotlinlogging.KotlinLogging
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlin.io.path.absolutePathString
import kotlin.io.path.div
import kotlin.jvm.optionals.getOrNull

private val LOG = KotlinLogging.logger { }
Expand All @@ -19,6 +23,12 @@ suspend fun killGta() {
.findFirst()
if (gtaProcess.isPresent) {
gtaProcess.get().destroyForcibly()

if (settings.autostartGta) {
LOG.info { "Restarting GTA5.exe" }
val gtaPath = WindowsAPI.readGtaLocation() / "PlayGTAV.exe"
Runtime.getRuntime().exec(arrayOf(gtaPath.absolutePathString()))
}
} else {
LOG.error { "GTA5.exe not found" }
_events.emit(Unit)
Expand Down
5 changes: 4 additions & 1 deletion client/src/main/kotlin/core/settings/Settings.kt
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
package dev.schlaubi.mastermind.core.settings

import androidx.compose.ui.input.key.Key
import androidx.compose.ui.input.key.nativeKeyCode
import io.ktor.http.*
import kotlinx.serialization.Serializable

const val F3_KEY = 113
val F3_KEY = Key.F3.nativeKeyCode

@Serializable
data class Settings(
val currentUrl: Url?,
val pastUrls: Set<Url>,
val userName: String,
val hotkey: Int = F3_KEY,
val autostartGta: Boolean = true,
val tokens: Map<String, String> = emptyMap()
)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package dev.schlaubi.mastermind.ui.components.settings

import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import dev.schlaubi.mastermind.core.settings.settings
import dev.schlaubi.mastermind.core.settings.writeSettings
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch

@Composable
fun AutoLaunchGtaSetting() {
val scope = rememberCoroutineScope()

CheckboxWithHeading("Auto-Launch GTA", settings.autostartGta, {
scope.launch(Dispatchers.IO) {
writeSettings(settings.copy(autostartGta = it))
}
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Keyboard
import androidx.compose.material3.Icon
import androidx.compose.runtime.*
import androidx.compose.ui.input.key.nativeKeyCode
import dev.schlaubi.mastermind.core.settings.settings
import dev.schlaubi.mastermind.core.settings.writeSettings
import dev.schlaubi.mastermind.util.keys
Expand All @@ -16,14 +17,14 @@ fun KeyboardInput() {
val scope = rememberCoroutineScope()

Box {
InputWithHeading(
TextInputWithHeading(
{ Icon(Icons.Default.Keyboard, null) }, "HotKey", initialValue = "F3",
isError = isError,
onValueChange = { isError = it !in keys },
onSubmit = {
if (!isError) {
scope.launch {
writeSettings(settings.copy(hotkey = keys[it]!!))
writeSettings(settings.copy(hotkey = keys[it]!!.nativeKeyCode))
}
}
}
Expand Down
88 changes: 52 additions & 36 deletions client/src/main/kotlin/ui/components/settings/Settings.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@ package dev.schlaubi.mastermind.ui.components.settings

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
Expand All @@ -27,12 +25,31 @@ fun Settings(modifier: Modifier = Modifier) {
) {
UsernameInput()
KeyboardInput()
AutoLaunchGtaSetting()
}
}
}

@Composable
fun InputWithHeading(
heading: String,
modifier: Modifier = Modifier,
content: @Composable ColumnScope.() -> Unit
) {

Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(5.dp),
modifier = modifier
) {
Text(heading, style = MaterialTheme.typography.headlineSmall)

content()
}
}

@Composable
fun TextInputWithHeading(
leadingIcon: @Composable () -> Unit,
heading: String,
initialValue: String,
Expand All @@ -42,41 +59,40 @@ fun InputWithHeading(
onValueChange: (String) -> Unit = {},
onSubmit: (String) -> Unit = {},
modifier: Modifier = Modifier
) {
var value by remember { mutableStateOf(initialValue) }
) = InputWithHeading(heading, modifier) {
val focusRequester = LocalFocusManager.current
var value by remember { mutableStateOf(initialValue) }

Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(5.dp),
modifier = modifier
) {
Text(heading, style = MaterialTheme.typography.headlineSmall)

OutlinedTextField(
value = value,
{ value = it; onValueChange(it) },
leadingIcon = leadingIcon,
trailingIcon = trailingIcon,
colors = TextFieldDefaults.colors(),
enabled = enabled,
isError = isError,
maxLines = 1,
modifier = Modifier.onKeyEvent {
if (it.type != KeyEventType.KeyDown) return@onKeyEvent true
OutlinedTextField(
value = value,
{ value = it; onValueChange(it) },
leadingIcon = leadingIcon,
trailingIcon = trailingIcon,
colors = TextFieldDefaults.colors(),
enabled = enabled,
isError = isError,
maxLines = 1,
modifier = Modifier.onKeyEvent {
if (it.type != KeyEventType.KeyDown) return@onKeyEvent true

when (it.key) {
Key.Escape -> {
value = initialValue
focusRequester.clearFocus()
}
when (it.key) {
Key.Escape -> {
value = initialValue
focusRequester.clearFocus()
}
}

false
}.onFocusChanged {
if (!it.isFocused && value != initialValue) {
onSubmit(value)
}
})
}
false
}.onFocusChanged {
if (!it.isFocused && value != initialValue) {
onSubmit(value)
}
})
}

@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun CheckboxWithHeading(heading: String, checked: Boolean, onCheckedChange: (Boolean) -> Unit) =
InputWithHeading(heading) {
Checkbox(checked, onCheckedChange)
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ fun UsernameInput() {
.collect { loading = false }
}

InputWithHeading({
TextInputWithHeading({
if (loading) CircularProgressIndicator(Modifier.size(ButtonDefaults.IconSize)) else Icon(
Icons.Default.AccountBox, "Username"
)
Expand Down
3 changes: 2 additions & 1 deletion windows_helper/src/main/kotlin/Extensions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package dev.schlaubi.mastermind.windows_helper
import java.lang.foreign.Arena
import java.lang.foreign.MemorySegment
import java.lang.foreign.SegmentAllocator
import kotlin.io.path.Path

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


object WindowsAPI : Arena by Arena.ofConfined() {
fun readGtaLocation() = readString(WindowsHelper::read_gta_location)
fun readGtaLocation() = Path(readString(WindowsHelper::read_gta_location))

fun registerKeyboardHook() = WindowsHelper.register_keyboard_hook()

Expand Down

0 comments on commit e5a2d55

Please sign in to comment.