Skip to content

Commit

Permalink
Merge pull request #2 from xiv-gear-planner/gear-acquisition-source
Browse files Browse the repository at this point in the history
Gear acquisition source logic
  • Loading branch information
xpdota authored Sep 3, 2024
2 parents 66d269d + 6635572 commit a1afcb7
Show file tree
Hide file tree
Showing 15 changed files with 359 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ import gg.xp.xivgear.dataapi.persistence.DataPersistence
import groovy.transform.CompileStatic
import groovy.util.logging.Slf4j
import io.micronaut.context.annotation.Context
import io.micronaut.json.JsonConfiguration
import jakarta.inject.Singleton

import java.time.Duration
import java.util.concurrent.*
import java.util.concurrent.CompletableFuture
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import java.util.concurrent.Future

import static gg.xp.xivapi.filters.SearchFilters.*

Expand Down Expand Up @@ -212,6 +214,45 @@ class DataManager implements AutoCloseable {
List<ItemBase> itemBases = client.getSearchIterator(ItemBase, itemFilter).toList().toSorted { it.rowId }
log.info "Loaded ${itemBases.size()} Items"

log.info "Loading Recipes"
SearchFilter recipeFilter = and(
gte("ItemResult.LevelItem", minIlvl),
lte("ItemResult.LevelItem", maxIlvl),
gt("ItemResult.EquipSlotCategory", 0),
// or(jobs
// .findAll { it.rowId > 0 }
// .collect {
// return eq("ItemResult.ClassJobCategory.${it.abbreviation}", 1)
// }
// )
)
List<Recipe> recipes = client.getSearchIterator(Recipe, recipeFilter).toList()
Set<Integer> itemsWithRecipes = recipes.collect { it.itemResult }.toSet()
log.info "Loaded ${recipes.size()} Recipes"

// There is currently no good way to do shops. SpecialShop items have a 60-item "Items" array which results
// in a massive response. It is too slow and bloated to consume raw. Trying to filter also results in
// unacceptable performance because xivapi has to do way too many joins.
// log.info "Loading Shops"
// Set<Integer> itemsWithShops = new HashSet<>()
// Searching is currently too slow because it has to do a double-join
// itemBases.collate(50).each { subList ->
// SearchFilter shopsFilter = or(
// subList.collect {
// eq "Item[].Item[]", it.rowId
// },
// )
// client.getSearchIterator(SpecialShop, shopsFilter).each {
// itemsWithShops.addAll it.item.collectMany { it.item }
// }
// }
// client.getListIterator(SpecialShop).each {
// it.item.each {
// itemsWithShops.addAll it.item
// }
// }
// log.info "Loaded ${itemsWithShops} Shop->Item Mappings"

log.info "Loading Materia"
SearchFilter materiaFilter = and(
gt(any("Item"), 0)
Expand Down Expand Up @@ -244,10 +285,10 @@ class DataManager implements AutoCloseable {
return [new FoodImpl(it, itemFood)] as List<Food>
}
}
food.<Food>sort { it.rowId }
food.<Food> sort { it.rowId }
log.info "Loaded ${food.size()} Foods"

def data = new FullData(versions, baseParams, itemBases, itemLevels, jobs, materia, food)
def data = new FullData(versions, baseParams, itemBases, itemLevels, jobs, materia, food, itemsWithRecipes)
return data
}
catch (Throwable t) {
Expand Down
22 changes: 19 additions & 3 deletions src/main/groovy/gg/xp/xivgear/dataapi/datamanager/FullData.groovy
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
package gg.xp.xivgear.dataapi.datamanager

import gg.xp.xivapi.clienttypes.XivApiSchemaVersion
import gg.xp.xivgear.dataapi.gear.GearSource
import gg.xp.xivgear.dataapi.models.*
import groovy.transform.CompileStatic
import groovy.transform.DefaultsMode
import groovy.transform.TupleConstructor

import java.time.Instant

@TupleConstructor(includeFields = true, defaultsMode = DefaultsMode.AUTO)
@CompileStatic
@TupleConstructor(includeFields = true, defaultsMode = DefaultsMode.AUTO, post = {
this.finishItems()
}, excludes = ['timestamp', 'items'])
class FullData implements Serializable {

// ALWAYS UPDATE THIS IF CHANGING THIS CLASS
// ALWAYS UPDATE THIS IF CHANGING THIS CLASS OR ANYTHING ELSE IN IT
// The persistence later avoids conflicts between concurrently-running versions by
// using a different object storage key based on the serialVersionUID
@Serial
static final long serialVersionUID = 4
static final long serialVersionUID = 5

final List<String> versions
final List<BaseParam> baseParams
Expand All @@ -21,7 +28,16 @@ class FullData implements Serializable {
final List<ClassJob> jobs
final List<Materia> materia
final List<Food> food
final Set<Integer> itemsWithRecipes
final Instant timestamp = Instant.now()
transient List<Item> items

void finishItems() {
items = itemBases.collect { base ->
GearAcquisitionSource source = GearSource.getAcquisitionSource(this, base)
return new ItemImpl(base, source) as Item
}
}

XivApiSchemaVersion getSchemaVersion() {
return baseParams[0].schemaVersion
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package gg.xp.xivgear.dataapi.endpoints


import gg.xp.xivgear.dataapi.datamanager.DataManager
import gg.xp.xivgear.dataapi.datamanager.FullData
import groovy.transform.CompileStatic
Expand All @@ -9,8 +8,6 @@ import io.micronaut.core.annotation.NonNull
import io.micronaut.http.HttpHeaders
import io.micronaut.http.HttpRequest
import io.micronaut.http.HttpResponse
import io.micronaut.jackson.codec.JsonMediaTypeCodec
import jakarta.inject.Inject

import java.time.ZoneOffset
import java.time.ZonedDateTime
Expand All @@ -27,8 +24,8 @@ import java.time.temporal.ChronoUnit
* <li>Returning 304 Not Modified when the client already has the newest data.</li>
* </ul>
*
* @param <In> A type that encompasses whatever necessary parameters.
* @param <Out> The response object type.
* @param <In> A type that encompasses whatever necessary parameters.
* @param <Out> The response object type.
*/
@TupleConstructor(includeFields = true, defaults = false)
@CompileStatic
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package gg.xp.xivgear.dataapi.endpoints
import gg.xp.xivgear.dataapi.datamanager.DataManager
import gg.xp.xivgear.dataapi.datamanager.FullData
import gg.xp.xivgear.dataapi.models.Item
import gg.xp.xivgear.dataapi.models.ItemImpl
import groovy.transform.CompileStatic
import groovy.transform.TupleConstructor
import io.micronaut.context.annotation.Context
import io.micronaut.http.HttpRequest
Expand All @@ -14,9 +14,9 @@ import io.micronaut.http.annotation.Get
import io.micronaut.http.annotation.Produces
import io.swagger.v3.oas.annotations.Operation


@Context
@Controller("/Items")
@CompileStatic
//@TupleConstructor(includeFields = true, defaults = false)
class ItemsEndpoint extends BaseDataEndpoint<String, Response> {

Expand All @@ -39,9 +39,15 @@ class ItemsEndpoint extends BaseDataEndpoint<String, Response> {

@Override
protected Response getContent(FullData fd, String job) {
List<Item> items = fd.itemBases
.findAll { it.classJobCategory.jobs[job] }
.collect { new ItemImpl(it) as Item }
// List<Item> items = fd.itemBases
// .findAll { it.classJobCategory.jobs[job] }
// .collect { base ->
// // TODO: is this heavy to recompute every time?
// // Can BaseDataEndpoint be augmented to cache this internally?
// GearAcquisitionSource source = GearSource.getAcquisitionSource(fd, base)
// return new ItemImpl(base, source) as Item
// }
List<Item> items = fd.items.findAll { it.classJobCategory.jobs[job] }
return new Response(items)
}
}
21 changes: 21 additions & 0 deletions src/main/groovy/gg/xp/xivgear/dataapi/gear/Expansion.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package gg.xp.xivgear.dataapi.gear

enum Expansion {

Stormblood(290, 310, 340),
Shadowbringers(430, 440, 470),
Endwalker(560, 570, 600),
Dawntrail(690, 700, 730)

final int artifactLevel
final int basicTomeLevel
final List<Integer> raidTierLevels

private Expansion(int artifactLevel, int basicTomeLevel, int firstRaidTierLevel) {
this.artifactLevel = artifactLevel
this.basicTomeLevel = basicTomeLevel
this.raidTierLevels = [firstRaidTierLevel, firstRaidTierLevel + 30, firstRaidTierLevel + 60].asImmutable()
}


}
66 changes: 66 additions & 0 deletions src/main/groovy/gg/xp/xivgear/dataapi/gear/GearLevels.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package gg.xp.xivgear.dataapi.gear


import jakarta.inject.Singleton

@Singleton
class GearLevels {

/**
* Check whether an ilvl matches the basic start-of-expac artifact level
*
* @param ilvl
* @return
*/
static boolean isArtifactLevel(int ilvl) {
return Expansion.values().any {
it.artifactLevel == ilvl
}
}

/**
* Check whether an ilvl matches the basic start-of-expac tome ilvl (e.g. Ronkan)
*
* @param ilvl
* @return
*/
static boolean isBasicTomeLevel(int ilvl) {
return Expansion.values().any {
it.basicTomeLevel == ilvl
}
}

private static boolean checkRelativeToRaid(int ilvl, int offset) {
return Expansion.values().any {
it.raidTierLevels.any { raidIlvl ->
raidIlvl + offset == ilvl
}
}
}

static boolean isSavageRaidLevel(int ilvl) {
return checkRelativeToRaid(ilvl, 0)
}

static boolean isSavageRaidWeaponLevel(int ilvl) {
return checkRelativeToRaid(ilvl, 5)
}

static boolean isNormalRaidLevel(int ilvl) {
return checkRelativeToRaid(ilvl, -20)
}

static boolean isUnAugmentedTomeLevel(int ilvl) {
return checkRelativeToRaid(ilvl, -10)
}

/**
* Check whether an ilvl matches the non-start-of-expac extreme trial ilvls
*
* @param ilvl
* @return
*/
static boolean isExTrialLevel(int ilvl) {
return checkRelativeToRaid(ilvl, -5) || checkRelativeToRaid(ilvl, -15)
}
}
Loading

0 comments on commit a1afcb7

Please sign in to comment.