Add campagin + character REST API.
This commit is contained in:
parent
495768e5fe
commit
bd4d65fe6a
34 changed files with 592 additions and 162 deletions
|
|
@ -3,6 +3,7 @@ import com.pixelized.server.lwa.model.campaign.CampaignStore
|
||||||
import com.pixelized.server.lwa.model.character.CharacterSheetService
|
import com.pixelized.server.lwa.model.character.CharacterSheetService
|
||||||
import com.pixelized.server.lwa.model.character.CharacterSheetStore
|
import com.pixelized.server.lwa.model.character.CharacterSheetStore
|
||||||
import com.pixelized.server.lwa.server.Engine
|
import com.pixelized.server.lwa.server.Engine
|
||||||
|
import org.koin.core.module.dsl.createdAtStart
|
||||||
import org.koin.core.module.dsl.singleOf
|
import org.koin.core.module.dsl.singleOf
|
||||||
import org.koin.dsl.module
|
import org.koin.dsl.module
|
||||||
|
|
||||||
|
|
@ -18,7 +19,7 @@ val serverModuleDependencies
|
||||||
|
|
||||||
val engineDependencies
|
val engineDependencies
|
||||||
get() = module {
|
get() = module {
|
||||||
singleOf(::Engine)
|
singleOf(constructor = ::Engine, options = { createdAtStart() })
|
||||||
}
|
}
|
||||||
|
|
||||||
val storeDependencies
|
val storeDependencies
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package com.pixelized.server.lwa.extention
|
package com.pixelized.server.lwa.extention
|
||||||
|
|
||||||
import com.pixelized.shared.lwa.protocol.Message
|
import com.pixelized.shared.lwa.protocol.websocket.Message
|
||||||
import io.ktor.websocket.Frame
|
import io.ktor.websocket.Frame
|
||||||
import io.ktor.websocket.readText
|
import io.ktor.websocket.readText
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,14 @@ package com.pixelized.server.lwa.model.campaign
|
||||||
import com.pixelized.shared.lwa.model.campaign.Campaign
|
import com.pixelized.shared.lwa.model.campaign.Campaign
|
||||||
import com.pixelized.shared.lwa.model.campaign.CampaignJson
|
import com.pixelized.shared.lwa.model.campaign.CampaignJson
|
||||||
import com.pixelized.shared.lwa.model.campaign.CampaignJsonFactory
|
import com.pixelized.shared.lwa.model.campaign.CampaignJsonFactory
|
||||||
import com.pixelized.shared.lwa.protocol.payload.UpdatePlayerCharacteristicMessage
|
import com.pixelized.shared.lwa.model.campaign.character
|
||||||
import com.pixelized.shared.lwa.usecase.CampaignUseCase
|
import com.pixelized.shared.lwa.usecase.CampaignUseCase
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
|
|
||||||
class CampaignService(
|
class CampaignService(
|
||||||
|
|
@ -17,33 +19,102 @@ class CampaignService(
|
||||||
private val useCase: CampaignUseCase,
|
private val useCase: CampaignUseCase,
|
||||||
) {
|
) {
|
||||||
private val scope = CoroutineScope(Dispatchers.IO + Job())
|
private val scope = CoroutineScope(Dispatchers.IO + Job())
|
||||||
private val campaign = store.campaignFlow().stateIn(
|
|
||||||
scope = scope,
|
private val campaign: Campaign get() = campaignFlow.value
|
||||||
started = SharingStarted.Eagerly,
|
|
||||||
initialValue = Campaign.EMPTY,
|
private val campaignFlow = store.campaignFlow()
|
||||||
)
|
.stateIn(
|
||||||
|
scope = scope,
|
||||||
|
started = SharingStarted.Eagerly,
|
||||||
|
initialValue = Campaign.EMPTY,
|
||||||
|
)
|
||||||
|
|
||||||
|
private val campaignJsonFlow: StateFlow<CampaignJson> = campaignFlow
|
||||||
|
.map { factory.convertToJson(it) }
|
||||||
|
.stateIn(
|
||||||
|
scope = scope,
|
||||||
|
started = SharingStarted.Eagerly,
|
||||||
|
initialValue = factory.convertToJson(campaignFlow.value),
|
||||||
|
)
|
||||||
|
|
||||||
fun campaign(): CampaignJson {
|
fun campaign(): CampaignJson {
|
||||||
return campaign.value.let(factory::convertToJson)
|
return campaignJsonFlow.value
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun update(
|
suspend fun addCharacter(characterId: String): Boolean {
|
||||||
message: UpdatePlayerCharacteristicMessage,
|
// fetch all the current campaign character
|
||||||
|
val characters = campaign.characters.toMutableMap()
|
||||||
|
// check if the character is in the campaign.
|
||||||
|
if (characters.containsKey(characterId)) return false
|
||||||
|
// update the corresponding character
|
||||||
|
characters[characterId] = campaign.character(id = characterId)
|
||||||
|
// save the campaign to the disk + update the flow.
|
||||||
|
store.save(
|
||||||
|
campaign = campaign.copy(characters = characters)
|
||||||
|
)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun removeCharacter(characterId: String): Boolean {
|
||||||
|
// fetch all the current campaign character
|
||||||
|
val characters = campaign.characters.toMutableMap()
|
||||||
|
// check if the character is in the campaign.
|
||||||
|
if (characters.containsKey(characterId).not()) return false
|
||||||
|
// update the corresponding character
|
||||||
|
characters.remove(characterId)
|
||||||
|
// save the campaign to the disk + update the flow.
|
||||||
|
store.save(
|
||||||
|
campaign = campaign.copy(characters = characters)
|
||||||
|
)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun addNpc(npcId: String): Boolean {
|
||||||
|
// fetch all the current campaign character
|
||||||
|
val characters = campaign.npcs.toMutableMap()
|
||||||
|
// check if the character is in the campaign.
|
||||||
|
if (characters.containsKey(npcId)) return false
|
||||||
|
// update the corresponding character
|
||||||
|
characters[npcId] = campaign.character(id = npcId)
|
||||||
|
// save the campaign to the disk + update the flow.
|
||||||
|
store.save(
|
||||||
|
campaign = campaign.copy(npcs = characters)
|
||||||
|
)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun removeNpc(npcId: String): Boolean {
|
||||||
|
// fetch all the current campaign character
|
||||||
|
val characters = campaign.npcs.toMutableMap()
|
||||||
|
// check if the character is in the campaign.
|
||||||
|
if (characters.containsKey(npcId).not()) return false
|
||||||
|
// update the corresponding character
|
||||||
|
characters.remove(npcId)
|
||||||
|
// save the campaign to the disk + update the flow.
|
||||||
|
store.save(
|
||||||
|
campaign = campaign.copy(npcs = characters)
|
||||||
|
)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data manipulation threw WebSocket.
|
||||||
|
|
||||||
|
suspend fun updateCharacteristic(
|
||||||
|
characterId: String,
|
||||||
|
characteristic: Campaign.CharacterInstance.Characteristic,
|
||||||
|
value: Int,
|
||||||
) {
|
) {
|
||||||
// fetch all the current campaign character
|
// fetch all the current campaign character
|
||||||
val characters = campaign.value.characters.toMutableMap()
|
val characters = campaign.characters.toMutableMap()
|
||||||
// update the corresponding character using the usecase
|
// update the corresponding character using the use case.
|
||||||
characters[message.characterId] = useCase.updateCharacteristic(
|
characters[characterId] = useCase.updateCharacteristic(
|
||||||
character = characters[message.characterId] ?: Campaign.CharacterInstance(
|
character = campaign.character(id = characterId),
|
||||||
characteristic = emptyMap(),
|
characteristic = characteristic,
|
||||||
usedSkill = emptyList(),
|
value = value,
|
||||||
),
|
|
||||||
characteristic = message.characteristic,
|
|
||||||
value = message.value,
|
|
||||||
)
|
)
|
||||||
// save the campaign to the disk + update the flow.
|
// save the campaign to the disk + update the flow.
|
||||||
store.save(
|
store.save(
|
||||||
campaign = campaign.value.copy(characters = characters)
|
campaign = campaign.copy(characters = characters)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,12 +1,15 @@
|
||||||
package com.pixelized.server.lwa.model.character
|
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.CharacterSheetJson
|
||||||
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheetJsonFactory
|
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheetJsonFactory
|
||||||
|
import com.pixelized.shared.lwa.protocol.rest.CharacterPreviewJson
|
||||||
import com.pixelized.shared.lwa.usecase.CharacterSheetUseCase
|
import com.pixelized.shared.lwa.usecase.CharacterSheetUseCase
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
|
|
||||||
class CharacterSheetService(
|
class CharacterSheetService(
|
||||||
|
|
@ -15,22 +18,66 @@ class CharacterSheetService(
|
||||||
private val useCase: CharacterSheetUseCase,
|
private val useCase: CharacterSheetUseCase,
|
||||||
) {
|
) {
|
||||||
private val scope = CoroutineScope(Dispatchers.IO + Job())
|
private val scope = CoroutineScope(Dispatchers.IO + Job())
|
||||||
private val sheets = store.characterSheetFlow().stateIn(
|
private val sheets get() = sheetsFlow.value
|
||||||
scope = scope,
|
private val sheetsFlow = store.characterSheetFlow()
|
||||||
started = SharingStarted.Eagerly,
|
.map { entry -> entry.associateBy { character -> character.id } }
|
||||||
initialValue = emptyList()
|
.stateIn(
|
||||||
)
|
scope = scope,
|
||||||
|
started = SharingStarted.Eagerly,
|
||||||
|
initialValue = emptyMap()
|
||||||
|
)
|
||||||
|
|
||||||
fun character(): List<CharacterSheetJson> {
|
fun characters(): List<CharacterPreviewJson> {
|
||||||
return sheets.value.map(factory::convertToJson)
|
return sheets.map { factory.convertToPreviewJson(sheet = it.value) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun characterSkillChange(
|
fun character(id: String): CharacterSheetJson? {
|
||||||
|
return sheets[id]?.let(factory::convertToJson)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun updateCharacter(character: CharacterSheetJson) {
|
||||||
|
return store.save(sheet = factory.convertFromJson(character))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deleteCharacter(characterId: String) : Boolean {
|
||||||
|
return store.delete(id = characterId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data manipulation threw WebSocket.
|
||||||
|
|
||||||
|
fun updateCharacterLevel(
|
||||||
|
characterId: String,
|
||||||
|
level: Int,
|
||||||
|
) {
|
||||||
|
sheets[characterId]?.let { character ->
|
||||||
|
val update = useCase.updateLevel(
|
||||||
|
character = character,
|
||||||
|
level = level,
|
||||||
|
)
|
||||||
|
store.save(sheet = update)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateCharacterSkillLevel(
|
||||||
|
characterId: String,
|
||||||
|
skillId: String,
|
||||||
|
level: Int,
|
||||||
|
) {
|
||||||
|
sheets[characterId]?.let { character ->
|
||||||
|
val update = useCase.updateSkillLevel(
|
||||||
|
character = character,
|
||||||
|
skillId = skillId,
|
||||||
|
level = level,
|
||||||
|
)
|
||||||
|
store.save(sheet = update)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateCharacterSkillUsage(
|
||||||
characterId: String,
|
characterId: String,
|
||||||
skillId: String,
|
skillId: String,
|
||||||
) {
|
) {
|
||||||
val character = sheets.value.firstOrNull { it.id == characterId }
|
sheets[characterId]?.let { character ->
|
||||||
if (character != null) {
|
|
||||||
val update = useCase.updateSkillUsage(
|
val update = useCase.updateSkillUsage(
|
||||||
character = character,
|
character = character,
|
||||||
skillId = skillId,
|
skillId = skillId,
|
||||||
|
|
|
||||||
|
|
@ -69,14 +69,17 @@ class CharacterSheetStore(
|
||||||
|
|
||||||
fun delete(id: String): Boolean {
|
fun delete(id: String): Boolean {
|
||||||
val file = characterSheetFile(id = id)
|
val file = characterSheetFile(id = id)
|
||||||
flow.value = flow.value.toMutableList()
|
val deleted = file.delete()
|
||||||
.also { data ->
|
if (deleted) {
|
||||||
data.removeIf { it.id == id }
|
flow.value = flow.value.toMutableList()
|
||||||
}
|
.also { data ->
|
||||||
.sortedBy {
|
data.removeIf { it.id == id }
|
||||||
it.name
|
}
|
||||||
}
|
.sortedBy {
|
||||||
return file.delete()
|
it.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return deleted
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(
|
@Throws(
|
||||||
|
|
|
||||||
|
|
@ -2,37 +2,41 @@ package com.pixelized.server.lwa.server
|
||||||
|
|
||||||
import com.pixelized.server.lwa.model.campaign.CampaignService
|
import com.pixelized.server.lwa.model.campaign.CampaignService
|
||||||
import com.pixelized.server.lwa.model.character.CharacterSheetService
|
import com.pixelized.server.lwa.model.character.CharacterSheetService
|
||||||
import com.pixelized.shared.lwa.protocol.Message
|
import com.pixelized.shared.lwa.protocol.websocket.Message
|
||||||
import com.pixelized.shared.lwa.protocol.MessageType
|
import com.pixelized.shared.lwa.protocol.websocket.payload.RestSynchronisation
|
||||||
import com.pixelized.shared.lwa.protocol.payload.UpdatePlayerCharacteristicMessage
|
import com.pixelized.shared.lwa.protocol.websocket.payload.RollMessage
|
||||||
import com.pixelized.shared.lwa.protocol.payload.UpdateSkillUsageMessage
|
import com.pixelized.shared.lwa.protocol.websocket.payload.UpdatePlayerCharacteristicMessage
|
||||||
import kotlinx.serialization.json.Json
|
import com.pixelized.shared.lwa.protocol.websocket.payload.UpdateSkillUsageMessage
|
||||||
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
|
|
||||||
class Engine(
|
class Engine(
|
||||||
private val characterService: CharacterSheetService,
|
val characterService: CharacterSheetService,
|
||||||
private val campaignService: CampaignService,
|
val campaignService: CampaignService,
|
||||||
private val json: Json,
|
|
||||||
) {
|
) {
|
||||||
|
val webSocket = MutableSharedFlow<Message>()
|
||||||
|
|
||||||
suspend fun handle(message: Message) {
|
suspend fun handle(message: Message) {
|
||||||
println(message)
|
when (val data = message.value) {
|
||||||
|
RestSynchronisation.Campaign -> Unit // TODO
|
||||||
|
|
||||||
when (message.type) {
|
is RestSynchronisation.CharacterUpdate -> Unit // TODO
|
||||||
MessageType.Roll -> {
|
|
||||||
Unit // Nothing to do here.
|
|
||||||
}
|
|
||||||
|
|
||||||
MessageType.UpdateSkillUsage -> {
|
is RollMessage -> Unit // Nothing to do here.
|
||||||
val data: UpdateSkillUsageMessage = json.decodeFromString(message.value)
|
|
||||||
characterService.characterSkillChange(
|
|
||||||
characterId = data.characterId,
|
|
||||||
skillId = data.skillId
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
MessageType.UpdatePlayerCharacteristic -> {
|
is UpdatePlayerCharacteristicMessage -> campaignService.updateCharacteristic(
|
||||||
val data: UpdatePlayerCharacteristicMessage = json.decodeFromString(message.value)
|
characterId = data.characterId,
|
||||||
campaignService.update(data)
|
characteristic = data.characteristic,
|
||||||
}
|
value = data.value,
|
||||||
|
)
|
||||||
|
|
||||||
|
is UpdateSkillUsageMessage -> characterService.updateCharacterSkillUsage(
|
||||||
|
characterId = data.characterId,
|
||||||
|
skillId = data.skillId
|
||||||
|
)
|
||||||
|
|
||||||
|
is RestSynchronisation.CharacterDelete -> characterService.deleteCharacter(
|
||||||
|
characterId = data.characterId,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3,12 +3,17 @@ package com.pixelized.server.lwa.server
|
||||||
|
|
||||||
import com.pixelized.server.lwa.extention.decodeFromFrame
|
import com.pixelized.server.lwa.extention.decodeFromFrame
|
||||||
import com.pixelized.server.lwa.extention.encodeToFrame
|
import com.pixelized.server.lwa.extention.encodeToFrame
|
||||||
import com.pixelized.server.lwa.model.campaign.CampaignService
|
import com.pixelized.server.lwa.server.rest.campaign.deleteCampaignCharacter
|
||||||
import com.pixelized.server.lwa.model.character.CharacterSheetService
|
import com.pixelized.server.lwa.server.rest.campaign.deleteCampaignNpc
|
||||||
|
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.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.shared.lwa.SERVER_PORT
|
import com.pixelized.shared.lwa.SERVER_PORT
|
||||||
import com.pixelized.shared.lwa.protocol.Message
|
|
||||||
import com.pixelized.shared.lwa.sharedModuleDependencies
|
import com.pixelized.shared.lwa.sharedModuleDependencies
|
||||||
import io.ktor.http.ContentType
|
|
||||||
import io.ktor.serialization.kotlinx.json.json
|
import io.ktor.serialization.kotlinx.json.json
|
||||||
import io.ktor.server.application.install
|
import io.ktor.server.application.install
|
||||||
import io.ktor.server.engine.EmbeddedServer
|
import io.ktor.server.engine.EmbeddedServer
|
||||||
|
|
@ -16,9 +21,10 @@ import io.ktor.server.engine.embeddedServer
|
||||||
import io.ktor.server.netty.Netty
|
import io.ktor.server.netty.Netty
|
||||||
import io.ktor.server.netty.NettyApplicationEngine
|
import io.ktor.server.netty.NettyApplicationEngine
|
||||||
import io.ktor.server.plugins.contentnegotiation.ContentNegotiation
|
import io.ktor.server.plugins.contentnegotiation.ContentNegotiation
|
||||||
import io.ktor.server.response.respond
|
import io.ktor.server.routing.delete
|
||||||
import io.ktor.server.response.respondText
|
|
||||||
import io.ktor.server.routing.get
|
import io.ktor.server.routing.get
|
||||||
|
import io.ktor.server.routing.put
|
||||||
|
import io.ktor.server.routing.route
|
||||||
import io.ktor.server.routing.routing
|
import io.ktor.server.routing.routing
|
||||||
import io.ktor.server.websocket.WebSockets
|
import io.ktor.server.websocket.WebSockets
|
||||||
import io.ktor.server.websocket.pingPeriod
|
import io.ktor.server.websocket.pingPeriod
|
||||||
|
|
@ -26,7 +32,6 @@ import io.ktor.server.websocket.timeout
|
||||||
import io.ktor.server.websocket.webSocket
|
import io.ktor.server.websocket.webSocket
|
||||||
import io.ktor.websocket.Frame
|
import io.ktor.websocket.Frame
|
||||||
import kotlinx.coroutines.channels.consumeEach
|
import kotlinx.coroutines.channels.consumeEach
|
||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
|
|
@ -40,7 +45,6 @@ typealias Server = EmbeddedServer<NettyApplicationEngine, NettyApplicationEngine
|
||||||
|
|
||||||
class LocalServer {
|
class LocalServer {
|
||||||
private var server: Server? = null
|
private var server: Server? = null
|
||||||
private val outgoingMessageBuffer = MutableSharedFlow<Message>()
|
|
||||||
|
|
||||||
fun create(
|
fun create(
|
||||||
port: Int = SERVER_PORT, // 16030
|
port: Int = SERVER_PORT, // 16030
|
||||||
|
|
@ -54,6 +58,8 @@ class LocalServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
val json by inject<Json>()
|
val json by inject<Json>()
|
||||||
|
val engine by inject<Engine>()
|
||||||
|
|
||||||
install(ContentNegotiation) {
|
install(ContentNegotiation) {
|
||||||
json(json)
|
json(json)
|
||||||
}
|
}
|
||||||
|
|
@ -65,40 +71,57 @@ class LocalServer {
|
||||||
masking = false
|
masking = false
|
||||||
}
|
}
|
||||||
|
|
||||||
val engine by inject<Engine>()
|
|
||||||
val characterService by inject<CharacterSheetService>()
|
|
||||||
val campaignService by inject<CampaignService>()
|
|
||||||
|
|
||||||
routing {
|
routing {
|
||||||
get(
|
|
||||||
path = "/",
|
|
||||||
body = {
|
|
||||||
call.respondText(contentType = ContentType.Text.Html) {
|
|
||||||
"""<html><body><ul>
|
|
||||||
<li><a href="http://127.0.0.1:16030/characters">characters</a></li>
|
|
||||||
<li><a href="http://127.0.0.1:16030/campaign">campaign</a></li>
|
|
||||||
</ul></body></html>"""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
get(
|
get(
|
||||||
path = "/characters",
|
path = "/characters",
|
||||||
body = {
|
body = engine.getCharacters(),
|
||||||
call.respond(characterService.character())
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
get(
|
route(path = "/character") {
|
||||||
path = "/campaign",
|
get(
|
||||||
body = {
|
path = "/detail",
|
||||||
call.respond(campaignService.campaign())
|
body = engine.getCharacter(),
|
||||||
|
)
|
||||||
|
put(
|
||||||
|
path = "/update",
|
||||||
|
body = engine.putCharacter(),
|
||||||
|
)
|
||||||
|
delete(
|
||||||
|
path = "/delete",
|
||||||
|
body = engine.deleteCharacter(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
route(path = "/campaign") {
|
||||||
|
get(
|
||||||
|
path = "",
|
||||||
|
body = engine.getCampaign(),
|
||||||
|
)
|
||||||
|
route(path = "/character") {
|
||||||
|
put(
|
||||||
|
path = "/update",
|
||||||
|
body = engine.putCampaignCharacter(),
|
||||||
|
)
|
||||||
|
delete(
|
||||||
|
path = "/delete",
|
||||||
|
body = engine.deleteCampaignCharacter(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
)
|
route(path = "/npc") {
|
||||||
|
put(
|
||||||
|
path = "/update",
|
||||||
|
body = engine.putCampaignNpc(),
|
||||||
|
)
|
||||||
|
delete(
|
||||||
|
path = "/delete",
|
||||||
|
body = engine.deleteCampaignNpc(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
webSocket(
|
webSocket(
|
||||||
path = "/ws",
|
path = "/ws",
|
||||||
handler = {
|
handler = {
|
||||||
val job = launch {
|
val job = launch {
|
||||||
// send local message to the clients
|
// send local message to the clients
|
||||||
outgoingMessageBuffer.collect { message ->
|
engine.webSocket.collect { message ->
|
||||||
send(json.encodeToFrame(message))
|
send(json.encodeToFrame(message))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -110,7 +133,7 @@ class LocalServer {
|
||||||
// log the message
|
// log the message
|
||||||
engine.handle(message)
|
engine.handle(message)
|
||||||
// broadcast to clients the message
|
// broadcast to clients the message
|
||||||
outgoingMessageBuffer.emit(message)
|
engine.webSocket.emit(message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.onFailure { exception ->
|
}.onFailure { exception ->
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
package com.pixelized.server.lwa.server.rest.campaign
|
||||||
|
|
||||||
|
import com.pixelized.server.lwa.server.Engine
|
||||||
|
import com.pixelized.shared.lwa.protocol.websocket.Message
|
||||||
|
import com.pixelized.shared.lwa.protocol.websocket.payload.RestSynchronisation
|
||||||
|
import io.ktor.http.HttpStatusCode
|
||||||
|
import io.ktor.server.response.respondText
|
||||||
|
|
||||||
|
fun Engine.deleteCampaignCharacter(): suspend io.ktor.server.routing.RoutingContext.() -> Unit {
|
||||||
|
return {
|
||||||
|
val id = call.queryParameters["id"]
|
||||||
|
val updated = id?.let { campaignService.removeCharacter(it) } ?: false
|
||||||
|
val code = when (updated) {
|
||||||
|
true -> HttpStatusCode.Accepted
|
||||||
|
else -> HttpStatusCode.UnprocessableEntity
|
||||||
|
}
|
||||||
|
call.respondText(
|
||||||
|
text = "$code",
|
||||||
|
status = code,
|
||||||
|
)
|
||||||
|
webSocket.emit(
|
||||||
|
Message(
|
||||||
|
from = "Server",
|
||||||
|
value = RestSynchronisation.Campaign,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
package com.pixelized.server.lwa.server.rest.campaign
|
||||||
|
|
||||||
|
import com.pixelized.server.lwa.server.Engine
|
||||||
|
import com.pixelized.shared.lwa.protocol.websocket.Message
|
||||||
|
import com.pixelized.shared.lwa.protocol.websocket.payload.RestSynchronisation
|
||||||
|
import io.ktor.http.HttpStatusCode
|
||||||
|
import io.ktor.server.response.respondText
|
||||||
|
|
||||||
|
fun Engine.deleteCampaignNpc(): suspend io.ktor.server.routing.RoutingContext.() -> Unit {
|
||||||
|
return {
|
||||||
|
val id = call.queryParameters["id"]
|
||||||
|
val updated = id?.let { campaignService.removeNpc(it) } ?: false
|
||||||
|
val code = when (updated) {
|
||||||
|
true -> HttpStatusCode.Accepted
|
||||||
|
else -> HttpStatusCode.UnprocessableEntity
|
||||||
|
}
|
||||||
|
call.respondText(
|
||||||
|
text = "$code",
|
||||||
|
status = code,
|
||||||
|
)
|
||||||
|
webSocket.emit(
|
||||||
|
Message(
|
||||||
|
from = "Server",
|
||||||
|
value = RestSynchronisation.Campaign,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
package com.pixelized.server.lwa.server.rest.campaign
|
||||||
|
|
||||||
|
import com.pixelized.server.lwa.server.Engine
|
||||||
|
import io.ktor.server.response.respond
|
||||||
|
|
||||||
|
fun Engine.getCampaign(): suspend io.ktor.server.routing.RoutingContext.() -> Unit {
|
||||||
|
return {
|
||||||
|
call.respond(campaignService.campaign())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
package com.pixelized.server.lwa.server.rest.campaign
|
||||||
|
|
||||||
|
import com.pixelized.server.lwa.server.Engine
|
||||||
|
import com.pixelized.shared.lwa.protocol.websocket.Message
|
||||||
|
import com.pixelized.shared.lwa.protocol.websocket.payload.RestSynchronisation
|
||||||
|
import io.ktor.http.HttpStatusCode
|
||||||
|
import io.ktor.server.response.respondText
|
||||||
|
|
||||||
|
fun Engine.putCampaignCharacter(): suspend io.ktor.server.routing.RoutingContext.() -> Unit {
|
||||||
|
return {
|
||||||
|
val id = call.queryParameters["id"]
|
||||||
|
val updated = id?.let { campaignService.addCharacter(it) } ?: false
|
||||||
|
val code = when (updated) {
|
||||||
|
true -> HttpStatusCode.Accepted
|
||||||
|
else -> HttpStatusCode.UnprocessableEntity
|
||||||
|
}
|
||||||
|
call.respondText(
|
||||||
|
text = "$code",
|
||||||
|
status = code,
|
||||||
|
)
|
||||||
|
webSocket.emit(
|
||||||
|
Message(
|
||||||
|
from = "Server",
|
||||||
|
value = RestSynchronisation.Campaign,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
package com.pixelized.server.lwa.server.rest.campaign
|
||||||
|
|
||||||
|
import com.pixelized.server.lwa.server.Engine
|
||||||
|
import com.pixelized.shared.lwa.protocol.websocket.Message
|
||||||
|
import com.pixelized.shared.lwa.protocol.websocket.payload.RestSynchronisation
|
||||||
|
import io.ktor.http.HttpStatusCode
|
||||||
|
import io.ktor.server.response.respondText
|
||||||
|
|
||||||
|
fun Engine.putCampaignNpc(): suspend io.ktor.server.routing.RoutingContext.() -> Unit {
|
||||||
|
return {
|
||||||
|
val id = call.queryParameters["id"]
|
||||||
|
val updated = id?.let { campaignService.addNpc(it) } ?: false
|
||||||
|
val code = when (updated) {
|
||||||
|
true -> HttpStatusCode.Accepted
|
||||||
|
else -> HttpStatusCode.UnprocessableEntity
|
||||||
|
}
|
||||||
|
call.respondText(
|
||||||
|
text = "$code",
|
||||||
|
status = code,
|
||||||
|
)
|
||||||
|
webSocket.emit(
|
||||||
|
Message(
|
||||||
|
from = "Server",
|
||||||
|
value = RestSynchronisation.Campaign,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
package com.pixelized.server.lwa.server.rest.character
|
||||||
|
|
||||||
|
import com.pixelized.server.lwa.server.Engine
|
||||||
|
import com.pixelized.shared.lwa.protocol.websocket.Message
|
||||||
|
import com.pixelized.shared.lwa.protocol.websocket.payload.RestSynchronisation
|
||||||
|
import io.ktor.http.HttpStatusCode
|
||||||
|
import io.ktor.server.response.respondText
|
||||||
|
|
||||||
|
fun Engine.deleteCharacter(): suspend io.ktor.server.routing.RoutingContext.() -> Unit {
|
||||||
|
return {
|
||||||
|
val id = call.parameters["id"]
|
||||||
|
val deleted = id?.let(characterService::deleteCharacter) ?: false
|
||||||
|
|
||||||
|
if (deleted && id != null) {
|
||||||
|
call.respondText(
|
||||||
|
text = "${HttpStatusCode.OK}",
|
||||||
|
status = HttpStatusCode.OK,
|
||||||
|
)
|
||||||
|
webSocket.emit(
|
||||||
|
Message(
|
||||||
|
from = "Server",
|
||||||
|
value = RestSynchronisation.CharacterDelete(characterId = id),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
call.respondText(
|
||||||
|
text = "${HttpStatusCode.UnprocessableEntity}",
|
||||||
|
status = HttpStatusCode.UnprocessableEntity,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
package com.pixelized.server.lwa.server.rest.character
|
||||||
|
|
||||||
|
import com.pixelized.server.lwa.server.Engine
|
||||||
|
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheetJson
|
||||||
|
import io.ktor.http.HttpStatusCode
|
||||||
|
import io.ktor.server.response.respond
|
||||||
|
import io.ktor.server.response.respondText
|
||||||
|
|
||||||
|
fun Engine.getCharacter(): suspend io.ktor.server.routing.RoutingContext.() -> Unit {
|
||||||
|
return {
|
||||||
|
val id = call.queryParameters["id"]
|
||||||
|
val body: CharacterSheetJson? = id?.let(characterService::character)
|
||||||
|
if (body != null) {
|
||||||
|
call.respond(body)
|
||||||
|
} else {
|
||||||
|
call.respondText(
|
||||||
|
text = "${HttpStatusCode.UnprocessableEntity}",
|
||||||
|
status = HttpStatusCode.UnprocessableEntity
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
package com.pixelized.server.lwa.server.rest.character
|
||||||
|
|
||||||
|
import com.pixelized.server.lwa.server.Engine
|
||||||
|
import io.ktor.server.response.respond
|
||||||
|
|
||||||
|
fun Engine.getCharacters(): suspend io.ktor.server.routing.RoutingContext.() -> Unit {
|
||||||
|
return {
|
||||||
|
call.respond(characterService.characters())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
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 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.updateCharacter(
|
||||||
|
character = form
|
||||||
|
)
|
||||||
|
call.respondText(
|
||||||
|
text = "${HttpStatusCode.OK}",
|
||||||
|
status = HttpStatusCode.OK
|
||||||
|
)
|
||||||
|
webSocket.emit(
|
||||||
|
Message(
|
||||||
|
from = "Server",
|
||||||
|
value = RestSynchronisation.CharacterUpdate(id = form.id),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,10 +2,10 @@ package com.pixelized.shared.lwa.model.campaign
|
||||||
|
|
||||||
data class Campaign(
|
data class Campaign(
|
||||||
val characters: Map<String, CharacterInstance>,
|
val characters: Map<String, CharacterInstance>,
|
||||||
|
val npcs: Map<String, CharacterInstance>,
|
||||||
) {
|
) {
|
||||||
data class CharacterInstance(
|
data class CharacterInstance(
|
||||||
val characteristic: Map<Characteristic, Int>,
|
val characteristic: Map<Characteristic, Int>,
|
||||||
val usedSkill: List<String>,
|
|
||||||
) {
|
) {
|
||||||
enum class Characteristic {
|
enum class Characteristic {
|
||||||
Damage,
|
Damage,
|
||||||
|
|
@ -16,6 +16,7 @@ data class Campaign(
|
||||||
companion object {
|
companion object {
|
||||||
val EMPTY = Campaign(
|
val EMPTY = Campaign(
|
||||||
characters = emptyMap(),
|
characters = emptyMap(),
|
||||||
|
npcs = emptyMap(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -23,10 +24,12 @@ data class Campaign(
|
||||||
fun Campaign.character(id: String): Campaign.CharacterInstance {
|
fun Campaign.character(id: String): Campaign.CharacterInstance {
|
||||||
return characters[id] ?: Campaign.CharacterInstance(
|
return characters[id] ?: Campaign.CharacterInstance(
|
||||||
characteristic = emptyMap(),
|
characteristic = emptyMap(),
|
||||||
usedSkill = emptyList(),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val Campaign.CharacterInstance.level
|
||||||
|
get() = characteristic[Campaign.CharacterInstance.Characteristic.Damage] ?: 1
|
||||||
|
|
||||||
val Campaign.CharacterInstance.damage
|
val Campaign.CharacterInstance.damage
|
||||||
get() = characteristic[Campaign.CharacterInstance.Characteristic.Damage] ?: 0
|
get() = characteristic[Campaign.CharacterInstance.Characteristic.Damage] ?: 0
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,17 +14,21 @@ class CampaignJsonFactory {
|
||||||
json: CampaignJsonV1,
|
json: CampaignJsonV1,
|
||||||
): Campaign {
|
): Campaign {
|
||||||
return Campaign(
|
return Campaign(
|
||||||
characters = json.characters.map { entry ->
|
characters = json.characters.mapValues { convertFromV1(json = it.value) },
|
||||||
entry.key to Campaign.CharacterInstance(
|
npcs = json.npcs.mapValues { convertFromV1(json = it.value) },
|
||||||
characteristic = entry.value.characteristic.map { char ->
|
)
|
||||||
when (char.key) {
|
}
|
||||||
CampaignJsonV1.CharacterInstanceJson.Characteristic.Damage -> Campaign.CharacterInstance.Characteristic.Damage
|
|
||||||
CampaignJsonV1.CharacterInstanceJson.Characteristic.Power -> Campaign.CharacterInstance.Characteristic.Power
|
private fun convertFromV1(
|
||||||
} to char.value
|
json: CampaignJsonV1.CharacterInstanceJson,
|
||||||
}.toMap(),
|
): Campaign.CharacterInstance {
|
||||||
usedSkill = entry.value.usedSkill,
|
return Campaign.CharacterInstance(
|
||||||
)
|
characteristic = json.characteristic.map { char ->
|
||||||
}.toMap()
|
when (char.key) {
|
||||||
|
CampaignJsonV1.CharacterInstanceJson.Characteristic.Damage -> Campaign.CharacterInstance.Characteristic.Damage
|
||||||
|
CampaignJsonV1.CharacterInstanceJson.Characteristic.Power -> Campaign.CharacterInstance.Characteristic.Power
|
||||||
|
} to char.value
|
||||||
|
}.toMap(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -32,17 +36,21 @@ class CampaignJsonFactory {
|
||||||
data: Campaign,
|
data: Campaign,
|
||||||
): CampaignJson {
|
): CampaignJson {
|
||||||
return CampaignJsonV1(
|
return CampaignJsonV1(
|
||||||
characters = data.characters.map { entry ->
|
characters = data.characters.mapValues { convertToJson(data = it.value) },
|
||||||
entry.key to CampaignJsonV1.CharacterInstanceJson(
|
npcs = data.npcs.mapValues { convertToJson(data = it.value) },
|
||||||
characteristic = entry.value.characteristic.map { char ->
|
)
|
||||||
when (char.key) {
|
}
|
||||||
Campaign.CharacterInstance.Characteristic.Damage -> CampaignJsonV1.CharacterInstanceJson.Characteristic.Damage
|
|
||||||
Campaign.CharacterInstance.Characteristic.Power -> CampaignJsonV1.CharacterInstanceJson.Characteristic.Power
|
private fun convertToJson(
|
||||||
} to char.value
|
data: Campaign.CharacterInstance,
|
||||||
}.toMap(),
|
): CampaignJsonV1.CharacterInstanceJson {
|
||||||
usedSkill = entry.value.usedSkill,
|
return CampaignJsonV1.CharacterInstanceJson(
|
||||||
)
|
characteristic = data.characteristic.map { char ->
|
||||||
}.toMap()
|
when (char.key) {
|
||||||
|
Campaign.CharacterInstance.Characteristic.Damage -> CampaignJsonV1.CharacterInstanceJson.Characteristic.Damage
|
||||||
|
Campaign.CharacterInstance.Characteristic.Power -> CampaignJsonV1.CharacterInstanceJson.Characteristic.Power
|
||||||
|
} to char.value
|
||||||
|
}.toMap(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -5,12 +5,12 @@ import kotlinx.serialization.Serializable
|
||||||
@Serializable
|
@Serializable
|
||||||
data class CampaignJsonV1(
|
data class CampaignJsonV1(
|
||||||
val characters: Map<String, CharacterInstanceJson>,
|
val characters: Map<String, CharacterInstanceJson>,
|
||||||
|
val npcs: Map<String, CharacterInstanceJson>,
|
||||||
) : CampaignJson {
|
) : CampaignJson {
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class CharacterInstanceJson(
|
data class CharacterInstanceJson(
|
||||||
val characteristic: Map<Characteristic, Int>,
|
val characteristic: Map<Characteristic, Int>,
|
||||||
val usedSkill: List<String>,
|
|
||||||
) {
|
) {
|
||||||
enum class Characteristic {
|
enum class Characteristic {
|
||||||
Damage,
|
Damage,
|
||||||
|
|
|
||||||
|
|
@ -3,4 +3,6 @@ package com.pixelized.shared.lwa.model.characterSheet
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
sealed interface CharacterSheetJson
|
sealed interface CharacterSheetJson {
|
||||||
|
val id: String
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package com.pixelized.shared.lwa.model.characterSheet
|
package com.pixelized.shared.lwa.model.characterSheet
|
||||||
|
|
||||||
|
import com.pixelized.shared.lwa.protocol.rest.CharacterPreviewJson
|
||||||
import com.pixelized.shared.lwa.usecase.CharacterSheetUseCase
|
import com.pixelized.shared.lwa.usecase.CharacterSheetUseCase
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -98,6 +99,16 @@ class CharacterSheetJsonFactory(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun convertToPreviewJson(
|
||||||
|
sheet: CharacterSheet,
|
||||||
|
): CharacterPreviewJson {
|
||||||
|
return CharacterPreviewJson(
|
||||||
|
id = sheet.id,
|
||||||
|
name = sheet.name,
|
||||||
|
level = sheet.level,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fun convertToJson(
|
fun convertToJson(
|
||||||
sheet: CharacterSheet,
|
sheet: CharacterSheet,
|
||||||
): CharacterSheetJson {
|
): CharacterSheetJson {
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class CharacterSheetJsonV1(
|
data class CharacterSheetJsonV1(
|
||||||
val id: String,
|
override val id: String,
|
||||||
val name: String,
|
val name: String,
|
||||||
val portrait: String?,
|
val portrait: String?,
|
||||||
val thumbnail: String?,
|
val thumbnail: String?,
|
||||||
|
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
package com.pixelized.shared.lwa.protocol
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class Message(
|
|
||||||
val from: String,
|
|
||||||
val type: MessageType,
|
|
||||||
val value: String,
|
|
||||||
)
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
package com.pixelized.shared.lwa.protocol
|
|
||||||
|
|
||||||
enum class MessageType {
|
|
||||||
Roll,
|
|
||||||
UpdateSkillUsage,
|
|
||||||
UpdatePlayerCharacteristic,
|
|
||||||
}
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
package com.pixelized.shared.lwa.protocol.payload
|
|
||||||
|
|
||||||
sealed interface MessagePayload
|
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
package com.pixelized.shared.lwa.protocol.rest
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
class CharacterPreviewJson(
|
||||||
|
val id: String,
|
||||||
|
val name: String,
|
||||||
|
val level: Int,
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
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,6 @@
|
||||||
|
package com.pixelized.shared.lwa.protocol.websocket.payload
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
sealed interface MessagePayload
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
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 object Campaign : RestSynchronisation()
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package com.pixelized.shared.lwa.protocol.payload
|
package com.pixelized.shared.lwa.protocol.websocket.payload
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package com.pixelized.shared.lwa.protocol.payload
|
package com.pixelized.shared.lwa.protocol.websocket.payload
|
||||||
|
|
||||||
import com.pixelized.shared.lwa.model.campaign.Campaign
|
import com.pixelized.shared.lwa.model.campaign.Campaign
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package com.pixelized.shared.lwa.protocol.payload
|
package com.pixelized.shared.lwa.protocol.websocket.payload
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
|
@ -57,32 +57,49 @@ class CharacterSheetUseCase {
|
||||||
return (constitution / 3)
|
return (constitution / 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update character sheet.
|
||||||
|
|
||||||
|
fun updateLevel(
|
||||||
|
character: CharacterSheet,
|
||||||
|
level: Int,
|
||||||
|
): CharacterSheet {
|
||||||
|
return character.copy(
|
||||||
|
level = level,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateSkillLevel(
|
||||||
|
character: CharacterSheet,
|
||||||
|
skillId: String,
|
||||||
|
level: Int,
|
||||||
|
): CharacterSheet {
|
||||||
|
return character.copy(
|
||||||
|
commonSkills = character.commonSkills.map { skill ->
|
||||||
|
skill.takeIf { skill.id == skillId }?.copy(level = level) ?: skill
|
||||||
|
},
|
||||||
|
specialSkills = character.specialSkills.map { skill ->
|
||||||
|
skill.takeIf { skill.id == skillId }?.copy(level = level) ?: skill
|
||||||
|
},
|
||||||
|
magicSkills = character.magicSkills.map { skill ->
|
||||||
|
skill.takeIf { skill.id == skillId }?.copy(level = level) ?: skill
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fun updateSkillUsage(
|
fun updateSkillUsage(
|
||||||
character: CharacterSheet,
|
character: CharacterSheet,
|
||||||
skillId: String,
|
skillId: String,
|
||||||
): CharacterSheet {
|
): CharacterSheet {
|
||||||
return character.copy(
|
return character.copy(
|
||||||
commonSkills = character.commonSkills.map { skill ->
|
commonSkills = character.commonSkills.map { skill ->
|
||||||
if (skill.id == skillId) {
|
skill.takeIf { skill.id == skillId }?.copy(used = skill.used.not()) ?: skill
|
||||||
skill.copy(used = skill.used.not())
|
|
||||||
} else {
|
|
||||||
skill
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
specialSkills = character.specialSkills.map { skill ->
|
specialSkills = character.specialSkills.map { skill ->
|
||||||
if (skill.id == skillId) {
|
skill.takeIf { skill.id == skillId }?.copy(used = skill.used.not()) ?: skill
|
||||||
skill.copy(used = skill.used.not())
|
|
||||||
} else {
|
|
||||||
skill
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
magicSkills = character.magicSkills.map { skill ->
|
magicSkills = character.magicSkills.map { skill ->
|
||||||
if (skill.id == skillId) {
|
skill.takeIf { skill.id == skillId }?.copy(used = skill.used.not()) ?: skill
|
||||||
skill.copy(used = skill.used.not())
|
},
|
||||||
} else {
|
|
||||||
skill
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue