Add visibility toggle for player & npc + refactor WebSocketMessage.
This commit is contained in:
parent
2d164b265e
commit
4c37d8b937
47 changed files with 475 additions and 304 deletions
|
@ -6,8 +6,8 @@ import com.pixelized.shared.lwa.model.alteration.Alteration
|
||||||
import com.pixelized.shared.lwa.model.alteration.AlterationJsonFactory
|
import com.pixelized.shared.lwa.model.alteration.AlterationJsonFactory
|
||||||
import com.pixelized.shared.lwa.model.campaign.Campaign.CharacterInstance
|
import com.pixelized.shared.lwa.model.campaign.Campaign.CharacterInstance
|
||||||
import com.pixelized.shared.lwa.model.campaign.factory.CampaignJsonFactory
|
import com.pixelized.shared.lwa.model.campaign.factory.CampaignJsonFactory
|
||||||
import com.pixelized.shared.lwa.protocol.websocket.Message
|
import com.pixelized.shared.lwa.protocol.websocket.SocketMessage
|
||||||
import com.pixelized.shared.lwa.protocol.websocket.payload.RestSynchronisation
|
import com.pixelized.shared.lwa.protocol.websocket.ToggleActiveAlteration
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
|
@ -88,15 +88,17 @@ class AlterationStore(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun handleMessage(message: Message) {
|
private suspend fun handleMessage(message: SocketMessage) {
|
||||||
when (val payload = message.value) {
|
when (message) {
|
||||||
is RestSynchronisation.ToggleActiveAlteration -> {
|
is ToggleActiveAlteration -> {
|
||||||
setActiveAlteration(
|
setActiveAlteration(
|
||||||
characterInstanceId = campaignJsonFactory.characterInstanceIdFromJson(
|
characterInstanceId = CharacterInstance.Id(
|
||||||
characterInstanceIdJson = payload.characterId,
|
prefix = message.prefix,
|
||||||
|
characterSheetId = message.characterSheetId,
|
||||||
|
instanceId = message.instanceId,
|
||||||
),
|
),
|
||||||
alterationId = payload.alterationId,
|
alterationId = message.alterationId,
|
||||||
active = payload.active,
|
active = message.active,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,9 +6,10 @@ import com.pixelized.shared.lwa.model.campaign.Campaign
|
||||||
import com.pixelized.shared.lwa.model.campaign.character
|
import com.pixelized.shared.lwa.model.campaign.character
|
||||||
import com.pixelized.shared.lwa.model.campaign.factory.CampaignJsonFactory
|
import com.pixelized.shared.lwa.model.campaign.factory.CampaignJsonFactory
|
||||||
import com.pixelized.shared.lwa.model.campaign.npc
|
import com.pixelized.shared.lwa.model.campaign.npc
|
||||||
import com.pixelized.shared.lwa.protocol.websocket.Message
|
import com.pixelized.shared.lwa.protocol.websocket.SocketMessage
|
||||||
import com.pixelized.shared.lwa.protocol.websocket.payload.CampaignMessage
|
import com.pixelized.shared.lwa.protocol.websocket.CampaignMessage
|
||||||
import com.pixelized.shared.lwa.protocol.websocket.payload.RestSynchronisation
|
import com.pixelized.shared.lwa.protocol.websocket.GameMasterEvent
|
||||||
|
import com.pixelized.shared.lwa.protocol.websocket.RestSynchronisation
|
||||||
import com.pixelized.shared.lwa.usecase.CampaignUseCase
|
import com.pixelized.shared.lwa.usecase.CampaignUseCase
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
@ -106,28 +107,46 @@ class CampaignStore(
|
||||||
|
|
||||||
// region : WebSocket message Handling.
|
// region : WebSocket message Handling.
|
||||||
|
|
||||||
private suspend fun handleMessage(message: Message) {
|
private suspend fun handleMessage(message: SocketMessage) {
|
||||||
when (val payload = message.value) {
|
when (message) {
|
||||||
is RestSynchronisation.Campaign -> {
|
is RestSynchronisation.Campaign -> {
|
||||||
campaign(update = true)
|
campaign(update = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
is CampaignMessage -> {
|
is CampaignMessage -> {
|
||||||
val instanceId = Campaign.CharacterInstance.Id(
|
val instanceId = Campaign.CharacterInstance.Id(
|
||||||
prefix = payload.prefix,
|
prefix = message.prefix,
|
||||||
characterSheetId = payload.characterSheetId,
|
characterSheetId = message.characterSheetId,
|
||||||
instanceId = payload.instanceId,
|
instanceId = message.instanceId,
|
||||||
)
|
)
|
||||||
when (payload) {
|
when (message) {
|
||||||
is CampaignMessage.UpdateCharacteristic -> updateCharacteristic(
|
is CampaignMessage.UpdateCharacteristic -> updateCharacteristic(
|
||||||
characterInstanceId = instanceId,
|
characterInstanceId = instanceId,
|
||||||
characteristic = factory.convertFromJson(json = payload.characteristic),
|
characteristic = factory.convertFromJson(json = message.characteristic),
|
||||||
value = payload.value,
|
value = message.value,
|
||||||
)
|
)
|
||||||
|
|
||||||
is CampaignMessage.UpdateDiminished -> updateDiminished(
|
is CampaignMessage.UpdateDiminished -> updateDiminished(
|
||||||
characterInstanceId = instanceId,
|
characterInstanceId = instanceId,
|
||||||
diminished = payload.diminished,
|
diminished = message.diminished,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
is GameMasterEvent -> when (message) {
|
||||||
|
is GameMasterEvent.ToggleNpc -> {
|
||||||
|
_campaignFlow.value = _campaignFlow.value.copy(
|
||||||
|
options = _campaignFlow.value.options.copy(
|
||||||
|
showNpcs = _campaignFlow.value.options.showNpcs.not()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
is GameMasterEvent.TogglePlayer -> {
|
||||||
|
_campaignFlow.value = _campaignFlow.value.copy(
|
||||||
|
options = _campaignFlow.value.options.copy(
|
||||||
|
showParty = _campaignFlow.value.options.showParty.not()
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,9 +5,9 @@ import com.pixelized.desktop.lwa.repository.network.NetworkRepository
|
||||||
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet
|
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet
|
||||||
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheetJsonFactory
|
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheetJsonFactory
|
||||||
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheetPreview
|
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheetPreview
|
||||||
import com.pixelized.shared.lwa.protocol.websocket.Message
|
import com.pixelized.shared.lwa.protocol.websocket.SocketMessage
|
||||||
import com.pixelized.shared.lwa.protocol.websocket.payload.RestSynchronisation
|
import com.pixelized.shared.lwa.protocol.websocket.RestSynchronisation
|
||||||
import com.pixelized.shared.lwa.protocol.websocket.payload.UpdateSkillUsageMessage
|
import com.pixelized.shared.lwa.protocol.websocket.UpdateSkillUsageMessage
|
||||||
import com.pixelized.shared.lwa.usecase.CharacterSheetUseCase
|
import com.pixelized.shared.lwa.usecase.CharacterSheetUseCase
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
@ -97,29 +97,29 @@ class CharacterSheetStore(
|
||||||
// endregion
|
// endregion
|
||||||
// region: WebSocket & data update.
|
// region: WebSocket & data update.
|
||||||
|
|
||||||
private suspend fun handleMessage(message: Message) {
|
private suspend fun handleMessage(message: SocketMessage) {
|
||||||
when (val payload = message.value) {
|
when (message) {
|
||||||
is RestSynchronisation.CharacterUpdate -> {
|
is RestSynchronisation.CharacterSheetUpdate -> {
|
||||||
getCharacterSheet(
|
getCharacterSheet(
|
||||||
characterSheetId = payload.id,
|
characterSheetId = message.characterSheetId,
|
||||||
forceUpdate = true,
|
forceUpdate = true,
|
||||||
)
|
)
|
||||||
if (_previewFlow.value.firstOrNull { it.characterSheetId == payload.id } == null) {
|
if (_previewFlow.value.firstOrNull { it.characterSheetId == message.characterSheetId } == null) {
|
||||||
charactersPreview()
|
charactersPreview()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
is RestSynchronisation.CharacterDelete -> {
|
is RestSynchronisation.CharacterSheetDelete -> {
|
||||||
_previewFlow.value = previewFlow.value.toMutableList()
|
_previewFlow.value = previewFlow.value.toMutableList()
|
||||||
.also { sheets -> sheets.removeIf { it.characterSheetId == payload.characterId } }
|
.also { sheets -> sheets.removeIf { it.characterSheetId == message.characterSheetId } }
|
||||||
_detailFlow.delete(payload.characterId)
|
_detailFlow.delete(message.characterSheetId)
|
||||||
}
|
}
|
||||||
|
|
||||||
is UpdateSkillUsageMessage -> {
|
is UpdateSkillUsageMessage -> {
|
||||||
updateCharacterSkillChange(
|
updateCharacterSkillChange(
|
||||||
characterId = payload.characterSheetId,
|
characterId = message.characterSheetId,
|
||||||
skillId = payload.skillId,
|
skillId = message.skillId,
|
||||||
used = payload.used,
|
used = message.used,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,7 @@ package com.pixelized.desktop.lwa.repository.network
|
||||||
|
|
||||||
import com.pixelized.desktop.lwa.repository.network.helper.connectWebSocket
|
import com.pixelized.desktop.lwa.repository.network.helper.connectWebSocket
|
||||||
import com.pixelized.desktop.lwa.repository.settings.SettingsRepository
|
import com.pixelized.desktop.lwa.repository.settings.SettingsRepository
|
||||||
import com.pixelized.shared.lwa.protocol.websocket.Message
|
import com.pixelized.shared.lwa.protocol.websocket.SocketMessage
|
||||||
import com.pixelized.shared.lwa.protocol.websocket.payload.MessagePayload
|
|
||||||
import io.ktor.client.HttpClient
|
import io.ktor.client.HttpClient
|
||||||
import io.ktor.client.engine.okhttp.OkHttp
|
import io.ktor.client.engine.okhttp.OkHttp
|
||||||
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
|
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
|
||||||
|
@ -20,7 +19,6 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.SharedFlow
|
import kotlinx.coroutines.flow.SharedFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
|
|
||||||
class NetworkRepository(
|
class NetworkRepository(
|
||||||
|
@ -31,9 +29,9 @@ class NetworkRepository(
|
||||||
private var networkJob: Job? = null
|
private var networkJob: Job? = null
|
||||||
private var client: HttpClient? = null
|
private var client: HttpClient? = null
|
||||||
|
|
||||||
private val outgoingMessageBuffer = MutableSharedFlow<Message>()
|
private val outgoingMessageBuffer = MutableSharedFlow<SocketMessage>()
|
||||||
private val incomingMessageBuffer = MutableSharedFlow<Message>()
|
private val incomingMessageBuffer = MutableSharedFlow<SocketMessage>()
|
||||||
val data: SharedFlow<Message> get() = incomingMessageBuffer
|
val data: SharedFlow<SocketMessage> get() = incomingMessageBuffer
|
||||||
|
|
||||||
private val _status = MutableStateFlow(Status.DISCONNECTED)
|
private val _status = MutableStateFlow(Status.DISCONNECTED)
|
||||||
val status: StateFlow<Status> get() = _status
|
val status: StateFlow<Status> get() = _status
|
||||||
|
@ -67,7 +65,7 @@ class NetworkRepository(
|
||||||
incoming.consumeEach { frame ->
|
incoming.consumeEach { frame ->
|
||||||
if (frame is Frame.Text) {
|
if (frame is Frame.Text) {
|
||||||
val data = frame.readText()
|
val data = frame.readText()
|
||||||
val message = json.decodeFromString<Message>(data)
|
val message = json.decodeFromString<SocketMessage>(data)
|
||||||
incomingMessageBuffer.emit(message)
|
incomingMessageBuffer.emit(message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,14 +94,9 @@ class NetworkRepository(
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun share(
|
suspend fun share(
|
||||||
playerName: String = settingsRepository.settings().playerName,
|
message: SocketMessage,
|
||||||
payload: MessagePayload,
|
|
||||||
) {
|
) {
|
||||||
if (status.value == Status.CONNECTED) {
|
if (status.value == Status.CONNECTED) {
|
||||||
val message = Message(
|
|
||||||
from = playerName,
|
|
||||||
value = payload,
|
|
||||||
)
|
|
||||||
// emit the message into the outgoing buffer
|
// emit the message into the outgoing buffer
|
||||||
outgoingMessageBuffer.emit(message)
|
outgoingMessageBuffer.emit(message)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,23 @@
|
||||||
package com.pixelized.desktop.lwa.repository.roll_history
|
package com.pixelized.desktop.lwa.repository.roll_history
|
||||||
|
|
||||||
import com.pixelized.desktop.lwa.repository.network.NetworkRepository
|
import com.pixelized.desktop.lwa.repository.network.NetworkRepository
|
||||||
import com.pixelized.shared.lwa.protocol.websocket.payload.RollMessage
|
import com.pixelized.shared.lwa.protocol.websocket.RollMessage
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.SharedFlow
|
import kotlinx.coroutines.flow.SharedFlow
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
|
import kotlinx.coroutines.flow.filter
|
||||||
|
import kotlinx.coroutines.flow.filterIsInstance
|
||||||
import kotlinx.coroutines.flow.mapNotNull
|
import kotlinx.coroutines.flow.mapNotNull
|
||||||
import kotlinx.coroutines.flow.shareIn
|
import kotlinx.coroutines.flow.shareIn
|
||||||
|
|
||||||
class RollHistoryRepository(
|
class RollHistoryRepository(
|
||||||
private val network: NetworkRepository,
|
network: NetworkRepository,
|
||||||
) {
|
) {
|
||||||
private val scope = CoroutineScope(Dispatchers.IO)
|
private val scope = CoroutineScope(Dispatchers.IO)
|
||||||
|
|
||||||
val rolls: SharedFlow<RollMessage> = network.data
|
val rolls: SharedFlow<RollMessage> = network.data
|
||||||
.mapNotNull { it.value as? RollMessage }
|
.filterIsInstance(RollMessage::class)
|
||||||
.shareIn(
|
.shareIn(
|
||||||
scope = scope,
|
scope = scope,
|
||||||
started = SharingStarted.Eagerly,
|
started = SharingStarted.Eagerly,
|
||||||
|
|
|
@ -13,7 +13,7 @@ import com.pixelized.shared.lwa.model.campaign.Campaign
|
||||||
import com.pixelized.shared.lwa.model.campaign.Campaign.CharacterInstance.Characteristic
|
import com.pixelized.shared.lwa.model.campaign.Campaign.CharacterInstance.Characteristic
|
||||||
import com.pixelized.shared.lwa.model.campaign.factory.CampaignJsonFactory
|
import com.pixelized.shared.lwa.model.campaign.factory.CampaignJsonFactory
|
||||||
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet
|
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet
|
||||||
import com.pixelized.shared.lwa.protocol.websocket.payload.CampaignMessage
|
import com.pixelized.shared.lwa.protocol.websocket.CampaignMessage
|
||||||
|
|
||||||
class CharacterDetailCharacteristicDialogViewModel(
|
class CharacterDetailCharacteristicDialogViewModel(
|
||||||
private val characterSheetRepository: CharacterSheetRepository,
|
private val characterSheetRepository: CharacterSheetRepository,
|
||||||
|
@ -79,7 +79,8 @@ class CharacterDetailCharacteristicDialogViewModel(
|
||||||
)
|
)
|
||||||
// share the data through the websocket.
|
// share the data through the websocket.
|
||||||
network.share(
|
network.share(
|
||||||
payload = CampaignMessage.UpdateCharacteristic(
|
message = CampaignMessage.UpdateCharacteristic(
|
||||||
|
timestamp = System.currentTimeMillis(),
|
||||||
prefix = characterInstanceId.prefix,
|
prefix = characterInstanceId.prefix,
|
||||||
characterSheetId = characterInstanceId.characterSheetId,
|
characterSheetId = characterInstanceId.characterSheetId,
|
||||||
instanceId = characterInstanceId.instanceId,
|
instanceId = characterInstanceId.instanceId,
|
||||||
|
|
|
@ -13,7 +13,7 @@ import com.pixelized.desktop.lwa.ui.overlay.roll.DifficultyUio.Difficulty
|
||||||
import com.pixelized.desktop.lwa.ui.overlay.roll.RollAction.RollActionUio
|
import com.pixelized.desktop.lwa.ui.overlay.roll.RollAction.RollActionUio
|
||||||
import com.pixelized.shared.lwa.model.AlteredCharacterSheet
|
import com.pixelized.shared.lwa.model.AlteredCharacterSheet
|
||||||
import com.pixelized.shared.lwa.model.AlteredCharacterSheetFactory
|
import com.pixelized.shared.lwa.model.AlteredCharacterSheetFactory
|
||||||
import com.pixelized.shared.lwa.protocol.websocket.payload.RollMessage
|
import com.pixelized.shared.lwa.protocol.websocket.RollMessage
|
||||||
import com.pixelized.shared.lwa.usecase.ExpressionUseCase
|
import com.pixelized.shared.lwa.usecase.ExpressionUseCase
|
||||||
import com.pixelized.shared.lwa.usecase.SkillStepUseCase
|
import com.pixelized.shared.lwa.usecase.SkillStepUseCase
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
|
@ -31,6 +31,7 @@ import lwacharactersheet.composeapp.generated.resources.roll_page__failure
|
||||||
import lwacharactersheet.composeapp.generated.resources.roll_page__special_success
|
import lwacharactersheet.composeapp.generated.resources.roll_page__special_success
|
||||||
import lwacharactersheet.composeapp.generated.resources.roll_page__success
|
import lwacharactersheet.composeapp.generated.resources.roll_page__success
|
||||||
import org.jetbrains.compose.resources.getString
|
import org.jetbrains.compose.resources.getString
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
class RollViewModel(
|
class RollViewModel(
|
||||||
private val characterSheetRepository: CharacterSheetRepository,
|
private val characterSheetRepository: CharacterSheetRepository,
|
||||||
|
@ -267,7 +268,8 @@ class RollViewModel(
|
||||||
val rollAction = rollAction ?: return
|
val rollAction = rollAction ?: return
|
||||||
|
|
||||||
val payload = RollMessage(
|
val payload = RollMessage(
|
||||||
id = RollMessage.RollId.create(),
|
timestamp = System.currentTimeMillis(),
|
||||||
|
uuid = UUID.randomUUID().toString(),
|
||||||
prefix = rollAction.characterInstanceId.prefix,
|
prefix = rollAction.characterInstanceId.prefix,
|
||||||
characterSheetId = rollAction.characterInstanceId.characterSheetId,
|
characterSheetId = rollAction.characterInstanceId.characterSheetId,
|
||||||
instanceId = rollAction.characterInstanceId.instanceId,
|
instanceId = rollAction.characterInstanceId.instanceId,
|
||||||
|
@ -294,7 +296,7 @@ class RollViewModel(
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
networkRepository.share(
|
networkRepository.share(
|
||||||
payload = payload,
|
message = payload,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -7,7 +7,7 @@ import com.pixelized.desktop.lwa.repository.campaign.CampaignRepository
|
||||||
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
|
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
|
||||||
import com.pixelized.desktop.lwa.repository.network.NetworkRepository
|
import com.pixelized.desktop.lwa.repository.network.NetworkRepository
|
||||||
import com.pixelized.shared.lwa.model.campaign.Campaign
|
import com.pixelized.shared.lwa.model.campaign.Campaign
|
||||||
import com.pixelized.shared.lwa.protocol.websocket.payload.UpdateSkillUsageMessage
|
import com.pixelized.shared.lwa.protocol.websocket.UpdateSkillUsageMessage
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
@ -84,7 +84,8 @@ class CharacterDetailViewModel(
|
||||||
) {
|
) {
|
||||||
val characterSheetId = displayedCharacterId.value?.characterSheetId ?: return
|
val characterSheetId = displayedCharacterId.value?.characterSheetId ?: return
|
||||||
network.share(
|
network.share(
|
||||||
payload = UpdateSkillUsageMessage(
|
message = UpdateSkillUsageMessage(
|
||||||
|
timestamp = System.currentTimeMillis(),
|
||||||
characterSheetId = characterSheetId,
|
characterSheetId = characterSheetId,
|
||||||
skillId = skillId,
|
skillId = skillId,
|
||||||
used = used.not(),
|
used = used.not(),
|
||||||
|
|
|
@ -9,7 +9,7 @@ import com.pixelized.desktop.lwa.repository.campaign.CampaignRepository
|
||||||
import com.pixelized.desktop.lwa.repository.network.NetworkRepository
|
import com.pixelized.desktop.lwa.repository.network.NetworkRepository
|
||||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.dialog.DiminishedStatDialogUio
|
import com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.dialog.DiminishedStatDialogUio
|
||||||
import com.pixelized.shared.lwa.model.campaign.Campaign
|
import com.pixelized.shared.lwa.model.campaign.Campaign
|
||||||
import com.pixelized.shared.lwa.protocol.websocket.payload.CampaignMessage
|
import com.pixelized.shared.lwa.protocol.websocket.CampaignMessage
|
||||||
import lwacharactersheet.composeapp.generated.resources.Res
|
import lwacharactersheet.composeapp.generated.resources.Res
|
||||||
import lwacharactersheet.composeapp.generated.resources.character_sheet__diminished__label
|
import lwacharactersheet.composeapp.generated.resources.character_sheet__diminished__label
|
||||||
import org.jetbrains.compose.resources.getString
|
import org.jetbrains.compose.resources.getString
|
||||||
|
@ -56,7 +56,8 @@ class CharacterDiminishedViewModel(
|
||||||
) {
|
) {
|
||||||
val diminished = dialog.value().text.toIntOrNull() ?: 0
|
val diminished = dialog.value().text.toIntOrNull() ?: 0
|
||||||
networkRepository.share(
|
networkRepository.share(
|
||||||
payload = CampaignMessage.UpdateDiminished(
|
message = CampaignMessage.UpdateDiminished(
|
||||||
|
timestamp = System.currentTimeMillis(),
|
||||||
prefix = dialog.characterInstanceId.prefix,
|
prefix = dialog.characterInstanceId.prefix,
|
||||||
characterSheetId = dialog.characterInstanceId.characterSheetId,
|
characterSheetId = dialog.characterInstanceId.characterSheetId,
|
||||||
instanceId = dialog.characterInstanceId.instanceId,
|
instanceId = dialog.characterInstanceId.instanceId,
|
||||||
|
|
|
@ -22,7 +22,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.flatMapMerge
|
import kotlinx.coroutines.flow.flatMapLatest
|
||||||
import kotlinx.coroutines.flow.flowOf
|
import kotlinx.coroutines.flow.flowOf
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
|
@ -53,7 +53,7 @@ abstract class CharacterRibbonViewModel(
|
||||||
*/
|
*/
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
val characters: StateFlow<List<CharacterPortraitUio>> = campaignRepository.campaignFlow
|
val characters: StateFlow<List<CharacterPortraitUio>> = campaignRepository.campaignFlow
|
||||||
.flatMapMerge { campaign ->
|
.flatMapLatest { campaign ->
|
||||||
when (campaign.data.isEmpty()) {
|
when (campaign.data.isEmpty()) {
|
||||||
true -> flowOf(emptyList())
|
true -> flowOf(emptyList())
|
||||||
else -> combine<CharacterPortraitUio?, List<CharacterPortraitUio>>(
|
else -> combine<CharacterPortraitUio?, List<CharacterPortraitUio>>(
|
||||||
|
|
|
@ -24,7 +24,7 @@ class NpcRibbonViewModel(
|
||||||
campaignRepository = campaignRepository,
|
campaignRepository = campaignRepository,
|
||||||
ribbonFactory = ribbonFactory,
|
ribbonFactory = ribbonFactory,
|
||||||
) {
|
) {
|
||||||
override val Campaign.data get() = npcs
|
override val Campaign.data get() = if (options.showNpcs) npcs else emptyMap()
|
||||||
|
|
||||||
override val enableCharacterSheet = false
|
override val enableCharacterSheet = false
|
||||||
override val enableCharacterStats = false
|
override val enableCharacterStats = false
|
||||||
|
|
|
@ -24,7 +24,7 @@ class PlayerRibbonViewModel(
|
||||||
campaignRepository = campaignRepository,
|
campaignRepository = campaignRepository,
|
||||||
ribbonFactory = ribbonFactory,
|
ribbonFactory = ribbonFactory,
|
||||||
) {
|
) {
|
||||||
override val Campaign.data get() = characters
|
override val Campaign.data get() = if (options.showParty) characters else emptyMap()
|
||||||
|
|
||||||
override val enableCharacterSheet = true
|
override val enableCharacterSheet = true
|
||||||
override val enableCharacterStats = true
|
override val enableCharacterStats = true
|
||||||
|
|
|
@ -10,11 +10,13 @@ import com.pixelized.shared.lwa.model.AlteredCharacterSheetFactory
|
||||||
import com.pixelized.shared.lwa.model.campaign.Campaign
|
import com.pixelized.shared.lwa.model.campaign.Campaign
|
||||||
import com.pixelized.shared.lwa.model.campaign.CampaignJsonV1.CharacterInstanceJsonV1.CharacteristicV1.Damage
|
import com.pixelized.shared.lwa.model.campaign.CampaignJsonV1.CharacterInstanceJsonV1.CharacteristicV1.Damage
|
||||||
import com.pixelized.shared.lwa.model.campaign.CampaignJsonV1.CharacterInstanceJsonV1.CharacteristicV1.Power
|
import com.pixelized.shared.lwa.model.campaign.CampaignJsonV1.CharacterInstanceJsonV1.CharacteristicV1.Power
|
||||||
import com.pixelized.shared.lwa.protocol.websocket.Message
|
import com.pixelized.shared.lwa.protocol.websocket.SocketMessage
|
||||||
import com.pixelized.shared.lwa.protocol.websocket.payload.CampaignMessage
|
import com.pixelized.shared.lwa.protocol.websocket.CampaignMessage
|
||||||
import com.pixelized.shared.lwa.protocol.websocket.payload.RestSynchronisation
|
import com.pixelized.shared.lwa.protocol.websocket.GameMasterEvent
|
||||||
import com.pixelized.shared.lwa.protocol.websocket.payload.RollMessage
|
import com.pixelized.shared.lwa.protocol.websocket.RestSynchronisation
|
||||||
import com.pixelized.shared.lwa.protocol.websocket.payload.UpdateSkillUsageMessage
|
import com.pixelized.shared.lwa.protocol.websocket.RollMessage
|
||||||
|
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.Res
|
||||||
import lwacharactersheet.composeapp.generated.resources.chat__characteristic__hp
|
import lwacharactersheet.composeapp.generated.resources.chat__characteristic__hp
|
||||||
import lwacharactersheet.composeapp.generated.resources.chat__characteristic__pp
|
import lwacharactersheet.composeapp.generated.resources.chat__characteristic__pp
|
||||||
|
@ -30,27 +32,27 @@ class TextMessageFactory(
|
||||||
private val formatTime = SimpleDateFormat("HH:mm:ss")
|
private val formatTime = SimpleDateFormat("HH:mm:ss")
|
||||||
|
|
||||||
suspend fun convertToTextMessage(
|
suspend fun convertToTextMessage(
|
||||||
message: Message,
|
message: SocketMessage,
|
||||||
): TextMessage? {
|
): TextMessage? {
|
||||||
val time = System.currentTimeMillis()
|
val time = message.timestamp
|
||||||
val id = formatId.format(time)
|
val id = formatId.format(time)
|
||||||
|
|
||||||
return when (val payload = message.value) {
|
return when (message) {
|
||||||
is RollMessage -> {
|
is RollMessage -> {
|
||||||
val sheetPreview = characterSheetRepository
|
val sheetPreview = characterSheetRepository
|
||||||
.characterPreview(characterId = payload.characterSheetId)
|
.characterPreview(characterId = message.characterSheetId)
|
||||||
?: return null
|
?: return null
|
||||||
|
|
||||||
RollTextMessageUio(
|
RollTextMessageUio(
|
||||||
id = "${payload.id.rollId}-${payload.id.timestamp}",
|
id = "${message.uuid}-${message.timestamp}",
|
||||||
timestamp = formatTime.format(time),
|
timestamp = formatTime.format(time),
|
||||||
character = sheetPreview.name,
|
character = sheetPreview.name,
|
||||||
skillLabel = payload.skillLabel,
|
skillLabel = message.skillLabel,
|
||||||
rollDifficulty = payload.rollDifficulty,
|
rollDifficulty = message.rollDifficulty,
|
||||||
rollValue = payload.rollValue,
|
rollValue = message.rollValue,
|
||||||
rollSuccessLimit = payload.rollSuccessLimit,
|
rollSuccessLimit = message.rollSuccessLimit,
|
||||||
resultLabel = payload.resultLabel,
|
resultLabel = message.resultLabel,
|
||||||
resultType = when (payload.critical) {
|
resultType = when (message.critical) {
|
||||||
RollMessage.Critical.CRITICAL_SUCCESS -> RollTextMessageUio.Critical.CRITICAL_SUCCESS
|
RollMessage.Critical.CRITICAL_SUCCESS -> RollTextMessageUio.Critical.CRITICAL_SUCCESS
|
||||||
RollMessage.Critical.SPECIAL_SUCCESS -> RollTextMessageUio.Critical.SPECIAL_SUCCESS
|
RollMessage.Critical.SPECIAL_SUCCESS -> RollTextMessageUio.Critical.SPECIAL_SUCCESS
|
||||||
RollMessage.Critical.SUCCESS -> RollTextMessageUio.Critical.SUCCESS
|
RollMessage.Critical.SUCCESS -> RollTextMessageUio.Critical.SUCCESS
|
||||||
|
@ -63,25 +65,25 @@ class TextMessageFactory(
|
||||||
|
|
||||||
is CampaignMessage.UpdateDiminished -> {
|
is CampaignMessage.UpdateDiminished -> {
|
||||||
val sheetPreview = characterSheetRepository
|
val sheetPreview = characterSheetRepository
|
||||||
.characterPreview(characterId = payload.characterSheetId)
|
.characterPreview(characterId = message.characterSheetId)
|
||||||
?: return null
|
?: return null
|
||||||
|
|
||||||
DiminishedTextMessageUio(
|
DiminishedTextMessageUio(
|
||||||
id = "${message.from}-$id-Diminished",
|
id = "${message.timestamp}-$id-Diminished",
|
||||||
timestamp = formatTime.format(time),
|
timestamp = formatTime.format(time),
|
||||||
character = sheetPreview.name,
|
character = sheetPreview.name,
|
||||||
diminished = payload.diminished,
|
diminished = message.diminished,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
is CampaignMessage.UpdateCharacteristic -> {
|
is CampaignMessage.UpdateCharacteristic -> {
|
||||||
val sheet = characterSheetRepository.characterDetail(
|
val sheet = characterSheetRepository.characterDetail(
|
||||||
characterSheetId = payload.characterSheetId,
|
characterSheetId = message.characterSheetId,
|
||||||
) ?: return null
|
) ?: return null
|
||||||
val characterInstanceId = Campaign.CharacterInstance.Id(
|
val characterInstanceId = Campaign.CharacterInstance.Id(
|
||||||
prefix = payload.prefix,
|
prefix = message.prefix,
|
||||||
characterSheetId = payload.characterSheetId,
|
characterSheetId = message.characterSheetId,
|
||||||
instanceId = payload.instanceId,
|
instanceId = message.instanceId,
|
||||||
)
|
)
|
||||||
val alterations = alterationRepository.alterations(
|
val alterations = alterationRepository.alterations(
|
||||||
characterInstanceId = characterInstanceId,
|
characterInstanceId = characterInstanceId,
|
||||||
|
@ -91,25 +93,26 @@ class TextMessageFactory(
|
||||||
alterations = alterations,
|
alterations = alterations,
|
||||||
)
|
)
|
||||||
CharacteristicTextMessageUio(
|
CharacteristicTextMessageUio(
|
||||||
id = "${message.from}-$id-Characteristic",
|
id = "${message.timestamp}-$id-Characteristic",
|
||||||
timestamp = formatTime.format(time),
|
timestamp = formatTime.format(time),
|
||||||
character = sheet.name,
|
character = sheet.name,
|
||||||
value = when (payload.characteristic) {
|
value = when (message.characteristic) {
|
||||||
Damage -> alteredSheet.maxHp - payload.value
|
Damage -> alteredSheet.maxHp - message.value
|
||||||
Power -> alteredSheet.maxPp - payload.value
|
Power -> alteredSheet.maxPp - message.value
|
||||||
},
|
},
|
||||||
characteristic = when (payload.characteristic) {
|
characteristic = when (message.characteristic) {
|
||||||
Damage -> getString(Res.string.chat__characteristic__hp)
|
Damage -> getString(Res.string.chat__characteristic__hp)
|
||||||
Power -> getString(Res.string.chat__characteristic__pp)
|
Power -> getString(Res.string.chat__characteristic__pp)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
RestSynchronisation.Campaign -> null
|
is RestSynchronisation.Campaign -> null
|
||||||
is RestSynchronisation.CharacterDelete -> null
|
is RestSynchronisation.CharacterSheetDelete -> null
|
||||||
is RestSynchronisation.CharacterUpdate -> null
|
is RestSynchronisation.CharacterSheetUpdate -> null
|
||||||
is RestSynchronisation.ToggleActiveAlteration -> null
|
is ToggleActiveAlteration -> null
|
||||||
is UpdateSkillUsageMessage -> null
|
is UpdateSkillUsageMessage -> null
|
||||||
|
is GameMasterEvent -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -14,8 +14,8 @@ import com.pixelized.desktop.lwa.repository.network.NetworkRepository
|
||||||
import com.pixelized.desktop.lwa.ui.navigation.screen.destination.CharacterSheetDestination
|
import com.pixelized.desktop.lwa.ui.navigation.screen.destination.CharacterSheetDestination
|
||||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.dialog.CharacterSheetDeleteConfirmationDialogUio
|
import com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.dialog.CharacterSheetDeleteConfirmationDialogUio
|
||||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.dialog.DiminishedStatDialogUio
|
import com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.dialog.DiminishedStatDialogUio
|
||||||
import com.pixelized.shared.lwa.protocol.websocket.payload.CampaignMessage
|
import com.pixelized.shared.lwa.protocol.websocket.CampaignMessage
|
||||||
import com.pixelized.shared.lwa.protocol.websocket.payload.UpdateSkillUsageMessage
|
import com.pixelized.shared.lwa.protocol.websocket.UpdateSkillUsageMessage
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
|
@ -80,7 +80,8 @@ class CharacterSheetViewModel(
|
||||||
fun onUseSkill(skill: CharacterSheetPageUio.Node) {
|
fun onUseSkill(skill: CharacterSheetPageUio.Node) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
network.share(
|
network.share(
|
||||||
payload = UpdateSkillUsageMessage(
|
message = UpdateSkillUsageMessage(
|
||||||
|
timestamp = System.currentTimeMillis(),
|
||||||
characterSheetId = argument.characterInstanceId.characterSheetId,
|
characterSheetId = argument.characterInstanceId.characterSheetId,
|
||||||
skillId = skill.id,
|
skillId = skill.id,
|
||||||
used = skill.used.not(),
|
used = skill.used.not(),
|
||||||
|
@ -143,7 +144,8 @@ class CharacterSheetViewModel(
|
||||||
suspend fun changeDiminished(dialog: DiminishedStatDialogUio) {
|
suspend fun changeDiminished(dialog: DiminishedStatDialogUio) {
|
||||||
val diminished = dialog.value().text.toIntOrNull() ?: 0
|
val diminished = dialog.value().text.toIntOrNull() ?: 0
|
||||||
network.share(
|
network.share(
|
||||||
payload = CampaignMessage.UpdateDiminished(
|
message = CampaignMessage.UpdateDiminished(
|
||||||
|
timestamp = System.currentTimeMillis(),
|
||||||
prefix = dialog.characterInstanceId.prefix,
|
prefix = dialog.characterInstanceId.prefix,
|
||||||
characterSheetId = dialog.characterInstanceId.characterSheetId,
|
characterSheetId = dialog.characterInstanceId.characterSheetId,
|
||||||
instanceId = dialog.characterInstanceId.instanceId,
|
instanceId = dialog.characterInstanceId.instanceId,
|
||||||
|
|
|
@ -29,9 +29,7 @@ import androidx.compose.material.MaterialTheme
|
||||||
import androidx.compose.material.Scaffold
|
import androidx.compose.material.Scaffold
|
||||||
import androidx.compose.material.Surface
|
import androidx.compose.material.Surface
|
||||||
import androidx.compose.material.Switch
|
import androidx.compose.material.Switch
|
||||||
import androidx.compose.material.SwitchColors
|
|
||||||
import androidx.compose.material.Text
|
import androidx.compose.material.Text
|
||||||
import androidx.compose.material.TextFieldDefaults
|
|
||||||
import androidx.compose.material.TopAppBar
|
import androidx.compose.material.TopAppBar
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.Add
|
import androidx.compose.material.icons.filled.Add
|
||||||
|
@ -43,7 +41,6 @@ import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.unit.Dp
|
import androidx.compose.ui.unit.Dp
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.pixelized.desktop.lwa.LocalWindowController
|
import com.pixelized.desktop.lwa.LocalWindowController
|
||||||
|
@ -63,6 +60,8 @@ import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__ed
|
||||||
import lwacharactersheet.composeapp.generated.resources.game_master__action
|
import lwacharactersheet.composeapp.generated.resources.game_master__action
|
||||||
import lwacharactersheet.composeapp.generated.resources.game_master__title
|
import lwacharactersheet.composeapp.generated.resources.game_master__title
|
||||||
import lwacharactersheet.composeapp.generated.resources.ic_cancel_24dp
|
import lwacharactersheet.composeapp.generated.resources.ic_cancel_24dp
|
||||||
|
import lwacharactersheet.composeapp.generated.resources.ic_visibility_24dp
|
||||||
|
import lwacharactersheet.composeapp.generated.resources.ic_visibility_off_24dp
|
||||||
import org.jetbrains.compose.resources.getString
|
import org.jetbrains.compose.resources.getString
|
||||||
import org.jetbrains.compose.resources.painterResource
|
import org.jetbrains.compose.resources.painterResource
|
||||||
import org.jetbrains.compose.resources.stringResource
|
import org.jetbrains.compose.resources.stringResource
|
||||||
|
@ -77,6 +76,7 @@ fun GameMasterScreen(
|
||||||
|
|
||||||
val characters = viewModel.characters.collectAsState()
|
val characters = viewModel.characters.collectAsState()
|
||||||
val gameMaster = viewModel.gameMaster.collectAsState()
|
val gameMaster = viewModel.gameMaster.collectAsState()
|
||||||
|
val npcVisibility = viewModel.npcVisibility.collectAsState()
|
||||||
val tags = viewModel.tags.collectAsState()
|
val tags = viewModel.tags.collectAsState()
|
||||||
|
|
||||||
Surface(
|
Surface(
|
||||||
|
@ -87,6 +87,7 @@ fun GameMasterScreen(
|
||||||
filter = viewModel.filter,
|
filter = viewModel.filter,
|
||||||
tags = tags,
|
tags = tags,
|
||||||
gameMaster = gameMaster,
|
gameMaster = gameMaster,
|
||||||
|
npcVisibility = npcVisibility,
|
||||||
characters = characters,
|
characters = characters,
|
||||||
onTag = viewModel::onTag,
|
onTag = viewModel::onTag,
|
||||||
onGameMaster = viewModel::onGameMaster,
|
onGameMaster = viewModel::onGameMaster,
|
||||||
|
@ -107,6 +108,11 @@ fun GameMasterScreen(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
onNpcVisibility = {
|
||||||
|
scope.launch {
|
||||||
|
viewModel.onNpcVisibility()
|
||||||
|
}
|
||||||
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,16 +126,18 @@ private fun GameMasterContent(
|
||||||
filter: LwaTextFieldUio,
|
filter: LwaTextFieldUio,
|
||||||
tags: State<List<GMTagUio>>,
|
tags: State<List<GMTagUio>>,
|
||||||
gameMaster: State<Boolean>,
|
gameMaster: State<Boolean>,
|
||||||
|
npcVisibility: State<Boolean>,
|
||||||
characters: State<List<GMCharacterUio>>,
|
characters: State<List<GMCharacterUio>>,
|
||||||
onGameMaster: (Boolean) -> Unit,
|
onGameMaster: (Boolean) -> Unit,
|
||||||
onTag: (GMTagUio.TagId) -> Unit,
|
onTag: (GMTagUio.TagId) -> Unit,
|
||||||
onCharacterAction: (String, GMCharacterUio.Action) -> Unit,
|
onCharacterAction: (String, GMCharacterUio.Action) -> Unit,
|
||||||
onCharacterSheetEdit: (String) -> Unit,
|
onCharacterSheetEdit: (String) -> Unit,
|
||||||
onCharacterSheetCreate: () -> Unit,
|
onCharacterSheetCreate: () -> Unit,
|
||||||
|
onNpcVisibility: () -> Unit,
|
||||||
) {
|
) {
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
Scaffold(
|
GameMasterLayout(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
topBar = {
|
topBar = {
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
|
@ -161,10 +169,8 @@ private fun GameMasterContent(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
content = { paddingValues ->
|
content = {
|
||||||
Column(
|
Column {
|
||||||
modifier = Modifier.padding(paddingValues = paddingValues)
|
|
||||||
) {
|
|
||||||
Surface(
|
Surface(
|
||||||
elevation = 1.dp,
|
elevation = 1.dp,
|
||||||
) {
|
) {
|
||||||
|
@ -210,7 +216,6 @@ private fun GameMasterContent(
|
||||||
items = tags.value,
|
items = tags.value,
|
||||||
) { tag ->
|
) { tag ->
|
||||||
GMTag(
|
GMTag(
|
||||||
style = MaterialTheme.lwa.typography.base.caption,
|
|
||||||
tag = tag,
|
tag = tag,
|
||||||
onTag = { onTag(tag.id) },
|
onTag = { onTag(tag.id) },
|
||||||
)
|
)
|
||||||
|
@ -219,7 +224,9 @@ private fun GameMasterContent(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier.fillMaxWidth().weight(1f),
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.weight(1f),
|
||||||
) {
|
) {
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
modifier = Modifier.matchParentSize(),
|
modifier = Modifier.matchParentSize(),
|
||||||
|
@ -251,22 +258,71 @@ private fun GameMasterContent(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
IconButton(
|
}
|
||||||
modifier = Modifier
|
}
|
||||||
.align(alignment = Alignment.BottomEnd)
|
},
|
||||||
.padding(all = padding)
|
fab = {
|
||||||
.background(
|
Row(
|
||||||
color = MaterialTheme.lwa.colorScheme.base.primary,
|
modifier = Modifier
|
||||||
shape = CircleShape,
|
.fillMaxWidth()
|
||||||
),
|
.padding(all = padding),
|
||||||
onClick = onCharacterSheetCreate,
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
) {
|
) {
|
||||||
Icon(
|
IconButton(
|
||||||
imageVector = Icons.Default.Add,
|
modifier = Modifier.background(
|
||||||
tint = MaterialTheme.lwa.colorScheme.base.onPrimary,
|
color = MaterialTheme.lwa.colorScheme.base.primary,
|
||||||
contentDescription = null,
|
shape = CircleShape,
|
||||||
)
|
),
|
||||||
}
|
onClick = onNpcVisibility,
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
painter = when (npcVisibility.value) {
|
||||||
|
true -> painterResource(Res.drawable.ic_visibility_off_24dp)
|
||||||
|
else -> painterResource(Res.drawable.ic_visibility_24dp)
|
||||||
|
},
|
||||||
|
tint = MaterialTheme.lwa.colorScheme.base.onPrimary,
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
IconButton(
|
||||||
|
modifier = Modifier.background(
|
||||||
|
color = MaterialTheme.lwa.colorScheme.base.primary,
|
||||||
|
shape = CircleShape,
|
||||||
|
),
|
||||||
|
onClick = onCharacterSheetCreate,
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Add,
|
||||||
|
tint = MaterialTheme.lwa.colorScheme.base.onPrimary,
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun GameMasterLayout(
|
||||||
|
modifier: Modifier,
|
||||||
|
topBar: @Composable () -> Unit,
|
||||||
|
content: @Composable () -> Unit,
|
||||||
|
fab: @Composable () -> Unit,
|
||||||
|
) {
|
||||||
|
Scaffold(
|
||||||
|
modifier = modifier,
|
||||||
|
topBar = topBar,
|
||||||
|
content = { paddingValues ->
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(paddingValues = paddingValues)
|
||||||
|
) {
|
||||||
|
content()
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.align(alignment = Alignment.BottomStart),
|
||||||
|
) {
|
||||||
|
fab()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,11 +4,13 @@ import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.pixelized.desktop.lwa.repository.campaign.CampaignRepository
|
import com.pixelized.desktop.lwa.repository.campaign.CampaignRepository
|
||||||
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
|
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
|
||||||
|
import com.pixelized.desktop.lwa.repository.network.NetworkRepository
|
||||||
import com.pixelized.desktop.lwa.repository.settings.SettingsRepository
|
import com.pixelized.desktop.lwa.repository.settings.SettingsRepository
|
||||||
import com.pixelized.desktop.lwa.ui.composable.textfield.LwaTextFieldUio
|
import com.pixelized.desktop.lwa.ui.composable.textfield.LwaTextFieldUio
|
||||||
import com.pixelized.desktop.lwa.ui.screen.gamemaster.items.GMCharacterUio
|
import com.pixelized.desktop.lwa.ui.screen.gamemaster.items.GMCharacterUio
|
||||||
import com.pixelized.desktop.lwa.ui.screen.gamemaster.items.GMTagUio
|
import com.pixelized.desktop.lwa.ui.screen.gamemaster.items.GMTagUio
|
||||||
import com.pixelized.desktop.lwa.ui.screen.gamemaster.items.GMTagUio.TagId
|
import com.pixelized.desktop.lwa.ui.screen.gamemaster.items.GMTagUio.TagId
|
||||||
|
import com.pixelized.shared.lwa.protocol.websocket.GameMasterEvent
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
|
@ -26,6 +28,7 @@ class GameMasterViewModel(
|
||||||
campaignRepository: CampaignRepository,
|
campaignRepository: CampaignRepository,
|
||||||
characterSheetRepository: CharacterSheetRepository,
|
characterSheetRepository: CharacterSheetRepository,
|
||||||
private val settingsRepository: SettingsRepository,
|
private val settingsRepository: SettingsRepository,
|
||||||
|
private val networkRepository: NetworkRepository,
|
||||||
private val factory: GameMasterFactory,
|
private val factory: GameMasterFactory,
|
||||||
private val useCase: GameMasterActionUseCase,
|
private val useCase: GameMasterActionUseCase,
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
@ -82,6 +85,14 @@ class GameMasterViewModel(
|
||||||
initialValue = false,
|
initialValue = false,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val npcVisibility = campaignRepository.campaignFlow
|
||||||
|
.map { it.options.showNpcs }
|
||||||
|
.stateIn(
|
||||||
|
scope = viewModelScope,
|
||||||
|
started = SharingStarted.Eagerly,
|
||||||
|
initialValue = false,
|
||||||
|
)
|
||||||
|
|
||||||
fun onGameMaster(value: Boolean) {
|
fun onGameMaster(value: Boolean) {
|
||||||
val settings = settingsRepository.settings()
|
val settings = settingsRepository.settings()
|
||||||
settingsRepository.update(
|
settingsRepository.update(
|
||||||
|
@ -114,4 +125,12 @@ class GameMasterViewModel(
|
||||||
it[id] = it.getOrPut(id) { true }.not()
|
it[id] = it.getOrPut(id) { true }.not()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun onNpcVisibility() {
|
||||||
|
networkRepository.share(
|
||||||
|
GameMasterEvent.ToggleNpc(
|
||||||
|
timestamp = System.currentTimeMillis(),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -144,7 +144,6 @@ fun GMCharacter(
|
||||||
) {
|
) {
|
||||||
character.tags.forEach { tag ->
|
character.tags.forEach { tag ->
|
||||||
GMTag(
|
GMTag(
|
||||||
style = MaterialTheme.lwa.typography.base.caption,
|
|
||||||
elevation = 4.dp,
|
elevation = 4.dp,
|
||||||
tag = tag,
|
tag = tag,
|
||||||
)
|
)
|
||||||
|
|
|
@ -41,7 +41,6 @@ fun GMTag(
|
||||||
padding: PaddingValues = GmTagDefault.padding,
|
padding: PaddingValues = GmTagDefault.padding,
|
||||||
shape: Shape = CircleShape,
|
shape: Shape = CircleShape,
|
||||||
elevation: Dp = 2.dp,
|
elevation: Dp = 2.dp,
|
||||||
style: TextStyle,
|
|
||||||
tag: GMTagUio,
|
tag: GMTagUio,
|
||||||
onTag: (() -> Unit)? = null,
|
onTag: (() -> Unit)? = null,
|
||||||
) {
|
) {
|
||||||
|
@ -60,7 +59,7 @@ fun GMTag(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.clickable(enabled = onTag != null) { onTag?.invoke() }
|
.clickable(enabled = onTag != null) { onTag?.invoke() }
|
||||||
.padding(paddingValues = padding),
|
.padding(paddingValues = padding),
|
||||||
style = style,
|
style = MaterialTheme.lwa.typography.base.caption,
|
||||||
color = animatedColor.value,
|
color = animatedColor.value,
|
||||||
text = tag.label,
|
text = tag.label,
|
||||||
)
|
)
|
||||||
|
|
|
@ -209,4 +209,24 @@ class CampaignService(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun updateToggleParty() {
|
||||||
|
store.save(
|
||||||
|
campaign = campaign.copy(
|
||||||
|
options = campaign.options.copy(
|
||||||
|
showParty = campaign.options.showParty.not()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun updateToggleNpc() {
|
||||||
|
store.save(
|
||||||
|
campaign = campaign.copy(
|
||||||
|
options = campaign.options.copy(
|
||||||
|
showNpcs = campaign.options.showNpcs.not()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -5,11 +5,13 @@ import com.pixelized.server.lwa.model.campaign.CampaignService
|
||||||
import com.pixelized.server.lwa.model.character.CharacterSheetService
|
import com.pixelized.server.lwa.model.character.CharacterSheetService
|
||||||
import com.pixelized.shared.lwa.model.campaign.Campaign
|
import com.pixelized.shared.lwa.model.campaign.Campaign
|
||||||
import com.pixelized.shared.lwa.model.campaign.factory.CampaignJsonFactory
|
import com.pixelized.shared.lwa.model.campaign.factory.CampaignJsonFactory
|
||||||
import com.pixelized.shared.lwa.protocol.websocket.Message
|
import com.pixelized.shared.lwa.protocol.websocket.SocketMessage
|
||||||
import com.pixelized.shared.lwa.protocol.websocket.payload.CampaignMessage
|
import com.pixelized.shared.lwa.protocol.websocket.CampaignMessage
|
||||||
import com.pixelized.shared.lwa.protocol.websocket.payload.RestSynchronisation
|
import com.pixelized.shared.lwa.protocol.websocket.GameMasterEvent
|
||||||
import com.pixelized.shared.lwa.protocol.websocket.payload.RollMessage
|
import com.pixelized.shared.lwa.protocol.websocket.RestSynchronisation
|
||||||
import com.pixelized.shared.lwa.protocol.websocket.payload.UpdateSkillUsageMessage
|
import com.pixelized.shared.lwa.protocol.websocket.RollMessage
|
||||||
|
import com.pixelized.shared.lwa.protocol.websocket.ToggleActiveAlteration
|
||||||
|
import com.pixelized.shared.lwa.protocol.websocket.UpdateSkillUsageMessage
|
||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
|
|
||||||
class Engine(
|
class Engine(
|
||||||
|
@ -18,46 +20,51 @@ class Engine(
|
||||||
val alterationService: AlterationService,
|
val alterationService: AlterationService,
|
||||||
val campaignJsonFactory: CampaignJsonFactory,
|
val campaignJsonFactory: CampaignJsonFactory,
|
||||||
) {
|
) {
|
||||||
val webSocket = MutableSharedFlow<Message>()
|
val webSocket = MutableSharedFlow<SocketMessage>()
|
||||||
|
|
||||||
suspend fun handle(message: Message) {
|
suspend fun handle(message: SocketMessage) {
|
||||||
when (val data = message.value) {
|
when (message) {
|
||||||
|
|
||||||
is RollMessage -> Unit // Nothing to do here.
|
is RollMessage -> Unit // Nothing to do here.
|
||||||
|
|
||||||
is CampaignMessage -> {
|
is CampaignMessage -> {
|
||||||
val instanceId = Campaign.CharacterInstance.Id(
|
val instanceId = Campaign.CharacterInstance.Id(
|
||||||
prefix = data.prefix,
|
prefix = message.prefix,
|
||||||
characterSheetId = data.characterSheetId,
|
characterSheetId = message.characterSheetId,
|
||||||
instanceId = data.instanceId,
|
instanceId = message.instanceId,
|
||||||
)
|
)
|
||||||
when (data) {
|
when (message) {
|
||||||
is CampaignMessage.UpdateCharacteristic -> campaignService.updateCharacteristic(
|
is CampaignMessage.UpdateCharacteristic -> campaignService.updateCharacteristic(
|
||||||
characterInstanceId = instanceId,
|
characterInstanceId = instanceId,
|
||||||
characteristic = campaignJsonFactory.convertFromJson(json = data.characteristic),
|
characteristic = campaignJsonFactory.convertFromJson(json = message.characteristic),
|
||||||
value = data.value,
|
value = message.value,
|
||||||
)
|
)
|
||||||
|
|
||||||
is CampaignMessage.UpdateDiminished -> campaignService.updateDiminished(
|
is CampaignMessage.UpdateDiminished -> campaignService.updateDiminished(
|
||||||
characterInstanceId = instanceId,
|
characterInstanceId = instanceId,
|
||||||
diminished = data.diminished,
|
diminished = message.diminished,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
is UpdateSkillUsageMessage -> characterService.updateCharacterSkillUsage(
|
is UpdateSkillUsageMessage -> characterService.updateCharacterSkillUsage(
|
||||||
characterSheetId = data.characterSheetId,
|
characterSheetId = message.characterSheetId,
|
||||||
skillId = data.skillId,
|
skillId = message.skillId,
|
||||||
used = data.used,
|
used = message.used,
|
||||||
)
|
)
|
||||||
|
|
||||||
RestSynchronisation.Campaign -> Unit // Handle in the Rest
|
is RestSynchronisation.Campaign -> Unit // Handle in the Rest
|
||||||
|
|
||||||
is RestSynchronisation.CharacterUpdate -> Unit // Handle in the Rest
|
is RestSynchronisation.CharacterSheetUpdate -> Unit // Handle in the Rest
|
||||||
|
|
||||||
is RestSynchronisation.CharacterDelete -> Unit // Handle in the Rest
|
is RestSynchronisation.CharacterSheetDelete -> Unit // Handle in the Rest
|
||||||
|
|
||||||
is RestSynchronisation.ToggleActiveAlteration -> Unit // Handle in the Rest
|
is ToggleActiveAlteration -> Unit // Handle in the Rest
|
||||||
|
|
||||||
|
is GameMasterEvent -> when (message) {
|
||||||
|
is GameMasterEvent.TogglePlayer -> campaignService.updateToggleParty()
|
||||||
|
is GameMasterEvent.ToggleNpc -> campaignService.updateToggleNpc()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -15,7 +15,7 @@ import com.pixelized.server.lwa.server.rest.character.getCharacter
|
||||||
import com.pixelized.server.lwa.server.rest.character.getCharacters
|
import com.pixelized.server.lwa.server.rest.character.getCharacters
|
||||||
import com.pixelized.server.lwa.server.rest.character.putCharacter
|
import com.pixelized.server.lwa.server.rest.character.putCharacter
|
||||||
import com.pixelized.shared.lwa.SERVER_PORT
|
import com.pixelized.shared.lwa.SERVER_PORT
|
||||||
import com.pixelized.shared.lwa.protocol.websocket.Message
|
import com.pixelized.shared.lwa.protocol.websocket.SocketMessage
|
||||||
import com.pixelized.shared.lwa.sharedModuleDependencies
|
import com.pixelized.shared.lwa.sharedModuleDependencies
|
||||||
import io.ktor.serialization.kotlinx.json.json
|
import io.ktor.serialization.kotlinx.json.json
|
||||||
import io.ktor.server.application.install
|
import io.ktor.server.application.install
|
||||||
|
@ -97,7 +97,7 @@ class LocalServer {
|
||||||
incoming.consumeEach { frame ->
|
incoming.consumeEach { frame ->
|
||||||
if (frame is Frame.Text) {
|
if (frame is Frame.Text) {
|
||||||
val data = frame.readText()
|
val data = frame.readText()
|
||||||
val message = json.decodeFromString<Message>(data)
|
val message = json.decodeFromString<SocketMessage>(data)
|
||||||
// log the message
|
// log the message
|
||||||
engine.handle(message)
|
engine.handle(message)
|
||||||
// broadcast to clients the message
|
// broadcast to clients the message
|
||||||
|
|
|
@ -2,8 +2,7 @@ package com.pixelized.server.lwa.server.rest.alteration
|
||||||
|
|
||||||
import com.pixelized.server.lwa.server.Engine
|
import com.pixelized.server.lwa.server.Engine
|
||||||
import com.pixelized.server.lwa.utils.extentions.characterInstanceId
|
import com.pixelized.server.lwa.utils.extentions.characterInstanceId
|
||||||
import com.pixelized.shared.lwa.protocol.websocket.Message
|
import com.pixelized.shared.lwa.protocol.websocket.ToggleActiveAlteration
|
||||||
import com.pixelized.shared.lwa.protocol.websocket.payload.RestSynchronisation
|
|
||||||
import io.ktor.http.HttpStatusCode
|
import io.ktor.http.HttpStatusCode
|
||||||
import io.ktor.server.request.receive
|
import io.ktor.server.request.receive
|
||||||
import io.ktor.server.response.respondText
|
import io.ktor.server.response.respondText
|
||||||
|
@ -32,15 +31,15 @@ fun Engine.putActiveAlteration(): suspend io.ktor.server.routing.RoutingContext.
|
||||||
)
|
)
|
||||||
// share the modification to all client through the websocket.
|
// share the modification to all client through the websocket.
|
||||||
webSocket.emit(
|
webSocket.emit(
|
||||||
Message(
|
ToggleActiveAlteration(
|
||||||
from = "Server",
|
timestamp = System.currentTimeMillis(),
|
||||||
value = RestSynchronisation.ToggleActiveAlteration(
|
prefix = characterInstanceId.prefix,
|
||||||
characterId = campaignJsonFactory.convertToJson(id = characterInstanceId),
|
characterSheetId = characterInstanceId.characterSheetId,
|
||||||
alterationId = alterationId,
|
instanceId = characterInstanceId.instanceId,
|
||||||
active = alterationService.isAlterationActive(
|
alterationId = alterationId,
|
||||||
characterInstanceId = characterInstanceId,
|
active = alterationService.isAlterationActive(
|
||||||
alterationId = alterationId
|
characterInstanceId = characterInstanceId,
|
||||||
),
|
alterationId = alterationId
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
@ -2,8 +2,7 @@ package com.pixelized.server.lwa.server.rest.campaign
|
||||||
|
|
||||||
import com.pixelized.server.lwa.server.Engine
|
import com.pixelized.server.lwa.server.Engine
|
||||||
import com.pixelized.server.lwa.utils.extentions.characterInstanceId
|
import com.pixelized.server.lwa.utils.extentions.characterInstanceId
|
||||||
import com.pixelized.shared.lwa.protocol.websocket.Message
|
import com.pixelized.shared.lwa.protocol.websocket.RestSynchronisation
|
||||||
import com.pixelized.shared.lwa.protocol.websocket.payload.RestSynchronisation
|
|
||||||
import io.ktor.http.HttpStatusCode
|
import io.ktor.http.HttpStatusCode
|
||||||
import io.ktor.server.response.respondText
|
import io.ktor.server.response.respondText
|
||||||
|
|
||||||
|
@ -24,9 +23,8 @@ fun Engine.removeCampaignCharacter(): suspend io.ktor.server.routing.RoutingCont
|
||||||
status = HttpStatusCode.Accepted,
|
status = HttpStatusCode.Accepted,
|
||||||
)
|
)
|
||||||
webSocket.emit(
|
webSocket.emit(
|
||||||
Message(
|
RestSynchronisation.Campaign(
|
||||||
from = "Server",
|
timestamp = System.currentTimeMillis(),
|
||||||
value = RestSynchronisation.Campaign,
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
} catch (exception: Exception) {
|
} catch (exception: Exception) {
|
||||||
|
|
|
@ -2,8 +2,7 @@ package com.pixelized.server.lwa.server.rest.campaign
|
||||||
|
|
||||||
import com.pixelized.server.lwa.server.Engine
|
import com.pixelized.server.lwa.server.Engine
|
||||||
import com.pixelized.server.lwa.utils.extentions.characterInstanceId
|
import com.pixelized.server.lwa.utils.extentions.characterInstanceId
|
||||||
import com.pixelized.shared.lwa.protocol.websocket.Message
|
import com.pixelized.shared.lwa.protocol.websocket.RestSynchronisation
|
||||||
import com.pixelized.shared.lwa.protocol.websocket.payload.RestSynchronisation
|
|
||||||
import io.ktor.http.HttpStatusCode
|
import io.ktor.http.HttpStatusCode
|
||||||
import io.ktor.server.response.respondText
|
import io.ktor.server.response.respondText
|
||||||
|
|
||||||
|
@ -24,9 +23,8 @@ fun Engine.deleteCampaignNpc(): suspend io.ktor.server.routing.RoutingContext.()
|
||||||
status = HttpStatusCode.Accepted,
|
status = HttpStatusCode.Accepted,
|
||||||
)
|
)
|
||||||
webSocket.emit(
|
webSocket.emit(
|
||||||
Message(
|
RestSynchronisation.Campaign(
|
||||||
from = "Server",
|
timestamp = System.currentTimeMillis(),
|
||||||
value = RestSynchronisation.Campaign,
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
} catch (exception: Exception) {
|
} catch (exception: Exception) {
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
package com.pixelized.server.lwa.server.rest.campaign
|
package com.pixelized.server.lwa.server.rest.campaign
|
||||||
|
|
||||||
import com.pixelized.server.lwa.server.Engine
|
import com.pixelized.server.lwa.server.Engine
|
||||||
import com.pixelized.shared.lwa.model.campaign.Campaign
|
|
||||||
import com.pixelized.shared.lwa.model.campaign.CampaignJsonV1
|
import com.pixelized.shared.lwa.model.campaign.CampaignJsonV1
|
||||||
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheetJson
|
import com.pixelized.shared.lwa.protocol.websocket.RestSynchronisation
|
||||||
import com.pixelized.shared.lwa.protocol.websocket.Message
|
|
||||||
import com.pixelized.shared.lwa.protocol.websocket.payload.RestSynchronisation
|
|
||||||
import io.ktor.http.HttpStatusCode
|
import io.ktor.http.HttpStatusCode
|
||||||
import io.ktor.server.request.receive
|
import io.ktor.server.request.receive
|
||||||
import io.ktor.server.response.respondText
|
import io.ktor.server.response.respondText
|
||||||
|
@ -29,9 +26,8 @@ fun Engine.putCampaignScene(): suspend io.ktor.server.routing.RoutingContext.()
|
||||||
)
|
)
|
||||||
|
|
||||||
webSocket.emit(
|
webSocket.emit(
|
||||||
Message(
|
RestSynchronisation.Campaign(
|
||||||
from = "Server",
|
timestamp = System.currentTimeMillis(),
|
||||||
value = RestSynchronisation.Campaign,
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,7 @@ package com.pixelized.server.lwa.server.rest.campaign
|
||||||
import com.pixelized.server.lwa.server.Engine
|
import com.pixelized.server.lwa.server.Engine
|
||||||
import com.pixelized.server.lwa.utils.extentions.characterSheetId
|
import com.pixelized.server.lwa.utils.extentions.characterSheetId
|
||||||
import com.pixelized.shared.lwa.model.campaign.Campaign
|
import com.pixelized.shared.lwa.model.campaign.Campaign
|
||||||
import com.pixelized.shared.lwa.protocol.websocket.Message
|
import com.pixelized.shared.lwa.protocol.websocket.RestSynchronisation
|
||||||
import com.pixelized.shared.lwa.protocol.websocket.payload.RestSynchronisation
|
|
||||||
import io.ktor.http.HttpStatusCode
|
import io.ktor.http.HttpStatusCode
|
||||||
import io.ktor.server.response.respondText
|
import io.ktor.server.response.respondText
|
||||||
|
|
||||||
|
@ -36,9 +35,8 @@ fun Engine.putCampaignCharacter(): suspend io.ktor.server.routing.RoutingContext
|
||||||
status = HttpStatusCode.Accepted,
|
status = HttpStatusCode.Accepted,
|
||||||
)
|
)
|
||||||
webSocket.emit(
|
webSocket.emit(
|
||||||
Message(
|
RestSynchronisation.Campaign(
|
||||||
from = "Server",
|
timestamp = System.currentTimeMillis(),
|
||||||
value = RestSynchronisation.Campaign,
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
} catch (exception: Exception) {
|
} catch (exception: Exception) {
|
||||||
|
|
|
@ -3,8 +3,7 @@ package com.pixelized.server.lwa.server.rest.campaign
|
||||||
import com.pixelized.server.lwa.server.Engine
|
import com.pixelized.server.lwa.server.Engine
|
||||||
import com.pixelized.server.lwa.utils.extentions.characterSheetId
|
import com.pixelized.server.lwa.utils.extentions.characterSheetId
|
||||||
import com.pixelized.shared.lwa.model.campaign.Campaign
|
import com.pixelized.shared.lwa.model.campaign.Campaign
|
||||||
import com.pixelized.shared.lwa.protocol.websocket.Message
|
import com.pixelized.shared.lwa.protocol.websocket.RestSynchronisation
|
||||||
import com.pixelized.shared.lwa.protocol.websocket.payload.RestSynchronisation
|
|
||||||
import io.ktor.http.HttpStatusCode
|
import io.ktor.http.HttpStatusCode
|
||||||
import io.ktor.server.response.respondText
|
import io.ktor.server.response.respondText
|
||||||
|
|
||||||
|
@ -39,9 +38,8 @@ fun Engine.putCampaignNpc(): suspend io.ktor.server.routing.RoutingContext.() ->
|
||||||
status = HttpStatusCode.Accepted,
|
status = HttpStatusCode.Accepted,
|
||||||
)
|
)
|
||||||
webSocket.emit(
|
webSocket.emit(
|
||||||
Message(
|
RestSynchronisation.Campaign(
|
||||||
from = "Server",
|
timestamp = System.currentTimeMillis(),
|
||||||
value = RestSynchronisation.Campaign,
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
} catch (exception: Exception) {
|
} catch (exception: Exception) {
|
||||||
|
|
|
@ -2,8 +2,7 @@ package com.pixelized.server.lwa.server.rest.character
|
||||||
|
|
||||||
import com.pixelized.server.lwa.server.Engine
|
import com.pixelized.server.lwa.server.Engine
|
||||||
import com.pixelized.server.lwa.utils.extentions.characterSheetId
|
import com.pixelized.server.lwa.utils.extentions.characterSheetId
|
||||||
import com.pixelized.shared.lwa.protocol.websocket.Message
|
import com.pixelized.shared.lwa.protocol.websocket.RestSynchronisation
|
||||||
import com.pixelized.shared.lwa.protocol.websocket.payload.RestSynchronisation
|
|
||||||
import io.ktor.http.HttpStatusCode
|
import io.ktor.http.HttpStatusCode
|
||||||
import io.ktor.server.response.respondText
|
import io.ktor.server.response.respondText
|
||||||
|
|
||||||
|
@ -18,10 +17,10 @@ fun Engine.deleteCharacter(): suspend io.ktor.server.routing.RoutingContext.() -
|
||||||
status = HttpStatusCode.OK,
|
status = HttpStatusCode.OK,
|
||||||
)
|
)
|
||||||
webSocket.emit(
|
webSocket.emit(
|
||||||
Message(
|
RestSynchronisation.CharacterSheetDelete(
|
||||||
from = "Server",
|
timestamp = System.currentTimeMillis(),
|
||||||
value = RestSynchronisation.CharacterDelete(characterId = characterSheetId),
|
characterSheetId = characterSheetId,
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
call.respondText(
|
call.respondText(
|
||||||
|
|
|
@ -2,8 +2,7 @@ package com.pixelized.server.lwa.server.rest.character
|
||||||
|
|
||||||
import com.pixelized.server.lwa.server.Engine
|
import com.pixelized.server.lwa.server.Engine
|
||||||
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheetJson
|
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheetJson
|
||||||
import com.pixelized.shared.lwa.protocol.websocket.Message
|
import com.pixelized.shared.lwa.protocol.websocket.RestSynchronisation
|
||||||
import com.pixelized.shared.lwa.protocol.websocket.payload.RestSynchronisation
|
|
||||||
import io.ktor.http.HttpStatusCode
|
import io.ktor.http.HttpStatusCode
|
||||||
import io.ktor.server.request.receive
|
import io.ktor.server.request.receive
|
||||||
import io.ktor.server.response.respondText
|
import io.ktor.server.response.respondText
|
||||||
|
@ -19,10 +18,10 @@ fun Engine.putCharacter(): suspend io.ktor.server.routing.RoutingContext.() -> U
|
||||||
status = HttpStatusCode.OK
|
status = HttpStatusCode.OK
|
||||||
)
|
)
|
||||||
webSocket.emit(
|
webSocket.emit(
|
||||||
Message(
|
RestSynchronisation.CharacterSheetUpdate(
|
||||||
from = "Server",
|
timestamp = System.currentTimeMillis(),
|
||||||
value = RestSynchronisation.CharacterUpdate(id = form.id),
|
characterSheetId = form.id,
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -4,6 +4,7 @@ data class Campaign(
|
||||||
val characters: Map<CharacterInstance.Id, CharacterInstance>,
|
val characters: Map<CharacterInstance.Id, CharacterInstance>,
|
||||||
val npcs: Map<CharacterInstance.Id, CharacterInstance>,
|
val npcs: Map<CharacterInstance.Id, CharacterInstance>,
|
||||||
val scene: Scene,
|
val scene: Scene,
|
||||||
|
val options: Options,
|
||||||
) {
|
) {
|
||||||
data class CharacterInstance(
|
data class CharacterInstance(
|
||||||
val characteristic: Map<Characteristic, Int>,
|
val characteristic: Map<Characteristic, Int>,
|
||||||
|
@ -53,11 +54,24 @@ data class Campaign(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class Options(
|
||||||
|
val showParty: Boolean,
|
||||||
|
val showNpcs: Boolean,
|
||||||
|
) {
|
||||||
|
companion object {
|
||||||
|
fun empty() = Options(
|
||||||
|
showParty = true,
|
||||||
|
showNpcs = false,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val EMPTY = Campaign(
|
val EMPTY = Campaign(
|
||||||
characters = emptyMap(),
|
characters = emptyMap(),
|
||||||
npcs = emptyMap(),
|
npcs = emptyMap(),
|
||||||
scene = Scene.empty(),
|
scene = Scene.empty(),
|
||||||
|
options = Options.empty(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,4 +14,7 @@ sealed interface CampaignJson {
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
sealed interface SceneJson
|
sealed interface SceneJson
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
sealed interface OptionJson
|
||||||
}
|
}
|
|
@ -7,6 +7,7 @@ data class CampaignJsonV1(
|
||||||
val characters: Map<String, CharacterInstanceJsonV1>,
|
val characters: Map<String, CharacterInstanceJsonV1>,
|
||||||
val npcs: Map<String, CharacterInstanceJsonV1>,
|
val npcs: Map<String, CharacterInstanceJsonV1>,
|
||||||
val scene: SceneJsonV1?,
|
val scene: SceneJsonV1?,
|
||||||
|
val options: OptionsJsonV1?,
|
||||||
) : CampaignJson {
|
) : CampaignJson {
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
|
@ -24,4 +25,10 @@ data class CampaignJsonV1(
|
||||||
data class SceneJsonV1(
|
data class SceneJsonV1(
|
||||||
val name: String,
|
val name: String,
|
||||||
) : CampaignJson.SceneJson
|
) : CampaignJson.SceneJson
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class OptionsJsonV1(
|
||||||
|
val showPlayer: Boolean,
|
||||||
|
val showNpcs: Boolean,
|
||||||
|
) : CampaignJson.OptionJson
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,6 +58,10 @@ class CampaignJsonFactory(
|
||||||
.toMap(),
|
.toMap(),
|
||||||
scene = CampaignJsonV1.SceneJsonV1(
|
scene = CampaignJsonV1.SceneJsonV1(
|
||||||
name = data.scene.name
|
name = data.scene.name
|
||||||
|
),
|
||||||
|
options = CampaignJsonV1.OptionsJsonV1(
|
||||||
|
showPlayer = data.options.showParty,
|
||||||
|
showNpcs = data.options.showNpcs,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,9 @@ class CampaignJsonV1Factory {
|
||||||
scene = campaignJson.scene
|
scene = campaignJson.scene
|
||||||
?.let { convertFromV1(it) }
|
?.let { convertFromV1(it) }
|
||||||
?: Campaign.Scene.empty(),
|
?: Campaign.Scene.empty(),
|
||||||
|
options = campaignJson.options
|
||||||
|
?.let { convertFromV1(it) }
|
||||||
|
?:Campaign.Options.empty()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,4 +69,13 @@ class CampaignJsonV1Factory {
|
||||||
name = sceneJson.name
|
name = sceneJson.name
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun convertFromV1(
|
||||||
|
optionsJson: CampaignJsonV1.OptionsJsonV1,
|
||||||
|
): Campaign.Options {
|
||||||
|
return Campaign.Options(
|
||||||
|
showParty = optionsJson.showPlayer,
|
||||||
|
showNpcs = optionsJson.showNpcs
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,16 +1,17 @@
|
||||||
package com.pixelized.shared.lwa.protocol.websocket.payload
|
package com.pixelized.shared.lwa.protocol.websocket
|
||||||
|
|
||||||
import com.pixelized.shared.lwa.model.campaign.CampaignJsonV1
|
import com.pixelized.shared.lwa.model.campaign.CampaignJsonV1
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
sealed interface CampaignMessage : MessagePayload {
|
sealed interface CampaignMessage : SocketMessage, CharacterInstanceIdMessage {
|
||||||
val prefix: Char
|
override val prefix: Char
|
||||||
val characterSheetId: String
|
override val characterSheetId: String
|
||||||
val instanceId: Int
|
override val instanceId: Int
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class UpdateCharacteristic(
|
data class UpdateCharacteristic(
|
||||||
|
override val timestamp: Long,
|
||||||
override val prefix: Char,
|
override val prefix: Char,
|
||||||
override val characterSheetId: String,
|
override val characterSheetId: String,
|
||||||
override val instanceId: Int,
|
override val instanceId: Int,
|
||||||
|
@ -20,6 +21,7 @@ sealed interface CampaignMessage : MessagePayload {
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class UpdateDiminished(
|
data class UpdateDiminished(
|
||||||
|
override val timestamp: Long,
|
||||||
override val prefix: Char,
|
override val prefix: Char,
|
||||||
override val characterSheetId: String,
|
override val characterSheetId: String,
|
||||||
override val instanceId: Int,
|
override val instanceId: Int,
|
|
@ -0,0 +1,15 @@
|
||||||
|
package com.pixelized.shared.lwa.protocol.websocket
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
sealed interface CharacterSheetIdMessage {
|
||||||
|
val characterSheetId: String
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
sealed interface CharacterInstanceIdMessage : CharacterSheetIdMessage {
|
||||||
|
override val characterSheetId: String
|
||||||
|
val prefix: Char
|
||||||
|
val instanceId: Int
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package com.pixelized.shared.lwa.protocol.websocket
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
sealed interface GameMasterEvent : SocketMessage {
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
class ToggleNpc(
|
||||||
|
override val timestamp: Long,
|
||||||
|
) : GameMasterEvent
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
class TogglePlayer(
|
||||||
|
override val timestamp: Long,
|
||||||
|
) : GameMasterEvent
|
||||||
|
}
|
|
@ -1,10 +0,0 @@
|
||||||
package com.pixelized.shared.lwa.protocol.websocket
|
|
||||||
|
|
||||||
import com.pixelized.shared.lwa.protocol.websocket.payload.MessagePayload
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class Message(
|
|
||||||
val from: String,
|
|
||||||
val value: MessagePayload,
|
|
||||||
)
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
package com.pixelized.shared.lwa.protocol.websocket
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
sealed class RestSynchronisation : SocketMessage {
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class CharacterSheetUpdate(
|
||||||
|
override val timestamp: Long,
|
||||||
|
override val characterSheetId: String,
|
||||||
|
) : RestSynchronisation(), CharacterSheetIdMessage
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class CharacterSheetDelete(
|
||||||
|
override val timestamp: Long,
|
||||||
|
override val characterSheetId: String,
|
||||||
|
) : RestSynchronisation(), CharacterSheetIdMessage
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class Campaign(
|
||||||
|
override val timestamp: Long,
|
||||||
|
) : RestSynchronisation()
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package com.pixelized.shared.lwa.protocol.websocket
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class RollMessage(
|
||||||
|
override val timestamp: Long,
|
||||||
|
val uuid: String,
|
||||||
|
val prefix: Char,
|
||||||
|
val characterSheetId: String,
|
||||||
|
val instanceId: Int?,
|
||||||
|
val skillLabel: String,
|
||||||
|
val rollValue: Int,
|
||||||
|
val resultLabel: String? = null,
|
||||||
|
val rollDifficulty: String? = null,
|
||||||
|
val rollSuccessLimit: Int? = null,
|
||||||
|
val critical: Critical? = null,
|
||||||
|
) : SocketMessage {
|
||||||
|
enum class Critical {
|
||||||
|
CRITICAL_SUCCESS,
|
||||||
|
SPECIAL_SUCCESS,
|
||||||
|
SUCCESS,
|
||||||
|
FAILURE,
|
||||||
|
CRITICAL_FAILURE
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
package com.pixelized.shared.lwa.protocol.websocket
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
sealed interface SocketMessage {
|
||||||
|
val timestamp: Long
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package com.pixelized.shared.lwa.protocol.websocket
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class ToggleActiveAlteration(
|
||||||
|
override val timestamp: Long,
|
||||||
|
override val characterSheetId: String,
|
||||||
|
override val prefix: Char,
|
||||||
|
override val instanceId: Int,
|
||||||
|
val alterationId: String,
|
||||||
|
val active: Boolean,
|
||||||
|
) : SocketMessage, CharacterInstanceIdMessage
|
|
@ -0,0 +1,11 @@
|
||||||
|
package com.pixelized.shared.lwa.protocol.websocket
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class UpdateSkillUsageMessage(
|
||||||
|
override val timestamp: Long,
|
||||||
|
override val characterSheetId: String,
|
||||||
|
val skillId: String,
|
||||||
|
val used: Boolean,
|
||||||
|
) : SocketMessage, CharacterSheetIdMessage
|
|
@ -1,6 +0,0 @@
|
||||||
package com.pixelized.shared.lwa.protocol.websocket.payload
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
sealed interface MessagePayload
|
|
|
@ -1,27 +0,0 @@
|
||||||
package com.pixelized.shared.lwa.protocol.websocket.payload
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
sealed class RestSynchronisation : MessagePayload {
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class CharacterUpdate(
|
|
||||||
val id: String,
|
|
||||||
) : RestSynchronisation()
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class CharacterDelete(
|
|
||||||
val characterId: String,
|
|
||||||
) : RestSynchronisation()
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class ToggleActiveAlteration(
|
|
||||||
val characterId: String,
|
|
||||||
val alterationId: String,
|
|
||||||
val active: Boolean,
|
|
||||||
) : RestSynchronisation()
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data object Campaign : RestSynchronisation()
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
package com.pixelized.shared.lwa.protocol.websocket.payload
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import java.util.UUID
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class RollMessage(
|
|
||||||
val id: RollId,
|
|
||||||
val prefix: Char,
|
|
||||||
val characterSheetId: String,
|
|
||||||
val instanceId: Int?,
|
|
||||||
val skillLabel: String,
|
|
||||||
val rollValue: Int,
|
|
||||||
val resultLabel: String? = null,
|
|
||||||
val rollDifficulty: String? = null,
|
|
||||||
val rollSuccessLimit: Int? = null,
|
|
||||||
val critical: Critical? = null,
|
|
||||||
) : MessagePayload {
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class RollId(
|
|
||||||
val rollId: String,
|
|
||||||
val timestamp: Long,
|
|
||||||
) {
|
|
||||||
companion object {
|
|
||||||
fun create(
|
|
||||||
rollId: String = UUID.randomUUID().toString(),
|
|
||||||
timestamp: Long = System.currentTimeMillis(),
|
|
||||||
) = RollId(
|
|
||||||
rollId = rollId,
|
|
||||||
timestamp = timestamp,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum class Critical {
|
|
||||||
CRITICAL_SUCCESS,
|
|
||||||
SPECIAL_SUCCESS,
|
|
||||||
SUCCESS,
|
|
||||||
FAILURE,
|
|
||||||
CRITICAL_FAILURE
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
package com.pixelized.shared.lwa.protocol.websocket.payload
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class UpdateSkillUsageMessage(
|
|
||||||
val characterSheetId: String,
|
|
||||||
val skillId: String,
|
|
||||||
val used: Boolean,
|
|
||||||
) : MessagePayload
|
|
Loading…
Add table
Add a link
Reference in a new issue