initial commit of functioning opening tracking

This commit is contained in:
Sheldan
2024-01-06 23:29:25 +01:00
parent b72c68dfe5
commit 45e7982330
176 changed files with 37635 additions and 0 deletions

View File

@@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>dev.sheldan.gw2.tools</groupId>
<artifactId>gw2-tools</artifactId>
<version>0.0.9-SNAPSHOT</version>
</parent>
<artifactId>gw2-api-client</artifactId>
<build>
<sourceDirectory>src/main/kotlin</sourceDirectory>
<testSourceDirectory>src/test/kotlin</testSourceDirectory>
<plugins>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<executions>
<execution>
<id>compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>test-compile</id>
<phase>test-compile</phase>
<goals>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-test-junit5</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
</dependency>
<dependency>
<groupId>io.github.kryszak</groupId>
<artifactId>gwatlin</artifactId>
</dependency>
<dependency>
<groupId>dev.sheldan.gw2.tools</groupId>
<artifactId>database</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,6 @@
package dev.sheldan.gw2.tools.config
interface ApiKey {
fun getApiKey(): String
fun setApiKey(key: String)
}

View File

@@ -0,0 +1,38 @@
package dev.sheldan.gw2.tools.config
import io.github.kryszak.gwatlin.api.account.GWAccountClient
import io.github.kryszak.gwatlin.api.characters.GWCharactersClient
import io.github.kryszak.gwatlin.api.items.GWItemsClient
import io.github.kryszak.gwatlin.api.miscellaneous.GWMiscellaneousClient
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.ScopedProxyMode
import org.springframework.web.context.annotation.RequestScope
@Configuration
class BeanConfig(val apiKey: ApiKey) {
@Bean
@RequestScope(proxyMode = ScopedProxyMode.DEFAULT)
fun gwCharacterClient(): GWCharactersClient {
return GWCharactersClient(apiKey.getApiKey())
}
@Bean
@RequestScope(proxyMode = ScopedProxyMode.DEFAULT)
fun getAccountClient(): GWAccountClient {
return GWAccountClient(apiKey.getApiKey())
}
@Bean
fun getMiscellaneousClient(): GWMiscellaneousClient {
return GWMiscellaneousClient()
}
@Bean
fun gwItemClient(): GWItemsClient {
return GWItemsClient()
}
}

View File

@@ -0,0 +1,69 @@
package dev.sheldan.gw2.tools.loader
import dev.sheldan.gw2.tools.models.*
import dev.sheldan.gw2.tools.service.ItemManagement
import io.github.kryszak.gwatlin.api.account.GWAccountClient
import io.github.kryszak.gwatlin.api.characters.GWCharactersClient
import io.github.kryszak.gwatlin.api.miscellaneous.GWMiscellaneousClient
import org.springframework.stereotype.Component
import org.springframework.web.context.annotation.RequestScope
@Component
@RequestScope
class AccountLoader(
val charClient: GWCharactersClient,
val accountClient: GWAccountClient,
val miscellaneousClient: GWMiscellaneousClient,
val itemManagement: ItemManagement
) {
fun getCharacters(): List<String>? {
return charClient.getCharacters()
}
fun getWallet(): AccountWalletView {
val wallet = accountClient.getWallet()
val currencies = miscellaneousClient.getCurrencies().associateBy { it.id }
val enrichedCurrencies = wallet.mapNotNull { walletCurrency ->
val currency = currencies[walletCurrency.id]
currency?.let {
EnrichedCurrency(walletCurrency.id, walletCurrency.value, it.name, it.description, it.icon)
}
}
return AccountWalletView(enrichedCurrencies)
}
fun getBank(): AccountVaultView {
val bank = accountClient.getAccountVault()
val itemIds = mutableSetOf<Int>()
val items = bank.filterNotNull().mapNotNull {
itemIds.add(it.id)
EnrichedItem(it.id, it.count, it.boundTo)
}
val itemStats = itemManagement.getItemsAsMap(itemIds.toList())
items.forEach { item ->
itemStats[item.id]?.let {
item.setValuesFromDbItem(it)
}
}
return AccountVaultView(items)
}
fun getMaterials(): AccountMaterialView{
val materials = accountClient.getMaterials()
val itemIds = mutableSetOf<Int>()
val items = materials
.filter { it.count > 0 }
.map {
itemIds.add(it.id)
EnrichedItem(it.id, it.count)
}
val actualMaterials = itemManagement.getItemsAsMap(itemIds.toList())
items.forEach { item ->
actualMaterials[item.id]?.let {
item.setValuesFromDbItem(it)
}
}
return AccountMaterialView(items)
}
}

View File

@@ -0,0 +1,14 @@
package dev.sheldan.gw2.tools.loader
import dev.sheldan.gw2.tools.models.EnrichedCurrency
import io.github.kryszak.gwatlin.api.miscellaneous.GWMiscellaneousClient
import org.springframework.stereotype.Component
@Component
class CurrencyLoader(
var miscellaneousClient: GWMiscellaneousClient,
) {
fun getAllCurrencies(): List<EnrichedCurrency> {
return miscellaneousClient.getCurrencies().map { EnrichedCurrency(it.id, 0, it.name, it.description, it.icon) }
}
}

