diff --git a/app/src/main/java/club/clubk/ktag/konfigurator/Device.kt b/app/src/main/java/club/clubk/ktag/konfigurator/Device.kt index 8b607aa..2b953fe 100644 --- a/app/src/main/java/club/clubk/ktag/konfigurator/Device.kt +++ b/app/src/main/java/club/clubk/ktag/konfigurator/Device.kt @@ -2,14 +2,60 @@ package club.clubk.ktag.konfigurator import java.util.UUID +const val EDIT_DELAY_TIME: Long = 3L + +sealed class DeviceState { + data object Configurable : DeviceState() + data object Ready : DeviceState() + data object Playing : DeviceState() + data object WrapUp : DeviceState() +} + +sealed class DeviceConfigureState { + data object Discovered: DeviceConfigureState() + data object Configuring: DeviceConfigureState() + data object Success: DeviceConfigureState() + data object Failure: DeviceConfigureState() +} + +enum class DeviceParameter { + PLAYER_ID, TEAM, SECONDARY_COLOR, MAX_HEALTH, SPECIAL_WEAPONS +} + data class Device(val uuid: UUID = UUID.randomUUID(), var name: String = "Unknown Device", - var address: String = "FF:FF:FF:FF:FF:FF", - var deviceType : Int? = null, - var team : Int? = null, - var playerID : Int? = null, - var deviceState: DeviceState? = null + var address: String = "00:00:00:00:00:00", + var deviceType: Int? = null, + var deviceState: DeviceState? = null, + // All configurable variables + private var _playerID: Int? = null, + private var _team: Int? = null, + private var _secondaryColor: Int? = null, + private var _maxHealth: Int? = null, + private var _specialWeapons: Int? = null ) { + var deviceConfigureState: DeviceConfigureState = DeviceConfigureState.Discovered + private set + + var dirtyPlayerID: Boolean = false + private set + var dirtyTeam: Boolean = false + private set + var dirtySecondaryColor: Boolean = false + private set + var dirtyMaxHealth: Boolean = false + private set + var dirtySpecialWeapons: Boolean = false + private set + + var lastEditTime: Long = 0L + private set + + val playerID: Int? get() = _playerID + val team: Int? get() = _team + val secondaryColor: Int? get() = _secondaryColor + val maxHealth: Int? get() = _maxHealth + val specialWeapons: Int? get() = _specialWeapons fun deviceTypeName(): String { return when(deviceType) { @@ -20,5 +66,67 @@ data class Device(val uuid: UUID = UUID.randomUUID(), else -> "Unknown Device Type" } } -} + fun deviceTypeDrawable() { + return + } + + fun isDirty(): Boolean { + return dirtyPlayerID || dirtyTeam || dirtySecondaryColor + || dirtyMaxHealth || dirtySpecialWeapons + } + + fun isPastEditTime(): Boolean { + return System.nanoTime() - lastEditTime!! >= EDIT_DELAY_TIME + } + + fun setParameter(parameter: DeviceParameter, value: Any) { + lastEditTime = System.nanoTime() + when (parameter) { + DeviceParameter.PLAYER_ID -> { + _playerID = value as Int + dirtyPlayerID = true + } + DeviceParameter.TEAM -> { + _team = value as Int + dirtyTeam = true + } + DeviceParameter.SECONDARY_COLOR -> { + _secondaryColor = value as Int + dirtySecondaryColor = true + } + DeviceParameter.MAX_HEALTH -> { + _maxHealth = value as Int + dirtyMaxHealth = true + } + DeviceParameter.SPECIAL_WEAPONS -> { + _specialWeapons = value as Int + dirtySpecialWeapons = true + } + } + } + + fun checkForDirt() { + if (isDirty() && isPastEditTime()) { + return + } + } + + fun getDirtyParameters(): List { + val changed = mutableListOf() + if (dirtyPlayerID) changed.add(DeviceParameter.PLAYER_ID) + if (dirtyTeam) changed.add(DeviceParameter.TEAM) + if (dirtySecondaryColor) changed.add(DeviceParameter.SECONDARY_COLOR) + if (dirtyMaxHealth) changed.add(DeviceParameter.MAX_HEALTH) + if (dirtySpecialWeapons) changed.add(DeviceParameter.SPECIAL_WEAPONS) + return changed + } + + fun clearDirt() { + dirtyPlayerID = false + dirtyTeam = false + dirtySecondaryColor = false + dirtyMaxHealth = false + dirtySpecialWeapons = false + } +} diff --git a/app/src/main/java/club/clubk/ktag/konfigurator/DeviceState.kt b/app/src/main/java/club/clubk/ktag/konfigurator/DeviceState.kt deleted file mode 100644 index 22ea035..0000000 --- a/app/src/main/java/club/clubk/ktag/konfigurator/DeviceState.kt +++ /dev/null @@ -1,8 +0,0 @@ -package club.clubk.ktag.konfigurator - -sealed class DeviceState { - object Configurable : DeviceState() - object Ready : DeviceState() - object Playing : DeviceState() - object WrapUp : DeviceState() -} \ No newline at end of file diff --git a/app/src/main/java/club/clubk/ktag/konfigurator/GameConfig.kt b/app/src/main/java/club/clubk/ktag/konfigurator/GameConfig.kt index ccf6988..47e96a0 100644 --- a/app/src/main/java/club/clubk/ktag/konfigurator/GameConfig.kt +++ b/app/src/main/java/club/clubk/ktag/konfigurator/GameConfig.kt @@ -5,5 +5,5 @@ data class GameConfig(var name: String = "Default", var pregameLength: Int = 60000, var numRounds: Int = 2, var maxHealth: Int = 10, - var numBombs: Int = 1 // Special Weapons Received on Game Reentry + var specialWeapons: Int = 1 // Special Weapons Received on Game Reentry ) diff --git a/app/src/main/java/club/clubk/ktag/konfigurator/MainActivity.kt b/app/src/main/java/club/clubk/ktag/konfigurator/MainActivity.kt index d67932b..e714f6a 100644 --- a/app/src/main/java/club/clubk/ktag/konfigurator/MainActivity.kt +++ b/app/src/main/java/club/clubk/ktag/konfigurator/MainActivity.kt @@ -1,8 +1,6 @@ package club.clubk.ktag.konfigurator import android.Manifest -import android.bluetooth.BluetoothManager -import android.content.Context import android.content.pm.PackageManager import android.os.Build import android.os.Bundle @@ -23,7 +21,6 @@ import androidx.core.content.ContextCompat import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.KeyboardType @@ -253,7 +250,7 @@ fun GameConfigEditor(oldGameConfig: GameConfig, var pregameLength by rememberSaveable(oldGameConfig.pregameLength) { mutableStateOf(oldGameConfig.pregameLength.toString()) } var numRounds by rememberSaveable(oldGameConfig.numRounds) { mutableStateOf(oldGameConfig.numRounds.toString()) } var maxHealth by rememberSaveable(oldGameConfig.maxHealth) { mutableStateOf(oldGameConfig.maxHealth.toString()) } - var numBombs by rememberSaveable(oldGameConfig.numBombs) { mutableStateOf(oldGameConfig.numBombs.toString()) } + var numBombs by rememberSaveable(oldGameConfig.specialWeapons) { mutableStateOf(oldGameConfig.specialWeapons.toString()) } // For tracking validation errors var gameLengthError by rememberSaveable { mutableStateOf(false) } @@ -283,7 +280,7 @@ fun GameConfigEditor(oldGameConfig: GameConfig, pregameLength = pregameLength.toIntOrNull() ?: oldGameConfig.pregameLength, numRounds = numRounds.toIntOrNull() ?: oldGameConfig.numRounds, maxHealth = maxHealth.toIntOrNull() ?: oldGameConfig.maxHealth, - numBombs = numBombs.toIntOrNull() ?: oldGameConfig.numBombs + specialWeapons = numBombs.toIntOrNull() ?: oldGameConfig.specialWeapons ) onSave(newGameConfig) } diff --git a/app/src/main/java/club/clubk/ktag/konfigurator/StateMachineViewModel.kt b/app/src/main/java/club/clubk/ktag/konfigurator/StateMachineViewModel.kt index aeedd61..267dbf5 100644 --- a/app/src/main/java/club/clubk/ktag/konfigurator/StateMachineViewModel.kt +++ b/app/src/main/java/club/clubk/ktag/konfigurator/StateMachineViewModel.kt @@ -69,10 +69,12 @@ class StateMachineViewModel(context: Context) : ViewModel() { when (packet) { is HelloPacket -> { // Log.d(TAG_BLE_SCAN, "HelloPacket scanned") - scannedDevice.name = packet.deviceName - scannedDevice.deviceType = packet.deviceType - scannedDevice.team = packet.teamId - scannedDevice.deviceState = DeviceState.Configurable + val scannedDevice = Device( + name = packet.deviceName, + address = result.device.address, + deviceType = packet.deviceType, + deviceState = DeviceState.Configurable) + scannedDevice.setParameter(DeviceParameter.TEAM, packet.teamId) addOrRefreshDevice(scannedDevice) } is ConsolePacket -> { @@ -148,9 +150,13 @@ class StateMachineViewModel(context: Context) : ViewModel() { var oldDevice = currentDevices[index] newDevice.name = oldDevice.name newDevice.deviceType = oldDevice.deviceType ?: newDevice.deviceType - newDevice.team = oldDevice.team ?: newDevice.team - newDevice.playerID = oldDevice.playerID ?: newDevice.playerID newDevice.deviceState = newDevice.deviceState ?: oldDevice.deviceState + oldDevice.team?.let { teamValue -> + newDevice.setParameter(DeviceParameter.TEAM, teamValue) + } + oldDevice.playerID?.let { playerIDValue -> + newDevice.setParameter(DeviceParameter.PLAYER_ID, playerIDValue) + } currentDevices[index] = newDevice } _devices.value = currentDevices @@ -165,18 +171,26 @@ class StateMachineViewModel(context: Context) : ViewModel() { if (index == -1) { return } var oldDevice = currentDevices[index] newDevice.deviceType = newDevice.deviceType ?: oldDevice.deviceType - newDevice.team = newDevice.team ?: oldDevice.team - newDevice.playerID = newDevice.playerID ?: oldDevice.playerID + oldDevice.team?.let { teamValue -> + newDevice.setParameter(DeviceParameter.TEAM, teamValue) + } + oldDevice.playerID?.let { playerIDValue -> + newDevice.setParameter(DeviceParameter.PLAYER_ID, playerIDValue) + } currentDevices[index] = newDevice _devices.value = currentDevices _allDevicesReady.value = allDevicesReady() } - fun updateDeviceTeam(deviceAddress: String, newTeam: Int) { + fun updateDeviceTeam(deviceAddress: String, newTeam: Int?) { _devices.update { currentList -> currentList.map { device -> if (device.address == deviceAddress) { - device.copy(team = newTeam) // Creates a new Device instance + val updatedDevice = device.copy() + if (newTeam != null) { + updatedDevice.setParameter(DeviceParameter.TEAM, newTeam) + } + updatedDevice // Return the modified device } else { device } @@ -187,7 +201,7 @@ class StateMachineViewModel(context: Context) : ViewModel() { fun cycleDeviceTeam(device: Device) { Log.d("STATEMACHINE", "cycling device team") - var newTeam = device.team ?: -1 + var newTeam: Int = (device.team?.toInt() ?: -1) newTeam++ if (newTeam > 2) { newTeam = 0 @@ -244,7 +258,7 @@ class StateMachineViewModel(context: Context) : ViewModel() { parameterPacketGenerator.generatePacket( targetAddress = device.address, subtype = 2, // Request Parameter Change - key1 = 1, value1 = teamId, // Key 1 is Team ID + key1 = 1, value1 = teamId.toInt(), // Key 1 is Team ID key2 = 4, value2 = gameCfg.maxHealth // Key 2 is Max Health ) // If a device for some reason can't be configured (e.g. missing address),