GetStoreItems was a stub returning an empty object, so every shop (Korolev / ICA / Osiris / QuickShop vendors) showed up empty. Build the store on the fly from the Blueprints title data: for the requested StoreId, list every item that declares an ItemShopsCraftingData entry for that store, converting its currency recipe ingredients into VirtualCurrencyPrices (SoftCurrency->SC, Aurum->AU, InsuranceCurrency->IN). Item-ingredient (crafting) entries are left to the crafting UI. Adds the StoreId/CatalogVersion fields to the request and the FGetStoreItemsResult / FStoreItem PlayFab response models. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -155,11 +155,72 @@ public class ClientController : Controller
|
||||
[Authorize(AuthenticationSchemes = UserAuthenticationOptions.DefaultScheme)]
|
||||
public IActionResult GetStoreItems(FGetStoreItems request)
|
||||
{
|
||||
return Ok(new ClientResponse<object>
|
||||
// The vendors (Korolev / ICA / Osiris / QuickShop) and other stores are defined
|
||||
// inside the Blueprints title data: each item lists a per-store entry under
|
||||
// ItemShopsCraftingData keyed by the store id, with the currency price in its
|
||||
// recipe ingredients. This endpoint was previously a stub returning {}, which is
|
||||
// why every shop showed up empty. We build the store on the fly from that data.
|
||||
var storeId = request.StoreId ?? "";
|
||||
var store = new List<FStoreItem>();
|
||||
try
|
||||
{
|
||||
var titleData = _titleDataService.Find(new List<string> { "Blueprints" });
|
||||
var blueprints = JsonSerializer.Deserialize<Dictionary<string, TitleDataBlueprintInfo>>(titleData["Blueprints"]);
|
||||
if (blueprints != null && !string.IsNullOrEmpty(storeId))
|
||||
{
|
||||
uint position = 0;
|
||||
foreach (var (itemId, blueprint) in blueprints)
|
||||
{
|
||||
if (blueprint.ItemShopsCraftingData == null) continue;
|
||||
if (!blueprint.ItemShopsCraftingData.TryGetValue(storeId, out var shopData)) continue;
|
||||
if (shopData?.ItemRecipeIngredients == null) continue;
|
||||
|
||||
// Only currency ingredients form a purchasable price. Entries whose
|
||||
// recipe is item-based (crafting) are handled by the crafting UI from
|
||||
// the blueprint data the client already has, not by the buy store.
|
||||
var prices = new Dictionary<string, uint>();
|
||||
foreach (var ingredient in shopData.ItemRecipeIngredients)
|
||||
{
|
||||
var code = ingredient.Currency switch
|
||||
{
|
||||
"SoftCurrency" => "SC",
|
||||
"Aurum" => "AU",
|
||||
"InsuranceCurrency" => "IN",
|
||||
_ => null,
|
||||
};
|
||||
if (code == null || ingredient.Amount < 0) continue;
|
||||
prices[code] = prices.TryGetValue(code, out var current)
|
||||
? current + (uint)ingredient.Amount
|
||||
: (uint)ingredient.Amount;
|
||||
}
|
||||
if (prices.Count == 0) continue;
|
||||
|
||||
store.Add(new FStoreItem
|
||||
{
|
||||
ItemId = itemId,
|
||||
VirtualCurrencyPrices = prices,
|
||||
RealCurrencyPrices = new Dictionary<string, uint>(),
|
||||
DisplayPosition = position++,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogWarning(e, "Failed to build store items for store {StoreId}", storeId);
|
||||
}
|
||||
|
||||
_logger.LogInformation("GetStoreItems '{StoreId}': {Count} item(s)", storeId, store.Count);
|
||||
return Ok(new ClientResponse<FGetStoreItemsResult>
|
||||
{
|
||||
Code = 200,
|
||||
Status = "OK",
|
||||
Data = new {}
|
||||
Data = new FGetStoreItemsResult
|
||||
{
|
||||
StoreId = string.IsNullOrEmpty(storeId) ? null : storeId,
|
||||
CatalogVersion = "StaticItems",
|
||||
Store = store,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user