using System; using System.Collections.Generic; using System.Linq; using RadicadeServer.Extensions; namespace RadicadeServer.RecNet.Avatar { public static class ConsumableCatalog { private static readonly Dictionary FriendlyToToken = new Dictionary(StringComparer.OrdinalIgnoreCase) { { "20% Off Coupon", "50oCPkzd3EerBd7nYNdkCw" }, { "87 Flavor Cake", "xwQWBB_fekmTqRc2LB92cg" }, { "Assorted Donuts", "ZuvkidodzkuOfGLDnTOFyg" }, { "Black & White Camera Film", "frOMH6WxDEG1fBqC4_83vg" }, { "Bubble Tea", "JxAl1wVJ1UGAjoT3m3ilug" }, { "Bubbly", "iiGTvhOCHkOTNJhb16Zbyw" }, { "Bucket Orange Hair Dye", "xr45B5QC4EyKXThtwZto_A" }, { "Butterfly Blue Hair Dye", "JwJeh15cjkOc9WWaGRibDQ" }, { "Cake Pops", "Efd3_dy4ZEqWr7i6j5x0aA" }, { "Candy Apples", "EmPvh3I6L0uK_1i8Wy_ylQ" }, { "Cauldron Crimson Hair Dye", "3R1bzI35fkChoFFRFbponQ" }, { "Celebration Cake", "Sk_1sm88ZU2zpWn01Lv7hw" }, { "Cheese Pizza", "5hIAZ9wg5EyG1cILf4FS2A" }, { "Chocolate Cake", "BbJb1_0g4EGJP_CeNrjpew" }, { "Chocolate Frosted Donuts", "mMCGPgK3tki5S_15q2Z81A" }, { "Chocolate Popcorn", "lWN_g4OcN0S0C4n6cSZq4g" }, { "Chocolate Variety Box", "K9RbXo-4U0q6NbGu8VL1Sw" }, { "Circuit Cerulean Hair Dye", "x9ntSHto50GpNWPwYCLUEg" }, { "Dawn Camera Film", "m0bVLwWGj0GuIBSb6wCk6Q" }, { "Dracula Film", "oG7CdvW7p0-S8sVe9w5vRw" }, { "EDM Emerald Hair Dye", "4L3JoaqkAUa1kz98nciPXw" }, { "Ego Potion", "Tpxqe_lycUelySRHM8B0Vw" }, { "Flaming Popcorn", "uswFSANaZES0EJMLfOgNSw" }, { "Frontier Forest Hair Dye", "YaVzcoefhk6zjbNDELLx8A" }, { "Ghost Beard Film", "1c0Djlp090uBDczEobYNQw" }, { "Gizmo Grape Hair Dye", "iEtWDLmv7ES87J4NE_TGJQ" }, { "Glazed Donuts", "7OZ5AE3uuUyqa0P-2W1ptg" }, { "Goblin Green Hair Dye", "jA3zzS31zEitBxtRCk7oew" }, { "Goblin King Film", "6SyCoJCgo0Wd6qlPlnMOtg" }, { "H2Oasis Blue Hair Dye", "P7HixsdkskmzgFMdFJ-WdA" }, { "Hawaiian Pizza", "_jnjYGBcyEWY5Ub4OezXcA" }, { "High Five O'Gold", "-hy0qD-iUk-v4NHxNzanmg" }, { "High Five O'Gunpowder", "YEfbJTnsR0yT_p7e7tb_kQ" }, { "High Five O'Lasers", "xHOwjwpXd0GDkvBz2VqieA" }, { "High Five O'Spells", "VQSgL2pTLkWx4B3kwYG7UA" }, { "High Five O'Whip", "lag2tZyB90W04lQ7ol4vMw" }, { "Invasion Donuts", "-_VNAj3P10aWCCJZoVTF4Q" }, { "Jumbotron Film", "Il4VmrnjDkqjmjzddqoIEw" }, { "Jungle Jade Hair Dye", "5Ugg8k19n0WH8GPFCDWTCQ" }, { "KO - Bear Claw", "ZtZnYBpKkECJlhHmkj4MiA" }, { "KO - Bees", "g3kxdlJv5kO8PuBXveM48w" }, { "KO - Cola", "wx--2TPTdEuGAqLCjs9Qag" }, { "KO - Fangs", "XOZcxx-Klkyhe-MDbTqiwA" }, { "KO - FryingPan", "uGVFydNSokCXFAmXu3aceQ" }, { "KO - Grenade", "EAhk3ZZdXEmH5wRAXXT24Q" }, { "KO - Ranger", "Av-wvjXvvkmNVSz7ZZnTiA" }, { "KO - Shield", "5AJin8T2iEG7BzOPOgx2HA" }, { "KO - Skull Wings", "U38Qe6rhEk6mFvArHfYjng" }, { "KO - Star Power", "yvqSbK2czkS2sUCRdrGaEw" }, { "KO - Tire Track", "J1WqFNUWo0OBi4LGKPDHWw" }, { "KREQ Red Hair Dye", "P1kCuPlRc0-NAg6JUlEH_g" }, { "Latte", "P15H1ONBhk-5DYYjid1ttg" }, { "Lounge Lavender Hair Dye", "Hh_O_RejGE-_PubyM8xHaw" }, { "Maker Mauve Hair Dye", "s2pxukIEt0uDeGVJmZayOw" }, { "Mousebot Magenta Hair Dye", "vXL0rrAk70SFxJlaJk0uqQ" }, { "PVPeach Hair Dye", "AQTYAh1it0GIGdgGO5sUHQ" }, { "Paula's Periwinkle Hair Dye", "UAOH6ccEbEmehJg8XW_D8w" }, { "Pepperoni Pizza", "mq23W-RSP0G8iGNLdrcpUw" }, { "Pirate Gold Hair Dye", "o0hG5O_eaUO0R8vPyW-Hvg" }, { "Popcorn", "QRx0aSTT9keMFdAJMQHdTg" }, { "Propulsion Purple Hair Dye", "xRtKWR-D40GUW43R0EFpNg" }, { "Ranger Roy-Al Blue Hair Dye", "8vlVslaWaUyFS-iDHhxW9g" }, { "Rebel Rose Hair Dye", "STFKahjHJ0SQJPfoDe4S1g" }, { "Recreational Raspberry Hair Dye", "eJh_BQ5y4UWwiMJzBKcwMQ" }, { "Red Apples", "uMHrUPLYFk2rJOW_uop5Aw" }, { "Red Velvet Cake", "LwaotjVEBUir0-w8126n_g" }, { "Root Beer", "JfnVXFmilU6ysv-VbTAe3A" }, { "Salted Pretzels", "InQ25wQMGkG_bvuD5rf2Ag" }, { "Sepia Camera Film", "A5M-yf9tgUihq1uab3v58g" }, { "Snowman Donuts", "jdrRJ7deWk2P9aRRrPy3zw" }, { "Sparklers", "hRdK6NGfAkGBmYSs_xGzXg" }, { "Standee Sandy Hair Dye", "inIuPzhhOEmz1RI8mZtSLg" }, { "Supreme Pizza", "wUCIKdJSvEmiQHYMyx4X4w" }, { "Sushi", "4My42w1D1Uu3-98pXB-x_Q" }, { "VR Cola", "YpL6eN6sKEquOYIYnbhvew" }, { "Witch Film", "mL3zCEuy2UWZxAV4V-OsMA" }, }; public static string ToClientDesc(string? value) { if (string.IsNullOrWhiteSpace(value)) return value ?? string.Empty; var parts = value.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); return string.Join(",", parts.Select(p => FriendlyToToken.TryGetValue(p, out var token) ? token : p)); } public const int DefaultCount = 5; private const long GrantedIdBase = 800_000_000; private const long GrantedIdSpan = 100_000_000; private static readonly DateTime GrantedAt = new(2023, 1, 1, 0, 0, 0, DateTimeKind.Utc); private static readonly System.Text.Json.JsonSerializerOptions CatalogReadOptions = new() { PropertyNameCaseInsensitive = true, Converters = { new System.Text.Json.Serialization.JsonStringEnumConverter() } }; public static List ParseItems(string? catalogJson) { if (string.IsNullOrWhiteSpace(catalogJson)) return new List(); try { return catalogJson.FromJson>(CatalogReadOptions) ?? new List(); } catch (System.Text.Json.JsonException) { return new List(); } } public static List DefaultInstances(string? catalogJson) { var catalog = ParseItems(catalogJson); if (catalog.Count == 0) return new List(); var instances = new List(); var taken = new HashSet(); foreach (var item in catalog) { var desc = ToClientDesc(item.ConsumableItemDesc); if (string.IsNullOrWhiteSpace(desc)) continue; var id = StableId(desc); while (!taken.Add(id)) id++; instances.Add(new Consumable { Id = id, ConsumableItemDesc = desc, Count = DefaultCount, InitialCount = DefaultCount, CreatedAt = GrantedAt, UnlockedLevel = 0, IsActive = false, ActiveDurationMinutes = 0 }); } return instances; } private static long StableId(string token) { uint hash = 2166136261; foreach (var c in token) { hash ^= c; hash *= 16777619; } return GrantedIdBase + (hash % GrantedIdSpan); } } }