View File

@@ -0,0 +1,98 @@
package dev.sheldan.gw2.tools.loader
import dev.sheldan.gw2.tools.entity.Item
import dev.sheldan.gw2.tools.models.*
import dev.sheldan.gw2.tools.service.ItemManagement
import io.github.kryszak.gwatlin.api.account.GWAccountClient
import io.github.kryszak.gwatlin.api.account.model.InventoryItem
import io.github.kryszak.gwatlin.api.characters.GWCharactersClient
import io.github.kryszak.gwatlin.api.characters.model.character.inventory.Bag
import io.github.kryszak.gwatlin.api.characters.model.character.inventory.InventorySlot
import org.springframework.stereotype.Component
import org.springframework.web.context.annotation.RequestScope
@Component
@RequestScope
class InventoryLoader(
val charClient: GWCharactersClient,
val accountClient: GWAccountClient,
val itemManagement: ItemManagement
) {
fun getInventory(characterName: String): List<Bag?>? {
return charClient.getInventory(characterName)
}
fun getFullCharacterInventory(characterName: String): CharacterInventory {
val itemIds = mutableSetOf<Int>()
val characterInventory = getCharacterInventory(characterName, itemIds)
val itemStats = getFullItemInfos(itemIds)
enrichCharacterInventory(characterInventory, itemStats)
return characterInventory
}
private fun getCharacterInventory(characterName: String, itemIds: MutableSet<Int>): CharacterInventory {
val characterInventory = getInventory(characterName)
val convertedBags = mutableListOf<InventoryBag>()
characterInventory?.let {
for (bag in characterInventory.filterNotNull()) {
convertedBags.addLast(convertApiBagToCharacterInventory(bag, itemIds))
}
}
return CharacterInventory(characterName, convertedBags)
}
fun getAccountInventory(): AccountInventoryView {
val characters = charClient.getCharacters()
val itemIds = mutableSetOf<Int>()
val inventories = mutableListOf<CharacterInventory>()
for (characterName in characters) {
inventories.addLast(getCharacterInventory(characterName, itemIds))
}
val itemStats = getFullItemInfos(itemIds)
inventories.forEach { enrichCharacterInventory(it, itemStats) }
return AccountInventoryView(inventories)
}
private fun enrichCharacterInventory(characterInventory: CharacterInventory, itemStats: Map<Int, Item>) {
return characterInventory.bags.forEach { bag ->
bag.items.forEach { item ->
itemStats[item.id]?.let {
item.setValuesFromDbItem(it)
}
}
}
}
private fun convertApiBagToCharacterInventory(bag: Bag, itemIds: MutableSet<Int>): InventoryBag {
val items = bag.inventory.filterNotNull().map { convertInventorySlot(it, itemIds) }
return InventoryBag(bag.id, bag.size, items)
}
private fun convertInventorySlot(slot: InventorySlot, itemIds: MutableSet<Int>): EnrichedItem {
itemIds.add(slot.id)
return EnrichedItem(slot.id, slot.count, slot.boundTo)
}
private fun convertInventoryItem(item: InventoryItem, itemIds: MutableSet<Int>): EnrichedItem {
itemIds.add(item.id)
return EnrichedItem(item.id, item.count, item.binding)
}
fun getSharedInventory(): AccountInventory {
val itemIds = mutableSetOf<Int>()
val sharedInventorySlots = accountClient.getInventory().filterNotNull()
val sharedItems = sharedInventorySlots.map { convertInventoryItem(it, itemIds) }
val fullItemInfo = getFullItemInfos(itemIds)
sharedItems.forEach { item ->
fullItemInfo[item.id]?.let {
item.setValuesFromDbItem(it)
}
}
return AccountInventory(sharedItems)
}
private fun getFullItemInfos(itemIds: MutableSet<Int>) = itemManagement.getItemsAsMap(itemIds.toList())
}

View File

@@ -0,0 +1,20 @@
package dev.sheldan.gw2.tools.loader
import dev.sheldan.gw2.tools.models.EnrichedItem
import io.github.kryszak.gwatlin.api.items.GWItemsClient
import org.springframework.stereotype.Component
@Component
class ItemLoader(
val itemClient: GWItemsClient
) {
fun getAllItems(): List<EnrichedItem> {
return itemClient.getItemIds().chunked(200)
.flatMap { (itemClient.getItems(it)) }
.map {
val item = EnrichedItem(it.id, 1)
item.setValuesFromItem(it)
item
}
}
}

View File

@@ -0,0 +1,6 @@
package dev.sheldan.gw2.tools.models
class AccountInventory(
val slots: List<EnrichedItem>
) {
}

View File

@@ -0,0 +1,6 @@
package dev.sheldan.gw2.tools.models
data class AccountInventoryView(
val inventories: List<CharacterInventory>
) {
}

