Files
Radicade/Server/Avatars/ConsumableCatalog.cs
T
2026-10-16 23:33:13 -07:00

172 lines
6.4 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using RadicadeServer.Extensions;
namespace RadicadeServer.RecNet.Avatar
{
public static class ConsumableCatalog
{
private static readonly Dictionary<string, string> FriendlyToToken =
new Dictionary<string, string>(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<ConsumableItem> ParseItems(string? catalogJson)
{
if (string.IsNullOrWhiteSpace(catalogJson)) return new List<ConsumableItem>();
try
{
return catalogJson.FromJson<List<ConsumableItem>>(CatalogReadOptions) ?? new List<ConsumableItem>();
}
catch (System.Text.Json.JsonException)
{
return new List<ConsumableItem>();
}
}
public static List<Consumable> DefaultInstances(string? catalogJson)
{
var catalog = ParseItems(catalogJson);
if (catalog.Count == 0) return new List<Consumable>();
var instances = new List<Consumable>();
var taken = new HashSet<long>();
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);
}
}
}