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