mirror of
https://github.com/DorkSquadRR/DorkNet.git
synced 2026-10-25 23:18:44 -07:00
feat: enhance inventory schema to support longer ItemSlug and add GiftBox equipment payload handling
This commit is contained in:
@@ -115,4 +115,18 @@ public class SanitizeController(ILogger<SanitizeController> logger) : Controller
|
||||
?? textForm ?? textQuery ?? string.Empty;
|
||||
return Ok(ProfanityFilter.IsClean(input));
|
||||
}
|
||||
|
||||
/// <summary>POST <c>api/sanitize/isPure</c> — December 2020 route
|
||||
/// used by room/settings forms. Its importer reads an <c>IsPure</c>
|
||||
/// object field, unlike the newer bare-bool route above.</summary>
|
||||
[HttpPost("api/sanitize/isPure")]
|
||||
public IActionResult IsPure(
|
||||
[FromBody] SanitizeBody? body,
|
||||
[FromForm(Name = "Text")] string? textForm,
|
||||
[FromQuery(Name = "text")] string? textQuery)
|
||||
{
|
||||
var input = body?.Text ?? body?.Input ?? body?.Value
|
||||
?? textForm ?? textQuery ?? string.Empty;
|
||||
return Ok(new { IsPure = ProfanityFilter.IsClean(input) });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ public class StorefrontsBuyController(
|
||||
StoreService.TryGetAvatarItemPayload(item.Slug, out var avatarItemType, out avatarItemDesc);
|
||||
var inventoryAvatarDesc = StoreService.InventoryAvatarItemDesc(avatarItemDesc);
|
||||
StoreService.TryGetConsumableItemDesc(item.Slug, out var consumableItemDesc);
|
||||
StoreService.TryGetEquipmentPayload(item.Slug, out var equipmentPrefabName, out var equipmentModificationGuid);
|
||||
StoreService.TryGetGiftBoxEquipmentPayload(item.Slug, out var equipmentPrefabName, out var equipmentModificationGuid);
|
||||
if (StoreService.TryGetHairDyePayload(item.Slug, out var hairDyeConsumableDesc, out var hairDyeColorGuid))
|
||||
{
|
||||
avatarItemType = 1;
|
||||
@@ -352,7 +352,7 @@ public class StorefrontsBuyController(
|
||||
{
|
||||
StoreService.TryGetAvatarItemPayload(grantedSlug, out avatarItemType, out avatarItemDesc);
|
||||
StoreService.TryGetConsumableItemDesc(grantedSlug, out consumableItemDesc);
|
||||
StoreService.TryGetEquipmentPayload(grantedSlug, out equipmentPrefabName, out equipmentModificationGuid);
|
||||
StoreService.TryGetGiftBoxEquipmentPayload(grantedSlug, out equipmentPrefabName, out equipmentModificationGuid);
|
||||
if (StoreService.TryGetHairDyePayload(grantedSlug, out var hairDyeConsumableDesc, out var hairDyeColorGuid))
|
||||
{
|
||||
avatarItemType = 1;
|
||||
|
||||
@@ -338,6 +338,7 @@ public class DorkNetDbContext(DbContextOptions<DorkNetDbContext> options) : DbCo
|
||||
modelBuilder.Entity<PlayerInventoryEntity>(e =>
|
||||
{
|
||||
e.HasKey(p => p.Id);
|
||||
e.Property(p => p.ItemSlug).HasMaxLength(128);
|
||||
// One row per (player, item) pair.
|
||||
e.HasIndex(p => new { p.PlayerId, p.ItemSlug }).IsUnique();
|
||||
e.HasIndex(p => p.PlayerId);
|
||||
|
||||
@@ -23,7 +23,7 @@ public class PlayerInventoryEntity
|
||||
/// Stored as a string rather than an int FK because a player can
|
||||
/// be granted items that aren't in the live store (admin-gifted,
|
||||
/// legacy retired items, etc.).</summary>
|
||||
[MaxLength(64)]
|
||||
[MaxLength(128)]
|
||||
public string ItemSlug { get; set; } = string.Empty;
|
||||
|
||||
public int Quantity { get; set; } = 1;
|
||||
|
||||
@@ -1669,7 +1669,7 @@ namespace DorkNet.Server.Migrations
|
||||
|
||||
b.Property<string>("ItemSlug")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<long>("PlayerId")
|
||||
|
||||
@@ -732,7 +732,7 @@ namespace DorkNet.Server.Migrations
|
||||
Id = table.Column<long>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
PlayerId = table.Column<long>(type: "INTEGER", nullable: false),
|
||||
ItemSlug = table.Column<string>(type: "TEXT", maxLength: 64, nullable: false),
|
||||
ItemSlug = table.Column<string>(type: "TEXT", maxLength: 128, nullable: false),
|
||||
Quantity = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
IsActive = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||
AcquiredAt = table.Column<DateTime>(type: "TEXT", nullable: false)
|
||||
|
||||
@@ -1666,7 +1666,7 @@ namespace DorkNet.Server.Migrations
|
||||
|
||||
b.Property<string>("ItemSlug")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<long>("PlayerId")
|
||||
|
||||
@@ -376,6 +376,40 @@ public class StoreService(DorkNetDbContext db, LevelService level, IConfiguratio
|
||||
out string modificationGuid) =>
|
||||
TryGetEquipmentPayload(slug, out prefabName, out modificationGuid, out _);
|
||||
|
||||
public static bool TryGetGiftBoxEquipmentPayload(
|
||||
string? slug,
|
||||
out string prefabName,
|
||||
out string modificationGuid,
|
||||
out EquipmentSkinEntry? entry)
|
||||
{
|
||||
if (!TryGetEquipmentPayload(slug, out prefabName, out modificationGuid, out entry))
|
||||
return false;
|
||||
|
||||
// The 2020 client previews GiftPackage equipment by spawning the
|
||||
// prefab. Spawning [MakerPen] outside the real tool equip flow wakes
|
||||
// MakerPen tool scripts without their visuals wired up, causing a
|
||||
// repeating MakerPenVisuals null-ref/spin. Still grant the skin as
|
||||
// inventory; just don't ask the gift-box/store-preview path to spawn it.
|
||||
if (IsMakerPenPrefab(prefabName))
|
||||
{
|
||||
prefabName = string.Empty;
|
||||
modificationGuid = string.Empty;
|
||||
entry = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool TryGetGiftBoxEquipmentPayload(
|
||||
string? slug,
|
||||
out string prefabName,
|
||||
out string modificationGuid) =>
|
||||
TryGetGiftBoxEquipmentPayload(slug, out prefabName, out modificationGuid, out _);
|
||||
|
||||
private static bool IsMakerPenPrefab(string? prefabName) =>
|
||||
string.Equals(prefabName, "[MakerPen]", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
private async Task SeedEquipmentSkinsAsync(HashSet<string> existingSlugs)
|
||||
{
|
||||
var catalog = _equipmentSkinCatalog.Value;
|
||||
@@ -942,7 +976,7 @@ public class StoreService(DorkNetDbContext db, LevelService level, IConfiguratio
|
||||
// here too.
|
||||
TryGetAvatarItemPayload(i.Slug, out var avatarItemType, out var avatarItemDesc);
|
||||
TryGetConsumableItemDesc(i.Slug, out var consumableItemDesc);
|
||||
TryGetEquipmentPayload(i.Slug, out var equipmentPrefabName, out var equipmentModificationGuid, out var equipmentEntry);
|
||||
TryGetGiftBoxEquipmentPayload(i.Slug, out var equipmentPrefabName, out var equipmentModificationGuid, out var equipmentEntry);
|
||||
var isHairDye = TryGetHairDyePayload(i.Slug, out var consumableHairDyeDesc, out var hairDyeColorGuid);
|
||||
if (isHairDye)
|
||||
{
|
||||
|
||||
@@ -101,6 +101,7 @@ public static class DatabaseBootstrap
|
||||
// IF NOT EXISTS no-ops when EnsureCreated already built them).
|
||||
await EnsureSignupCodeTablesAsync(db);
|
||||
await EnsureServerSettingsColumnsAsync(db);
|
||||
await EnsureInventorySchemaAsync(db);
|
||||
await EnsureLeaderboardSchemaAsync(db);
|
||||
|
||||
// Coach system account at Player.Id=1. The RR-Original room seeder
|
||||
@@ -303,6 +304,16 @@ public static class DatabaseBootstrap
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task EnsureInventorySchemaAsync(DorkNetDbContext db)
|
||||
{
|
||||
var provider = db.Database.ProviderName ?? string.Empty;
|
||||
if (provider.Contains("Npgsql", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
await db.Database.ExecuteSqlRawAsync(
|
||||
@"ALTER TABLE ""PlayerInventory"" ALTER COLUMN ""ItemSlug"" TYPE character varying(128);");
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task EnsureLeaderboardSchemaAsync(DorkNetDbContext db)
|
||||
{
|
||||
var provider = db.Database.ProviderName ?? string.Empty;
|
||||
|
||||
Reference in New Issue
Block a user