ReModel: remove the CharacterInstanceId: server

This commit is contained in:
Thomas Andres Gomez 2025-03-24 18:03:41 +01:00
parent a69f95e62d
commit a5adc61e90
61 changed files with 1072 additions and 1038 deletions

View file

@ -1,13 +1,33 @@
package com.pixelized.server.lwa.model.alteration
import com.pixelized.shared.lwa.model.alteration.AlterationJson
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
class AlterationService(
store: AlterationStore,
) {
private val scope = CoroutineScope(Dispatchers.IO + Job())
private val alterationsFlow = store.alterationsFlow()
private val alterationHashFlow = alterationsFlow
.map { data -> data.associateBy { it.id } }
.stateIn(
scope = scope,
started = SharingStarted.Eagerly,
initialValue = emptyMap()
)
fun alterations(): List<AlterationJson> {
return alterationsFlow.value
}
fun alteration(alterationId: String): AlterationJson? {
return alterationHashFlow.value[alterationId]
}
}

View file

@ -2,10 +2,7 @@ package com.pixelized.server.lwa.model.campaign
import com.pixelized.shared.lwa.model.campaign.Campaign
import com.pixelized.shared.lwa.model.campaign.CampaignJson
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.usecase.CampaignUseCase
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
@ -17,7 +14,6 @@ import kotlinx.coroutines.flow.stateIn
class CampaignService(
private val store: CampaignStore,
private val factory: CampaignJsonFactory,
private val useCase: CampaignUseCase,
) {
private val scope = CoroutineScope(Dispatchers.IO + Job())
@ -41,36 +37,14 @@ class CampaignService(
return campaignJsonFlow.value
}
suspend fun addCharacter(
characterInstanceId: Campaign.CharacterInstance.Id,
fun addCharacter(
characterSheetId: String,
): Boolean {
// fetch all the current campaign character
val characters = campaign.characters.toMutableMap()
// check if the character is in the campaign.
if (characters.containsKey(characterInstanceId)) return false
// update the corresponding character
characters[characterInstanceId] = campaign.character(id = characterInstanceId)
// save the campaign to the disk + update the flow.
return try {
store.save(
campaign = campaign.copy(characters = characters)
)
true
} catch (exception: Exception) {
false
}
}
suspend fun removeCharacter(
characterInstanceId: Campaign.CharacterInstance.Id,
): Boolean {
// fetch all the current campaign character
val characters = campaign.characters.toMutableMap()
// check if the character is in the campaign.
if (characters.containsKey(characterInstanceId).not()) return false
// update the corresponding character
characters.remove(characterInstanceId)
// save the campaign to the disk + update the flow.
// check if the character is already in the campaign.
if (campaign.characters.contains(characterSheetId)) return false
// update the corresponding instance
val characters = campaign.characters.toMutableSet().also { it.add(characterSheetId) }
// save the campaign to the disk (update the flow).
return try {
store.save(
campaign = campaign.copy(characters = characters)
@ -82,18 +56,34 @@ class CampaignService(
}
suspend fun addNpc(
npcInstanceId: Campaign.CharacterInstance.Id,
characterSheetId: String,
): Boolean {
// check if the character is already in the campaign.
if (campaign.npcs.contains(characterSheetId)) return false
// update the corresponding instance
val characters = campaign.npcs.toMutableSet().also { it.add(characterSheetId) }
// save the campaign to the disk (update the flow).
return try {
store.save(
campaign = campaign.copy(npcs = characters)
)
true
} catch (exception: Exception) {
false
}
}
suspend fun removeCharacter(
characterSheetId: String,
): Boolean {
// fetch all the current campaign character
val npcs = campaign.npcs.toMutableMap()
// check if the character is in the campaign.
if (npcs.containsKey(npcInstanceId)) return false
// update the corresponding character
npcs[npcInstanceId] = campaign.npc(id = npcInstanceId)
if (campaign.characters.contains(characterSheetId).not()) return false
// update the corresponding instance
val characters = campaign.characters.toMutableSet().also { it.remove(characterSheetId) }
// save the campaign to the disk + update the flow.
return try {
store.save(
campaign = campaign.copy(npcs = npcs)
campaign = campaign.copy(characters = characters)
)
true
} catch (exception: Exception) {
@ -102,18 +92,16 @@ class CampaignService(
}
suspend fun removeNpc(
npcInstanceId: Campaign.CharacterInstance.Id,
characterSheetId: String,
): Boolean {
// fetch all the current campaign character
val npcs = campaign.npcs.toMutableMap()
// check if the character is in the campaign.
if (npcs.containsKey(npcInstanceId).not()) return false
// update the corresponding character
npcs.remove(npcInstanceId)
if (campaign.npcs.contains(characterSheetId).not()) return false
// update the corresponding instance
val characters = campaign.npcs.toMutableSet().also { it.remove(characterSheetId) }
// save the campaign to the disk + update the flow.
return try {
store.save(
campaign = campaign.copy(npcs = npcs)
campaign = campaign.copy(npcs = characters)
)
true
} catch (exception: Exception) {
@ -124,35 +112,7 @@ class CampaignService(
suspend fun removeInstance(
characterSheetId: String,
): Boolean {
// fetch all the current campaign character
val characterIds = campaign.characters
.filterKeys { it.characterSheetId == characterSheetId }
.keys
val npcIds = campaign.npcs
.filterKeys { it.characterSheetId == characterSheetId }
.keys
// check if the character is in the campaign.
if (characterIds.isEmpty() && npcIds.isEmpty()) return false
// update the corresponding character
val characters = campaign.characters.toMutableMap()
val npcs = campaign.npcs.toMutableMap()
characterIds.forEach(characters::remove)
npcIds.forEach(npcs::remove)
// save the campaign to the disk + update the flow.
return try {
store.save(
campaign = campaign.copy(
characters = characters,
npcs = npcs,
)
)
true
} catch (exception: Exception) {
false
}
return removeCharacter(characterSheetId) || removeNpc(characterSheetId)
}
suspend fun setScene(
@ -171,127 +131,127 @@ class CampaignService(
// Data manipulation through WebSocket.
suspend fun updateCharacteristic(
characterInstanceId: Campaign.CharacterInstance.Id,
characteristic: Campaign.CharacterInstance.Characteristic,
value: Int,
) {
when (characterInstanceId.prefix) {
Campaign.CharacterInstance.Id.PLAYER -> {
// fetch all the current campaign character
val characters = campaign.characters.toMutableMap()
// update the corresponding character using the use case.
characters[characterInstanceId] = useCase.updateCharacteristic(
instance = campaign.character(id = characterInstanceId),
characteristic = characteristic,
value = value,
)
// save the campaign to the disk + update the flow.
store.save(
campaign = campaign.copy(characters = characters)
)
}
Campaign.CharacterInstance.Id.NPC -> {
// fetch all the current campaign character
val npcs = campaign.npcs.toMutableMap()
// update the corresponding character using the use case.
npcs[characterInstanceId] = useCase.updateCharacteristic(
instance = campaign.npc(id = characterInstanceId),
characteristic = characteristic,
value = value,
)
// save the campaign to the disk + update the flow.
store.save(
campaign = campaign.copy(npcs = npcs)
)
}
}
}
suspend fun updateDiminished(
characterInstanceId: Campaign.CharacterInstance.Id,
diminished: Int,
) {
when (characterInstanceId.prefix) {
Campaign.CharacterInstance.Id.PLAYER -> {
// fetch all the current campaign character
val characters = campaign.characters.toMutableMap()
// update the corresponding character using the use case.
characters[characterInstanceId] = useCase.updateDiminished(
instance = campaign.character(id = characterInstanceId),
diminished = diminished,
)
// save the campaign to the disk + update the flow.
store.save(
campaign = campaign.copy(characters = characters)
)
}
Campaign.CharacterInstance.Id.NPC -> {
// fetch all the current campaign character
val npcs = campaign.npcs.toMutableMap()
// update the corresponding character using the use case.
npcs[characterInstanceId] = useCase.updateDiminished(
instance = campaign.npc(id = characterInstanceId),
diminished = diminished,
)
// save the campaign to the disk + update the flow.
store.save(
campaign = campaign.copy(npcs = npcs)
)
}
}
}
suspend fun toggleAlteration(
characterInstanceId: Campaign.CharacterInstance.Id,
alterationId: String,
) {
when (characterInstanceId.prefix) {
Campaign.CharacterInstance.Id.PLAYER -> {
// fetch all the current campaign character
val characters = campaign.characters.toMutableMap()
// update the corresponding character alterations
characters[characterInstanceId]?.let { character ->
characters[characterInstanceId] = character.copy(
alterations = character.alterations.toMutableList().also { alterations ->
if (alterations.contains(alterationId)) {
alterations.remove(alterationId)
} else {
alterations.add(alterationId)
}
},
)
}
// save the campaign to the disk + update the flow.
store.save(
campaign = campaign.copy(characters = characters)
)
}
Campaign.CharacterInstance.Id.NPC -> {
// fetch all the current campaign character
val characters = campaign.npcs.toMutableMap()
// update the corresponding character alterations
characters[characterInstanceId]?.let { character ->
characters[characterInstanceId] = character.copy(
alterations = character.alterations.toMutableList().also { alterations ->
if (alterations.contains(alterationId)) {
alterations.remove(alterationId)
} else {
alterations.add(alterationId)
}
},
)
}
// save the campaign to the disk + update the flow.
store.save(
campaign = campaign.copy(npcs = characters)
)
}
}
}
// suspend fun updateCharacteristic(
// characterInstanceId: Campaign.CharacterInstance.Id,
// characteristic: Campaign.CharacterInstance.Characteristic,
// value: Int,
// ) {
// when (characterInstanceId.prefix) {
// Campaign.CharacterInstance.Id.PLAYER -> {
// // fetch all the current campaign character
// val characters = campaign.characters.toMutableMap()
// // update the corresponding character using the use case.
// characters[characterInstanceId] = useCase.updateCharacteristic(
// instance = campaign.character(id = characterInstanceId),
// characteristic = characteristic,
// value = value,
// )
// // save the campaign to the disk + update the flow.
// store.save(
// campaign = campaign.copy(characters = characters)
// )
// }
//
// Campaign.CharacterInstance.Id.NPC -> {
// // fetch all the current campaign character
// val npcs = campaign.npcs.toMutableMap()
// // update the corresponding character using the use case.
// npcs[characterInstanceId] = useCase.updateCharacteristic(
// instance = campaign.npc(id = characterInstanceId),
// characteristic = characteristic,
// value = value,
// )
// // save the campaign to the disk + update the flow.
// store.save(
// campaign = campaign.copy(npcs = npcs)
// )
// }
// }
// }
//
// suspend fun updateDiminished(
// characterInstanceId: Campaign.CharacterInstance.Id,
// diminished: Int,
// ) {
// when (characterInstanceId.prefix) {
// Campaign.CharacterInstance.Id.PLAYER -> {
// // fetch all the current campaign character
// val characters = campaign.characters.toMutableMap()
// // update the corresponding character using the use case.
// characters[characterInstanceId] = useCase.updateDiminished(
// instance = campaign.character(id = characterInstanceId),
// diminished = diminished,
// )
// // save the campaign to the disk + update the flow.
// store.save(
// campaign = campaign.copy(characters = characters)
// )
// }
//
// Campaign.CharacterInstance.Id.NPC -> {
// // fetch all the current campaign character
// val npcs = campaign.npcs.toMutableMap()
// // update the corresponding character using the use case.
// npcs[characterInstanceId] = useCase.updateDiminished(
// instance = campaign.npc(id = characterInstanceId),
// diminished = diminished,
// )
// // save the campaign to the disk + update the flow.
// store.save(
// campaign = campaign.copy(npcs = npcs)
// )
// }
// }
// }
//
// suspend fun toggleAlteration(
// characterInstanceId: Campaign.CharacterInstance.Id,
// alterationId: String,
// ) {
// when (characterInstanceId.prefix) {
// Campaign.CharacterInstance.Id.PLAYER -> {
// // fetch all the current campaign character
// val characters = campaign.characters.toMutableMap()
// // update the corresponding character alterations
// characters[characterInstanceId]?.let { character ->
// characters[characterInstanceId] = character.copy(
// alterations = character.alterations.toMutableList().also { alterations ->
// if (alterations.contains(alterationId)) {
// alterations.remove(alterationId)
// } else {
// alterations.add(alterationId)
// }
// },
// )
// }
// // save the campaign to the disk + update the flow.
// store.save(
// campaign = campaign.copy(characters = characters)
// )
// }
//
// Campaign.CharacterInstance.Id.NPC -> {
// // fetch all the current campaign character
// val characters = campaign.npcs.toMutableMap()
// // update the corresponding character alterations
// characters[characterInstanceId]?.let { character ->
// characters[characterInstanceId] = character.copy(
// alterations = character.alterations.toMutableList().also { alterations ->
// if (alterations.contains(alterationId)) {
// alterations.remove(alterationId)
// } else {
// alterations.add(alterationId)
// }
// },
// )
// }
// // save the campaign to the disk + update the flow.
// store.save(
// campaign = campaign.copy(npcs = characters)
// )
// }
// }
// }
suspend fun updateToggleParty() {
store.save(

View file

@ -18,7 +18,7 @@ class CampaignStore(
private val factory: CampaignJsonFactory,
private val json: Json,
) {
private val campaignFlow = MutableStateFlow(value = Campaign.EMPTY)
private val campaignFlow = MutableStateFlow(value = Campaign.empty())
init {
// create the directory if needed.
@ -38,7 +38,7 @@ class CampaignStore(
loadCampaign()
} catch (exception: Exception) {
println(exception) // TODO proper exception handling
Campaign.EMPTY
Campaign.empty()
}
}
@ -55,7 +55,7 @@ class CampaignStore(
}
// Guard, if the file is empty we load a default campaign.
if (json.isBlank()) return Campaign.EMPTY
if (json.isBlank()) return Campaign.empty()
val campaign = try {
val data = this.json.decodeFromString<CampaignJson>(json)
@ -74,7 +74,7 @@ class CampaignStore(
fun save(campaign: Campaign) {
// convert the data to json format
val json = try {
factory.convertToJson(data = campaign).let(json::encodeToString)
factory.convertToJson(campaign = campaign).let(json::encodeToString)
} catch (exception: Exception) {
throw JsonConversionException(root = exception)
}

View file

@ -1,9 +1,8 @@
package com.pixelized.server.lwa.model.character
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheetJson
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheetJsonFactory
import com.pixelized.shared.lwa.model.characterSheet.factory.CharacterSheetJsonFactory
import com.pixelized.shared.lwa.protocol.rest.CharacterPreviewJson
import com.pixelized.shared.lwa.usecase.CharacterSheetUseCase
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
@ -14,7 +13,6 @@ import kotlinx.coroutines.flow.stateIn
class CharacterSheetService(
private val store: CharacterSheetStore,
private val factory: CharacterSheetJsonFactory,
private val useCase: CharacterSheetUseCase,
) {
private val scope = CoroutineScope(Dispatchers.IO + Job())
private val sheets get() = sheetsFlow.value
@ -30,12 +28,14 @@ class CharacterSheetService(
return sheets.map { factory.convertToPreviewJson(sheet = it.value) }
}
fun characterSheet(id: String): CharacterSheetJson? {
return sheets[id]?.let(factory::convertToJson)
fun characterSheet(characterSheetId: String): CharacterSheetJson? {
return sheets[characterSheetId]?.let(factory::convertToJson)
}
suspend fun updateCharacterSheet(character: CharacterSheetJson) {
return store.save(sheet = factory.convertFromJson(character))
return store.save(
sheet = factory.convertFromJson(character)
)
}
fun deleteCharacterSheet(characterSheetId: String): Boolean {
@ -44,30 +44,62 @@ class CharacterSheetService(
// Data manipulation through WebSocket.
fun updateCharacterLevel(
characterId: String,
level: Int,
fun updateAlteration(
characterSheetId: String,
alterationId: String,
active: Boolean,
) {
sheets[characterId]?.let { character ->
val update = useCase.updateLevel(
character = character,
level = level,
)
sheets[characterSheetId]?.let { character ->
val contain = character.alterations.contains(alterationId)
if (active && contain.not()) {
val alterations = character.alterations.toMutableList().also {
it.add(alterationId)
}
store.save(
sheet = character.copy(
alterations = alterations,
)
)
}
if (active.not() && contain) {
val alterations = character.alterations.toMutableList().also {
it.remove(alterationId)
}
store.save(
sheet = character.copy(
alterations = alterations,
)
)
}
}
}
fun updateDamage(
characterSheetId: String,
damage: Int,
) {
sheets[characterSheetId]?.let { character ->
val update = character.copy(damage = damage)
store.save(sheet = update)
}
}
fun updateCharacterSkillLevel(
characterId: String,
skillId: String,
level: Int,
fun updateDiminished(
characterSheetId: String,
diminished: Int,
) {
sheets[characterId]?.let { character ->
val update = useCase.updateSkillLevel(
character = character,
skillId = skillId,
level = level,
)
sheets[characterSheetId]?.let { character ->
val update = character.copy(diminished = diminished)
store.save(sheet = update)
}
}
fun updateFatigue(
characterSheetId: String,
fatigue: Int,
) {
sheets[characterSheetId]?.let { character ->
val update = character.copy(fatigue = fatigue)
store.save(sheet = update)
}
}
@ -78,10 +110,16 @@ class CharacterSheetService(
used: Boolean,
) {
sheets[characterSheetId]?.let { character ->
val update = useCase.updateSkillUsage(
character = character,
skillId = skillId,
used = used,
val update = character.copy(
commonSkills = character.commonSkills.map { skill ->
skill.takeIf { skill.id == skillId }?.copy(used = used) ?: skill
},
specialSkills = character.specialSkills.map { skill ->
skill.takeIf { skill.id == skillId }?.copy(used = used) ?: skill
},
magicSkills = character.magicSkills.map { skill ->
skill.takeIf { skill.id == skillId }?.copy(used = used) ?: skill
},
)
store.save(sheet = update)
}

View file

@ -2,7 +2,7 @@ package com.pixelized.server.lwa.model.character
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheetJson
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheetJsonFactory
import com.pixelized.shared.lwa.model.characterSheet.factory.CharacterSheetJsonFactory
import com.pixelized.shared.lwa.utils.PathProvider
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers

View file

@ -3,16 +3,13 @@ package com.pixelized.server.lwa.server
import com.pixelized.server.lwa.model.alteration.AlterationService
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.CampaignMessage
import com.pixelized.shared.lwa.protocol.websocket.CampaignMessage.ToggleActiveAlteration
import com.pixelized.shared.lwa.protocol.websocket.GameEvent
import com.pixelized.shared.lwa.protocol.websocket.ApiSynchronisation
import com.pixelized.shared.lwa.protocol.websocket.CampaignEvent
import com.pixelized.shared.lwa.protocol.websocket.CharacterSheetEvent
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.RollEvent
import com.pixelized.shared.lwa.protocol.websocket.SocketMessage
import com.pixelized.shared.lwa.protocol.websocket.UpdateSkillUsageMessage
import kotlinx.coroutines.flow.MutableSharedFlow
class Engine(
@ -26,55 +23,52 @@ class Engine(
suspend fun handle(message: SocketMessage) {
when (message) {
is RollMessage -> Unit // Nothing to do here.
is CampaignMessage -> {
val instanceId = Campaign.CharacterInstance.Id(
prefix = message.prefix,
characterSheetId = message.characterSheetId,
instanceId = message.instanceId,
)
when (message) {
is CampaignMessage.UpdateCharacteristic -> campaignService.updateCharacteristic(
characterInstanceId = instanceId,
characteristic = campaignJsonFactory.convertFromJson(json = message.characteristic),
value = message.newValue,
)
is CampaignMessage.UpdateDiminished -> campaignService.updateDiminished(
characterInstanceId = instanceId,
diminished = message.diminished,
)
is ToggleActiveAlteration -> campaignService.toggleAlteration(
characterInstanceId = instanceId,
alterationId = message.alterationId,
)
}
}
is UpdateSkillUsageMessage -> characterService.updateCharacterSkillUsage(
characterSheetId = message.characterSheetId,
skillId = message.skillId,
used = message.used,
)
is RestSynchronisation.Campaign -> Unit // Handle in the Rest
is RestSynchronisation.CharacterSheetUpdate -> Unit // Handle in the Rest
is RestSynchronisation.CharacterSheetDelete -> Unit // Handle in the Rest
is ToggleActiveAlteration -> Unit // Handle in the Rest
is RollEvent -> Unit // Nothing to do here.
is GameMasterEvent -> when (message) {
is GameMasterEvent.TogglePlayer -> campaignService.updateToggleParty()
is GameMasterEvent.ToggleNpc -> campaignService.updateToggleNpc()
is GameMasterEvent.DisplayPortrait -> Unit // Nothing to do here.
}
is GameEvent -> when (message) {
is GameEvent.DisplayPortrait -> Unit // Nothing to do here.
is CharacterSheetEvent -> when (message) {
is CharacterSheetEvent.UpdateAlteration -> characterService.updateAlteration(
characterSheetId = message.characterSheetId,
alterationId = message.alterationId,
active = message.active,
)
is CharacterSheetEvent.UpdateDamage -> characterService.updateDamage(
characterSheetId = message.characterSheetId,
damage = message.damage,
)
is CharacterSheetEvent.UpdateDiminished -> characterService.updateDiminished(
characterSheetId = message.characterSheetId,
diminished = message.diminished,
)
is CharacterSheetEvent.UpdateFatigue -> characterService.updateFatigue(
characterSheetId = message.characterSheetId,
fatigue = message.fatigue,
)
is CharacterSheetEvent.UpdateSkillUsageEvent -> characterService.updateCharacterSkillUsage(
characterSheetId = message.characterSheetId,
skillId = message.skillId,
used = message.used,
)
}
is CampaignEvent -> when (message) {
is CampaignEvent.CharacterAdded -> Unit // TODO
is CampaignEvent.CharacterRemoved -> Unit // TODO
is CampaignEvent.NpcAdded -> Unit // TODO
is CampaignEvent.NpcRemoved -> Unit // TODO
is CampaignEvent.UpdateScene -> Unit // TODO
}
is ApiSynchronisation -> Unit // Nothing to do there.
}
}
}

View file

@ -1,18 +1,22 @@
package com.pixelized.server.lwa.server
import com.pixelized.server.lwa.server.rest.alteration.getAlteration
import com.pixelized.server.lwa.server.rest.alteration.getAlterations
import com.pixelized.server.lwa.server.rest.campaign.deleteCampaignNpc
import com.pixelized.server.lwa.server.rest.campaign.removeCampaignNpc
import com.pixelized.server.lwa.server.rest.campaign.getCampaign
import com.pixelized.server.lwa.server.rest.campaign.putCampaignCharacter
import com.pixelized.server.lwa.server.rest.campaign.putCampaignNpc
import com.pixelized.server.lwa.server.rest.campaign.putCampaignScene
import com.pixelized.server.lwa.server.rest.campaign.putToggleAlteration
import com.pixelized.server.lwa.server.rest.campaign.removeCampaignCharacter
import com.pixelized.server.lwa.server.rest.character.deleteCharacter
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.server.lwa.server.rest.character.putCharacterAlteration
import com.pixelized.server.lwa.server.rest.character.putCharacterDamage
import com.pixelized.server.lwa.server.rest.character.putCharacterDiminished
import com.pixelized.server.lwa.server.rest.character.putCharacterFatigue
import com.pixelized.shared.lwa.SERVER_PORT
import com.pixelized.shared.lwa.protocol.websocket.SocketMessage
import com.pixelized.shared.lwa.sharedModuleDependencies
@ -111,40 +115,66 @@ class LocalServer {
}
}
)
get(
path = "/alterations",
body = engine.getAlterations(),
)
get(
path = "/characters",
body = engine.getCharacters(),
)
route(path = "/character") {
route(
path = "/alteration",
) {
get(
path = "/all",
body = engine.getAlterations(),
)
get(
path = "/detail",
body = engine.getAlteration(),
)
}
route(
path = "/character",
) {
get(
path = "/all",
body = engine.getCharacters(),
)
get(
path = "/detail",
body = engine.getCharacter(),
)
put(
path = "/update",
body = engine.putCharacter(),
)
delete(
path = "/delete",
body = engine.deleteCharacter(),
)
route(
path = "/update",
) {
put(
path = "/sheet",
body = engine.putCharacter(),
)
put(
path = "/damage",
body = engine.putCharacterDamage(),
)
put(
path = "/fatigue",
body = engine.putCharacterFatigue(),
)
put(
path = "/diminished",
body = engine.putCharacterDiminished(),
)
put(
path = "/alteration",
body = engine.putCharacterAlteration(),
)
}
}
route(path = "/campaign") {
get(
path = "",
body = engine.getCampaign(),
)
put(
path = "/toggleAlteration",
body = engine.putToggleAlteration(),
)
route(path = "/character") {
put(
path = "/update",
path = "/add",
body = engine.putCampaignCharacter(),
)
delete(
@ -154,12 +184,12 @@ class LocalServer {
}
route(path = "/npc") {
put(
path = "/update",
path = "/add",
body = engine.putCampaignNpc(),
)
delete(
path = "/delete",
body = engine.deleteCampaignNpc(),
body = engine.removeCampaignNpc(),
)
}
put(

View file

@ -0,0 +1,29 @@
package com.pixelized.server.lwa.server.rest.alteration
import com.pixelized.server.lwa.server.Engine
import com.pixelized.server.lwa.utils.extentions.alterationId
import io.ktor.http.HttpStatusCode
import io.ktor.server.response.respond
import io.ktor.server.response.respondText
fun Engine.getAlteration(): suspend io.ktor.server.routing.RoutingContext.() -> Unit {
return {
try {
// get the query parameter
val alterationId = call.queryParameters.alterationId
// get the alteration of the given id.
val alteration = alterationService
.alteration(alterationId = alterationId)
?: error("Alteration with id:$alterationId not found.")
// send it back to the user.
call.respond(
message = alteration,
)
} catch (exception: Exception) {
call.respondText(
text = exception.localizedMessage,
status = HttpStatusCode.UnprocessableEntity,
)
}
}
}

View file

@ -5,6 +5,8 @@ import io.ktor.server.response.respond
fun Engine.getAlterations(): suspend io.ktor.server.routing.RoutingContext.() -> Unit {
return {
call.respond(alterationService.alterations())
call.respond(
message = alterationService.alterations(),
)
}
}

View file

@ -1,8 +1,8 @@
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.RestSynchronisation
import com.pixelized.server.lwa.utils.extentions.characterSheetId
import com.pixelized.shared.lwa.protocol.websocket.CampaignEvent
import io.ktor.http.HttpStatusCode
import io.ktor.server.response.respondText
@ -10,21 +10,24 @@ fun Engine.removeCampaignCharacter(): suspend io.ktor.server.routing.RoutingCont
return {
try {
// get the query parameter
val characterInstanceId = call.queryParameters.characterInstanceId
val characterSheetId = call.queryParameters.characterSheetId
// remove the character form the party
val updated = campaignService.removeCharacter(characterInstanceId = characterInstanceId)
val updated = campaignService.removeCharacter(
characterSheetId = characterSheetId,
)
// error case
if (!updated) {
error("Unexpected error when removing character (id:$characterInstanceId) from party.")
if (updated.not()) {
error("Unexpected error when removing character (characterSheetId:$characterSheetId) from party.")
}
// API & WebSocket responses
call.respondText(
text = "$HttpStatusCode.Accepted",
status = HttpStatusCode.Accepted,
text = "${HttpStatusCode.OK}",
status = HttpStatusCode.OK,
)
webSocket.emit(
RestSynchronisation.Campaign(
value = CampaignEvent.CharacterRemoved(
timestamp = System.currentTimeMillis(),
characterSheetId = characterSheetId,
)
)
} catch (exception: Exception) {

View file

@ -1,29 +1,29 @@
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.RestSynchronisation
import com.pixelized.server.lwa.utils.extentions.characterSheetId
import com.pixelized.shared.lwa.protocol.websocket.CampaignEvent
import io.ktor.http.HttpStatusCode
import io.ktor.server.response.respondText
fun Engine.deleteCampaignNpc(): suspend io.ktor.server.routing.RoutingContext.() -> Unit {
fun Engine.removeCampaignNpc(): suspend io.ktor.server.routing.RoutingContext.() -> Unit {
return {
try {
// get the query parameter
val characterInstanceId = call.queryParameters.characterInstanceId
val characterSheetId = call.queryParameters.characterSheetId
// remove the character form the party
val updated = campaignService.removeNpc(npcInstanceId = characterInstanceId)
val updated = campaignService.removeNpc(characterSheetId = characterSheetId)
// error case
if (!updated) {
error("Unexpected error when removing character (id:$characterInstanceId) from npcs.")
if (updated.not()) {
error("Unexpected error when removing character (characterSheetId:$characterSheetId) from npcs.")
}
// API & WebSocket responses
call.respondText(
text = "$HttpStatusCode.Accepted",
status = HttpStatusCode.Accepted,
text = "${HttpStatusCode.OK}",
status = HttpStatusCode.OK,
)
webSocket.emit(
RestSynchronisation.Campaign(
value = CampaignEvent.UpdateScene(
timestamp = System.currentTimeMillis(),
)
)

View file

@ -5,6 +5,8 @@ import io.ktor.server.response.respond
fun Engine.getCampaign(): suspend io.ktor.server.routing.RoutingContext.() -> Unit {
return {
call.respond(campaignService.campaignJson())
call.respond(
message = campaignService.campaignJson(),
)
}
}

View file

@ -0,0 +1,38 @@
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.protocol.websocket.CampaignEvent
import io.ktor.http.HttpStatusCode
import io.ktor.server.response.respondText
fun Engine.putCampaignCharacter(): suspend io.ktor.server.routing.RoutingContext.() -> Unit {
return {
try {
// get the query parameter
val characterSheetId = call.queryParameters.characterSheetId
// add the character to the party.
val update = campaignService.addCharacter(characterSheetId = characterSheetId)
// error case
if (update.not()) {
error("Unexpected error occurred when the character instance was added to the party")
}
// API & WebSocket responses.
call.respondText(
text = "Character $characterSheetId successfully added to the party",
status = HttpStatusCode.OK,
)
webSocket.emit(
value = CampaignEvent.CharacterAdded(
timestamp = System.currentTimeMillis(),
characterSheetId = characterSheetId,
)
)
} catch (exception: Exception) {
call.respondText(
text = "${exception.message}",
status = HttpStatusCode.UnprocessableEntity,
)
}
}
}

View file

@ -0,0 +1,38 @@
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.protocol.websocket.CampaignEvent
import io.ktor.http.HttpStatusCode
import io.ktor.server.response.respondText
fun Engine.putCampaignNpc(): suspend io.ktor.server.routing.RoutingContext.() -> Unit {
return {
try {
// get the query parameter
val characterSheetId = call.queryParameters.characterSheetId
// add the character to the npcs.
val update = campaignService.addNpc(characterSheetId = characterSheetId)
// error case
if (update.not()) {
error("Unexpected error occurred when the character instance was added to the npcs")
}
// API & WebSocket responses.
call.respondText(
text = "Character $characterSheetId successfully added to the npcs",
status = HttpStatusCode.OK,
)
webSocket.emit(
value = CampaignEvent.NpcAdded(
timestamp = System.currentTimeMillis(),
characterSheetId = characterSheetId,
)
)
} catch (exception: Exception) {
call.respondText(
text = "${exception.message}",
status = HttpStatusCode.UnprocessableEntity,
)
}
}
}

View file

@ -1,34 +1,40 @@
package com.pixelized.server.lwa.server.rest.campaign
import com.pixelized.server.lwa.server.Engine
import com.pixelized.shared.lwa.model.campaign.CampaignJsonV1
import com.pixelized.shared.lwa.protocol.websocket.RestSynchronisation
import com.pixelized.shared.lwa.model.campaign.CampaignJsonV2
import com.pixelized.shared.lwa.protocol.websocket.CampaignEvent
import io.ktor.http.HttpStatusCode
import io.ktor.server.request.receive
import io.ktor.server.response.respondText
fun Engine.putCampaignScene(): suspend io.ktor.server.routing.RoutingContext.() -> Unit {
return {
val form = call.receive<CampaignJsonV1.SceneJsonV1>()
val scene = campaignJsonFactory.convertFromJson(json = form)
val updated = campaignService.setScene(scene = scene)
val code = when (updated) {
true -> HttpStatusCode.Accepted
else -> HttpStatusCode.UnprocessableEntity
}
call.respondText(
text = "$code",
status = code,
)
webSocket.emit(
RestSynchronisation.Campaign(
timestamp = System.currentTimeMillis(),
try {
// Get the scene json from the body of the request
val form = call.receive<CampaignJsonV2.SceneJsonV2>()
// convert the scene into the a usable data model.
val scene = campaignJsonFactory.convertFromJson(json = form)
// update the campaign.
val updated = campaignService.setScene(scene = scene)
// error case
if (updated.not()) {
error("Unexpected error when updating the scene.")
}
// API & WebSocket responses
call.respondText(
text = "${HttpStatusCode.OK}",
status = HttpStatusCode.OK,
)
)
webSocket.emit(
value = CampaignEvent.UpdateScene(
timestamp = System.currentTimeMillis(),
)
)
} catch (exception: Exception) {
call.respondText(
text = exception.localizedMessage,
status = HttpStatusCode.UnprocessableEntity,
)
}
}
}

View file

@ -1,51 +0,0 @@
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.RestSynchronisation
import io.ktor.http.HttpStatusCode
import io.ktor.server.response.respondText
fun Engine.putCampaignCharacter(): suspend io.ktor.server.routing.RoutingContext.() -> Unit {
return {
try {
// get the query parameter
val characterSheetId = call.queryParameters.characterSheetId
// check if the character is already in the party.
val instanceId = campaignService.campaign().characters.keys
.firstOrNull { key -> key.characterSheetId == characterSheetId }
// handle the error case.
if (instanceId != null) {
error("Character (characterSheetId:$characterSheetId) Already in party")
}
// create the instance id for the character.
val id = Campaign.CharacterInstance.Id(
prefix = Campaign.CharacterInstance.Id.PLAYER,
characterSheetId = characterSheetId,
instanceId = 0,
)
// add the character to the party.
if (campaignService.addCharacter(id).not()) {
error("Unexpected error occurred when the character instance was added to the party")
}
// API & WebSocket responses.
call.respondText(
text = "Character $characterSheetId successfully added to the party",
status = HttpStatusCode.Accepted,
)
webSocket.emit(
RestSynchronisation.Campaign(
timestamp = System.currentTimeMillis(),
)
)
} catch (exception: Exception) {
call.run {
respondText(
text = "${exception.message}",
status = HttpStatusCode.UnprocessableEntity,
)
}
}
}
}

View file

@ -1,54 +0,0 @@
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.RestSynchronisation
import io.ktor.http.HttpStatusCode
import io.ktor.server.response.respondText
fun Engine.putCampaignNpc(): suspend io.ktor.server.routing.RoutingContext.() -> Unit {
return {
try {
// get the query parameter
val characterSheetId = call.queryParameters.characterSheetId
// compute the npc id base on similar character sheets.
val instanceId = campaignService.campaign().npcs.keys
.filter { it.characterSheetId == characterSheetId }
.reduceOrNull { acc, id ->
if (acc.instanceId < id.instanceId) {
id
} else {
acc
}
}
// create the instance id for the character.
val id = Campaign.CharacterInstance.Id(
prefix = Campaign.CharacterInstance.Id.NPC,
characterSheetId = characterSheetId,
instanceId = instanceId?.let { it.instanceId + 1 } ?: 0,
)
// add the character to the npcs.
if (campaignService.addNpc(id).not()) {
error("Unexpected error occurred when the character instance was added to the npcs")
}
// API & WebSocket responses.
call.respondText(
text = "Character $characterSheetId successfully added to the npcs",
status = HttpStatusCode.Accepted,
)
webSocket.emit(
RestSynchronisation.Campaign(
timestamp = System.currentTimeMillis(),
)
)
} catch (exception: Exception) {
call.run {
respondText(
text = "${exception.message}",
status = HttpStatusCode.UnprocessableEntity,
)
}
}
}
}

View file

@ -1,54 +0,0 @@
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.CampaignMessage
import io.ktor.http.HttpStatusCode
import io.ktor.server.request.receive
import io.ktor.server.response.respondText
fun Engine.putToggleAlteration(): suspend io.ktor.server.routing.RoutingContext.() -> Unit {
return {
try {
// get the query parameter
val characterInstanceId = call.queryParameters.characterInstanceId
// fetch the query parameters
val alterationId = call.receive<String>()
// Update the alteration
campaignService.toggleAlteration(
characterInstanceId = characterInstanceId,
alterationId = alterationId,
)
// build the Http response & send it
call.respondText(
text = "$HttpStatusCode.Accepted",
status = HttpStatusCode.Accepted,
)
val isAlterationActive = campaignService.campaign()
.instances[characterInstanceId]
?.alterations
?.contains(alterationId)
?: false
// share the modification to all client through the websocket.
webSocket.emit(
CampaignMessage.ToggleActiveAlteration(
timestamp = System.currentTimeMillis(),
prefix = characterInstanceId.prefix,
characterSheetId = characterInstanceId.characterSheetId,
instanceId = characterInstanceId.instanceId,
alterationId = alterationId,
active = isAlterationActive,
)
)
} catch (exception: Exception) {
call.respondText(
text = exception.localizedMessage,
status = HttpStatusCode.UnprocessableEntity,
)
}
}
}

View file

@ -2,7 +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.RestSynchronisation
import com.pixelized.shared.lwa.protocol.websocket.ApiSynchronisation
import io.ktor.http.HttpStatusCode
import io.ktor.server.response.respondText
@ -12,7 +12,9 @@ fun Engine.deleteCharacter(): suspend io.ktor.server.routing.RoutingContext.() -
val deleted = characterService.deleteCharacterSheet(
characterSheetId = characterSheetId
) && campaignService.removeInstance(
)
// Remove the character fom the campaign if needed.
campaignService.removeInstance(
characterSheetId = characterSheetId,
)
@ -22,7 +24,7 @@ fun Engine.deleteCharacter(): suspend io.ktor.server.routing.RoutingContext.() -
status = HttpStatusCode.OK,
)
webSocket.emit(
RestSynchronisation.CharacterSheetDelete(
value = ApiSynchronisation.CharacterSheetDelete(
timestamp = System.currentTimeMillis(),
characterSheetId = characterSheetId,
),

View file

@ -8,12 +8,18 @@ import io.ktor.server.response.respondText
fun Engine.getCharacter(): suspend io.ktor.server.routing.RoutingContext.() -> Unit {
return {
val id = call.queryParameters.characterSheetId
val body = characterService.characterSheet(id)
if (body != null) {
call.respond(body)
} else {
try {
// get the query parameter
val characterSheetId = call.queryParameters.characterSheetId
// get the character sheet of the given id.
val characterSheet = characterService
.characterSheet(characterSheetId = characterSheetId)
?: error("CharacterSheet with id:$characterSheetId not found.")
// send it back to the user.
call.respond(
message = characterSheet,
)
} catch (exception: Exception) {
call.respondText(
text = "${HttpStatusCode.UnprocessableEntity}",
status = HttpStatusCode.UnprocessableEntity

View file

@ -5,6 +5,8 @@ import io.ktor.server.response.respond
fun Engine.getCharacters(): suspend io.ktor.server.routing.RoutingContext.() -> Unit {
return {
call.respond(characterService.characters())
call.respond(
message = characterService.characters(),
)
}
}

View file

@ -2,26 +2,33 @@ 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.RestSynchronisation
import com.pixelized.shared.lwa.protocol.websocket.ApiSynchronisation
import io.ktor.http.HttpStatusCode
import io.ktor.server.request.receive
import io.ktor.server.response.respondText
fun Engine.putCharacter(): suspend io.ktor.server.routing.RoutingContext.() -> Unit {
return {
val form = call.receive<CharacterSheetJson>()
characterService.updateCharacterSheet(
character = form
)
call.respondText(
text = "${HttpStatusCode.OK}",
status = HttpStatusCode.OK
)
webSocket.emit(
RestSynchronisation.CharacterSheetUpdate(
timestamp = System.currentTimeMillis(),
characterSheetId = form.id,
),
)
try {
val form = call.receive<CharacterSheetJson>()
characterService.updateCharacterSheet(
character = form,
)
call.respondText(
text = "${HttpStatusCode.OK}",
status = HttpStatusCode.OK,
)
webSocket.emit(
value = ApiSynchronisation.CharacterSheetUpdate(
timestamp = System.currentTimeMillis(),
characterSheetId = form.id,
),
)
} catch (exception: Exception) {
call.respondText(
text = "${HttpStatusCode.UnprocessableEntity}",
status = HttpStatusCode.UnprocessableEntity,
)
}
}
}

View file

@ -0,0 +1,44 @@
package com.pixelized.server.lwa.server.rest.character
import com.pixelized.server.lwa.server.Engine
import com.pixelized.server.lwa.utils.extentions.alterationId
import com.pixelized.server.lwa.utils.extentions.characterSheetId
import com.pixelized.shared.lwa.protocol.websocket.CharacterSheetEvent
import io.ktor.http.HttpStatusCode
import io.ktor.server.response.respondText
fun Engine.putCharacterAlteration(): suspend io.ktor.server.routing.RoutingContext.() -> Unit {
return {
try {
// get the query parameter
val characterSheetId = call.queryParameters.characterSheetId
val alterationId = call.queryParameters.alterationId
val active = call.queryParameters["active"]?.toBooleanStrictOrNull()
?: error("Missing active parameter.")
// Update the character damage
characterService.updateAlteration(
characterSheetId = characterSheetId,
alterationId = alterationId,
active = active
)
// API & WebSocket responses.
call.respondText(
text = "${HttpStatusCode.OK}",
status = HttpStatusCode.OK,
)
webSocket.emit(
value = CharacterSheetEvent.UpdateAlteration(
timestamp = System.currentTimeMillis(),
characterSheetId = characterSheetId,
alterationId = alterationId,
active = active,
)
)
} catch (exception: Exception) {
call.respondText(
text = "${HttpStatusCode.UnprocessableEntity}",
status = HttpStatusCode.UnprocessableEntity,
)
}
}
}

View file

@ -0,0 +1,40 @@
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.CharacterSheetEvent
import io.ktor.http.HttpStatusCode
import io.ktor.server.response.respondText
fun Engine.putCharacterDamage(): suspend io.ktor.server.routing.RoutingContext.() -> Unit {
return {
try {
// get the query parameter
val characterSheetId = call.queryParameters.characterSheetId
val damage = call.queryParameters["damage"]?.toIntOrNull()
?: error("Missing damage parameter.")
// Update the character damage
characterService.updateDamage(
characterSheetId = characterSheetId,
damage = damage
)
// API & WebSocket responses.
call.respondText(
text = "${HttpStatusCode.OK}",
status = HttpStatusCode.OK,
)
webSocket.emit(
value = CharacterSheetEvent.UpdateDamage(
timestamp = System.currentTimeMillis(),
characterSheetId = characterSheetId,
damage = damage,
)
)
} catch (exception: Exception) {
call.respondText(
text = "${HttpStatusCode.UnprocessableEntity}",
status = HttpStatusCode.UnprocessableEntity,
)
}
}
}

View file

@ -0,0 +1,40 @@
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.CharacterSheetEvent
import io.ktor.http.HttpStatusCode
import io.ktor.server.response.respondText
fun Engine.putCharacterDiminished(): suspend io.ktor.server.routing.RoutingContext.() -> Unit {
return {
try {
// get the query parameter
val characterSheetId = call.queryParameters.characterSheetId
val diminished = call.queryParameters["diminished"]?.toIntOrNull()
?: error("Missing diminished parameter.")
// Update the character damage
characterService.updateDiminished(
characterSheetId = characterSheetId,
diminished = diminished
)
// API & WebSocket responses.
call.respondText(
text = "${HttpStatusCode.OK}",
status = HttpStatusCode.OK,
)
webSocket.emit(
value = CharacterSheetEvent.UpdateDiminished(
timestamp = System.currentTimeMillis(),
characterSheetId = characterSheetId,
diminished = diminished,
)
)
} catch (exception: Exception) {
call.respondText(
text = "${HttpStatusCode.UnprocessableEntity}",
status = HttpStatusCode.UnprocessableEntity,
)
}
}
}

View file

@ -0,0 +1,40 @@
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.CharacterSheetEvent
import io.ktor.http.HttpStatusCode
import io.ktor.server.response.respondText
fun Engine.putCharacterFatigue(): suspend io.ktor.server.routing.RoutingContext.() -> Unit {
return {
try {
// get the query parameter
val characterSheetId = call.queryParameters.characterSheetId
val fatigue = call.queryParameters["fatigue"]?.toIntOrNull()
?: error("Missing fatigue parameter.")
// Update the character damage
characterService.updateFatigue(
characterSheetId = characterSheetId,
fatigue = fatigue
)
// API & WebSocket responses.
call.respondText(
text = "${HttpStatusCode.OK}",
status = HttpStatusCode.OK,
)
webSocket.emit(
value = CharacterSheetEvent.UpdateFatigue(
timestamp = System.currentTimeMillis(),
characterSheetId = characterSheetId,
fatigue = fatigue,
)
)
} catch (exception: Exception) {
call.respondText(
text = "${HttpStatusCode.UnprocessableEntity}",
status = HttpStatusCode.UnprocessableEntity,
)
}
}
}

View file

@ -1,20 +1,9 @@
package com.pixelized.server.lwa.utils.extentions
import com.pixelized.shared.lwa.model.campaign.Campaign
import io.ktor.http.Parameters
val Parameters.characterInstanceId: Campaign.CharacterInstance.Id
get() = Campaign.CharacterInstance.Id(
characterSheetId = characterSheetId,
instanceId = instanceId,
prefix = prefix,
)
val Parameters.characterSheetId
get() = this["characterSheetId"] ?: error("Missing character sheet id.")
get() = this["characterSheetId"] ?: error("Missing characterSheetId parameter.")
val Parameters.instanceId: Int
get() = this["instanceId"]?.toIntOrNull() ?: error("Missing character instance id.")
val Parameters.prefix: Char
get() = this["prefix"]?.get(0) ?: error("Missing character prefix.")
val Parameters.alterationId
get() = this["alterationId"] ?: error("Missing alterationId parameter.")