mirror of
https://github.com/DorkSquadRR/DorkNet.git
synced 2026-10-25 15:08:47 -07:00
feat: Enhance avatar gifts and items handling; normalize gift descriptions and include color variants with unique IDs
This commit is contained in:
@@ -367,14 +367,35 @@ public class AvatarGiftsController(
|
||||
// GiftRarity, GiftContext. Missing any one → KeyNotFoundException
|
||||
// surfaces as "Failed to download gifts: Malformed Response" from
|
||||
// BootSequence and BLOCKS LOGIN.
|
||||
public static object ToWire(GiftPackageEntity g) => new
|
||||
/// <summary>The desc the client matches against api/avatar/v4/items in
|
||||
/// OutfitManager.UnlockAvatarItemAndMarkNew after the gift box is
|
||||
/// consumed. That endpoint emits outfit items as the 4-part "{guid},,,"
|
||||
/// form (a bare guid crashes the client's AvatarItem parser), and the
|
||||
/// match is an EXACT string compare — so an outfit gift whose desc has
|
||||
/// fewer than 4 comma-parts (legacy rows stored the bare guid) makes
|
||||
/// Find() miss and NRE, which strips the item on consume. Pad outfit
|
||||
/// descs to 4 parts here so BOTH new and already-persisted gifts match.
|
||||
/// Hair dyes (AvatarItemType 1) match by bare colour guid — leave them;
|
||||
/// currency-only gifts have an empty desc.</summary>
|
||||
private static string NormalizeAvatarWireDesc(GiftPackageEntity g)
|
||||
{
|
||||
var d = g.AvatarItemDescOrHairDyeDesc ?? string.Empty;
|
||||
if (d.Length == 0 || g.AvatarItemType == 1) return d;
|
||||
var parts = d.Split(',').Length;
|
||||
return parts >= 4 ? d : d + new string(',', 4 - parts);
|
||||
}
|
||||
|
||||
public static object ToWire(GiftPackageEntity g)
|
||||
{
|
||||
var avatarDesc = NormalizeAvatarWireDesc(g);
|
||||
return new
|
||||
{
|
||||
g.Id,
|
||||
g.FromPlayerId,
|
||||
g.ConsumableItemDesc,
|
||||
g.AvatarItemType,
|
||||
AvatarItemDesc = g.AvatarItemDescOrHairDyeDesc,
|
||||
g.AvatarItemDescOrHairDyeDesc,
|
||||
AvatarItemDesc = avatarDesc,
|
||||
AvatarItemDescOrHairDyeDesc = avatarDesc,
|
||||
g.EquipmentPrefabName,
|
||||
g.EquipmentModificationGuid,
|
||||
g.CurrencyType,
|
||||
@@ -409,5 +430,6 @@ public class AvatarGiftsController(
|
||||
g.ErrorMessage,
|
||||
g.SupportsCurrentPlatform,
|
||||
g.IsGifted,
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,6 +220,32 @@ public class AvatarItemsController(
|
||||
if (result.Count >= maxItems) return result;
|
||||
result.Add(item);
|
||||
}
|
||||
// Colored variants aren't in the base avatar_item_lookup catalog, so
|
||||
// without this the "everyone owns everything" wardrobe was missing all
|
||||
// ~1.8k colorways — the player didn't own them AND buying one gifted a
|
||||
// variant desc ("{guid},{combo},{mask},") that wasn't in this list, so
|
||||
// the client's post-consume UnlockAvatarItemAndMarkNew Find() missed
|
||||
// and NRE'd (the item vanished on buy). Emit each variant with its
|
||||
// verbatim equip descriptor and a UNIQUE id hashed from the FULL
|
||||
// descriptor (the base-guid hash would collide with the base item and
|
||||
// every sibling colorway).
|
||||
foreach (var v in StoreService.ColorVariantCatalog.Values)
|
||||
{
|
||||
if (result.Count >= maxItems) return result;
|
||||
if (string.IsNullOrWhiteSpace(v.descriptor)) continue;
|
||||
result.Add(new UnlockedAvatarItemDto
|
||||
{
|
||||
AvatarItemType = AvatarItemType.Outfit,
|
||||
AvatarItemDesc = v.descriptor,
|
||||
AvatarItemId = StableAvatarItemIdFull(v.descriptor),
|
||||
PlatformMask = unchecked((int)0xFFFFFFFF),
|
||||
FriendlyName = v.item_name ?? string.Empty,
|
||||
Tooltip = string.Empty,
|
||||
Rarity = 0,
|
||||
TagList = string.Empty,
|
||||
IsBaseAvatarItem = false,
|
||||
});
|
||||
}
|
||||
foreach (var slug in StoreService.AllHairDyeSlugs)
|
||||
{
|
||||
if (result.Count >= maxItems) break;
|
||||
@@ -547,6 +573,18 @@ public class AvatarItemsController(
|
||||
return id == 0 ? 1 : id;
|
||||
}
|
||||
|
||||
/// <summary>Stable id from the FULL descriptor string (not just the base
|
||||
/// guid). Colored variants share a base guid but are distinct wardrobe
|
||||
/// entries, so they must hash the whole "{guid},{combo},{mask}," string
|
||||
/// to get ids distinct from the base item and each other.</summary>
|
||||
public static int StableAvatarItemIdFull(string? descriptor)
|
||||
{
|
||||
uint h = 2166136261u;
|
||||
foreach (var c in descriptor ?? string.Empty) h = (h ^ c) * 16777619u;
|
||||
var id = (int)(h & 0x7FFFFFFF);
|
||||
return id == 0 ? 1 : id;
|
||||
}
|
||||
|
||||
private static string PrettyName(string raw)
|
||||
{
|
||||
if (string.IsNullOrEmpty(raw)) return string.Empty;
|
||||
|
||||
Reference in New Issue
Block a user