View File

@@ -0,0 +1,6 @@
package dev.sheldan.gw2.tools.models
class AccountMaterialView(
val slots: List<EnrichedItem>
) {
}

View File

@@ -0,0 +1,6 @@
package dev.sheldan.gw2.tools.models
class AccountVaultView(
val slots: List<EnrichedItem>
) {
}

View File

@@ -0,0 +1,6 @@
package dev.sheldan.gw2.tools.models
class AccountWalletView(
val currencies: List<EnrichedCurrency>
) {
}

View File

@@ -0,0 +1,8 @@
package dev.sheldan.gw2.tools.models
data class CharacterInventory(
val name: String,
val bags: List<InventoryBag>
)
{
}

View File

@@ -0,0 +1,10 @@
package dev.sheldan.gw2.tools.models
class EnrichedCurrency(
val id: Int,
var amount: Int,
val name: String,
val description: String,
val iconUrl: String
) {
}

View File

@@ -0,0 +1,33 @@
package dev.sheldan.gw2.tools.models
import io.github.kryszak.gwatlin.api.items.model.item.Item
data class EnrichedItem(
val id: Int,
var count: Int,
val boundTo: String? = null,
var iconUrl: String? = null,
var name: String? = null,
var description: String? = null,
var type: Gw2TItemType? = null,
var level: Int? = null,
var rarity: Gw2TItemRarity? = null
) {
fun setValuesFromItem(item: Item) {
this.name = item.name
this.level = item.level
this.description = item.description
this.type = Gw2TItemType.convertFromAPI(item.type)
this.rarity = Gw2TItemRarity.convertFromAPI(item.rarity)
this.iconUrl = item.icon.ifBlank { "https://render.guildwars2.com/file/4BC52199DBDEEF5D4D90736B582DDA0F092B0DE4/434780.png" } // default icon if nothing is shown
}
fun setValuesFromDbItem(item: dev.sheldan.gw2.tools.entity.Item) {
this.name = item.name
this.description = item.description
this.type = Gw2TItemType.valueOf(item.type)
this.rarity = Gw2TItemRarity.valueOf(item.rarity)
this.iconUrl = item.iconUrl
}
}

View File

@@ -0,0 +1,28 @@
package dev.sheldan.gw2.tools.models
import io.github.kryszak.gwatlin.api.items.model.item.ItemRarity
enum class Gw2TItemRarity {
JUNK,
BASIC,
FINE,
MASTERWORK,
RARE,
EXOTIC,
ASCENDED,
LEGENDARY;
companion object {
fun convertFromAPI(rarity: ItemRarity): Gw2TItemRarity = when (rarity) {
ItemRarity.FINE -> FINE
ItemRarity.MASTERWORK -> MASTERWORK
ItemRarity.RARE -> RARE
ItemRarity.EXOTIC -> EXOTIC
ItemRarity.JUNK -> JUNK
ItemRarity.BASIC -> BASIC
ItemRarity.ASCENDED -> ASCENDED
ItemRarity.LEGENDARY -> LEGENDARY
}
}
}

View File

@@ -0,0 +1,51 @@
package dev.sheldan.gw2.tools.models
import io.github.kryszak.gwatlin.api.items.model.item.ItemType
enum class Gw2TItemType {
CONTAINER,
ARMOR,
BACK,
BAG,
CONSUMABLE,
CRAFTING_MATERIAL,
GATHERING,
GIZMO,
JADE_TECH_MODULE,
KEY,
MINI_PET,
POWER_CORE,
TOOL,
TRAIT,
TRINKET,
TROPHY,
UPGRADE_COMPONENT,
WEAPON,
RELIC;
companion object {
fun convertFromAPI(type: ItemType): Gw2TItemType = when (type) {
ItemType.CONTAINER -> CONTAINER
ItemType.ARMOR -> ARMOR
ItemType.BACK -> BACK
ItemType.BAG -> BAG
ItemType.CONSUMABLE -> CONSUMABLE
ItemType.CRAFTING_MATERIAL -> CRAFTING_MATERIAL
ItemType.GATHERING -> GATHERING
ItemType.GIZMO -> GIZMO
ItemType.JADE_TECH_MODULE -> JADE_TECH_MODULE
ItemType.KEY -> KEY
ItemType.MINI_PET -> MINI_PET
ItemType.POWER_CORE -> POWER_CORE
ItemType.TOOL -> TOOL
ItemType.TRAIT -> TRAIT
ItemType.TRINKET -> TRINKET
ItemType.TROPHY -> TROPHY
ItemType.UPGRADE_COMPONENT -> UPGRADE_COMPONENT
ItemType.WEAPON -> WEAPON
ItemType.RELIC -> RELIC
}
}
}

View File

@@ -0,0 +1,8 @@
package dev.sheldan.gw2.tools.models
data class InventoryBag(
val id: Int,
val size: Int,
val items: List<EnrichedItem>
) {
}