ReModel of the ActiveAlteration system into the Campaign.
This commit is contained in:
parent
ecb0a6705f
commit
b314a28f82
22 changed files with 254 additions and 317 deletions
|
|
@ -48,14 +48,11 @@ class DataSyncViewModel(
|
|||
.combine(campaignRepository.campaignFlow) { _, campaign: Campaign -> campaign }
|
||||
.distinctUntilChanged()
|
||||
.onEach { campaign ->
|
||||
(campaign.characters.keys + campaign.npcs.keys).forEach { id ->
|
||||
campaign.instances.keys.forEach { id ->
|
||||
characterRepository.characterDetail(
|
||||
characterSheetId = id.characterSheetId,
|
||||
forceUpdate = true,
|
||||
)
|
||||
alterationRepository.updateActiveAlterations(
|
||||
characterInstanceId = id,
|
||||
)
|
||||
}
|
||||
}
|
||||
.launchIn(this)
|
||||
|
|
|
|||
|
|
@ -26,17 +26,4 @@ interface LwaClient {
|
|||
suspend fun campaignRemoveNpc(characterSheetId: String, instanceId: Int)
|
||||
|
||||
suspend fun alterations(): List<AlterationJson>
|
||||
|
||||
suspend fun activeAlterations(
|
||||
prefix: Char,
|
||||
characterSheetId: String,
|
||||
instanceId: Int,
|
||||
): List<String>
|
||||
|
||||
suspend fun toggleActiveAlterations(
|
||||
prefix: Char,
|
||||
characterSheetId: String,
|
||||
instanceId: Int,
|
||||
alterationId: String,
|
||||
)
|
||||
}
|
||||
|
|
@ -73,24 +73,4 @@ class LwaClientImpl(
|
|||
override suspend fun alterations(): List<AlterationJson> = client
|
||||
.get("$root/alterations")
|
||||
.body()
|
||||
|
||||
override suspend fun activeAlterations(
|
||||
prefix: Char,
|
||||
characterSheetId: String,
|
||||
instanceId: Int,
|
||||
): List<String> = client
|
||||
.get("$root/alterations/active?characterSheetId=$characterSheetId&instanceId=$instanceId&prefix=$prefix")
|
||||
.body()
|
||||
|
||||
override suspend fun toggleActiveAlterations(
|
||||
prefix: Char,
|
||||
characterSheetId: String,
|
||||
instanceId: Int,
|
||||
alterationId: String,
|
||||
) = client
|
||||
.put("$root/alterations/active/toggle?characterSheetId=$characterSheetId&instanceId=$instanceId&prefix=$prefix") {
|
||||
contentType(ContentType.Application.Json)
|
||||
setBody(alterationId)
|
||||
}
|
||||
.body<Unit>()
|
||||
}
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
package com.pixelized.desktop.lwa.repository.alteration
|
||||
|
||||
import com.pixelized.desktop.lwa.repository.campaign.CampaignStore
|
||||
import com.pixelized.shared.lwa.model.alteration.Alteration
|
||||
import com.pixelized.shared.lwa.model.alteration.FieldAlteration
|
||||
import com.pixelized.shared.lwa.model.campaign.Campaign
|
||||
import com.pixelized.shared.lwa.model.campaign.Campaign.CharacterInstance
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
|
@ -13,22 +15,20 @@ import kotlinx.coroutines.flow.combine
|
|||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
|
||||
// Theses typealias are there for readability only.
|
||||
private typealias AlterationId = String
|
||||
|
||||
class AlterationRepository(
|
||||
private val store: AlterationStore,
|
||||
private val campaignStore: CampaignStore,
|
||||
private val alterationStore: AlterationStore,
|
||||
) {
|
||||
private val scope = CoroutineScope(Dispatchers.IO + Job())
|
||||
private val activeAlterationMapFlow: StateFlow<Map<CharacterInstance.Id, Map<String, List<FieldAlteration>>>> =
|
||||
combine(
|
||||
store.alterations,
|
||||
store.active,
|
||||
) { alterations, actives ->
|
||||
actives.map { activeEntry ->
|
||||
alterationStore.alterationsFlow,
|
||||
campaignStore.campaignFlow,
|
||||
) { alterations, campaign: Campaign ->
|
||||
campaign.instances.map { activeEntry ->
|
||||
activeEntry.key to transformToAlterationFieldMap(
|
||||
alterations = alterations,
|
||||
actives = activeEntry.value
|
||||
actives = activeEntry.value.alterations,
|
||||
)
|
||||
}.toMap()
|
||||
}.stateIn(
|
||||
|
|
@ -49,32 +49,13 @@ class AlterationRepository(
|
|||
return activeAlterationMapFlow.value[characterInstanceId] ?: emptyMap()
|
||||
}
|
||||
|
||||
suspend fun updateActiveAlterations(
|
||||
characterInstanceId: CharacterInstance.Id,
|
||||
) {
|
||||
store.updateActiveAlterations(
|
||||
characterInstanceId = characterInstanceId,
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun toggleActiveAlteration(
|
||||
characterInstanceId: CharacterInstance.Id,
|
||||
alterationId: String,
|
||||
) {
|
||||
// alteration was active for the character toggle it off.
|
||||
store.toggleActiveAlteration(
|
||||
characterInstanceId = characterInstanceId,
|
||||
alterationId = alterationId,
|
||||
)
|
||||
}
|
||||
|
||||
private fun transformToAlterationFieldMap(
|
||||
alterations: Map<String, Alteration>,
|
||||
actives: List<String>,
|
||||
): Map<String, List<FieldAlteration>> {
|
||||
val fieldAlterations = hashMapOf<String, MutableList<FieldAlteration>>()
|
||||
actives.forEach { id: AlterationId ->
|
||||
alterations[id]?.let { alteration ->
|
||||
actives.forEach { alterationId ->
|
||||
alterations[alterationId]?.let { alteration ->
|
||||
alteration.fields.forEach { field ->
|
||||
fieldAlterations
|
||||
.getOrPut(field.fieldId) { mutableListOf() }
|
||||
|
|
|
|||
|
|
@ -1,13 +1,8 @@
|
|||
package com.pixelized.desktop.lwa.repository.alteration
|
||||
|
||||
import com.pixelized.desktop.lwa.network.LwaClient
|
||||
import com.pixelized.desktop.lwa.repository.network.NetworkRepository
|
||||
import com.pixelized.shared.lwa.model.alteration.Alteration
|
||||
import com.pixelized.shared.lwa.model.alteration.AlterationJsonFactory
|
||||
import com.pixelized.shared.lwa.model.campaign.Campaign.CharacterInstance
|
||||
import com.pixelized.shared.lwa.model.campaign.factory.CampaignJsonFactory
|
||||
import com.pixelized.shared.lwa.protocol.websocket.SocketMessage
|
||||
import com.pixelized.shared.lwa.protocol.websocket.ToggleActiveAlteration
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
|
|
@ -17,38 +12,20 @@ import kotlinx.coroutines.launch
|
|||
|
||||
class AlterationStore(
|
||||
private val alterationFactory: AlterationJsonFactory,
|
||||
private val campaignJsonFactory: CampaignJsonFactory,
|
||||
private val network: NetworkRepository,
|
||||
private val client: LwaClient,
|
||||
) {
|
||||
private val _alterations = MutableStateFlow<Map<String, Alteration>>(emptyMap())
|
||||
val alterations: StateFlow<Map<String, Alteration>> = _alterations
|
||||
|
||||
private val _active = MutableStateFlow<Map<CharacterInstance.Id, List<String>>>(emptyMap())
|
||||
val active: StateFlow<Map<CharacterInstance.Id, List<String>>> get() = _active
|
||||
private val _alterationsFlow = MutableStateFlow<Map<String, Alteration>>(emptyMap())
|
||||
val alterationsFlow: StateFlow<Map<String, Alteration>> = _alterationsFlow
|
||||
|
||||
init {
|
||||
val scope = CoroutineScope(Dispatchers.IO + Job())
|
||||
scope.launch {
|
||||
updateAlterations()
|
||||
}
|
||||
scope.launch {
|
||||
network.data.collect(::handleMessage)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun updateAlterations() {
|
||||
_alterations.value = loadAlteration()
|
||||
}
|
||||
|
||||
suspend fun updateActiveAlterations(
|
||||
characterInstanceId: CharacterInstance.Id,
|
||||
) {
|
||||
_active.value = _active.value.toMutableMap().also {
|
||||
it[characterInstanceId] = loadActiveAlterations(
|
||||
characterInstanceId = characterInstanceId,
|
||||
)
|
||||
}
|
||||
_alterationsFlow.value = loadAlteration()
|
||||
}
|
||||
|
||||
private suspend fun loadAlteration(): Map<String, Alteration> {
|
||||
|
|
@ -57,69 +34,11 @@ class AlterationStore(
|
|||
return data.associateBy { it.id }
|
||||
}
|
||||
|
||||
private suspend fun loadActiveAlterations(
|
||||
characterInstanceId: CharacterInstance.Id,
|
||||
): List<String> {
|
||||
val request = client.activeAlterations(
|
||||
prefix = characterInstanceId.prefix,
|
||||
characterSheetId = characterInstanceId.characterSheetId,
|
||||
instanceId = characterInstanceId.instanceId,
|
||||
)
|
||||
return request
|
||||
}
|
||||
|
||||
fun alterations(): Collection<Alteration> {
|
||||
return alterations.value.values
|
||||
return alterationsFlow.value.values
|
||||
}
|
||||
|
||||
fun alteration(alterationId: String): Alteration? {
|
||||
return alterations.value[alterationId]
|
||||
}
|
||||
|
||||
suspend fun toggleActiveAlteration(
|
||||
characterInstanceId: CharacterInstance.Id,
|
||||
alterationId: String,
|
||||
) {
|
||||
client.toggleActiveAlterations(
|
||||
prefix = characterInstanceId.prefix,
|
||||
characterSheetId = characterInstanceId.characterSheetId,
|
||||
instanceId = characterInstanceId.instanceId,
|
||||
alterationId = alterationId,
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun handleMessage(message: SocketMessage) {
|
||||
when (message) {
|
||||
is ToggleActiveAlteration -> {
|
||||
setActiveAlteration(
|
||||
characterInstanceId = CharacterInstance.Id(
|
||||
prefix = message.prefix,
|
||||
characterSheetId = message.characterSheetId,
|
||||
instanceId = message.instanceId,
|
||||
),
|
||||
alterationId = message.alterationId,
|
||||
active = message.active,
|
||||
)
|
||||
}
|
||||
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun setActiveAlteration(
|
||||
characterInstanceId: CharacterInstance.Id,
|
||||
alterationId: String,
|
||||
active: Boolean,
|
||||
) {
|
||||
_active.value = _active.value.toMutableMap().also { map ->
|
||||
map[characterInstanceId] = map[characterInstanceId]?.toMutableList()
|
||||
?.also {
|
||||
when {
|
||||
it.contains(alterationId) && !active -> it.remove(alterationId)
|
||||
!it.contains(alterationId) && active -> it.add(alterationId)
|
||||
}
|
||||
}
|
||||
?: listOfNotNull(if (active) alterationId else null)
|
||||
}
|
||||
return alterationsFlow.value[alterationId]
|
||||
}
|
||||
}
|
||||
|
|
@ -130,6 +130,11 @@ class CampaignStore(
|
|||
characterInstanceId = instanceId,
|
||||
diminished = message.diminished,
|
||||
)
|
||||
|
||||
is CampaignMessage.ToggleActiveAlteration -> updateAlterations(
|
||||
characterInstanceId = instanceId,
|
||||
alterationId = message.alterationId,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -162,8 +167,8 @@ class CampaignStore(
|
|||
) {
|
||||
val campaign = _campaignFlow.value
|
||||
|
||||
when {
|
||||
campaign.characters.containsKey(characterInstanceId) -> {
|
||||
when (characterInstanceId.prefix) {
|
||||
Campaign.CharacterInstance.Id.PLAYER -> {
|
||||
val characters = campaign.characters.toMutableMap().also {
|
||||
it[characterInstanceId] = useCase.updateCharacteristic(
|
||||
instance = campaign.character(id = characterInstanceId),
|
||||
|
|
@ -174,7 +179,7 @@ class CampaignStore(
|
|||
_campaignFlow.value = _campaignFlow.value.copy(characters = characters)
|
||||
}
|
||||
|
||||
campaign.npcs.containsKey(characterInstanceId) -> {
|
||||
Campaign.CharacterInstance.Id.NPC -> {
|
||||
val npcs = campaign.npcs.toMutableMap().also {
|
||||
it[characterInstanceId] = useCase.updateCharacteristic(
|
||||
instance = campaign.npc(id = characterInstanceId),
|
||||
|
|
@ -193,8 +198,8 @@ class CampaignStore(
|
|||
) {
|
||||
val campaign = _campaignFlow.value
|
||||
|
||||
when {
|
||||
campaign.characters.containsKey(characterInstanceId) -> {
|
||||
when (characterInstanceId.prefix) {
|
||||
Campaign.CharacterInstance.Id.PLAYER -> {
|
||||
val characters = campaign.characters.toMutableMap().also {
|
||||
it[characterInstanceId] = useCase.updateDiminished(
|
||||
instance = campaign.character(id = characterInstanceId),
|
||||
|
|
@ -204,7 +209,7 @@ class CampaignStore(
|
|||
_campaignFlow.value = _campaignFlow.value.copy(characters = characters)
|
||||
}
|
||||
|
||||
campaign.npcs.containsKey(characterInstanceId) -> {
|
||||
Campaign.CharacterInstance.Id.NPC -> {
|
||||
val npcs = campaign.npcs.toMutableMap().also {
|
||||
it[characterInstanceId] = useCase.updateDiminished(
|
||||
instance = campaign.npc(id = characterInstanceId),
|
||||
|
|
@ -216,6 +221,53 @@ class CampaignStore(
|
|||
}
|
||||
}
|
||||
|
||||
suspend fun updateAlterations(
|
||||
characterInstanceId: Campaign.CharacterInstance.Id,
|
||||
alterationId: String,
|
||||
) {
|
||||
val campaign = _campaignFlow.value
|
||||
|
||||
when (characterInstanceId.prefix) {
|
||||
Campaign.CharacterInstance.Id.PLAYER -> {
|
||||
// fetch all the current campaign character
|
||||
val characters = campaign.characters.toMutableMap()
|
||||
// update the corresponding character alterations
|
||||
characters[characterInstanceId]?.let { character ->
|
||||
characters[characterInstanceId] = character.copy(
|
||||
alterations = character.alterations.toMutableList().also { alterations ->
|
||||
if (alterations.contains(alterationId)) {
|
||||
alterations.remove(alterationId)
|
||||
} else {
|
||||
alterations.add(alterationId)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
// update the flow.
|
||||
_campaignFlow.value = _campaignFlow.value.copy(characters = characters)
|
||||
}
|
||||
|
||||
Campaign.CharacterInstance.Id.NPC -> {
|
||||
// fetch all the current campaign character
|
||||
val characters = campaign.npcs.toMutableMap()
|
||||
// update the corresponding character alterations
|
||||
characters[characterInstanceId]?.let { character ->
|
||||
characters[characterInstanceId] = character.copy(
|
||||
alterations = character.alterations.toMutableList().also { alterations ->
|
||||
if (alterations.contains(alterationId)) {
|
||||
alterations.remove(alterationId)
|
||||
} else {
|
||||
alterations.add(alterationId)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
// update the flow.
|
||||
_campaignFlow.value = _campaignFlow.value.copy(npcs = characters)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
private fun MutableStateFlow<Campaign>.update(campaign: Campaign): Campaign {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ import com.pixelized.shared.lwa.protocol.websocket.GameMasterEvent
|
|||
import com.pixelized.shared.lwa.protocol.websocket.RestSynchronisation
|
||||
import com.pixelized.shared.lwa.protocol.websocket.RollMessage
|
||||
import com.pixelized.shared.lwa.protocol.websocket.SocketMessage
|
||||
import com.pixelized.shared.lwa.protocol.websocket.ToggleActiveAlteration
|
||||
import com.pixelized.shared.lwa.protocol.websocket.UpdateSkillUsageMessage
|
||||
import lwacharactersheet.composeapp.generated.resources.Res
|
||||
import lwacharactersheet.composeapp.generated.resources.chat__characteristic_change__hp_down
|
||||
|
|
@ -65,45 +64,48 @@ class TextMessageFactory(
|
|||
)
|
||||
}
|
||||
|
||||
is CampaignMessage.UpdateDiminished -> {
|
||||
val sheetPreview = characterSheetRepository
|
||||
.characterPreview(characterId = message.characterSheetId)
|
||||
?: return null
|
||||
is CampaignMessage -> when (message) {
|
||||
is CampaignMessage.UpdateDiminished -> {
|
||||
val sheetPreview = characterSheetRepository
|
||||
.characterPreview(characterId = message.characterSheetId)
|
||||
?: return null
|
||||
|
||||
DiminishedTextMessageUio(
|
||||
id = "${message.timestamp}-$id-Diminished",
|
||||
timestamp = formatTime.format(time),
|
||||
character = sheetPreview.name,
|
||||
diminished = message.diminished,
|
||||
)
|
||||
}
|
||||
DiminishedTextMessageUio(
|
||||
id = "${message.timestamp}-$id-Diminished",
|
||||
timestamp = formatTime.format(time),
|
||||
character = sheetPreview.name,
|
||||
diminished = message.diminished,
|
||||
)
|
||||
}
|
||||
|
||||
is CampaignMessage.UpdateCharacteristic -> {
|
||||
val sheet = characterSheetRepository.characterDetail(
|
||||
characterSheetId = message.characterSheetId,
|
||||
) ?: return null
|
||||
is CampaignMessage.UpdateCharacteristic -> {
|
||||
val sheet = characterSheetRepository.characterDetail(
|
||||
characterSheetId = message.characterSheetId,
|
||||
) ?: return null
|
||||
|
||||
// We are talking about damage / consumption there so old value have to be put first.
|
||||
val value = message.oldValue - message.newValue
|
||||
// We are talking about damage / consumption there so old value have to be put first.
|
||||
val value = message.oldValue - message.newValue
|
||||
|
||||
CharacteristicTextMessageUio(
|
||||
id = "${message.timestamp}-$id-Characteristic",
|
||||
timestamp = formatTime.format(time),
|
||||
label = when {
|
||||
message.characteristic == Damage && value < 0 -> Res.string.chat__characteristic_change__hp_down
|
||||
message.characteristic == Damage -> Res.string.chat__characteristic_change__hp_up
|
||||
message.characteristic == Power && value < 0 -> Res.string.chat__characteristic_change__pp_down
|
||||
else -> Res.string.chat__characteristic_change__pp_up
|
||||
},
|
||||
character = sheet.name,
|
||||
value = abs(value),
|
||||
)
|
||||
CharacteristicTextMessageUio(
|
||||
id = "${message.timestamp}-$id-Characteristic",
|
||||
timestamp = formatTime.format(time),
|
||||
label = when {
|
||||
message.characteristic == Damage && value < 0 -> Res.string.chat__characteristic_change__hp_down
|
||||
message.characteristic == Damage -> Res.string.chat__characteristic_change__hp_up
|
||||
message.characteristic == Power && value < 0 -> Res.string.chat__characteristic_change__pp_down
|
||||
else -> Res.string.chat__characteristic_change__pp_up
|
||||
},
|
||||
character = sheet.name,
|
||||
value = abs(value),
|
||||
)
|
||||
}
|
||||
|
||||
is CampaignMessage.ToggleActiveAlteration -> null // TODO
|
||||
}
|
||||
|
||||
is RestSynchronisation.Campaign -> null
|
||||
is RestSynchronisation.CharacterSheetDelete -> null
|
||||
is RestSynchronisation.CharacterSheetUpdate -> null
|
||||
is ToggleActiveAlteration -> null
|
||||
is UpdateSkillUsageMessage -> null
|
||||
is GameMasterEvent -> null
|
||||
is GameEvent.DisplayPortrait -> null
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue