@@ -29,6 +29,7 @@ import {
2929
3030const MAX_INTEL_POINTS = 2779 ;
3131const MAX_TABLE_PREVIEW_ROWS = 10000 ;
32+ const INVENTORY_EDITABLE_COLUMNS = new Set ( [ "stack_size" , "quality_level" , "position_index" , "current_durability" , "max_durability" ] ) ;
3233let craftingRecipeCatalogCache = null ;
3334
3435export class UnsupportedCapabilityError extends Error {
@@ -1504,7 +1505,17 @@ export async function playerProfile(db, id) {
15041505 left join dune.accounts ac on ac.id = a.owner_account_id
15051506 where a.id = $1` , [ actorId ] ) ;
15061507 if ( ! result . rows [ 0 ] ) throw new Error ( "Player not found" ) ;
1507- return { capabilities : await playerCapabilities ( db ) , player : result . rows [ 0 ] } ;
1508+ const row = result . rows [ 0 ] ;
1509+ const [ factions , guilds ] = await Promise . all ( [
1510+ leadershipFactions ( db ) . catch ( ( ) => new Map ( ) ) ,
1511+ leadershipGuilds ( db ) . catch ( ( ) => new Map ( ) )
1512+ ] ) ;
1513+ const controllerId = String ( row . player_controller_id || "" ) ;
1514+ const actorIdKey = String ( row . actor_id || "" ) ;
1515+ const accountIdKey = String ( row . account_id || "" ) ;
1516+ row . faction = factions . get ( controllerId ) || factions . get ( actorIdKey ) || "Unassigned" ;
1517+ row . guild = guilds . get ( controllerId ) || guilds . get ( actorIdKey ) || guilds . get ( accountIdKey ) || "Unavailable" ;
1518+ return { capabilities : await playerCapabilities ( db ) , player : row } ;
15081519}
15091520
15101521export async function playerInventory ( db , id ) {
@@ -1517,7 +1528,11 @@ export async function playerInventory(db, id) {
15171528 i.position_index,
15181529 i.inventory_id,
15191530 coalesce((i.stats->'FItemStackAndDurabilityStats'->1->>'CurrentDurability'), null) as current_durability,
1520- coalesce((i.stats->'FItemStackAndDurabilityStats'->1->>'MaxDurability'), null) as max_durability,
1531+ coalesce(
1532+ nullif((i.stats->'FItemStackAndDurabilityStats'->1->>'MaxDurability')::numeric, 0),
1533+ nullif((i.stats->'FItemStackAndDurabilityStats'->1->>'DecayedMaxDurability')::numeric, 0),
1534+ null
1535+ ) as max_durability,
15211536 i.stats
15221537 from dune.items i
15231538 join dune.inventories inv on i.inventory_id = inv.id
@@ -2526,6 +2541,40 @@ export async function deleteInventoryItem(db, playerId, itemId) {
25262541 } ) ;
25272542}
25282543
2544+ export async function updateInventoryItem ( db , playerId , itemId , values ) {
2545+ await requireCapability ( await supportsInventoryEdit ( db ) , "Inventory edit requires dune.items and dune.inventories." ) ;
2546+ const safeItemId = intParam ( itemId , "item id" , 1 ) ;
2547+ const nextValues = Object . fromEntries ( Object . entries ( values || { } ) . filter ( ( [ key ] ) => INVENTORY_EDITABLE_COLUMNS . has ( key ) ) ) ;
2548+ return db . transaction ( async ( tx ) => {
2549+ const player = await resolvePlayerMutationTarget ( tx , playerId ) ;
2550+ const owned = await tx . query ( `
2551+ select i.id, i.stats
2552+ from dune.items i
2553+ join dune.inventories inv on inv.id = i.inventory_id
2554+ where i.id = $1 and inv.actor_id = $2
2555+ for update` , [ safeItemId , player . actorId ] ) ;
2556+ if ( ! owned . rows [ 0 ] ) throw new Error ( "Inventory item was not found in the selected player's directly-owned inventory" ) ;
2557+
2558+ const hasMax = Object . prototype . hasOwnProperty . call ( nextValues , "max_durability" ) && nextValues . max_durability !== null && nextValues . max_durability !== "" ;
2559+ const hasCurrent = Object . prototype . hasOwnProperty . call ( nextValues , "current_durability" ) && nextValues . current_durability !== null && nextValues . current_durability !== "" ;
2560+ if ( hasMax || hasCurrent ) {
2561+ const stats = owned . rows [ 0 ] . stats || { } ;
2562+ const durability = { ...( stats . FItemStackAndDurabilityStats ?. [ 1 ] || { } ) } ;
2563+ const maxKey = Object . prototype . hasOwnProperty . call ( durability , "MaxDurability" ) ? "MaxDurability" : "DecayedMaxDurability" ;
2564+ const nextMax = numberParam ( hasMax ? nextValues . max_durability : durability [ maxKey ] , "max durability" , 0 , 100 ) ;
2565+ const nextCurrent = numberParam ( hasCurrent ? nextValues . current_durability : durability . CurrentDurability , "current durability" , 0 , nextMax ) ;
2566+ durability . CurrentDurability = nextCurrent ;
2567+ durability [ maxKey ] = nextMax ;
2568+ nextValues . stats = { ...stats , FItemStackAndDurabilityStats : [ stats . FItemStackAndDurabilityStats ?. [ 0 ] || [ ] , durability ] } ;
2569+ }
2570+ delete nextValues . current_durability ;
2571+ delete nextValues . max_durability ;
2572+
2573+ const rowId = JSON . stringify ( { pk : { id : safeItemId } } ) ;
2574+ return updateTableRow ( tx , "dune" , "items" , rowId , nextValues ) ;
2575+ } ) ;
2576+ }
2577+
25292578export async function giveItemToStorage ( db , storageId , { itemName = "" , itemId = "" , templateId = "" , quantity = 1 , quality = 0 } ) {
25302579 await requireCapability ( await supportsStorageGiveItem ( db ) , "Storage give-item requires compatible dune.inventories and dune.items insert columns." ) ;
25312580 const target = intParam ( storageId , "storage id" , 1 ) ;
@@ -2740,6 +2789,7 @@ async function playerCapabilities(db) {
27402789 craftingRecipes : await supportsCraftingRecipes ( db ) ,
27412790 researchItems : await supportsResearchItems ( db ) ,
27422791 inventoryDelete : await supportsInventoryDelete ( db ) ,
2792+ inventoryEdit : await supportsInventoryEdit ( db ) ,
27432793 repairGear : await supportsRepairGear ( db ) ,
27442794 repairVehicleDecay : await supportsRepairVehicleDecay ( db ) ,
27452795 refuelVehicle : await supportsRefuelVehicle ( db ) ,
@@ -2938,6 +2988,10 @@ async function supportsInventoryDelete(db) {
29382988 await functionExists ( db , "dune.delete_item(bigint)" ) ;
29392989}
29402990
2991+ async function supportsInventoryEdit ( db ) {
2992+ return await tableExists ( db , "items" ) && await tableExists ( db , "inventories" ) ;
2993+ }
2994+
29412995async function supportsStorageGiveItem ( db ) {
29422996 if ( ! ( await tableExists ( db , "items" ) ) || ! ( await tableExists ( db , "inventories" ) ) ) return false ;
29432997 const inventoryColumns = await columnsFor ( db , "inventories" ) ;
0 commit comments