Update client to add throw consume equip to InventoryItem.
This commit is contained in:
parent
9fce3f1cb8
commit
ae820f5979
22 changed files with 791 additions and 121 deletions
|
|
@ -1,5 +1,7 @@
|
|||
package com.pixelized.server.lwa.model.inventory
|
||||
|
||||
import com.pixelized.server.lwa.model.item.ItemStore
|
||||
import com.pixelized.server.lwa.server.exception.BusinessException
|
||||
import com.pixelized.shared.lwa.model.inventory.Inventory
|
||||
import com.pixelized.shared.lwa.model.inventory.InventoryJson
|
||||
import com.pixelized.shared.lwa.model.inventory.factory.InventoryJsonFactory
|
||||
|
|
@ -9,9 +11,11 @@ import kotlinx.coroutines.Job
|
|||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import java.util.UUID
|
||||
|
||||
class InventoryService(
|
||||
private val inventoryStore: InventoryStore,
|
||||
private val itemStore: ItemStore,
|
||||
private val factory: InventoryJsonFactory,
|
||||
) {
|
||||
private val scope = CoroutineScope(Dispatchers.IO + Job())
|
||||
|
|
@ -51,13 +55,185 @@ class InventoryService(
|
|||
}
|
||||
|
||||
@Throws
|
||||
fun createItem(
|
||||
fun createInventoryItem(
|
||||
characterSheetId: String,
|
||||
itemId: String,
|
||||
) : String {
|
||||
return inventoryStore.createItem(
|
||||
characterSheetId = characterSheetId,
|
||||
): String {
|
||||
// get the inventory of the character, if none create one.
|
||||
val inventory = inventoryStore.inventoryFlow().value[characterSheetId]
|
||||
?: Inventory.empty(characterSheetId = characterSheetId)
|
||||
// create an inventoryId.
|
||||
val inventoryId = inventory.items.createInventoryId()
|
||||
// create an inventory Item.
|
||||
val item = Inventory.Item(
|
||||
inventoryId = inventoryId,
|
||||
itemId = itemId,
|
||||
count = 1f,
|
||||
equipped = false,
|
||||
)
|
||||
// update the inventory with the updated item.
|
||||
val updatedInventory = inventory.copy(
|
||||
items = inventory.items.toMutableList().also {
|
||||
it.add(item)
|
||||
}
|
||||
)
|
||||
// save the inventory
|
||||
inventoryStore.save(
|
||||
inventory = updatedInventory,
|
||||
create = false,
|
||||
)
|
||||
return inventoryId
|
||||
}
|
||||
|
||||
@Throws
|
||||
fun changeInventoryItemCount(
|
||||
characterSheetId: String,
|
||||
inventoryId: String,
|
||||
count: Float,
|
||||
) {
|
||||
if (count < 0) {
|
||||
throw BusinessException(
|
||||
message = "InventoryItem (id:$inventoryId) quantity cannot go below 0.",
|
||||
)
|
||||
}
|
||||
// get the inventory of the character, if none create one.
|
||||
val inventory = inventoryStore.inventoryFlow().value[characterSheetId]
|
||||
?: Inventory.empty(characterSheetId = characterSheetId)
|
||||
// Guard case.
|
||||
val inventoryItemIndex = inventory.items.indexOfFirst { it.inventoryId == inventoryId }
|
||||
if (inventoryItemIndex < 0) {
|
||||
throw BusinessException(
|
||||
message = "InventoryItem (id:$inventoryId) not found in Inventory(characterSheetId:$characterSheetId).",
|
||||
)
|
||||
}
|
||||
// update the inventory with the updated item.
|
||||
val updatedInventory = inventory.copy(
|
||||
items = inventory.items.toMutableList().also { items ->
|
||||
if (count == 0f) {
|
||||
items.removeAt(inventoryItemIndex)
|
||||
} else {
|
||||
items[inventoryItemIndex] = items[inventoryItemIndex].copy(count = count)
|
||||
}
|
||||
}
|
||||
)
|
||||
// save the inventory
|
||||
inventoryStore.save(
|
||||
inventory = updatedInventory,
|
||||
create = false,
|
||||
)
|
||||
}
|
||||
|
||||
@Throws
|
||||
fun consumeInventoryItem(
|
||||
characterSheetId: String,
|
||||
inventoryId: String,
|
||||
) {
|
||||
// get the inventory of the character, if none create one.
|
||||
val inventory = inventoryStore.inventoryFlow().value[characterSheetId]
|
||||
?: Inventory.empty(characterSheetId = characterSheetId)
|
||||
// Guard case.
|
||||
val inventoryItemIndex = inventory.items.indexOfFirst { it.inventoryId == inventoryId }
|
||||
if (inventoryItemIndex < 0) {
|
||||
throw BusinessException(
|
||||
message = "InventoryItem (id:$inventoryId) not found in Inventory(characterSheetId:$characterSheetId).",
|
||||
)
|
||||
}
|
||||
// other Guard case.
|
||||
val itemId = inventory.items[inventoryItemIndex].itemId
|
||||
val item = itemStore.item(itemId = itemId)
|
||||
?: throw BusinessException(message = "Item (id:$itemId) not found.")
|
||||
if (item.options.consumable.not()) {
|
||||
throw BusinessException(message = "Item (id:$itemId) is not consumable.")
|
||||
}
|
||||
// update the inventory with the updated item.
|
||||
val updatedInventory = inventory.copy(
|
||||
items = inventory.items.toMutableList().also { items ->
|
||||
val inventoryItem = inventory.items[inventoryItemIndex]
|
||||
if (inventoryItem.count - 1f <= 0f) {
|
||||
items.removeAt(inventoryItemIndex)
|
||||
} else {
|
||||
items[inventoryItemIndex] = inventoryItem.copy(count = inventoryItem.count - 1f)
|
||||
}
|
||||
}
|
||||
)
|
||||
// save the inventory
|
||||
inventoryStore.save(
|
||||
inventory = updatedInventory,
|
||||
create = false,
|
||||
)
|
||||
}
|
||||
|
||||
@Throws
|
||||
fun equipInventoryItem(
|
||||
characterSheetId: String,
|
||||
inventoryId: String,
|
||||
equip: Boolean,
|
||||
) {
|
||||
// get the inventory of the character, if none create one.
|
||||
val inventory = inventoryStore.inventoryFlow().value[characterSheetId]
|
||||
?: Inventory.empty(characterSheetId = characterSheetId)
|
||||
// Guard case.
|
||||
val inventoryItemIndex = inventory.items.indexOfFirst { it.inventoryId == inventoryId }
|
||||
if (inventoryItemIndex < 0) {
|
||||
throw BusinessException(
|
||||
message = "InventoryItem (id:$inventoryId) not found in Inventory(characterSheetId:$characterSheetId).",
|
||||
)
|
||||
}
|
||||
// other Guard case.
|
||||
val itemId = inventory.items[inventoryItemIndex].itemId
|
||||
val item = itemStore.item(itemId = itemId)
|
||||
?: throw BusinessException(message = "Item (id:$itemId) not found.")
|
||||
if (item.options.equipable.not()) {
|
||||
throw BusinessException(message = "Item (id:$itemId) is not equipable.")
|
||||
}
|
||||
// update the inventory with the updated item.
|
||||
val updatedInventory = inventory.copy(
|
||||
items = inventory.items.toMutableList().also { items ->
|
||||
items[inventoryItemIndex] = inventory.items[inventoryItemIndex].copy(
|
||||
equipped = equip
|
||||
)
|
||||
}
|
||||
)
|
||||
// save the inventory
|
||||
inventoryStore.save(
|
||||
inventory = updatedInventory,
|
||||
create = false,
|
||||
)
|
||||
}
|
||||
|
||||
@Throws
|
||||
fun deleteInventoryItem(
|
||||
characterSheetId: String,
|
||||
inventoryId: String,
|
||||
) {
|
||||
// get the inventory of the character, if none create one.
|
||||
val inventory = inventoryStore.inventoryFlow().value[characterSheetId]
|
||||
?: Inventory.empty(characterSheetId = characterSheetId)
|
||||
// Guard case.
|
||||
val inventoryItemIndex = inventory.items.indexOfFirst { it.inventoryId == inventoryId }
|
||||
if (inventoryItemIndex < 0) {
|
||||
throw BusinessException(
|
||||
message = "InventoryItem (id:$inventoryId) not found in Inventory(characterSheetId:$characterSheetId)",
|
||||
)
|
||||
}
|
||||
// update the inventory with the updated item.
|
||||
val updatedInventory = inventory.copy(
|
||||
items = inventory.items.toMutableList().also { items ->
|
||||
items.removeAt(inventoryItemIndex)
|
||||
}
|
||||
)
|
||||
// save the inventory
|
||||
inventoryStore.save(
|
||||
inventory = updatedInventory,
|
||||
create = false,
|
||||
)
|
||||
}
|
||||
|
||||
private fun List<Inventory.Item>.createInventoryId(): String {
|
||||
var inventoryId: String
|
||||
do {
|
||||
inventoryId = UUID.randomUUID().toString()
|
||||
} while (any { inventoryId == it.inventoryId })
|
||||
return inventoryId
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -153,49 +153,7 @@ class InventoryStore(
|
|||
}
|
||||
}
|
||||
|
||||
@Throws
|
||||
fun createItem(
|
||||
characterSheetId: String,
|
||||
itemId: String,
|
||||
): String {
|
||||
val (updatedInventory, inventoryId) = inventoryFlow.value.toMutableMap().let { characters ->
|
||||
// get the inventory of the character, if none create one.
|
||||
val inventory = characters[characterSheetId]
|
||||
?: Inventory.empty(characterSheetId = characterSheetId)
|
||||
// create an inventoryId.
|
||||
val inventoryId = inventory.items.createInventoryId()
|
||||
// create an inventory Item.
|
||||
val item = Inventory.Item(
|
||||
inventoryId = inventoryId,
|
||||
itemId = itemId,
|
||||
count = 1f,
|
||||
equipped = false,
|
||||
)
|
||||
// update the inventory with the updated item.
|
||||
inventory.copy(
|
||||
items = inventory.items.toMutableList().also {
|
||||
it.add(item)
|
||||
}
|
||||
) to inventoryId
|
||||
}
|
||||
// save the inventory
|
||||
save(
|
||||
inventory = updatedInventory,
|
||||
create = false,
|
||||
)
|
||||
// return the inventory ID.
|
||||
return inventoryId
|
||||
}
|
||||
|
||||
private fun inventoryFile(id: String): File {
|
||||
return File("${pathProvider.inventoryPath()}${id}.json")
|
||||
}
|
||||
|
||||
private fun List<Inventory.Item>.createInventoryId(): String {
|
||||
var inventoryId: String
|
||||
do {
|
||||
inventoryId = UUID.randomUUID().toString()
|
||||
} while (any { inventoryId == it.inventoryId })
|
||||
return inventoryId
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,10 @@ class ItemStore(
|
|||
}
|
||||
}
|
||||
|
||||
fun item(itemId: String?): Item? {
|
||||
return itemFlow.value.firstOrNull { it.id == itemId }
|
||||
}
|
||||
|
||||
fun itemsFlow(): StateFlow<List<Item>> = itemFlow
|
||||
|
||||
private fun updateItemsFlow() {
|
||||
|
|
|
|||
|
|
@ -19,8 +19,12 @@ 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.server.lwa.server.rest.inventory.createInventory
|
||||
import com.pixelized.server.lwa.server.rest.inventory.changeInventoryItemCount
|
||||
import com.pixelized.server.lwa.server.rest.inventory.consumeInventoryItem
|
||||
import com.pixelized.server.lwa.server.rest.inventory.createInventoryItem
|
||||
import com.pixelized.server.lwa.server.rest.inventory.equipInventoryItem
|
||||
import com.pixelized.server.lwa.server.rest.inventory.deleteInventory
|
||||
import com.pixelized.server.lwa.server.rest.inventory.deleteInventoryItem
|
||||
import com.pixelized.server.lwa.server.rest.inventory.getInventory
|
||||
import com.pixelized.server.lwa.server.rest.inventory.putInventory
|
||||
import com.pixelized.server.lwa.server.rest.item.deleteItem
|
||||
|
|
@ -218,7 +222,7 @@ class LocalServer {
|
|||
body = engine.deleteAlteration()
|
||||
)
|
||||
}
|
||||
route(path = "item") {
|
||||
route(path = "/item") {
|
||||
get(
|
||||
path = "/all",
|
||||
body = engine.getItems(),
|
||||
|
|
@ -236,7 +240,7 @@ class LocalServer {
|
|||
body = engine.deleteItem(),
|
||||
)
|
||||
}
|
||||
route(path = "tag") {
|
||||
route(path = "/tag") {
|
||||
get(
|
||||
path = "/character",
|
||||
body = engine.getCharacterTags(),
|
||||
|
|
@ -250,7 +254,7 @@ class LocalServer {
|
|||
body = engine.getItemTags(),
|
||||
)
|
||||
}
|
||||
route(path = "inventory") {
|
||||
route(path = "/inventory") {
|
||||
get(
|
||||
path = "/detail",
|
||||
body = engine.getInventory(),
|
||||
|
|
@ -259,14 +263,34 @@ class LocalServer {
|
|||
path = "/update",
|
||||
body = engine.putInventory()
|
||||
)
|
||||
put(
|
||||
path = "/create",
|
||||
body = engine.createInventory()
|
||||
)
|
||||
delete(
|
||||
path = "/delete",
|
||||
body = engine.deleteInventory()
|
||||
)
|
||||
route(
|
||||
path = "/item"
|
||||
) {
|
||||
put(
|
||||
path = "/create",
|
||||
body = engine.createInventoryItem()
|
||||
)
|
||||
put(
|
||||
path = "/count",
|
||||
body = engine.changeInventoryItemCount()
|
||||
)
|
||||
put(
|
||||
path = "/consume",
|
||||
body = engine.consumeInventoryItem()
|
||||
)
|
||||
put(
|
||||
path = "/equip",
|
||||
body = engine.equipInventoryItem()
|
||||
)
|
||||
delete(
|
||||
path = "/delete",
|
||||
body = engine.deleteInventoryItem()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
package com.pixelized.server.lwa.server.rest.inventory
|
||||
|
||||
import com.pixelized.server.lwa.server.Engine
|
||||
import com.pixelized.server.lwa.utils.extentions.characterSheetId
|
||||
import com.pixelized.server.lwa.utils.extentions.exception
|
||||
import com.pixelized.server.lwa.utils.extentions.inventoryId
|
||||
import com.pixelized.server.lwa.utils.extentions.itemId
|
||||
import com.pixelized.shared.lwa.protocol.rest.APIResponse
|
||||
import com.pixelized.shared.lwa.protocol.websocket.ApiSynchronisation
|
||||
import io.ktor.server.response.respond
|
||||
import io.ktor.server.routing.RoutingContext
|
||||
|
||||
fun Engine.deleteInventoryItem(): suspend RoutingContext.() -> Unit {
|
||||
return {
|
||||
try {
|
||||
// get the query parameter
|
||||
val characterSheetId = call.queryParameters.characterSheetId
|
||||
val inventoryId = call.queryParameters.inventoryId
|
||||
// add the item to the inventory.
|
||||
inventoryService.deleteInventoryItem(
|
||||
characterSheetId = characterSheetId,
|
||||
inventoryId = inventoryId,
|
||||
)
|
||||
// API & WebSocket responses.
|
||||
call.respond(
|
||||
message = APIResponse.success(),
|
||||
)
|
||||
webSocket.emit(
|
||||
value = ApiSynchronisation.InventoryUpdate(
|
||||
timestamp = System.currentTimeMillis(),
|
||||
characterSheetId = characterSheetId,
|
||||
),
|
||||
)
|
||||
} catch (exception: Exception) {
|
||||
call.exception(
|
||||
exception = exception,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
package com.pixelized.server.lwa.server.rest.inventory
|
||||
|
||||
import com.pixelized.server.lwa.server.Engine
|
||||
import com.pixelized.server.lwa.utils.extentions.characterSheetId
|
||||
import com.pixelized.server.lwa.utils.extentions.count
|
||||
import com.pixelized.server.lwa.utils.extentions.exception
|
||||
import com.pixelized.server.lwa.utils.extentions.inventoryId
|
||||
import com.pixelized.shared.lwa.protocol.rest.APIResponse
|
||||
import com.pixelized.shared.lwa.protocol.websocket.ApiSynchronisation
|
||||
import io.ktor.server.response.respond
|
||||
import io.ktor.server.routing.RoutingContext
|
||||
|
||||
fun Engine.changeInventoryItemCount(): suspend RoutingContext.() -> Unit {
|
||||
return {
|
||||
try {
|
||||
// get the query parameter
|
||||
val characterSheetId = call.queryParameters.characterSheetId
|
||||
val inventoryId = call.queryParameters.inventoryId
|
||||
val count = call.queryParameters.count
|
||||
// add the item to the inventory.
|
||||
inventoryService.changeInventoryItemCount(
|
||||
characterSheetId = characterSheetId,
|
||||
inventoryId = inventoryId,
|
||||
count = count,
|
||||
)
|
||||
// API & WebSocket responses.
|
||||
call.respond(
|
||||
message = APIResponse.success(),
|
||||
)
|
||||
webSocket.emit(
|
||||
value = ApiSynchronisation.InventoryUpdate(
|
||||
timestamp = System.currentTimeMillis(),
|
||||
characterSheetId = characterSheetId,
|
||||
),
|
||||
)
|
||||
} catch (exception: Exception) {
|
||||
call.exception(
|
||||
exception = exception,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
package com.pixelized.server.lwa.server.rest.inventory
|
||||
|
||||
import com.pixelized.server.lwa.server.Engine
|
||||
import com.pixelized.server.lwa.utils.extentions.characterSheetId
|
||||
import com.pixelized.server.lwa.utils.extentions.exception
|
||||
import com.pixelized.server.lwa.utils.extentions.inventoryId
|
||||
import com.pixelized.shared.lwa.protocol.rest.APIResponse
|
||||
import com.pixelized.shared.lwa.protocol.websocket.ApiSynchronisation
|
||||
import io.ktor.server.response.respond
|
||||
import io.ktor.server.routing.RoutingContext
|
||||
|
||||
fun Engine.consumeInventoryItem(): suspend RoutingContext.() -> Unit {
|
||||
return {
|
||||
try {
|
||||
// get the query parameter
|
||||
val characterSheetId = call.queryParameters.characterSheetId
|
||||
val inventoryId = call.queryParameters.inventoryId
|
||||
// add the item to the inventory.
|
||||
inventoryService.consumeInventoryItem(
|
||||
characterSheetId = characterSheetId,
|
||||
inventoryId = inventoryId,
|
||||
)
|
||||
// API & WebSocket responses.
|
||||
call.respond(
|
||||
message = APIResponse.success(),
|
||||
)
|
||||
webSocket.emit(
|
||||
value = ApiSynchronisation.InventoryUpdate(
|
||||
timestamp = System.currentTimeMillis(),
|
||||
characterSheetId = characterSheetId,
|
||||
),
|
||||
)
|
||||
} catch (exception: Exception) {
|
||||
call.exception(
|
||||
exception = exception,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package com.pixelized.server.lwa.server.rest.inventory
|
||||
|
||||
import com.pixelized.server.lwa.server.Engine
|
||||
import com.pixelized.server.lwa.utils.extentions.characterSheetId
|
||||
import com.pixelized.server.lwa.utils.extentions.equip
|
||||
import com.pixelized.server.lwa.utils.extentions.exception
|
||||
import com.pixelized.server.lwa.utils.extentions.inventoryId
|
||||
import com.pixelized.shared.lwa.protocol.rest.APIResponse
|
||||
import com.pixelized.shared.lwa.protocol.websocket.ApiSynchronisation
|
||||
import io.ktor.server.response.respond
|
||||
import io.ktor.server.routing.RoutingContext
|
||||
|
||||
fun Engine.equipInventoryItem(): suspend RoutingContext.() -> Unit {
|
||||
return {
|
||||
try {
|
||||
// get the query parameter
|
||||
val characterSheetId = call.queryParameters.characterSheetId
|
||||
val inventoryId = call.queryParameters.inventoryId
|
||||
val equip = call.queryParameters.equip
|
||||
|
||||
// add the item to the inventory.
|
||||
inventoryService.equipInventoryItem(
|
||||
characterSheetId = characterSheetId,
|
||||
inventoryId = inventoryId,
|
||||
equip = equip,
|
||||
)
|
||||
// API & WebSocket responses.
|
||||
call.respond(
|
||||
message = APIResponse.success(),
|
||||
)
|
||||
webSocket.emit(
|
||||
value = ApiSynchronisation.InventoryUpdate(
|
||||
timestamp = System.currentTimeMillis(),
|
||||
characterSheetId = characterSheetId,
|
||||
),
|
||||
)
|
||||
} catch (exception: Exception) {
|
||||
call.exception(
|
||||
exception = exception,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -9,14 +9,14 @@ import com.pixelized.shared.lwa.protocol.websocket.ApiSynchronisation
|
|||
import io.ktor.server.response.respond
|
||||
import io.ktor.server.routing.RoutingContext
|
||||
|
||||
fun Engine.createInventory(): suspend RoutingContext.() -> Unit {
|
||||
fun Engine.createInventoryItem(): suspend RoutingContext.() -> Unit {
|
||||
return {
|
||||
try {
|
||||
// get the query parameter
|
||||
val characterSheetId = call.queryParameters.characterSheetId
|
||||
val itemId = call.queryParameters.itemId
|
||||
// add the item to the inventory.
|
||||
val inventoryId = inventoryService.createItem(
|
||||
val inventoryId = inventoryService.createInventoryItem(
|
||||
characterSheetId = characterSheetId,
|
||||
itemId = itemId,
|
||||
)
|
||||
|
|
@ -10,6 +10,7 @@ inline fun <reified T> Parameters.param(
|
|||
): T {
|
||||
return when (T::class) {
|
||||
String::class -> this[name] as? T
|
||||
Float::class -> this[name]?.toFloatOrNull() as? T
|
||||
Boolean::class -> this[name]?.toBooleanStrictOrNull() as? T
|
||||
else -> null
|
||||
} ?: throw MissingParameterException(
|
||||
|
|
@ -30,12 +31,24 @@ val Parameters.alterationId: String
|
|||
code = APIResponse.ErrorCode.AlterationId,
|
||||
)
|
||||
|
||||
val Parameters.inventoryId: String
|
||||
get() = param(
|
||||
name = "inventoryId",
|
||||
code = APIResponse.ErrorCode.InventoryId,
|
||||
)
|
||||
|
||||
val Parameters.itemId: String
|
||||
get() = param(
|
||||
name = "itemId",
|
||||
code = APIResponse.ErrorCode.ItemId,
|
||||
)
|
||||
|
||||
val Parameters.count: Float
|
||||
get() = param(
|
||||
name = "count",
|
||||
code = APIResponse.ErrorCode.Count,
|
||||
)
|
||||
|
||||
val Parameters.create: Boolean
|
||||
get() = param(
|
||||
name = "create",
|
||||
|
|
@ -46,4 +59,10 @@ val Parameters.active: Boolean
|
|||
get() = param(
|
||||
name = "active",
|
||||
code = APIResponse.ErrorCode.Active,
|
||||
)
|
||||
|
||||
val Parameters.equip: Boolean
|
||||
get() = param(
|
||||
name = "equip",
|
||||
code = APIResponse.ErrorCode.Equip,
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue