Import march-2020-03-10 from private repo (scrubbed 2026-05-27)
Targets Rec Room 2020.03.10 client (also serves 2020.03.06).
Re-import after adding:
- DorkNet.ClientMod/dorknet-clientmod.json.template — config schema
the launcher's manifest-driven patcher renders into UserData/.
- tools/build-patcher-zip.ps1 — produces dorknet-clientpatch-{key}.zip
for v1-march-* Release uploads.
- .github/workflows/release.yml — on tag push publishes both
dorknet-server-march_2020_03_10-win-x64.zip and
dorknet-clientpatch-march_2020_03_10.zip as Release assets.
Same scrub rules as december; tools/build-patcher-zip.ps1 added to
the maintainer-side allow-list so it survives.
@@ -0,0 +1,556 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using DorkNet.Server.Data.Entities;
|
||||
|
||||
namespace DorkNet.Server.Data;
|
||||
|
||||
public class DorkNetDbContext(DbContextOptions<DorkNetDbContext> options) : DbContext(options)
|
||||
{
|
||||
public DbSet<PlayerEntity> Players => Set<PlayerEntity>();
|
||||
public DbSet<AvatarEntity> Avatars => Set<AvatarEntity>();
|
||||
public DbSet<PlayerSettingEntity> PlayerSettings => Set<PlayerSettingEntity>();
|
||||
public DbSet<RelationshipEntity> Relationships => Set<RelationshipEntity>();
|
||||
public DbSet<RoomEntity> Rooms => Set<RoomEntity>();
|
||||
public DbSet<RoomRoleEntity> RoomRoles => Set<RoomRoleEntity>();
|
||||
public DbSet<LeaderboardChannelMetaEntity> LeaderboardChannelMeta => Set<LeaderboardChannelMetaEntity>();
|
||||
public DbSet<RoomBookmarkEntity> RoomBookmarks => Set<RoomBookmarkEntity>();
|
||||
public DbSet<RoomDataBlobEntity> RoomDataBlobs => Set<RoomDataBlobEntity>();
|
||||
public DbSet<DormStateEntity> DormStates => Set<DormStateEntity>();
|
||||
public DbSet<AdminActionEntity> AdminActions => Set<AdminActionEntity>();
|
||||
public DbSet<InventionEntity> Inventions => Set<InventionEntity>();
|
||||
public DbSet<ReportEntity> Reports => Set<ReportEntity>();
|
||||
public DbSet<IpBanEntity> IpBans => Set<IpBanEntity>();
|
||||
public DbSet<MessageEntity> Messages => Set<MessageEntity>();
|
||||
public DbSet<ChatMessageEntity> ChatMessages => Set<ChatMessageEntity>();
|
||||
public DbSet<ChatThreadEntity> ChatThreads => Set<ChatThreadEntity>();
|
||||
public DbSet<ChatThreadMemberEntity> ChatThreadMembers => Set<ChatThreadMemberEntity>();
|
||||
public DbSet<CheerEntity> Cheers => Set<CheerEntity>();
|
||||
public DbSet<CurrencyBalanceEntity> CurrencyBalances => Set<CurrencyBalanceEntity>();
|
||||
public DbSet<PlayerEventEntity> PlayerEvents => Set<PlayerEventEntity>();
|
||||
public DbSet<PlayerEventResponseEntity> PlayerEventResponses => Set<PlayerEventResponseEntity>();
|
||||
public DbSet<ObjectiveProgressEntity> ObjectiveProgress => Set<ObjectiveProgressEntity>();
|
||||
public DbSet<SubscriptionEntity> Subscriptions => Set<SubscriptionEntity>();
|
||||
public DbSet<PhotoEntity> Photos => Set<PhotoEntity>();
|
||||
public DbSet<StoreItemEntity> StoreItems => Set<StoreItemEntity>();
|
||||
public DbSet<InventionVersionEntity> InventionVersions => Set<InventionVersionEntity>();
|
||||
public DbSet<RoomBanEntity> RoomBans => Set<RoomBanEntity>();
|
||||
public DbSet<PlayerInventoryEntity> PlayerInventory => Set<PlayerInventoryEntity>();
|
||||
public DbSet<GiftPackageEntity> GiftPackages => Set<GiftPackageEntity>();
|
||||
public DbSet<BugReportEntity> BugReports => Set<BugReportEntity>();
|
||||
public DbSet<ClubEntity> Clubs => Set<ClubEntity>();
|
||||
public DbSet<ClubMembershipEntity> ClubMemberships => Set<ClubMembershipEntity>();
|
||||
public DbSet<RoyaleMatchEntity> RoyaleMatches => Set<RoyaleMatchEntity>();
|
||||
public DbSet<RoyaleMatchPlayerEntity> RoyaleMatchPlayers => Set<RoyaleMatchPlayerEntity>();
|
||||
public DbSet<RoyalePlayerProgressEntity> RoyalePlayerProgress => Set<RoyalePlayerProgressEntity>();
|
||||
public DbSet<TestCaseEntity> TestCases => Set<TestCaseEntity>();
|
||||
public DbSet<TestPassEntity> TestPasses => Set<TestPassEntity>();
|
||||
public DbSet<PlayerDeviceEntity> PlayerDevices => Set<PlayerDeviceEntity>();
|
||||
public DbSet<NotificationPrefsEntity> NotificationPrefs => Set<NotificationPrefsEntity>();
|
||||
public DbSet<CohortAssignmentEntity> CohortAssignments => Set<CohortAssignmentEntity>();
|
||||
public DbSet<CouponEntity> Coupons => Set<CouponEntity>();
|
||||
public DbSet<CouponRedemptionEntity> CouponRedemptions => Set<CouponRedemptionEntity>();
|
||||
public DbSet<LeaderboardStatEntity> LeaderboardStats => Set<LeaderboardStatEntity>();
|
||||
public DbSet<PlayerEloEntity> PlayerElo => Set<PlayerEloEntity>();
|
||||
public DbSet<PushTokenEntity> PushTokens => Set<PushTokenEntity>();
|
||||
public DbSet<PlatformIgnoreEntity> PlatformIgnores => Set<PlatformIgnoreEntity>();
|
||||
public DbSet<CardEntity> Cards => Set<CardEntity>();
|
||||
public DbSet<RoomVisitEntity> RoomVisits => Set<RoomVisitEntity>();
|
||||
public DbSet<RoomSceneEntity> RoomScenes => Set<RoomSceneEntity>();
|
||||
public DbSet<PrivateInstanceEntity> PrivateInstances => Set<PrivateInstanceEntity>();
|
||||
public DbSet<PrivateInstanceInviteeEntity> PrivateInstanceInvitees => Set<PrivateInstanceInviteeEntity>();
|
||||
public DbSet<GameSessionEntity> GameSessions => Set<GameSessionEntity>();
|
||||
public DbSet<CommunityBoardEntity> CommunityBoardRows => Set<CommunityBoardEntity>();
|
||||
public DbSet<LoadingScreenTipEntity> LoadingScreenTips => Set<LoadingScreenTipEntity>();
|
||||
public DbSet<ServerSettingsEntity> ServerSettings => Set<ServerSettingsEntity>();
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
// SQLite-specific NOCASE collation works via UseCollation; Postgres
|
||||
// doesn't have NOCASE. Provider-conditional helper applied to the
|
||||
// three string columns the wire API matches case-insensitively
|
||||
// (Room.Name, RoomScene.Name, Club.Name).
|
||||
//
|
||||
// FOLLOW-UP: on Postgres we currently fall back to default case-
|
||||
// sensitive collation on these columns. In practice this is fine
|
||||
// because the wire API users always type the same casing as the
|
||||
// stored value, but if we want strict parity with SQLite NOCASE
|
||||
// semantics we should add a functional LOWER(...) unique index
|
||||
// via raw SQL in a Postgres migration, OR enable the citext
|
||||
// extension and switch the column type. Tracked for post-cutover
|
||||
// hardening; not a launch blocker.
|
||||
var isSqlite = Database.IsSqlite();
|
||||
modelBuilder.Entity<PlayerEntity>(e =>
|
||||
{
|
||||
e.HasKey(p => p.Id);
|
||||
e.HasIndex(p => p.Username).IsUnique();
|
||||
e.HasOne(p => p.Avatar).WithOne(a => a.Player).HasForeignKey<AvatarEntity>(a => a.PlayerId);
|
||||
e.HasMany(p => p.Settings).WithOne(s => s.Player).HasForeignKey(s => s.PlayerId);
|
||||
e.HasMany(p => p.Relationships).WithOne(r => r.Requester).HasForeignKey(r => r.RequesterId);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<RelationshipEntity>(e =>
|
||||
{
|
||||
e.HasKey(r => r.Id);
|
||||
e.HasIndex(r => new { r.RequesterId, r.TargetId }).IsUnique();
|
||||
});
|
||||
|
||||
modelBuilder.Entity<PlayerSettingEntity>(e =>
|
||||
{
|
||||
e.HasKey(s => s.Id);
|
||||
e.HasIndex(s => new { s.PlayerId, s.Key }).IsUnique();
|
||||
});
|
||||
|
||||
modelBuilder.Entity<RoomEntity>(e =>
|
||||
{
|
||||
e.HasKey(r => r.Id);
|
||||
// Room names are case-insensitive in the wire API
|
||||
// (api/rooms/v2/name/{name}) — store collation-insensitive so
|
||||
// GetByName lookups don't depend on the user's casing.
|
||||
e.HasIndex(r => r.Name).IsUnique();
|
||||
if (isSqlite) e.Property(r => r.Name).UseCollation("NOCASE");
|
||||
// Hot-feed sorts by HotScore desc — keep it indexed.
|
||||
e.HasIndex(r => r.HotScore);
|
||||
e.HasIndex(r => r.CreatorPlayerId);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<RoomBookmarkEntity>(e =>
|
||||
{
|
||||
e.HasKey(b => b.Id);
|
||||
e.HasIndex(b => new { b.PlayerId, b.RoomId }).IsUnique();
|
||||
e.HasIndex(b => b.PlayerId);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<RoomDataBlobEntity>(e =>
|
||||
{
|
||||
e.HasKey(b => b.Id);
|
||||
// BlobName is the cdn url segment the client requests; must
|
||||
// be unique across the table because the catch-all matches
|
||||
// by string.
|
||||
e.HasIndex(b => b.BlobName).IsUnique();
|
||||
// "All versions of this room" + "find current" both index
|
||||
// by RoomId. Sort by UploadedAt desc when listing history.
|
||||
e.HasIndex(b => b.RoomId);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<RoomSceneEntity>(e =>
|
||||
{
|
||||
e.HasKey(s => s.Id);
|
||||
// BuildRoomDetails fetches all scenes for one room ordered
|
||||
// by OrderIndex. Composite index covers both predicate and
|
||||
// sort.
|
||||
e.HasIndex(s => new { s.RoomId, s.OrderIndex }).IsUnique();
|
||||
// Sub-room goto resolves by (room, name). Case-insensitive
|
||||
// match — same NOCASE collation pattern as RoomEntity.Name.
|
||||
e.HasIndex(s => new { s.RoomId, s.Name });
|
||||
if (isSqlite) e.Property(s => s.Name).UseCollation("NOCASE");
|
||||
});
|
||||
|
||||
modelBuilder.Entity<DormStateEntity>(e =>
|
||||
{
|
||||
// PlayerId is already declared as [Key] on the entity; explicit
|
||||
// here so EF doesn't expect an Id auto-pk.
|
||||
e.HasKey(d => d.PlayerId);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<AdminActionEntity>(e =>
|
||||
{
|
||||
e.HasKey(a => a.Id);
|
||||
// The audit log is read in reverse-chronological order;
|
||||
// index Timestamp desc for the common "give me recent
|
||||
// admin actions" query.
|
||||
e.HasIndex(a => a.Timestamp);
|
||||
// Filter "all actions taken by admin X" or "all actions
|
||||
// targeting player Y" both want indexes.
|
||||
e.HasIndex(a => a.AdminPlayerId);
|
||||
e.HasIndex(a => new { a.TargetType, a.TargetId });
|
||||
});
|
||||
|
||||
modelBuilder.Entity<InventionEntity>(e =>
|
||||
{
|
||||
e.HasKey(i => i.Id);
|
||||
e.HasIndex(i => i.CreatorPlayerId);
|
||||
// Popular tab orders by CheerCount desc; index it.
|
||||
e.HasIndex(i => i.CheerCount);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<ReportEntity>(e =>
|
||||
{
|
||||
e.HasKey(r => r.Id);
|
||||
// Admin queue reads "open reports ordered by oldest" —
|
||||
// index ResolvedAt so the WHERE IS NULL filter is fast.
|
||||
e.HasIndex(r => r.ResolvedAt);
|
||||
e.HasIndex(r => r.TargetPlayerId);
|
||||
e.HasIndex(r => r.ReporterPlayerId);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<IpBanEntity>(e =>
|
||||
{
|
||||
e.HasKey(b => b.Id);
|
||||
// Middleware queries by Cidr per request — keep it
|
||||
// indexed even though the table will be small.
|
||||
e.HasIndex(b => b.Cidr);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<MessageEntity>(e =>
|
||||
{
|
||||
e.HasKey(m => m.Id);
|
||||
// Inbox query: "messages I received, ordered by SentAt
|
||||
// desc". Index Recipient + SentAt for that path.
|
||||
e.HasIndex(m => new { m.RecipientPlayerId, m.SentAt });
|
||||
e.HasIndex(m => new { m.SenderPlayerId, m.SentAt });
|
||||
});
|
||||
|
||||
modelBuilder.Entity<ChatMessageEntity>(e =>
|
||||
{
|
||||
e.HasKey(c => c.Id);
|
||||
// Thread fetch is "ThreadKey + SentAt desc, take 50".
|
||||
e.HasIndex(c => new { c.ThreadKey, c.SentAt });
|
||||
});
|
||||
|
||||
modelBuilder.Entity<ChatThreadEntity>(e =>
|
||||
{
|
||||
e.HasKey(t => t.Id);
|
||||
// One metadata row per thread — concurrent rename calls
|
||||
// would otherwise duplicate-insert.
|
||||
e.HasIndex(t => t.ThreadKey).IsUnique();
|
||||
});
|
||||
|
||||
modelBuilder.Entity<ChatThreadMemberEntity>(e =>
|
||||
{
|
||||
e.HasKey(m => m.Id);
|
||||
// (Thread, Player) is the natural key — Snooze/MarkRead/
|
||||
// Leave race conditions would otherwise insert duplicate
|
||||
// membership rows under the same player.
|
||||
e.HasIndex(m => new { m.ThreadKey, m.PlayerId }).IsUnique();
|
||||
e.HasIndex(m => m.PlayerId);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<CheerEntity>(e =>
|
||||
{
|
||||
e.HasKey(c => c.Id);
|
||||
// Re-cheer is idempotent on the (from, target, type)
|
||||
// tuple — unique index lets us upsert cleanly.
|
||||
e.HasIndex(c => new { c.FromPlayerId, c.TargetPlayerId, c.TargetRoomId, c.TargetPhotoId, c.Type })
|
||||
.IsUnique();
|
||||
e.HasIndex(c => c.TargetPlayerId);
|
||||
e.HasIndex(c => c.TargetRoomId);
|
||||
e.HasIndex(c => c.TargetPhotoId);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<PhotoEntity>(e =>
|
||||
{
|
||||
e.HasKey(p => p.Id);
|
||||
// Feed pagination is "WHERE IsPublic AND DeletedAt IS NULL
|
||||
// ORDER BY CreatedAt DESC" — index CreatedAt for that.
|
||||
e.HasIndex(p => p.CreatedAt);
|
||||
e.HasIndex(p => p.UploaderPlayerId);
|
||||
e.HasIndex(p => p.RoomId);
|
||||
// BlobName is the cdn URL the client requests; lookups by
|
||||
// it are common (admin moderation, dedupe checks).
|
||||
e.HasIndex(p => p.BlobName);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<StoreItemEntity>(e =>
|
||||
{
|
||||
e.HasKey(s => s.Id);
|
||||
// Slug is referenced from Avatar.InventoryJson — must be
|
||||
// unique so the inventory resolver gets a deterministic
|
||||
// hit when looking up "what does this slug mean?".
|
||||
e.HasIndex(s => s.Slug).IsUnique();
|
||||
// Storefront tab queries filter by storefront + active +
|
||||
// category in that order; index storefront for the most
|
||||
// selective predicate first.
|
||||
e.HasIndex(s => s.Storefront);
|
||||
e.HasIndex(s => new { s.IsActive, s.Category });
|
||||
});
|
||||
|
||||
modelBuilder.Entity<CurrencyBalanceEntity>(e =>
|
||||
{
|
||||
e.HasKey(c => c.Id);
|
||||
// One wallet row per (player, currency) — unique on the
|
||||
// pair so AwardCurrency upserts cleanly.
|
||||
e.HasIndex(c => new { c.PlayerId, c.CurrencyType }).IsUnique();
|
||||
});
|
||||
|
||||
modelBuilder.Entity<PlayerEventEntity>(e =>
|
||||
{
|
||||
e.HasKey(ev => ev.Id);
|
||||
e.HasIndex(ev => ev.CreatorPlayerId);
|
||||
e.HasIndex(ev => ev.StartsAt);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<PlayerEventResponseEntity>(e =>
|
||||
{
|
||||
e.HasKey(r => r.Id);
|
||||
// One response per (event, player); upsert via this
|
||||
// unique index.
|
||||
e.HasIndex(r => new { r.EventId, r.PlayerId }).IsUnique();
|
||||
e.HasIndex(r => r.PlayerId);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<ObjectiveProgressEntity>(e =>
|
||||
{
|
||||
e.HasKey(o => o.Id);
|
||||
e.HasIndex(o => new { o.PlayerId, o.Key }).IsUnique();
|
||||
});
|
||||
|
||||
modelBuilder.Entity<SubscriptionEntity>(e =>
|
||||
{
|
||||
e.HasKey(s => s.Id);
|
||||
// One subscription per (subscriber, target) pair.
|
||||
e.HasIndex(s => new { s.SubscriberPlayerId, s.TargetPlayerId })
|
||||
.IsUnique();
|
||||
// SubscriberCount aggregations index by target.
|
||||
e.HasIndex(s => s.TargetPlayerId);
|
||||
e.HasIndex(s => s.SubscriberPlayerId);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<InventionVersionEntity>(e =>
|
||||
{
|
||||
e.HasKey(v => v.Id);
|
||||
// Version-list query: WHERE InventionId = X ORDER BY
|
||||
// VersionNumber DESC. Index covers both predicates.
|
||||
e.HasIndex(v => new { v.InventionId, v.VersionNumber })
|
||||
.IsUnique();
|
||||
});
|
||||
|
||||
modelBuilder.Entity<RoomBanEntity>(e =>
|
||||
{
|
||||
e.HasKey(b => b.Id);
|
||||
// Match-service join check: "is this player banned from
|
||||
// this room?". Compound index makes that O(log n).
|
||||
e.HasIndex(b => new { b.RoomId, b.BannedPlayerId });
|
||||
e.HasIndex(b => b.BannedPlayerId);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<PlayerInventoryEntity>(e =>
|
||||
{
|
||||
e.HasKey(p => p.Id);
|
||||
// One row per (player, item) pair.
|
||||
e.HasIndex(p => new { p.PlayerId, p.ItemSlug }).IsUnique();
|
||||
e.HasIndex(p => p.PlayerId);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<GiftPackageEntity>(e =>
|
||||
{
|
||||
e.HasKey(g => g.Id);
|
||||
// Inbox query: unconsumed gifts for a player.
|
||||
e.HasIndex(g => new { g.RecipientPlayerId, g.Consumed });
|
||||
});
|
||||
|
||||
modelBuilder.Entity<BugReportEntity>(e =>
|
||||
{
|
||||
e.HasKey(b => b.Id);
|
||||
// Admin queue reads "unread bugs ordered by oldest" —
|
||||
// ReadAt index for the WHERE IS NULL filter.
|
||||
e.HasIndex(b => b.ReadAt);
|
||||
e.HasIndex(b => b.ReporterPlayerId);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<ClubEntity>(e =>
|
||||
{
|
||||
e.HasKey(c => c.Id);
|
||||
e.HasIndex(c => c.Name).IsUnique();
|
||||
// GetByName lookups are case-insensitive on the wire.
|
||||
if (isSqlite) e.Property(c => c.Name).UseCollation("NOCASE");
|
||||
e.HasIndex(c => c.CreatorPlayerId);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<ClubMembershipEntity>(e =>
|
||||
{
|
||||
e.HasKey(m => m.Id);
|
||||
// One membership per (club, player) pair.
|
||||
e.HasIndex(m => new { m.ClubId, m.PlayerId }).IsUnique();
|
||||
e.HasIndex(m => m.PlayerId);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<RoyaleMatchEntity>(e =>
|
||||
{
|
||||
e.HasKey(m => m.Id);
|
||||
e.HasIndex(m => m.CompletedAt);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<RoyaleMatchPlayerEntity>(e =>
|
||||
{
|
||||
e.HasKey(p => p.Id);
|
||||
e.HasIndex(p => new { p.MatchId, p.PlayerId });
|
||||
e.HasIndex(p => p.PlayerId);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<RoyalePlayerProgressEntity>(e =>
|
||||
{
|
||||
e.HasKey(p => p.Id);
|
||||
e.HasIndex(p => p.PlayerId).IsUnique();
|
||||
});
|
||||
|
||||
modelBuilder.Entity<TestCaseEntity>(e =>
|
||||
{
|
||||
e.HasKey(t => t.Pk);
|
||||
// Wire Id (string) is what the client uses in URL params;
|
||||
// unique so the lookup-by-string-id is fast.
|
||||
e.HasIndex(t => t.Id).IsUnique();
|
||||
e.HasIndex(t => t.TestPassId);
|
||||
e.HasIndex(t => t.Status);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<TestPassEntity>(e =>
|
||||
{
|
||||
e.HasKey(p => p.Id);
|
||||
// Don't auto-generate uint Id; we set it explicitly so it
|
||||
// matches the upstream JIRA pass id when seeded.
|
||||
e.Property(p => p.Id).ValueGeneratedNever();
|
||||
});
|
||||
|
||||
modelBuilder.Entity<PlayerDeviceEntity>(e =>
|
||||
{
|
||||
e.HasKey(d => d.Id);
|
||||
// Lookup "all accounts using this device" for ban
|
||||
// enforcement.
|
||||
e.HasIndex(d => d.DeviceId);
|
||||
e.HasIndex(d => d.PlayerId);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<NotificationPrefsEntity>(e =>
|
||||
{
|
||||
e.HasKey(n => n.Id);
|
||||
// One pref row per (player, platform).
|
||||
e.HasIndex(n => new { n.PlayerId, n.Platform }).IsUnique();
|
||||
});
|
||||
|
||||
modelBuilder.Entity<CohortAssignmentEntity>(e =>
|
||||
{
|
||||
e.HasKey(c => c.Id);
|
||||
// Sticky assignment: one per (player, cohort).
|
||||
e.HasIndex(c => new { c.PlayerId, c.CohortKey }).IsUnique();
|
||||
});
|
||||
|
||||
modelBuilder.Entity<CouponEntity>(e =>
|
||||
{
|
||||
e.HasKey(c => c.Id);
|
||||
e.HasIndex(c => c.Code).IsUnique();
|
||||
});
|
||||
|
||||
modelBuilder.Entity<CouponRedemptionEntity>(e =>
|
||||
{
|
||||
e.HasKey(r => r.Id);
|
||||
// Enforce one-redeem-per-player.
|
||||
e.HasIndex(r => new { r.CouponId, r.PlayerId }).IsUnique();
|
||||
});
|
||||
|
||||
modelBuilder.Entity<LeaderboardStatEntity>(e =>
|
||||
{
|
||||
e.HasKey(s => s.Id);
|
||||
// One row per (player, channel) — enforced unique so
|
||||
// SetStats can upsert without race conditions.
|
||||
e.HasIndex(s => new { s.PlayerId, s.StatChannel }).IsUnique();
|
||||
// Rank computation: ORDER BY Value DESC over a channel.
|
||||
e.HasIndex(s => new { s.StatChannel, s.Value });
|
||||
});
|
||||
|
||||
modelBuilder.Entity<PlayerEloEntity>(e =>
|
||||
{
|
||||
e.HasKey(p => p.Id);
|
||||
e.HasIndex(p => new { p.PlayerId, p.GameMode }).IsUnique();
|
||||
// Matchmaker reads ranked players ordered by Elo DESC.
|
||||
e.HasIndex(p => new { p.GameMode, p.Elo });
|
||||
});
|
||||
|
||||
modelBuilder.Entity<PushTokenEntity>(e =>
|
||||
{
|
||||
e.HasKey(t => t.Id);
|
||||
// One token per (player, platform) — APNS revokes the
|
||||
// old one when the user reinstalls, so we upsert.
|
||||
e.HasIndex(t => new { t.PlayerId, t.Platform }).IsUnique();
|
||||
e.HasIndex(t => t.Token);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<PlatformIgnoreEntity>(e =>
|
||||
{
|
||||
e.HasKey(i => i.Id);
|
||||
// One ignore-row per (player, platform, platform user id).
|
||||
e.HasIndex(i => new { i.PlayerId, i.Platform, i.PlatformUserId }).IsUnique();
|
||||
});
|
||||
|
||||
modelBuilder.Entity<CardEntity>(e =>
|
||||
{
|
||||
e.HasKey(c => c.Id);
|
||||
// Home-screen query: WHERE PlayerId IS NULL OR = me
|
||||
// ORDER BY Priority DESC, CreatedAt DESC.
|
||||
e.HasIndex(c => c.PlayerId);
|
||||
e.HasIndex(c => c.ExpiresAt);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<RoomVisitEntity>(e =>
|
||||
{
|
||||
e.HasKey(v => v.Id);
|
||||
// One row per (room, player) — enforced unique so the
|
||||
// visit-upsert doesn't create duplicates under concurrent
|
||||
// /goto calls. Lookup-by-pair is the hot path so the
|
||||
// composite index doubles as the SELECT support index.
|
||||
e.HasIndex(v => new { v.RoomId, v.PlayerId }).IsUnique();
|
||||
// Per-player history view (admin / dev console).
|
||||
e.HasIndex(v => v.PlayerId);
|
||||
// "Recent visitors of this room" view.
|
||||
e.HasIndex(v => new { v.RoomId, v.LastVisitAt });
|
||||
});
|
||||
|
||||
modelBuilder.Entity<PrivateInstanceEntity>(e =>
|
||||
{
|
||||
// Id is server-allocated (computed nonce), not autoincrement.
|
||||
// Mark ValueGenerated.Never so EF doesn't try to round-trip
|
||||
// through a sequence on insert.
|
||||
e.HasKey(p => p.Id);
|
||||
e.Property(p => p.Id).ValueGeneratedNever();
|
||||
e.HasIndex(p => p.OwnerPlayerId);
|
||||
// Quick lookup for "is this player in any private instance"
|
||||
// queries used by NotificationService.
|
||||
e.HasIndex(p => new { p.RoomId, p.SubRoomId });
|
||||
});
|
||||
|
||||
modelBuilder.Entity<PrivateInstanceInviteeEntity>(e =>
|
||||
{
|
||||
// Composite PK: one row per (instance, invitee). Naturally
|
||||
// dedupes repeat-invite calls.
|
||||
e.HasKey(i => new { i.PrivateInstanceId, i.PlayerId });
|
||||
// Reverse-lookup index for "what private instances am I
|
||||
// invited to" queries (the watch's invite inbox).
|
||||
e.HasIndex(i => i.PlayerId);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<GameSessionEntity>(e =>
|
||||
{
|
||||
// Postgres bigserial; SQLite gets INTEGER PRIMARY KEY
|
||||
// AUTOINCREMENT semantics. Both providers' sequences are
|
||||
// process-shared so two replicas don't allocate id=1.
|
||||
e.HasKey(s => s.Id);
|
||||
// The hot lookup is "find a non-full session in this room
|
||||
// and region" — composite index covers it.
|
||||
e.HasIndex(s => new { s.RoomId, s.Region });
|
||||
});
|
||||
|
||||
modelBuilder.Entity<CommunityBoardEntity>(e =>
|
||||
{
|
||||
// Single-row table, id always 1. We don't autoincrement;
|
||||
// the row is upserted explicitly.
|
||||
e.HasKey(c => c.Id);
|
||||
e.Property(c => c.Id).ValueGeneratedNever();
|
||||
});
|
||||
|
||||
modelBuilder.Entity<ServerSettingsEntity>(e =>
|
||||
{
|
||||
// Single-row table, id always 1 — same pattern as
|
||||
// CommunityBoardRows above.
|
||||
e.HasKey(s => s.Id);
|
||||
e.Property(s => s.Id).ValueGeneratedNever();
|
||||
});
|
||||
|
||||
modelBuilder.Entity<LeaderboardChannelMetaEntity>(e =>
|
||||
{
|
||||
// Channel int IS the primary key — there's only one
|
||||
// metadata row per stat-channel id, and the channel id
|
||||
// is what the watch reports on POST /SetStats.
|
||||
e.HasKey(c => c.Channel);
|
||||
e.Property(c => c.Channel).ValueGeneratedNever();
|
||||
e.HasIndex(c => c.RoomId);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace DorkNet.Server.Data.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// Append-only audit row written every time an admin performs a
|
||||
/// privileged action (ban, unban, promote, demote, room delete,
|
||||
/// MOTD change, etc.). The admin watch UI's "audit" tab reads
|
||||
/// from this in reverse-chronological order.
|
||||
///
|
||||
/// Rows are never deleted from the application — privileged actions
|
||||
/// stay on the record. Storage cost is negligible at single-server
|
||||
/// scale.
|
||||
/// </summary>
|
||||
public class AdminActionEntity
|
||||
{
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>The admin who performed the action.</summary>
|
||||
public long AdminPlayerId { get; set; }
|
||||
|
||||
/// <summary>Free-form action name. Convention: lower-snake-case verb,
|
||||
/// e.g. <c>ban_player</c>, <c>unban_player</c>, <c>promote_admin</c>,
|
||||
/// <c>delete_room</c>, <c>set_motd</c>.</summary>
|
||||
[MaxLength(64)]
|
||||
public string Action { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>Targeted entity type — <c>player</c>, <c>room</c>,
|
||||
/// <c>system</c>. Free-form so future actions can introduce new
|
||||
/// kinds without a migration.</summary>
|
||||
[MaxLength(32)]
|
||||
public string TargetType { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>Numeric id of the target. <c>0</c> for system-wide
|
||||
/// actions like setting the MOTD.</summary>
|
||||
public long TargetId { get; set; }
|
||||
|
||||
/// <summary>Optional human reason the admin supplied at action
|
||||
/// time. Surfaced to the audit log UI verbatim.</summary>
|
||||
[MaxLength(512)]
|
||||
public string Reason { get; set; } = string.Empty;
|
||||
|
||||
public DateTime Timestamp { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace DorkNet.Server.Data.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// Per-player avatar state. The 2020 client persists a mix of structured
|
||||
/// and free-form blobs:
|
||||
/// <list type="bullet">
|
||||
/// <item><c>OutfitSelections</c> — comma-separated GUIDs of equipped
|
||||
/// items per slot (head, torso, legs, feet, accessories). Sent
|
||||
/// verbatim to <c>POST api/avatar/v2</c>.</item>
|
||||
/// <item><c>FaceFeatures</c> — JSON blob with eyeId/eyePos/eyeScl/
|
||||
/// mouthId etc. produced by the in-game face editor.</item>
|
||||
/// <item><c>HairColor</c> / <c>SkinColor</c> — color vault GUIDs from
|
||||
/// the client's baked hair/skin color tables.</item>
|
||||
/// <item><c>SavedOutfitsJson</c> — list of named outfit presets the
|
||||
/// watch's Backpack tab shows under "saved".</item>
|
||||
/// <item><c>EquippedItemsJson</c> / <c>InventoryJson</c> — kept for the
|
||||
/// v3 wire shape (list of <see cref="DorkNet.Models.Avatar.AvatarItemInstance"/>).</item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public class AvatarEntity
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public long PlayerId { get; set; }
|
||||
|
||||
// JSON-serialised list of equipped item IDs (v3 shape)
|
||||
public string EquippedItemsJson { get; set; } = "[]";
|
||||
|
||||
// JSON-serialised full inventory (v3 shape)
|
||||
public string InventoryJson { get; set; } = "[]";
|
||||
|
||||
/// <summary>v2 outfit selections — comma-separated GUIDs per slot.</summary>
|
||||
[MaxLength(2048)]
|
||||
public string OutfitSelections { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>v2 face features — opaque JSON written by the face
|
||||
/// editor; we never parse it server-side, just round-trip.</summary>
|
||||
[MaxLength(8192)]
|
||||
public string FaceFeatures { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(64)]
|
||||
public string HairColor { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(64)]
|
||||
public string SkinColor { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>Saved outfit presets — JSON list of named slots so the
|
||||
/// watch's "Saved" tab can recall them.</summary>
|
||||
public string SavedOutfitsJson { get; set; } = "[]";
|
||||
|
||||
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
public PlayerEntity? Player { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace DorkNet.Server.Data.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// One bug report submitted via the in-game "Report a Bug" UI
|
||||
/// (<c>POST /api/bugreporting/v2/reportbug</c>). Surfaces in the
|
||||
/// admin moderation queue at <c>GET /api/admin/v1/bugreports</c>.
|
||||
/// </summary>
|
||||
public class BugReportEntity
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public long ReporterPlayerId { get; set; }
|
||||
|
||||
[MaxLength(128)]
|
||||
public string Title { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(4000)]
|
||||
public string Body { get; set; } = string.Empty;
|
||||
|
||||
public long GameSessionId { get; set; }
|
||||
|
||||
[MaxLength(64)]
|
||||
public string ClientVersion { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(32)]
|
||||
public string Platform { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>Optional category for routing — also reused by Phase
|
||||
/// 11's <c>POST /api/hile/v1/log</c> (huddle telemetry) which
|
||||
/// piggybacks on this table with Category=`hile`.</summary>
|
||||
[MaxLength(32)]
|
||||
public string Category { get; set; } = "bug";
|
||||
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
public DateTime? ReadAt { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace DorkNet.Server.Data.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// In-game text-chat message. Sent to the chat.rec.net/thread
|
||||
/// endpoint family; backed by a flat per-thread row table where the
|
||||
/// thread id is just the canonical (lower, higher) pair of player ids
|
||||
/// for DMs, or the room id for room-wide chats.
|
||||
///
|
||||
/// We keep a separate table from <see cref="MessageEntity"/> because
|
||||
/// the wire shape and history-fetch semantics differ — chat is
|
||||
/// append-and-read-recent, messages are inbox-style with read
|
||||
/// receipts.
|
||||
/// </summary>
|
||||
public class ChatMessageEntity
|
||||
{
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>String thread key. Format: <c>dm:<low>:<high></c> for
|
||||
/// direct messages between two players (lower id first), or
|
||||
/// <c>room:<roomId></c> for room-wide chats.</summary>
|
||||
[MaxLength(64)]
|
||||
public string ThreadKey { get; set; } = string.Empty;
|
||||
|
||||
public long SenderPlayerId { get; set; }
|
||||
|
||||
[MaxLength(2000)]
|
||||
public string Body { get; set; } = string.Empty;
|
||||
|
||||
public DateTime SentAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
/// <summary>Build the canonical DM thread key for two players.
|
||||
/// Order-independent so both sides hit the same row.</summary>
|
||||
public static string DmKey(long a, long b) =>
|
||||
a < b ? $"dm:{a}:{b}" : $"dm:{b}:{a}";
|
||||
|
||||
public static string RoomKey(long roomId) => $"room:{roomId}";
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace DorkNet.Server.Data.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// Per-thread metadata for chat: name (for group chats), creator, and
|
||||
/// timestamps. Rows here are sparse — a two-person DM doesn't need
|
||||
/// one unless the players want a custom thread name. Group chats
|
||||
/// always have a row so the member set + name are persisted.
|
||||
/// </summary>
|
||||
public class ChatThreadEntity
|
||||
{
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>Canonical thread key (matches <c>ChatMessageEntity.ThreadKey</c>).
|
||||
/// Format: <c>dm:<low>:<high></c> for DMs,
|
||||
/// <c>group:<guid></c> for group chats, <c>room:<id></c> for room-wide.</summary>
|
||||
[MaxLength(96)]
|
||||
public string ThreadKey { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>Optional custom name. DMs default to empty (watch renders
|
||||
/// "Chat with <username>" client-side); group chats persist a
|
||||
/// name set via <c>PUT thread/{id}/rename</c>.</summary>
|
||||
[MaxLength(128)]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
public long CreatorPlayerId { get; set; }
|
||||
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
namespace DorkNet.Server.Data.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// Per-(thread, player) row: membership, per-player snooze, and the
|
||||
/// last-read message id used for unread counts and the inbox's "X
|
||||
/// unread" badge. One row per active participant. A "leave" deletes
|
||||
/// the row so the player no longer receives new messages on that
|
||||
/// thread.
|
||||
///
|
||||
/// For two-person DMs without a custom name, rows are created lazily
|
||||
/// on first MarkRead / Snooze / Leave — the thread itself still works
|
||||
/// fine without rows (the message table is the source of truth for
|
||||
/// who participated).
|
||||
/// </summary>
|
||||
public class ChatThreadMemberEntity
|
||||
{
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>The thread this membership applies to. Matches
|
||||
/// <c>ChatMessageEntity.ThreadKey</c> / <c>ChatThreadEntity.ThreadKey</c>.</summary>
|
||||
public string ThreadKey { get; set; } = string.Empty;
|
||||
|
||||
public long PlayerId { get; set; }
|
||||
|
||||
public DateTime JoinedAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
/// <summary>When set, the watch's inbox treats this thread as
|
||||
/// muted until the UTC timestamp. Cleared by re-snoozing with a
|
||||
/// null payload.</summary>
|
||||
public DateTime? SnoozeUntil { get; set; }
|
||||
|
||||
/// <summary>Id of the last <c>ChatMessageEntity</c> the player
|
||||
/// has acknowledged via <c>PUT thread/{id}/read</c>. Drives the
|
||||
/// per-thread unread counter on the watch's inbox tab.</summary>
|
||||
public long? LastReadMessageId { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
namespace DorkNet.Server.Data.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// One cheer (the watch's positive-feedback button). Targets exactly
|
||||
/// one of: a player (stored on <see cref="TargetPlayerId"/>), a room
|
||||
/// (<see cref="TargetRoomId"/>), or a photo (<see cref="TargetPhotoId"/>).
|
||||
/// Unused targets are 0. Aggregated reputation queries SUM rows by
|
||||
/// target.
|
||||
///
|
||||
/// One row per (FromPlayer, target, Type) — re-cheering is idempotent
|
||||
/// (we upsert on the unique index).
|
||||
/// </summary>
|
||||
public class CheerEntity
|
||||
{
|
||||
public long Id { get; set; }
|
||||
|
||||
public long FromPlayerId { get; set; }
|
||||
|
||||
public long TargetPlayerId { get; set; }
|
||||
public long TargetRoomId { get; set; }
|
||||
public long TargetPhotoId { get; set; }
|
||||
public long TargetInventionId { get; set; }
|
||||
|
||||
/// <summary>RoomieCheerType enum mirror: 0=General, 1=Helpful,
|
||||
/// 2=GreatHost, 3=Sportsman, 4=Creative, 5=Credit. Stored as int
|
||||
/// to leave room for future categories without a migration.</summary>
|
||||
public int Type { get; set; }
|
||||
|
||||
public DateTime CheeredAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace DorkNet.Server.Data.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// A "Group" / club — wire type <c>RecNet.Group</c>
|
||||
/// (<c>Cpp2IL_CS/.../RecNet/Group.cs</c>). Field names + types match
|
||||
/// the client's <c>Group.Deserialize</c> shape so the watch round-
|
||||
/// trips cleanly. Surfaces in the watch's profile tab as the player's
|
||||
/// primary-group affiliation.
|
||||
/// </summary>
|
||||
public class ClubEntity
|
||||
{
|
||||
/// <summary>Mirrors wire field <c>GroupId</c>.</summary>
|
||||
public long Id { get; set; }
|
||||
|
||||
[MaxLength(128)]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(2000)]
|
||||
public string Description { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>Mirrors wire <c>CreatorId</c> (Int32). Cast to int
|
||||
/// in serialiser.</summary>
|
||||
public long CreatorPlayerId { get; set; }
|
||||
|
||||
[MaxLength(256)]
|
||||
public string ImageName { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>GroupBanStatus enum: 0=GoodStanding, 1=InReview,
|
||||
/// 2=TempLock, 3=Permaban.</summary>
|
||||
public int BanStatus { get; set; } = 0;
|
||||
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
/// <summary>One row per (club, player). Permissions is the
|
||||
/// <c>GroupMembershipPermissions</c> flags enum (Member=0, Moderator=24,
|
||||
/// CoOwner=124, Owner=127, Pending=128 for join-requests on private
|
||||
/// groups).</summary>
|
||||
public class ClubMembershipEntity
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public long ClubId { get; set; }
|
||||
public long PlayerId { get; set; }
|
||||
|
||||
/// <summary>GroupMembershipPermissions flags enum value.</summary>
|
||||
public int Permissions { get; set; } = 0;
|
||||
|
||||
public DateTime JoinedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
namespace DorkNet.Server.Data.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// Single-row table holding the dorm community board state. Replaces
|
||||
/// <c>data/community_board.json</c> on disk + in-memory cache so admin
|
||||
/// edits propagate across replicas without a file-watcher invalidation
|
||||
/// dance.
|
||||
///
|
||||
/// Only one row exists, with <see cref="Id"/> = 1. Reading is a single
|
||||
/// SELECT (cheap; the board is one document, not paginated). Writing
|
||||
/// is a single UPDATE — no synchronization needed because there's only
|
||||
/// ever one row to contend on, and admin edits are rare.
|
||||
/// </summary>
|
||||
public class CommunityBoardEntity
|
||||
{
|
||||
/// <summary>Always 1. We model it as an int PK rather than a
|
||||
/// composite or singleton-table pattern because EF Core needs a key
|
||||
/// to track changes; pinning to id=1 keeps the upsert pattern
|
||||
/// simple.</summary>
|
||||
public int Id { get; set; } = 1;
|
||||
|
||||
/// <summary>JSON-serialised <c>CommunityBoardState</c>. Stored as
|
||||
/// text rather than jsonb because we never query inside it — it's
|
||||
/// loaded as a single blob and round-tripped to the client.</summary>
|
||||
public string Json { get; set; } = "{}";
|
||||
|
||||
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace DorkNet.Server.Data.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// Admin-issued promo coupon. Players redeem by code via
|
||||
/// <c>POST /api/coupons/v1/redeem/{code}</c>. Each redemption
|
||||
/// inserts a <see cref="CouponRedemptionEntity"/> row (one per
|
||||
/// (coupon, player) pair so we can enforce one-redeem-per-player).
|
||||
/// </summary>
|
||||
public class CouponEntity
|
||||
{
|
||||
public long Id { get; set; }
|
||||
|
||||
[MaxLength(64)]
|
||||
public string Code { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(256)]
|
||||
public string Description { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>RewardType: 0=Currency, 1=ItemSlug, 2=Subscription.</summary>
|
||||
public int RewardType { get; set; }
|
||||
|
||||
/// <summary>Currency type if RewardType=0; otherwise unused.</summary>
|
||||
public int RewardCurrencyType { get; set; }
|
||||
|
||||
public long RewardAmount { get; set; }
|
||||
|
||||
/// <summary>Item slug if RewardType=1.</summary>
|
||||
[MaxLength(64)]
|
||||
public string RewardItemSlug { get; set; } = string.Empty;
|
||||
|
||||
public bool IsActive { get; set; } = true;
|
||||
public int MaxRedemptions { get; set; } = 0;
|
||||
public int RedemptionCount { get; set; } = 0;
|
||||
|
||||
public DateTime? ExpiresAt { get; set; }
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
public class CouponRedemptionEntity
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public long CouponId { get; set; }
|
||||
public long PlayerId { get; set; }
|
||||
public DateTime RedeemedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
namespace DorkNet.Server.Data.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// Per-player wallet for a single currency. The 2020 client knows
|
||||
/// about a small set of <c>CurrencyType</c>s (1=Coins, 2=Tokens, …);
|
||||
/// each gets its own row keyed by (PlayerId, CurrencyType).
|
||||
///
|
||||
/// Updates go through <see cref="DorkNet.Server.Services.LevelService"/>
|
||||
/// or admin grants; reads back through the
|
||||
/// <c>storefronts/v4/balance/{currencyType}</c> endpoint.
|
||||
/// </summary>
|
||||
public class CurrencyBalanceEntity
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public long PlayerId { get; set; }
|
||||
public int CurrencyType { get; set; }
|
||||
public long Balance { get; set; }
|
||||
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace DorkNet.Server.Data.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// Per-player dorm state. Decouples each player's dorm save bytes from
|
||||
/// the canonical RoomEntity row at <c>RoomId=1</c> (which is shared
|
||||
/// across every dorm visit and would otherwise leak one player's save
|
||||
/// into every other player's dorm).
|
||||
///
|
||||
/// One row per account that has ever entered their dorm. Created on the
|
||||
/// first <c>/api/rooms/v4/details/1</c> hit and updated whenever the
|
||||
/// player saves their dorm via Maker Pen.
|
||||
/// </summary>
|
||||
public class DormStateEntity
|
||||
{
|
||||
/// <summary>The owning account id. Primary key — one dorm state row
|
||||
/// per player.</summary>
|
||||
[Key]
|
||||
public long PlayerId { get; set; }
|
||||
|
||||
/// <summary>Blob name for the player's most recent dorm save. Format
|
||||
/// <c>dorm_p<accountId>_v<n>.dat</c>; matches the
|
||||
/// <see cref="RoomDataBlobEntity.BlobName"/> stored when the upload
|
||||
/// landed. Empty string before the player has saved.</summary>
|
||||
[MaxLength(128)]
|
||||
public string CurrentDataBlobName { get; set; } = string.Empty;
|
||||
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace DorkNet.Server.Data.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// Active game session backing the matchmaking <c>JoinOrCreate</c> flow
|
||||
/// in <see cref="DorkNet.Server.Services.GameSessionService"/>. Replaces
|
||||
/// the in-process <c>ConcurrentDictionary</c> + atomic counter so:
|
||||
/// <list type="bullet">
|
||||
/// <item>Session ids are allocated by Postgres bigserial — no
|
||||
/// replica-local counter that collides with another replica's
|
||||
/// after restart.</item>
|
||||
/// <item>A "find a non-full session in this room+region" query
|
||||
/// coordinates across all replicas; without it, two players
|
||||
/// joining via different replicas could each create their own
|
||||
/// fresh session for the same room and end up isolated.</item>
|
||||
/// </list>
|
||||
///
|
||||
/// Sessions are deleted when their PlayerCount hits 0 (handled in the
|
||||
/// service, no FK cascade needed). Brief mid-rejoin flicker is fine —
|
||||
/// the next JoinOrCreate just creates a new session with a new id.
|
||||
/// </summary>
|
||||
public class GameSessionEntity
|
||||
{
|
||||
/// <summary>bigserial — allocated by Postgres on insert. Crosses
|
||||
/// replicas safely because the sequence is shared.</summary>
|
||||
public long Id { get; set; }
|
||||
|
||||
[MaxLength(64)] public string RoomId { get; set; } = string.Empty;
|
||||
[MaxLength(64)] public string ActivityLevelId { get; set; } = string.Empty;
|
||||
[MaxLength(16)] public string Region { get; set; } = "us";
|
||||
[MaxLength(128)] public string PhotonRoomName { get; set; } = string.Empty;
|
||||
public int MaxCapacity { get; set; } = 8;
|
||||
public int PlayerCount { get; set; } = 0;
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace DorkNet.Server.Data.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// Per <c>RecNet.Avatars+GiftPackage</c> wire shape (decompiled at
|
||||
/// <c>Cpp2IL_CS/.../RecNet/Avatars.cs:192-555</c>) — a queued gift the
|
||||
/// recipient can claim from the watch's "gifts" inbox. Used for both
|
||||
/// admin-granted gifts and gift-drop / mystery-box / level-up prizes.
|
||||
///
|
||||
/// Field names + types match the client's
|
||||
/// <c>GiftPackage.Deserialize(Dictionary<String, Object>)</c>
|
||||
/// directly so the watch round-trips cleanly. <see cref="Consumed"/>
|
||||
/// is the bool the client reads — we additionally stamp
|
||||
/// <see cref="ConsumedAt"/> for server-side bookkeeping (not on wire).
|
||||
/// </summary>
|
||||
public class GiftPackageEntity
|
||||
{
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>The player whose inbox this gift sits in.</summary>
|
||||
public long RecipientPlayerId { get; set; }
|
||||
|
||||
/// <summary>Wire field (Nullable<Int32>) — the player who
|
||||
/// sent the gift, or null for system / drop gifts.</summary>
|
||||
public int? FromPlayerId { get; set; }
|
||||
|
||||
[MaxLength(128)]
|
||||
public string ConsumableItemDesc { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>Wire field <c>AvatarItemType</c> as Nullable<int>
|
||||
/// (0 = Outfit, 1 = HairDye). Null when the gift has no avatar
|
||||
/// item (currency-only, equipment-only, etc.).</summary>
|
||||
public int? AvatarItemType { get; set; }
|
||||
|
||||
/// <summary>Wire field name is exactly <c>AvatarItemDescOrHairDyeDesc</c>
|
||||
/// — content is either the AvatarItem GUID (when AvatarItemType=0)
|
||||
/// or the HairDye desc string (when AvatarItemType=1).</summary>
|
||||
[MaxLength(128)]
|
||||
public string AvatarItemDescOrHairDyeDesc { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(128)]
|
||||
public string EquipmentPrefabName { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(64)]
|
||||
public string EquipmentModificationGuid { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>CurrencyType enum: 0=Invalid, 1=LaserTagTickets,
|
||||
/// 2=RecCenterTokens, 100=LostSkullsGold, 101=DraculaSilver,
|
||||
/// 200=RecRoyale_Season1.</summary>
|
||||
public int CurrencyType { get; set; } = 0;
|
||||
|
||||
public int Currency { get; set; } = 0;
|
||||
public int Xp { get; set; } = 0;
|
||||
public int Level { get; set; } = 0;
|
||||
|
||||
/// <summary>GiftContext enum (large, see Avatars.cs comments).
|
||||
/// 0 = Default, 100 = LevelUp, 1000 = Holiday, etc.</summary>
|
||||
public int GiftContext { get; set; } = 0;
|
||||
|
||||
/// <summary>GiftRarity: -1=None, 0=Common, 10=Uncommon, 20=Rare,
|
||||
/// 30=Epic, 50=Legendary.</summary>
|
||||
public int GiftRarity { get; set; } = 0;
|
||||
|
||||
[MaxLength(512)]
|
||||
public string Message { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>PlatformType: -1=All, 0=Steam, 1=Oculus, 2=PlayStation,
|
||||
/// 3=Microsoft, 4=HeadlessBot, 5=IOS.</summary>
|
||||
public int Platform { get; set; } = -1;
|
||||
|
||||
/// <summary>Asset name string for the Unity Material that the
|
||||
/// gift box renders with.</summary>
|
||||
[MaxLength(128)]
|
||||
public string PackageMaterial { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>Asset name string for the GiftPackageVariant
|
||||
/// ScriptableObject (e.g. "Standard", "Holiday", etc.).</summary>
|
||||
[MaxLength(128)]
|
||||
public string PackageVariant { get; set; } = string.Empty;
|
||||
|
||||
public bool Consumed { get; set; } = false;
|
||||
public bool IsValid { get; set; } = true;
|
||||
|
||||
[MaxLength(512)]
|
||||
public string ErrorMessage { get; set; } = string.Empty;
|
||||
|
||||
public bool SupportsCurrentPlatform { get; set; } = true;
|
||||
public bool IsGifted { get; set; } = false;
|
||||
|
||||
/// <summary>Server-side audit timestamp; not part of wire
|
||||
/// shape.</summary>
|
||||
public DateTime? ConsumedAt { get; set; }
|
||||
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace DorkNet.Server.Data.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// A Maker-Pen creation that the player has saved as a reusable
|
||||
/// "invention" — can be re-spawned in any room they enter, shared with
|
||||
/// other players, or featured on the watch's Inventions tab. The
|
||||
/// underlying SpawnableTemplateData protobuf bytes are uploaded via
|
||||
/// <c>storage.rec.net/upload</c> with FileType=Invention (5).
|
||||
/// </summary>
|
||||
public class InventionEntity
|
||||
{
|
||||
public long Id { get; set; }
|
||||
|
||||
public long CreatorPlayerId { get; set; }
|
||||
|
||||
/// <summary>Stable opaque GUID the client uses to deduplicate
|
||||
/// instantiated inventions across rooms (matches
|
||||
/// <c>Invention.ReplicationId</c>). Generated server-side at
|
||||
/// create time.</summary>
|
||||
[MaxLength(64)]
|
||||
public string ReplicationId { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(128)]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(2000)]
|
||||
public string Description { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(256)]
|
||||
public string ImageName { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>Legacy permission column (private=0/friends=1/public=2)
|
||||
/// — kept for backward-compat with existing rows; new logic uses
|
||||
/// <see cref="GeneralPermission"/> + <see cref="CreatorPermission"/>
|
||||
/// (InventionPermission enum: Unassigned=0, LimitedOneUseOnly=10,
|
||||
/// UseOnly=20, EditAndSave=40, Publish=60, Charge=80,
|
||||
/// Unlimited=100).</summary>
|
||||
public int Permission { get; set; } = 0;
|
||||
|
||||
/// <summary>InventionPermission value the creator gets when
|
||||
/// spawning their own creation (default Unlimited=100).</summary>
|
||||
public int CreatorPermission { get; set; } = 100;
|
||||
|
||||
/// <summary>InventionPermission value other players get when
|
||||
/// spawning. Defaults Unassigned=0 (private).</summary>
|
||||
public int GeneralPermission { get; set; } = 0;
|
||||
|
||||
/// <summary>True once <c>POST api/inventions/v2/publish</c> sets
|
||||
/// a non-Unassigned <see cref="GeneralPermission"/>. Stays true
|
||||
/// across re-edits — the wire field tracks "has this ever been
|
||||
/// published".</summary>
|
||||
public bool IsPublished { get; set; } = false;
|
||||
|
||||
/// <summary>1-based latest version index. Bumped each time
|
||||
/// <c>POST api/inventions/v3/addversion</c> uploads new bytes.
|
||||
/// Mirrors <c>Invention.CurrentVersionNumber</c>.</summary>
|
||||
public int CurrentVersionNumber { get; set; } = 1;
|
||||
|
||||
/// <summary>Set on first publish. Null until then.</summary>
|
||||
public DateTime? FirstPublishedAt { get; set; }
|
||||
|
||||
/// <summary>If the creator was in a room when first saving,
|
||||
/// the originating room id for analytics.</summary>
|
||||
public long? CreationRoomId { get; set; }
|
||||
|
||||
/// <summary>How many distinct players have spawned this
|
||||
/// invention in any room (rolling counter — increments on
|
||||
/// download).</summary>
|
||||
public int NumPlayersHaveUsedInRoom { get; set; } = 0;
|
||||
|
||||
/// <summary>True for AG (community-built) inventions, false for
|
||||
/// "Rec Room Original" / staff-baked ones.</summary>
|
||||
public bool IsAgInvention { get; set; } = true;
|
||||
|
||||
/// <summary>Most recent uploaded blob name. Format
|
||||
/// <c>invention_<id>_v<n>.dat</c>; the cdn catch-all serves the
|
||||
/// matching <see cref="RoomDataBlobEntity"/> bytes.</summary>
|
||||
[MaxLength(128)]
|
||||
public string CurrentBlobName { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(1024)]
|
||||
public string TagsCsv { get; set; } = string.Empty;
|
||||
|
||||
public int CheerCount { get; set; } = 0;
|
||||
public int SpawnCount { get; set; } = 0;
|
||||
|
||||
/// <summary>Soft-delete flag. When set, the row is hidden from
|
||||
/// browse / search / detail endpoints but stays in the table so
|
||||
/// existing references (cheers, reports) keep resolving and the
|
||||
/// blob bytes can be restored if needed.</summary>
|
||||
public bool IsDeleted { get; set; } = false;
|
||||
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace DorkNet.Server.Data.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// One historical version of an <see cref="InventionEntity"/>. Each
|
||||
/// time the creator uploads a new SpawnableTemplateData blob via
|
||||
/// <c>POST api/inventions/v3/addversion</c>, we snapshot the prior
|
||||
/// blob name into a new row here so the watch's "version history"
|
||||
/// tab and `GET api/inventions/v1/versions?inventionId=X` can list
|
||||
/// them. Indexed on (InventionId, VersionNumber DESC) for the
|
||||
/// common "show me the version list" query.
|
||||
/// </summary>
|
||||
public class InventionVersionEntity
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public long InventionId { get; set; }
|
||||
|
||||
/// <summary>Mirrors <c>InventionVersion.ReplicationId</c> — opaque
|
||||
/// GUID the client uses to deduplicate spawns of this specific
|
||||
/// version across rooms.</summary>
|
||||
[MaxLength(64)]
|
||||
public string ReplicationId { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>1-based version index. Auto-assigned to
|
||||
/// max(VersionNumber) + 1 on insert.</summary>
|
||||
public int VersionNumber { get; set; }
|
||||
|
||||
[MaxLength(128)]
|
||||
public string BlobName { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>Tokens it costs to spawn this version of the
|
||||
/// invention (decompiled wire field
|
||||
/// <c>InventionVersion.InstantiationCost</c>).</summary>
|
||||
public int InstantiationCost { get; set; } = 0;
|
||||
|
||||
/// <summary>Watt budget the creation consumes
|
||||
/// (<c>InventionVersion.LightsCost</c>).</summary>
|
||||
public int LightsCost { get; set; } = 0;
|
||||
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace DorkNet.Server.Data.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// IP-level ban for blocking misbehaving traffic before the JWT-based
|
||||
/// player ban can apply. Checked by <c>IpBanCheckMiddleware</c> ahead
|
||||
/// of authentication; matching requests get a 403.
|
||||
///
|
||||
/// CIDR notation lets a single row block a /24 or /32. The expiry is
|
||||
/// optional — null means "permanent until manually removed".
|
||||
/// </summary>
|
||||
public class IpBanEntity
|
||||
{
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>CIDR or single-IP string (<c>1.2.3.4</c> or <c>1.2.3.0/24</c>).
|
||||
/// Compared against <c>HttpContext.Connection.RemoteIpAddress</c>.</summary>
|
||||
[MaxLength(64)]
|
||||
public string Cidr { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(512)]
|
||||
public string Reason { get; set; } = string.Empty;
|
||||
|
||||
public long BannedByAdminId { get; set; }
|
||||
public DateTime BannedAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
/// <summary>Null = permanent.</summary>
|
||||
public DateTime? Until { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
namespace DorkNet.Server.Data.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// Admin-curated metadata for a leaderboard <c>StatChannel</c> id. The
|
||||
/// 2020 watch reports raw integer channel ids via
|
||||
/// <c>POST api/Leaderboard/v1/SetStats</c>; this table lets admins map
|
||||
/// each channel to a specific room (so the room detail page can list
|
||||
/// "its" leaderboards) and a human-readable name + ordering hint. Rows
|
||||
/// here override the hardcoded <c>AdminController.KnownStatChannels</c>
|
||||
/// fallback. Channels with no row stay listed as "Channel N".
|
||||
///
|
||||
/// One channel id, one row. Repeated <c>SetStats</c> calls for the same
|
||||
/// channel from any room write to that channel's value rows; the meta
|
||||
/// row only changes when an admin renames or re-maps it.
|
||||
/// </summary>
|
||||
public class LeaderboardChannelMetaEntity
|
||||
{
|
||||
/// <summary>Same int the watch reports for this channel. Primary
|
||||
/// key — there's only ever one meta row per channel.</summary>
|
||||
public int Channel { get; set; }
|
||||
|
||||
/// <summary>Room this channel "belongs to" for the per-room detail
|
||||
/// view. 0 = global / unscoped (e.g. cross-room player progression
|
||||
/// counters). The same room can own many channels (e.g. Stunt
|
||||
/// Runner has one channel per course).</summary>
|
||||
public long RoomId { get; set; }
|
||||
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>When true, a lower stored value is a better score (race
|
||||
/// times, lap times, etc.). The list endpoint sorts ascending.</summary>
|
||||
public bool LowerIsBetter { get; set; }
|
||||
|
||||
/// <summary>UI hint: "count" (default), "time-ms" for elapsed-time
|
||||
/// channels, "score" for points. The SPA formats accordingly.</summary>
|
||||
public string ValueFormat { get; set; } = "count";
|
||||
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace DorkNet.Server.Data.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// Tip shown on the dorm-load splash. Served via
|
||||
/// <c>cdn.{rec.net,localhost}/config/LoadingScreenTipData</c>; edited via
|
||||
/// the admin SPA. Wire shape per <c>RecNet/LoadingScreenTip.cs</c>
|
||||
/// requires Title/Message/ImageName + Context/PlatformMask/HasImage
|
||||
/// flags + an optional RoomNames list (scopes the tip to specific
|
||||
/// rooms).
|
||||
/// </summary>
|
||||
public class LoadingScreenTipEntity
|
||||
{
|
||||
public long Id { get; set; }
|
||||
|
||||
[MaxLength(128)] public string Title { get; set; } = string.Empty;
|
||||
[MaxLength(512)] public string Message { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>Optional uploaded image (RoomDataBlob filename). Empty
|
||||
/// when the tip is text-only; CdnController sets
|
||||
/// <c>HasImage</c> in the wire payload based on this.</summary>
|
||||
[MaxLength(128)] public string ImageName { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>RecNet LoadingScreenContext enum (0 = Any). Controls
|
||||
/// which loading screens the tip is eligible for.</summary>
|
||||
public int Context { get; set; } = 0;
|
||||
|
||||
/// <summary>PlatformMask bitfield (-1 = every platform). Used by
|
||||
/// the watch to filter out tips that reference platform-specific
|
||||
/// features (e.g. mobile-only).</summary>
|
||||
public int PlatformMask { get; set; } = -1;
|
||||
|
||||
/// <summary>CSV of room names this tip is scoped to. Empty = show
|
||||
/// in any room's loading screen. Example: "DormRoom,MakerRoom".</summary>
|
||||
[MaxLength(512)] public string RoomNamesCsv { get; set; } = string.Empty;
|
||||
|
||||
public int SortOrder { get; set; } = 0;
|
||||
public bool IsActive { get; set; } = true;
|
||||
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace DorkNet.Server.Data.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// Direct message between two players. Backs the watch's
|
||||
/// <c>api/messages/v2</c> endpoints (inbox + send + mark-read).
|
||||
///
|
||||
/// One row per message. Threading happens at read time — the inbox
|
||||
/// query groups by (Sender, Recipient) pair to surface the most
|
||||
/// recent message per conversation.
|
||||
/// </summary>
|
||||
public class MessageEntity
|
||||
{
|
||||
public long Id { get; set; }
|
||||
|
||||
public long SenderPlayerId { get; set; }
|
||||
public long RecipientPlayerId { get; set; }
|
||||
|
||||
[MaxLength(2000)]
|
||||
public string Body { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>RecNet <c>Message.MessageType</c> wire value (see
|
||||
/// <c>Cpp2IL_CS/.../RecNet/Message.cs</c>). Default 30 =
|
||||
/// TextMessage. Other values used by the 2020 client: 0/6 =
|
||||
/// GameInvite[V2], 3/7 = PartyActivitySwitch[V2], 10 =
|
||||
/// RequestGameInvite (the "ask to join" flow), 1 =
|
||||
/// GameInviteDeclined, 11 = RequestGameInviteDeclined, 20 =
|
||||
/// FriendStatusOnline.</summary>
|
||||
public int Type { get; set; } = 30;
|
||||
|
||||
/// <summary>Optional RecNet room id carried by invite and party
|
||||
/// activity messages. The client uses this to render room-aware
|
||||
/// cards and passes it back when accepting V2 invites.</summary>
|
||||
public long? RoomId { get; set; }
|
||||
|
||||
public DateTime SentAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
/// <summary>Null until the recipient hits the message in the
|
||||
/// watch UI; set to the read timestamp at that point.</summary>
|
||||
public DateTime? ReadAt { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace DorkNet.Server.Data.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// Per-player objective / achievement progress. The 2020 client's
|
||||
/// <c>Objectives.MyProgress</c> response is two arrays — Objectives
|
||||
/// and ObjectiveGroups — keyed by string id. We collapse that to one
|
||||
/// table here; group rows distinguish themselves with a leading
|
||||
/// <c>group:</c> prefix on <see cref="Key"/>.
|
||||
/// </summary>
|
||||
public class ObjectiveProgressEntity
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public long PlayerId { get; set; }
|
||||
|
||||
/// <summary>Objective id from the client's hardcoded objective
|
||||
/// table (e.g. <c>tutorial_dorm_decorate</c>). Group rows use
|
||||
/// <c>group:<groupId></c>.</summary>
|
||||
[MaxLength(128)]
|
||||
public string Key { get; set; } = string.Empty;
|
||||
|
||||
public bool IsCompleted { get; set; }
|
||||
public DateTime? ClearedAt { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace DorkNet.Server.Data.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// One in-game camera photo, posted to the social feed. The actual
|
||||
/// pixel bytes live in <see cref="RoomDataBlobEntity"/> keyed by
|
||||
/// <see cref="BlobName"/> (uploaded earlier via storage.rec.net's
|
||||
/// /upload endpoint with FileType=Image). This entity wraps that blob
|
||||
/// with the social metadata: who took it, where, who's tagged in it,
|
||||
/// when it was posted, and how many cheers it has.
|
||||
///
|
||||
/// Public photos are visible without auth on feed.rec.net; private
|
||||
/// photos are only listable by the uploader (and admins). Soft-delete
|
||||
/// via <see cref="DeletedAt"/> so moderation can take a photo down
|
||||
/// without losing the audit trail.
|
||||
/// </summary>
|
||||
public class PhotoEntity
|
||||
{
|
||||
public long Id { get; set; }
|
||||
|
||||
public long UploaderPlayerId { get; set; }
|
||||
|
||||
/// <summary>The cdn filename — the same string returned by
|
||||
/// storage.rec.net/upload and used in the cdn.rec.net/{name}
|
||||
/// download path. Indexed because feed lookups join blob bytes
|
||||
/// via this key.</summary>
|
||||
[MaxLength(256)]
|
||||
public string BlobName { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>Optional caption typed on the watch's "Share" panel
|
||||
/// before posting. Limited so a single photo can't grow the
|
||||
/// table row unbounded.</summary>
|
||||
[MaxLength(2048)]
|
||||
public string Caption { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>The room the photo was taken in (resolved from
|
||||
/// PlayerPresenceService at upload time). 0 if the player wasn't
|
||||
/// in any room (rare — only happens during loading).</summary>
|
||||
public long RoomId { get; set; }
|
||||
|
||||
/// <summary>Comma-separated list of tagged player IDs. The watch
|
||||
/// builds this from the players visible in the camera's frustum
|
||||
/// when the shutter was pressed. Tagged players show up in their
|
||||
/// own "Photos of me" feed.</summary>
|
||||
[MaxLength(2048)]
|
||||
public string TaggedPlayerIdsCsv { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>If false, photo only appears in the uploader's own
|
||||
/// "My photos" page (and admin views); if true, it shows up on
|
||||
/// the public feed.rec.net feed and any tagged player's
|
||||
/// "Photos of me" tab. Defaults to true since the camera's
|
||||
/// "Share" button is the natural action — making it private is
|
||||
/// an explicit toggle.</summary>
|
||||
public bool IsPublic { get; set; } = true;
|
||||
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
/// <summary>Soft-delete sentinel — non-null means the photo is
|
||||
/// hidden from every feed but still in the table for audit.
|
||||
/// Admin moderation tools set this; the bytes blob is kept until
|
||||
/// a separate cleanup job decides the audit window has elapsed.</summary>
|
||||
public DateTime? DeletedAt { get; set; }
|
||||
|
||||
/// <summary>Denormalised cheer counter — incremented when a
|
||||
/// CheerEntity row is inserted with TargetPhotoId=this.Id, so the
|
||||
/// feed sort doesn't have to JOIN+aggregate every render.</summary>
|
||||
public int CheerCount { get; set; }
|
||||
|
||||
public int ViewCount { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace DorkNet.Server.Data.Entities;
|
||||
|
||||
public class PlayerEntity
|
||||
{
|
||||
public long Id { get; set; }
|
||||
|
||||
// Stable per-installation identifier the client sends as `deviceId` in
|
||||
// platformlogin / account-create form bodies. We deliberately use this
|
||||
// (not `platformId`) so accounts are NOT keyed to Steam IDs — anyone
|
||||
// running the client gets a unique persistent account based on the
|
||||
// hardware-derived device hash, regardless of which Steam emulator
|
||||
// (Goldberg, none, real Steam) is in front. Indexed unique below.
|
||||
[MaxLength(128)]
|
||||
public string DeviceId { get; set; } = string.Empty;
|
||||
|
||||
// Last-seen platform info — informational, NOT part of account identity.
|
||||
public int LastPlatform { get; set; } = 0;
|
||||
|
||||
[MaxLength(128)]
|
||||
public string LastPlatformId { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(64)]
|
||||
public string Username { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(64)]
|
||||
public string DisplayName { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(512)]
|
||||
public string Bio { get; set; } = string.Empty;
|
||||
|
||||
public int Level { get; set; } = 1;
|
||||
public int XP { get; set; } = 0;
|
||||
public int Reputation { get; set; } = 0;
|
||||
public bool IsVerified { get; set; } = false;
|
||||
|
||||
// New accounts default to non-developer. Admins grant the badge
|
||||
// privilege via the SPA's Players → Profile flags tab on a
|
||||
// per-player basis (used to default to true while we were
|
||||
// bootstrapping the emulator; flipped off now that the build is
|
||||
// stable and we don't want every walk-in to spawn with the dev
|
||||
// console unlocked).
|
||||
public bool IsDeveloper { get; set; } = false;
|
||||
// Mirrors IsDeveloper for the overhead badge slider — the 2020 watch
|
||||
// gates the in-settings "Developer Display Mode" slider on a single
|
||||
// role check (`role/developer/{id}`), and the slider's positions
|
||||
// render as "Community Team" / "Developer" above the player's head
|
||||
// (verified in Cpp2IL_ISIL/.../PlayerUI.txt:9085-9099 — slider value
|
||||
// 1 → "Community Team", 2 → "Developer"). Keep this field separate
|
||||
// from IsDeveloper so admins can mark someone as community-team
|
||||
// without granting full dev privileges; the role endpoint ORs both.
|
||||
public bool IsCommunityTeam { get; set; } = false;
|
||||
public bool CanReceiveInvites { get; set; } = true;
|
||||
public bool IsJunior { get; set; } = false;
|
||||
|
||||
[MaxLength(256)]
|
||||
public string? ProfileImageName { get; set; }
|
||||
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
public DateTime LastSeenAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
// ── Phase 1 account hardening ─────────────────────────────────────────
|
||||
// Optional contact email. Nullable because the 2020 client never asks
|
||||
// for one; reserved for future password-reset / admin-recovery flows.
|
||||
[MaxLength(256)]
|
||||
public string? Email { get; set; }
|
||||
|
||||
// When non-null AND `> DateTime.UtcNow`, BanCheckMiddleware short-circuits
|
||||
// every authenticated request from this account with 401. Setting to a
|
||||
// past timestamp acts as a "previously banned" audit marker without
|
||||
// blocking access.
|
||||
public DateTime? BannedUntil { get; set; }
|
||||
|
||||
// Privilege flag for `[AdminOnly]` endpoints (Phase 5). Defaults false;
|
||||
// PlayerService bumps this to true when the very first account on a
|
||||
// fresh DB is created so there's always at least one root admin.
|
||||
public bool IsAdmin { get; set; } = false;
|
||||
|
||||
// Last IP that authenticated against this account. Updated by the
|
||||
// request-tracing pipeline so we don't write IPs from anonymous paths.
|
||||
[MaxLength(64)]
|
||||
public string? LastIp { get; set; }
|
||||
|
||||
// The deviceId that originally created this account. Immutable after
|
||||
// creation — exists for the audit trail in case the live DeviceId
|
||||
// rotates (e.g., user re-installs and the hardware hash shifts; the
|
||||
// account stays bound to whatever they typed in /account/create the
|
||||
// first time).
|
||||
[MaxLength(128)]
|
||||
public string? CreatedFromDeviceId { get; set; }
|
||||
|
||||
// BCP-47 locale tag (e.g. "en-US"). Optional; informs future
|
||||
// localisation work and is currently set from the client's accept-
|
||||
// language header at login.
|
||||
[MaxLength(16)]
|
||||
public string? Locale { get; set; }
|
||||
|
||||
/// <summary>BCrypt hash of the account password. Null when the
|
||||
/// account has never set one — the in-game settings screen calls
|
||||
/// /account/me/haspassword and prompts the user to create one
|
||||
/// before sensitive operations. Format: BCrypt's standard
|
||||
/// `$2a$<cost>$<salt><hash>` so the verifier
|
||||
/// reads cost + salt directly, no separate column needed.</summary>
|
||||
[MaxLength(128)]
|
||||
public string? PasswordHash { get; set; }
|
||||
|
||||
/// <summary>Player's birthday (date only; no timezone). Set during
|
||||
/// signup and used to derive <see cref="IsJunior"/> on Junior cutoff
|
||||
/// boundary crossing. Nullable for legacy accounts created before
|
||||
/// the field existed.</summary>
|
||||
public DateTime? Birthday { get; set; }
|
||||
|
||||
/// <summary>Optional phone number — used by the watch's
|
||||
/// account-recovery flow. Stored verbatim, never validated.</summary>
|
||||
[MaxLength(32)]
|
||||
public string? Phone { get; set; }
|
||||
|
||||
// Navigation
|
||||
public AvatarEntity? Avatar { get; set; }
|
||||
public List<PlayerSettingEntity> Settings { get; set; } = [];
|
||||
public List<RelationshipEntity> Relationships { get; set; } = [];
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace DorkNet.Server.Data.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// A player-scheduled gathering ("event") in a specific room. Backs
|
||||
/// the watch's Events tab — players can RSVP via
|
||||
/// <see cref="PlayerEventResponseEntity"/>.
|
||||
/// </summary>
|
||||
public class PlayerEventEntity
|
||||
{
|
||||
public long Id { get; set; }
|
||||
|
||||
public long CreatorPlayerId { get; set; }
|
||||
public long RoomId { get; set; }
|
||||
|
||||
[MaxLength(128)]
|
||||
public string Title { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(2000)]
|
||||
public string Description { get; set; } = string.Empty;
|
||||
|
||||
public DateTime StartsAt { get; set; }
|
||||
public DateTime EndsAt { get; set; }
|
||||
|
||||
public int Capacity { get; set; } = 0;
|
||||
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
/// <summary>One row per RSVP'd player + event.</summary>
|
||||
public class PlayerEventResponseEntity
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public long EventId { get; set; }
|
||||
public long PlayerId { get; set; }
|
||||
/// <summary>0=Going, 1=Maybe, 2=NotGoing — matches the watch's
|
||||
/// three-state RSVP toggle.</summary>
|
||||
public int Response { get; set; }
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace DorkNet.Server.Data.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// One row per (player, item) pair. Backs both the
|
||||
/// <c>/api/equipment/v2/getUnlocked</c> and
|
||||
/// <c>/api/consumables/v1/getUnlocked</c> endpoints — the type comes
|
||||
/// from the joined <see cref="StoreItemEntity.Category"/>.
|
||||
///
|
||||
/// For equipment, <see cref="Quantity"/> is always 1 and
|
||||
/// <see cref="IsActive"/> tracks whether it's equipped. For
|
||||
/// consumables, <see cref="Quantity"/> is the stack size and
|
||||
/// <see cref="IsActive"/> tracks whether the player has it favourited /
|
||||
/// quick-equipped on the watch.
|
||||
/// </summary>
|
||||
public class PlayerInventoryEntity
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public long PlayerId { get; set; }
|
||||
|
||||
/// <summary>FK by string to <see cref="StoreItemEntity.Slug"/>.
|
||||
/// 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)]
|
||||
public string ItemSlug { get; set; } = string.Empty;
|
||||
|
||||
public int Quantity { get; set; } = 1;
|
||||
public bool IsActive { get; set; } = false;
|
||||
|
||||
public DateTime AcquiredAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace DorkNet.Server.Data.Entities;
|
||||
|
||||
public class PlayerSettingEntity
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public long PlayerId { get; set; }
|
||||
|
||||
[MaxLength(128)]
|
||||
public string Key { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(1024)]
|
||||
public string Value { get; set; } = string.Empty;
|
||||
|
||||
public PlayerEntity? Player { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace DorkNet.Server.Data.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// One per (player, deviceId) — recorded on
|
||||
/// <c>POST /api/deviceid/v1/register</c>. Lets admins flag
|
||||
/// duplicate-account abuse: when a banned player creates a new
|
||||
/// account on the same device, the new account inherits the device
|
||||
/// ban automatically.
|
||||
/// </summary>
|
||||
public class PlayerDeviceEntity
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public long PlayerId { get; set; }
|
||||
|
||||
[MaxLength(128)]
|
||||
public string DeviceId { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(32)]
|
||||
public string Platform { get; set; } = string.Empty;
|
||||
|
||||
public DateTime FirstSeen { get; set; } = DateTime.UtcNow;
|
||||
public DateTime LastSeen { get; set; } = DateTime.UtcNow;
|
||||
|
||||
/// <summary>Set by admin tooling — if true, every account using
|
||||
/// this device is auto-banned at login.</summary>
|
||||
public bool IsBanned { get; set; } = false;
|
||||
}
|
||||
|
||||
/// <summary>Per-player notification preferences. iOS-style toggle
|
||||
/// page; Android / Quest just persist the same shape.</summary>
|
||||
public class NotificationPrefsEntity
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public long PlayerId { get; set; }
|
||||
|
||||
[MaxLength(32)]
|
||||
public string Platform { get; set; } = string.Empty;
|
||||
|
||||
public bool AllowAll { get; set; } = true;
|
||||
public bool AllowFriendRequest { get; set; } = true;
|
||||
public bool AllowMessage { get; set; } = true;
|
||||
public bool AllowEventInvite { get; set; } = true;
|
||||
public bool AllowAnnouncements { get; set; } = true;
|
||||
|
||||
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
/// <summary>Sticky cohort assignment — one row per (player, cohort
|
||||
/// key). Created on first hit to <c>GET /api/cohort/v1/{key}</c> with
|
||||
/// a randomly selected variant; remains stable for the lifetime of
|
||||
/// the player so A/B tests don't flicker between sessions.</summary>
|
||||
public class CohortAssignmentEntity
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public long PlayerId { get; set; }
|
||||
|
||||
[MaxLength(64)]
|
||||
public string CohortKey { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(32)]
|
||||
public string Variant { get; set; } = string.Empty;
|
||||
|
||||
public DateTime AssignedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace DorkNet.Server.Data.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// Durable record of a private (invite-only) Photon match created via
|
||||
/// <c>POST /goto/room/{name}?CreatePrivateInstance=True</c>. Replaces
|
||||
/// the in-process <c>ConcurrentDictionary</c> in
|
||||
/// <see cref="DorkNet.Server.Services.PrivateInstanceService"/> so
|
||||
/// invitations land on any replica.
|
||||
///
|
||||
/// Without this row in shared storage, an invite issued by Player A
|
||||
/// (replica 1) wouldn't be visible to Player B's <c>POST /goto/instance/{id}</c>
|
||||
/// when their request lands on replica 2 — they'd be routed to a fresh
|
||||
/// public lobby instead of the inviter's match.
|
||||
///
|
||||
/// The associated invite list lives in <see cref="PrivateInstanceInviteeEntity"/>;
|
||||
/// we keep it as a join table rather than a JSON column so the per-row
|
||||
/// "is X invited to Y?" check stays a fast indexed lookup.
|
||||
/// </summary>
|
||||
public class PrivateInstanceEntity
|
||||
{
|
||||
/// <summary>The instance id used as the wire <c>roomInstanceId</c>
|
||||
/// in matchmaking responses. Generated server-side at creation
|
||||
/// time; stable for the lifetime of the match. NOT autoincrement —
|
||||
/// the value is computed from owner/room/sub plus a nonce so the
|
||||
/// id is itself unforgeable without the nonce.</summary>
|
||||
public long Id { get; set; }
|
||||
|
||||
public long RoomId { get; set; }
|
||||
public long SubRoomId { get; set; }
|
||||
public long OwnerPlayerId { get; set; }
|
||||
|
||||
[MaxLength(256)] public string PhotonRoomId { get; set; } = string.Empty;
|
||||
[MaxLength(64)] public string Location { get; set; } = string.Empty;
|
||||
[MaxLength(256)] public string DataBlob { get; set; } = string.Empty;
|
||||
[MaxLength(16)] public string PhotonRegion { get; set; } = "us";
|
||||
public int MaxCapacity { get; set; } = 8;
|
||||
[MaxLength(128)] public string Name { get; set; } = string.Empty;
|
||||
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
namespace DorkNet.Server.Data.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// Join row marking that <see cref="PlayerId"/> is on the invite list
|
||||
/// for <see cref="PrivateInstanceId"/>. Created when the owner sends an
|
||||
/// invite via <c>POST /invite</c> (handled in <c>MessagesController</c>);
|
||||
/// checked on <c>POST /goto/instance/{id}</c> by
|
||||
/// <c>PrivateInstanceService.CanJoin</c>.
|
||||
///
|
||||
/// Composite PK on (PrivateInstanceId, PlayerId) — naturally unique;
|
||||
/// repeat-invite calls become idempotent no-ops.
|
||||
/// </summary>
|
||||
public class PrivateInstanceInviteeEntity
|
||||
{
|
||||
public long PrivateInstanceId { get; set; }
|
||||
public long PlayerId { get; set; }
|
||||
public DateTime InvitedAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
/// <summary>The MessageEntity.Id of the latest invite for this
|
||||
/// (instance, player). Lets <c>GoToInvite</c> resolve the
|
||||
/// roomInstanceId even when the watch's accept flow has already
|
||||
/// raced through <c>POST /api/messages/v3/delete</c> and removed
|
||||
/// the underlying message row. Without this column the server
|
||||
/// returned ErrorCode 40 ("invite expired") for any successful
|
||||
/// accept where DELETE landed first — which was the common case
|
||||
/// because the 2020 watch fires DELETE and POST /goto/invite/{id}
|
||||
/// in parallel.</summary>
|
||||
public long? LatestInviteMessageId { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace DorkNet.Server.Data.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// One push-notification token per (player, platform). Backs
|
||||
/// <c>POST api/messages/v1/IOSSaveDeviceToken</c> +
|
||||
/// <c>IOSClearDeviceToken</c>. Stored so an APNS / FCM proxy could
|
||||
/// fan out push notifications to mobile clients; on a private
|
||||
/// server we just persist for audit + future use.
|
||||
/// </summary>
|
||||
public class PushTokenEntity
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public long PlayerId { get; set; }
|
||||
|
||||
/// <summary>Platform: "ios", "android", "fcm", etc.</summary>
|
||||
[MaxLength(16)]
|
||||
public string Platform { get; set; } = "ios";
|
||||
|
||||
[MaxLength(256)]
|
||||
public string Token { get; set; } = string.Empty;
|
||||
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// One row per (player, platform user id) that the player has
|
||||
/// chosen to ignore even before they appear in
|
||||
/// <see cref="RelationshipEntity"/>. Backs
|
||||
/// <c>POST api/relationships/v1/bulkignoreplatformusers</c> — when
|
||||
/// a Steam friend joins later, the relationship is auto-set to
|
||||
/// Ignored. Lets the import stick across friend-discovery cycles.
|
||||
/// </summary>
|
||||
public class PlatformIgnoreEntity
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public long PlayerId { get; set; }
|
||||
|
||||
/// <summary>PlatformType enum: 0=Steam, 1=Oculus, 2=PlayStation,
|
||||
/// 3=Microsoft, 5=IOS.</summary>
|
||||
public int Platform { get; set; }
|
||||
|
||||
[MaxLength(64)]
|
||||
public string PlatformUserId { get; set; } = string.Empty;
|
||||
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// One row per "card" displayed on the watch's home screen / cards
|
||||
/// tab. Backs <c>GET api/cards/v1/all</c>. Cards are short tappable
|
||||
/// tiles ("Daily Login", "New Room: Foo", "Friend invited you to
|
||||
/// X") seeded by the server and consumed by the client.
|
||||
/// </summary>
|
||||
public class CardEntity
|
||||
{
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>If null, the card is global (shown to everyone).
|
||||
/// If set, only visible to that specific player.</summary>
|
||||
public long? PlayerId { get; set; }
|
||||
|
||||
[MaxLength(128)]
|
||||
public string Title { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(2000)]
|
||||
public string Body { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(256)]
|
||||
public string ImageName { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(512)]
|
||||
public string ActionUrl { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>Card category — "announcement", "daily", "event",
|
||||
/// "system". Drives the icon the watch renders.</summary>
|
||||
[MaxLength(32)]
|
||||
public string Category { get; set; } = "announcement";
|
||||
|
||||
public int Priority { get; set; } = 0;
|
||||
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
public DateTime? ExpiresAt { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
namespace DorkNet.Server.Data.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// Storage-side enum mirroring the int values previously hard-coded in
|
||||
/// <see cref="RelationshipEntity"/>. Stays separate from the on-the-wire
|
||||
/// <c>DorkNet.Models.Relationships.RelationshipStatus</c> so the contract
|
||||
/// can evolve without touching the DB representation. Underlying int
|
||||
/// values match — no migration data fixup needed.
|
||||
/// </summary>
|
||||
public enum RelationshipStatus
|
||||
{
|
||||
/// <summary>Mutual friend (both directions accepted).</summary>
|
||||
Friend = 1,
|
||||
|
||||
/// <summary>Outgoing request from <see cref="RelationshipEntity.RequesterId"/>
|
||||
/// awaiting accept/decline by <see cref="RelationshipEntity.TargetId"/>.</summary>
|
||||
PendingSent = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Reserved for the receiving-side view if we later denormalise. The
|
||||
/// backing column is still 1-2-4 in practice; PendingReceived is what
|
||||
/// the wire DTO computes from the caller's perspective when the row's
|
||||
/// PendingSent direction is "into" them.
|
||||
/// </summary>
|
||||
PendingReceived = 3,
|
||||
|
||||
/// <summary>Block held by <see cref="RelationshipEntity.RequesterId"/>
|
||||
/// against <see cref="RelationshipEntity.TargetId"/>. Hides the target
|
||||
/// from the requester's friend list and prevents new requests both ways.</summary>
|
||||
Blocked = 4,
|
||||
}
|
||||
|
||||
public class RelationshipEntity
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public long RequesterId { get; set; }
|
||||
public long TargetId { get; set; }
|
||||
public RelationshipStatus Status { get; set; }
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
/// <summary>True when <see cref="RequesterId"/> favorited
|
||||
/// <see cref="TargetId"/>. Favorited shows up first in the friend
|
||||
/// list and triggers an extra notification on "online".</summary>
|
||||
public bool Favorited { get; set; }
|
||||
|
||||
/// <summary>True when <see cref="RequesterId"/> muted text from
|
||||
/// <see cref="TargetId"/>. Drops chat-message notifications but
|
||||
/// keeps the friendship intact.</summary>
|
||||
public bool Muted { get; set; }
|
||||
|
||||
/// <summary>True when <see cref="RequesterId"/> ignored
|
||||
/// <see cref="TargetId"/> (a soft block — hides the player from
|
||||
/// the room browser without breaking the relationship row).</summary>
|
||||
public bool Ignored { get; set; }
|
||||
|
||||
public PlayerEntity? Requester { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace DorkNet.Server.Data.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// One in-game player report. Created by any authenticated player via
|
||||
/// the watch's "report player" UI; surfaces in the admin moderation
|
||||
/// queue at <c>GET api/admin/v1/reports</c> until an admin resolves it.
|
||||
/// </summary>
|
||||
public class ReportEntity
|
||||
{
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>Account id of the player filing the report.</summary>
|
||||
public long ReporterPlayerId { get; set; }
|
||||
|
||||
/// <summary>Account id of the player being reported.</summary>
|
||||
public long TargetPlayerId { get; set; }
|
||||
|
||||
/// <summary>Free-form category the watch sends — convention is
|
||||
/// numeric matching the client's <c>RoomieReportCategory</c> enum
|
||||
/// (Harassment=1, Inappropriate=2, Cheating=3, Spam=4, Other=5).</summary>
|
||||
public int Category { get; set; }
|
||||
|
||||
/// <summary>The reporter's free-text description. Capped at 1000
|
||||
/// chars by the watch UI.</summary>
|
||||
[MaxLength(1000)]
|
||||
public string Message { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>Optional game session id for context — admins can
|
||||
/// correlate to room/server logs around the time of the report.</summary>
|
||||
public long GameSessionId { get; set; }
|
||||
|
||||
/// <summary>Room the offending behaviour happened in (0 if N/A).</summary>
|
||||
public long RoomId { get; set; }
|
||||
|
||||
/// <summary>If the report targets an invention, the invention id
|
||||
/// (0 otherwise).</summary>
|
||||
public long TargetInventionId { get; set; }
|
||||
|
||||
/// <summary>If the report targets a room (rather than the player
|
||||
/// in it), the room id (0 otherwise).</summary>
|
||||
public long TargetRoomId { get; set; }
|
||||
|
||||
/// <summary>If the report targets a player event, the event id
|
||||
/// (0 otherwise).</summary>
|
||||
public long TargetEventId { get; set; }
|
||||
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
/// <summary>Null while the report sits in the admin queue; set
|
||||
/// when an admin resolves it via
|
||||
/// <c>POST api/admin/v1/reports/{id}/resolve</c>. Together with
|
||||
/// <see cref="ResolverAdminId"/> + <see cref="ResolutionNote"/>
|
||||
/// forms the full audit trail.</summary>
|
||||
public DateTime? ResolvedAt { get; set; }
|
||||
|
||||
public long? ResolverAdminId { get; set; }
|
||||
|
||||
[MaxLength(512)]
|
||||
public string ResolutionNote { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace DorkNet.Server.Data.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// One per-room ban issued by a room owner / admin via
|
||||
/// <c>POST /api/rooms/v2/banfromroom</c>. The match service consults
|
||||
/// these rows when resolving an instance join: if the joining player
|
||||
/// has an active row matching the room id, the join is refused.
|
||||
/// </summary>
|
||||
public class RoomBanEntity
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public long RoomId { get; set; }
|
||||
public long BannedPlayerId { get; set; }
|
||||
public long BannedByPlayerId { get; set; }
|
||||
|
||||
/// <summary>BanType enum mirror: 0 = Soft (kick), 1 = Permanent,
|
||||
/// 2 = Temporary (until <see cref="Until"/>).</summary>
|
||||
public int BanType { get; set; }
|
||||
|
||||
public DateTime? Until { get; set; }
|
||||
|
||||
[MaxLength(512)]
|
||||
public string Reason { get; set; } = string.Empty;
|
||||
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace DorkNet.Server.Data.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// A "favorite" / bookmark — when a player taps the heart on a room in the
|
||||
/// watch. Backs `api/rooms/v2/mybookmarks`.
|
||||
/// </summary>
|
||||
public class RoomBookmarkEntity
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public long PlayerId { get; set; }
|
||||
public long RoomId { get; set; }
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace DorkNet.Server.Data.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// Metadata for a single saved version of a room's PersistedRoomData
|
||||
/// protobuf. The actual bytes live in S3 at the canonical
|
||||
/// (bucket, key) returned by <see cref="Services.BlobRouter.Route"/>;
|
||||
/// this row only carries the lookup string + provenance.
|
||||
///
|
||||
/// One row per save. Visitors fetching the room get the row whose
|
||||
/// <see cref="BlobName"/> matches the current
|
||||
/// <c>RoomEntity.CurrentDataBlobName</c>; the CDN controller takes
|
||||
/// that name, routes it via <see cref="Services.BlobRouter"/>, and
|
||||
/// streams bytes out of S3.
|
||||
///
|
||||
/// Was originally a fat row with a <c>Bytes</c> column; that column
|
||||
/// was dropped once S3 became the canonical store. Only text columns
|
||||
/// remain in the DB.
|
||||
/// </summary>
|
||||
public class RoomDataBlobEntity
|
||||
{
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>FK to RoomEntity. Indexed for "give me all versions of
|
||||
/// this room" queries (history, GC). Set to 0 for shared assets
|
||||
/// not bound to a specific room (HTRs, PV images, polaroids).</summary>
|
||||
public long RoomId { get; set; }
|
||||
|
||||
/// <summary>The string the client uses as the cdn URL segment.
|
||||
/// <see cref="Services.BlobRouter.Route"/> converts this into a
|
||||
/// canonical (bucket, key) deterministically.</summary>
|
||||
[MaxLength(128)]
|
||||
public string BlobName { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>The player id of the uploader. Audit trail; also used by
|
||||
/// the GC to keep the room owner's saves longer than visitor saves.</summary>
|
||||
public long UploadedByPlayerId { get; set; }
|
||||
|
||||
public DateTime UploadedAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
/// <summary>Comma-separated list of file names referenced by the
|
||||
/// PersistedRoomData (e.g. invention thumbnails, audio clips). The
|
||||
/// client passes these via the upload's referencedFilenames argument;
|
||||
/// the server uses them later when GC'ing orphaned blobs.</summary>
|
||||
[MaxLength(2048)]
|
||||
public string ReferencedFilenamesCsv { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Legacy bytes column. The codebase no longer writes to this — S3
|
||||
/// is the canonical store — but rows imported / uploaded before the
|
||||
/// S3-only cutover still hold their bytes here, and the backfill
|
||||
/// migrator (<c>POST /api/admin/v1/storage/backfill</c>) reads them
|
||||
/// to upload into S3. After backfill is verified, a follow-up EF
|
||||
/// migration drops this column entirely and only metadata remains.
|
||||
/// Nullable so freshly-inserted rows can omit it without breaking
|
||||
/// SQLite's NOT NULL invariant.
|
||||
/// </summary>
|
||||
public byte[]? Bytes { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace DorkNet.Server.Data.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// A user-creatable Rec Room "room" — has a name, a creator, a hub scene
|
||||
/// (the AGRoomRuntimeConfig.Locations entry it spawns into), and metadata
|
||||
/// for the watch UI's room browser.
|
||||
///
|
||||
/// Naming maps: in the wire JSON the client expects mostly PascalCase
|
||||
/// (Room.Deserialize at RVA 0x114E430). Property names match.
|
||||
///
|
||||
/// Two-way relationship with PlayerEntity for ownership / bookmark / role
|
||||
/// browsing — kept on the room side as ID columns rather than a navigation
|
||||
/// to keep PlayerEntity unchanged.
|
||||
/// </summary>
|
||||
public class RoomEntity
|
||||
{
|
||||
public long Id { get; set; }
|
||||
|
||||
[MaxLength(128)]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(2000)]
|
||||
public string Description { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>The player who created the room (NOT the dorm owner — every
|
||||
/// real Rec Room has a creator player id; for seeded "RecRoomOriginal"
|
||||
/// rooms we set this to 1 / the system account).</summary>
|
||||
public long CreatorPlayerId { get; set; }
|
||||
|
||||
[MaxLength(256)]
|
||||
public string ImageName { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>RoomState enum (int): 0 = Active, 1 = Archived.</summary>
|
||||
public int State { get; set; } = 0;
|
||||
|
||||
/// <summary>RoomAccessibility enum (int): 0 = Private, 1 = Public,
|
||||
/// 2 = LimitedAccessibility / FriendsOnly.</summary>
|
||||
public int Accessibility { get; set; } = 1;
|
||||
|
||||
public bool SupportsLevelVoting { get; set; } = false;
|
||||
|
||||
/// <summary>True for AG (user-built) rooms, false for "Rec Room
|
||||
/// Original" rooms. The watch tabs `#community` (AG) and
|
||||
/// `#recroomoriginal` (RR Originals) filter on this.</summary>
|
||||
public bool IsAGRoom { get; set; } = true;
|
||||
|
||||
public bool IsDormRoom { get; set; } = false;
|
||||
public bool CloningAllowed { get; set; } = false;
|
||||
public bool SupportsVRLow { get; set; } = true;
|
||||
public bool SupportsMobile { get; set; } = false;
|
||||
public bool SupportsScreens { get; set; } = true;
|
||||
public bool SupportsWalkVR { get; set; } = true;
|
||||
public bool SupportsTeleportVR { get; set; } = true;
|
||||
public bool AllowsJuniors { get; set; } = true;
|
||||
public int RoomWarningMask { get; set; } = 0;
|
||||
|
||||
[MaxLength(512)]
|
||||
public string CustomRoomWarning { get; set; } = string.Empty;
|
||||
|
||||
public bool DisableMicAutoMute { get; set; } = false;
|
||||
|
||||
/// <summary>RoomScene.RoomSceneLocationId GUID — foreign-keys to a
|
||||
/// Locations[] entry in resources.assets. This is what
|
||||
/// AGRoomSettings.TryGetRoomSceneLocationById matches.
|
||||
/// Default: DormRoom location GUID extracted from the asset.</summary>
|
||||
[MaxLength(64)]
|
||||
public string LocationReplicationId { get; set; } = "76d98498-60a1-430c-ab76-b54a29b7a163";
|
||||
|
||||
/// <summary>Comma-separated tags. The 2020 watch supports a small set
|
||||
/// (#community, #recroomoriginal, #featured, etc.) — keeping it as a
|
||||
/// flat string avoids a join table for the v0 watch implementation.</summary>
|
||||
[MaxLength(1024)]
|
||||
public string TagsCsv { get; set; } = string.Empty;
|
||||
|
||||
public int CheerCount { get; set; } = 0;
|
||||
public int FavoriteCount { get; set; } = 0;
|
||||
|
||||
/// <summary>Total joins across all players (every <c>/goto</c>
|
||||
/// counts; same player rejoining bumps it again). Mirrors
|
||||
/// official Rec.Net <c>Stats.VisitCount</c>.</summary>
|
||||
public int VisitCount { get; set; } = 0;
|
||||
|
||||
/// <summary>Distinct players who've ever visited (each player
|
||||
/// counts once no matter how many times they rejoin). Mirrors
|
||||
/// official Rec.Net <c>Stats.VisitorCount</c>. Bumped only when
|
||||
/// <see cref="RoomVisitEntity"/> inserts a new row for the
|
||||
/// (room, player) pair.</summary>
|
||||
public int VisitorCount { get; set; } = 0;
|
||||
|
||||
/// <summary>Score the watch uses to sort the "Hot" tab. Higher = more
|
||||
/// visible. Seeded rooms get bumped above empty user rooms so they show
|
||||
/// up first in the browser.</summary>
|
||||
public double HotScore { get; set; } = 0;
|
||||
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
/// <summary>True keeps the room out of room browse / search /
|
||||
/// "RR Originals" feeds while leaving <c>/goto</c>, clone, and
|
||||
/// admin-tool access intact. Used for rooms that exist in the seed
|
||||
/// (MakerRoom, EventRoom, paintball sub-maps merged into the
|
||||
/// Paintball lobby, etc.) but shouldn't show up to players because
|
||||
/// either there's a unified room hosting their scenes elsewhere or
|
||||
/// they're admin-only utility rooms.</summary>
|
||||
public bool HiddenFromBrowse { get; set; } = false;
|
||||
|
||||
/// <summary>Name of the latest <see cref="RoomDataBlobEntity"/> row
|
||||
/// for this room — also what we put in
|
||||
/// <c>RoomDetails.Scenes[0].DataBlobName</c> so the client knows which
|
||||
/// blob to download. Empty for AG-Original baked rooms (rec center,
|
||||
/// paintball, etc.) which have no per-room save bytes; the dorm and
|
||||
/// user-built / cloned rooms point at their latest save.</summary>
|
||||
[MaxLength(128)]
|
||||
public string CurrentDataBlobName { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
namespace DorkNet.Server.Data.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// Per-room player role grant. Drives RoomDetails.CoOwners /
|
||||
/// Moderators / Hosts arrays (and their Invited* counterparts when
|
||||
/// <see cref="Accepted"/> is false). Each (RoomId, PlayerId, Role)
|
||||
/// tuple is unique — granting the same role twice is a no-op.
|
||||
/// </summary>
|
||||
public class RoomRoleEntity
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public long RoomId { get; set; }
|
||||
public long PlayerId { get; set; }
|
||||
|
||||
/// <summary>RoleKind: 0 = CoOwner, 1 = Moderator, 2 = Host.</summary>
|
||||
public int Role { get; set; }
|
||||
|
||||
/// <summary>False while the invite is still pending. Accepted
|
||||
/// rows show up in CoOwners/Moderators/Hosts; pending rows show
|
||||
/// up in InvitedCoOwners/InvitedModerators/InvitedHosts.</summary>
|
||||
public bool Accepted { get; set; } = true;
|
||||
|
||||
public long? GrantedByPlayerId { get; set; }
|
||||
public System.DateTime GrantedAt { get; set; } = System.DateTime.UtcNow;
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace DorkNet.Server.Data.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// One scene within a multi-scene custom room. Most rooms historically
|
||||
/// had only Scenes[0] (synthesised in <c>BuildRoomDetails</c> from
|
||||
/// <see cref="RoomEntity.LocationReplicationId"/> +
|
||||
/// <see cref="RoomEntity.CurrentDataBlobName"/>); rooms imported from a
|
||||
/// multi-scene archive write one row per chapter here, and the wire-shape
|
||||
/// builder emits the full <c>Scenes[]</c> array from this table when any
|
||||
/// rows exist.
|
||||
///
|
||||
/// <para>The scene's <see cref="RoomSceneId"/> on the wire is this table's
|
||||
/// <see cref="OrderIndex"/> — the matchmaking <c>SubRoomId</c> the watch
|
||||
/// passes to <c>/goto/room/{name}/{subroom}</c> matches against
|
||||
/// <see cref="Name"/>, then resolves to <see cref="OrderIndex"/> for
|
||||
/// <c>RoomInstance.SubRoomId</c>.</para>
|
||||
/// </summary>
|
||||
public class RoomSceneEntity
|
||||
{
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>FK to <see cref="RoomEntity"/>. Indexed so the per-room
|
||||
/// fetch in <c>BuildRoomDetails</c> is one query.</summary>
|
||||
public long RoomId { get; set; }
|
||||
|
||||
/// <summary>0-based index this scene occupies in the wire
|
||||
/// <c>Scenes[]</c> array. Doubles as the <c>RoomSceneId</c> the
|
||||
/// matchmaking flow uses for <c>RoomInstance.SubRoomId</c>.</summary>
|
||||
public int OrderIndex { get; set; }
|
||||
|
||||
/// <summary>Display name (e.g. "Lobby", "Ch1_Headfirst"). Matched
|
||||
/// case-insensitively against the sub-room segment of
|
||||
/// <c>/goto/room/{name}/{subroom}</c>.</summary>
|
||||
[MaxLength(128)]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>The <c>RoomSceneLocationId</c> GUID the client uses to
|
||||
/// look up the bundled stage prefab via
|
||||
/// <c>AGRoomSettings.TryGetRoomSceneLocationById</c>. Defaults to
|
||||
/// the MakerRoom (Basement) scene GUID — the canonical "blank
|
||||
/// canvas" stage 2020 custom rooms were built on. Extracted from
|
||||
/// resources.assets via tools/extract-locations-binary.py: the
|
||||
/// "Maker Room" Location entry has SceneName=Basement and
|
||||
/// ReplicationId=a75f7547-79eb-47c6-8986-6767abcb4f92.</summary>
|
||||
[MaxLength(64)]
|
||||
public string RoomSceneLocationId { get; set; } = "a75f7547-79eb-47c6-8986-6767abcb4f92";
|
||||
|
||||
/// <summary>The <see cref="RoomDataBlobEntity.BlobName"/> the watch
|
||||
/// downloads as the persisted state for this scene.</summary>
|
||||
[MaxLength(128)]
|
||||
public string DataBlobName { get; set; } = string.Empty;
|
||||
|
||||
public int MaxPlayers { get; set; } = 8;
|
||||
public bool IsSandbox { get; set; } = false;
|
||||
public bool CanMatchmakeInto { get; set; } = true;
|
||||
|
||||
public DateTime DataModifiedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
namespace DorkNet.Server.Data.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// One row per (Room, Player) recording the player's visit history
|
||||
/// to that room. Backs the proper <c>RoomEntity.VisitorCount</c>
|
||||
/// (count of unique players who've visited) vs <c>VisitCount</c>
|
||||
/// (total joins, including the same player multiple times) split
|
||||
/// the official Rec.Net stats column distinguishes.
|
||||
///
|
||||
/// Upserted by <c>GoToController</c> on every <c>POST /goto/room</c>
|
||||
/// so the per-room "who's been here, when" history is queryable for
|
||||
/// the Hot-rooms ranking + admin diagnostics.
|
||||
/// </summary>
|
||||
public class RoomVisitEntity
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public long RoomId { get; set; }
|
||||
public long PlayerId { get; set; }
|
||||
|
||||
/// <summary>Set once on the player's first visit; immutable after.
|
||||
/// Used to decide whether to bump RoomEntity.VisitorCount.</summary>
|
||||
public DateTime FirstVisitAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
/// <summary>Updated on every visit. Drives "recent visitors"
|
||||
/// queries.</summary>
|
||||
public DateTime LastVisitAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
/// <summary>Per-player visit count (this player visited this room
|
||||
/// N times). Sum across all rows = RoomEntity.VisitCount.</summary>
|
||||
public int VisitCount { get; set; } = 0;
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace DorkNet.Server.Data.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// One Rec Royale match. Inserted by the server when
|
||||
/// <c>POST api/royale/v2/matchcomplete</c> arrives so we keep an
|
||||
/// audit trail (the client doesn't read this table — it only reads
|
||||
/// the aggregated <see cref="RoyalePlayerProgressEntity"/>).
|
||||
/// </summary>
|
||||
public class RoyaleMatchEntity
|
||||
{
|
||||
public long Id { get; set; }
|
||||
|
||||
public DateTime CompletedAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
/// <summary>From <c>MatchCompleteStats.Rank</c> — the player's
|
||||
/// finish position (1 = Victory Royale).</summary>
|
||||
public int Rank { get; set; }
|
||||
|
||||
public int NumEliminations { get; set; }
|
||||
public int SecondsAlive { get; set; }
|
||||
public bool WalkGame { get; set; }
|
||||
public bool CustomGame { get; set; }
|
||||
public int ChestsOpened { get; set; }
|
||||
public int ShieldPotionsConsumed { get; set; }
|
||||
public int HealthPotionsConsumed { get; set; }
|
||||
public int SecondsInAir { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>One per (match, player) — server-side audit only; not
|
||||
/// exposed to client. Lets us aggregate per-match contributions
|
||||
/// retroactively.</summary>
|
||||
public class RoyaleMatchPlayerEntity
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public long MatchId { get; set; }
|
||||
public long PlayerId { get; set; }
|
||||
|
||||
public int Rank { get; set; }
|
||||
public int NumEliminations { get; set; }
|
||||
public int SecondsAlive { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>One per player — mirrors wire type
|
||||
/// <c>RecRoyalePlayerProgress</c> (TotalXP/Level/RankIdx/RankName +
|
||||
/// per-level XP thresholds and acorn reward). The watch reads this
|
||||
/// from <c>GET api/royale/v1/current</c>.</summary>
|
||||
public class RoyalePlayerProgressEntity
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public long PlayerId { get; set; }
|
||||
|
||||
public long TotalXP { get; set; }
|
||||
public int Level { get; set; }
|
||||
public int RankIdx { get; set; }
|
||||
|
||||
[MaxLength(64)]
|
||||
public string RankName { get; set; } = "Recruit";
|
||||
|
||||
public long CurrentLevelXPThreshold { get; set; }
|
||||
public long NextLevelXPThreshold { get; set; } = 100;
|
||||
public int NextLevelAcornReward { get; set; } = 50;
|
||||
|
||||
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
namespace DorkNet.Server.Data.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// Single-row table holding server-wide runtime toggles that admins can
|
||||
/// flip from the SPA without a redeploy. Modelled after
|
||||
/// <see cref="CommunityBoardEntity"/>: <see cref="Id"/> is pinned to 1
|
||||
/// so EF Core has a key to track changes against, and reads/writes
|
||||
/// touch one row.
|
||||
///
|
||||
/// Add new boolean (or scalar) columns directly to this entity as more
|
||||
/// toggles appear — keeping them strongly typed beats a generic
|
||||
/// key/value table for the dozen-or-so global switches we'll ever have.
|
||||
/// </summary>
|
||||
public class ServerSettingsEntity
|
||||
{
|
||||
public int Id { get; set; } = 1;
|
||||
|
||||
/// <summary>When true, the watch's account-creation endpoints
|
||||
/// (<c>POST /account/create</c> and <c>POST /api/account/v1/create</c>)
|
||||
/// short-circuit with <c>Success=false</c> and the watch surfaces
|
||||
/// the error to the player. Existing logins are unaffected; only
|
||||
/// brand-new account requests are blocked.</summary>
|
||||
public bool SignupsDisabled { get; set; }
|
||||
|
||||
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace DorkNet.Server.Data.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// One leaderboard stat row per (player, statChannel). Backs
|
||||
/// <c>api/Leaderboard/v1/SetStats</c> + <c>api/Leaderboard/v2/getPlayerRank</c>.
|
||||
///
|
||||
/// The 2020 watch's <c>RecNet.Leaderboards</c> uses an int channel
|
||||
/// id (e.g. 1=PaintballWins, 2=DodgeballHits, etc.) and a single
|
||||
/// long value per channel. A player's "rank" is computed as
|
||||
/// <c>1 + count(*)</c> of rows in the same channel with a higher
|
||||
/// value.
|
||||
/// </summary>
|
||||
public class LeaderboardStatEntity
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public long PlayerId { get; set; }
|
||||
|
||||
/// <summary>RecNet stat channel id (small int per game mode +
|
||||
/// stat type — e.g. paintball-CTF-wins, dodgeball-hits).</summary>
|
||||
public int StatChannel { get; set; }
|
||||
|
||||
/// <summary>Aggregate stat value. Set semantics depend on
|
||||
/// <see cref="SetMode"/>: 0=Always, 1=OnlyIfHigher, 2=OnlyIfLower,
|
||||
/// 3=Increment. Most stat channels are mode 1 (high score).</summary>
|
||||
public long Value { get; set; }
|
||||
|
||||
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Match-result Elo per (player, game mode). Backs
|
||||
/// <c>api/PlayerElo/v1/reportPlayerElo</c>. The 2020 watch reports
|
||||
/// an Elo delta after each ranked match (Royale, Paintball,
|
||||
/// Soccer); we accumulate it per game mode for matchmaking.
|
||||
/// </summary>
|
||||
public class PlayerEloEntity
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public long PlayerId { get; set; }
|
||||
|
||||
/// <summary>RecNet game mode id (small int). We don't enumerate
|
||||
/// these; the wire just sends an int and we pass it through.</summary>
|
||||
public int GameMode { get; set; }
|
||||
|
||||
/// <summary>Current Elo. Default 1000 on first row.</summary>
|
||||
public int Elo { get; set; } = 1000;
|
||||
|
||||
public int Wins { get; set; }
|
||||
public int Losses { get; set; }
|
||||
public int MatchesPlayed { get; set; }
|
||||
|
||||
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace DorkNet.Server.Data.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// One purchasable item in the in-game store. The watch's Shop tab
|
||||
/// renders these, and the purchase flow (initiatepurchase →
|
||||
/// processpurchase → completepurchase) verifies the player has enough
|
||||
/// of <see cref="CurrencyType"/> currency, deducts <see cref="Price"/>,
|
||||
/// and appends <see cref="Slug"/> to the buyer's
|
||||
/// <see cref="AvatarEntity.InventoryJson"/> list so the customisation
|
||||
/// menu can equip it.
|
||||
///
|
||||
/// Item slots / categories track the avatar slots the watch's
|
||||
/// outfit-selector groups items by — Head, Torso, Legs, Feet,
|
||||
/// Accessory, Face, Hair, plus non-avatar categories (Consumable,
|
||||
/// RoomTemplate, Emote) that don't go into outfit selections but
|
||||
/// still show up in the player's inventory.
|
||||
/// </summary>
|
||||
public class StoreItemEntity
|
||||
{
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>Stable string identifier — what we put in
|
||||
/// InventoryJson and OutfitSelections. Format is a GUID for
|
||||
/// avatar items (so the watch's avatar resolver matches the
|
||||
/// baked AvatarItemDefinition catalog), or a kebab-case slug for
|
||||
/// non-avatar items (consumables / templates). Unique.</summary>
|
||||
// Widened from 64→128 in 2026-05 to accommodate the
|
||||
// wardrobe-colored-{guid}-{color} slugs the color-variant seeder
|
||||
// generates — longest in the catalog is ~68 chars (long color
|
||||
// names like "WhiteHatHacker" + 36-char GUID + prefix).
|
||||
[MaxLength(128)]
|
||||
public string Slug { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(128)]
|
||||
public string DisplayName { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(1024)]
|
||||
public string Description { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>Avatar slot or item type. One of: head, torso, legs,
|
||||
/// feet, accessory, face, hair, consumable, roomtemplate, emote.
|
||||
/// </summary>
|
||||
[MaxLength(32)]
|
||||
public string Category { get; set; } = "accessory";
|
||||
|
||||
/// <summary>cdn filename (relative to cdn.rec.net/) for the
|
||||
/// store-tile thumbnail. Empty = the watch falls back to a
|
||||
/// silhouette. Same format as RoomEntity.ImageName.</summary>
|
||||
[MaxLength(256)]
|
||||
public string ImageName { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>Currency the item is priced in. 2 = standard tokens
|
||||
/// (the everyday currency earned from level-up + cheers); higher
|
||||
/// numbers reserved for premium currencies (e.g. 1 = real-money
|
||||
/// purchases — never enabled on a private server).</summary>
|
||||
public int CurrencyType { get; set; } = 2;
|
||||
|
||||
public long Price { get; set; }
|
||||
|
||||
/// <summary>Listing flag. False = hidden from the store but kept
|
||||
/// in the catalog so existing inventory references stay
|
||||
/// resolvable. Admin-only mutation.</summary>
|
||||
public bool IsActive { get; set; } = true;
|
||||
|
||||
/// <summary>True for limited-time / event items. The watch
|
||||
/// renders an "ends in" countdown alongside these and pulls them
|
||||
/// from the catalog when AvailableUntil expires (we keep the row,
|
||||
/// just flip IsActive=false on expiry).</summary>
|
||||
public bool IsLimitedTime { get; set; }
|
||||
|
||||
public DateTime? AvailableUntil { get; set; }
|
||||
|
||||
/// <summary>Storefront grouping. <c>"main"</c> = the everyday
|
||||
/// shop; <c>"giftdrop:N"</c> = a specific rotating gift-drop shelf
|
||||
/// the 2020 client probes via /storefronts/v3/giftdropstore/{N};
|
||||
/// <c>"rro"</c> = every RRO/Rec Center in-room shelf;
|
||||
/// <c>"all"</c> = every in-room shelf; <c>"season:N"</c> =
|
||||
/// season-pass ladders. Default is main.
|
||||
/// </summary>
|
||||
[MaxLength(32)]
|
||||
public string Storefront { get; set; } = "main";
|
||||
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
namespace DorkNet.Server.Data.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// Asymmetric "follow" relationship: <see cref="SubscriberPlayerId"/>
|
||||
/// follows <see cref="TargetPlayerId"/> for activity updates.
|
||||
/// Distinct from <see cref="RelationshipEntity"/>'s mutual friend
|
||||
/// model — subscriptions are one-way and don't require acceptance.
|
||||
/// </summary>
|
||||
public class SubscriptionEntity
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public long SubscriberPlayerId { get; set; }
|
||||
public long TargetPlayerId { get; set; }
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace DorkNet.Server.Data.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// QA test case — wire type <c>RecNet.TestCase</c>
|
||||
/// (<c>Cpp2IL_CS/.../RecNet/TestCase.cs</c>). The 2020 Rec Room
|
||||
/// client uses this to surface JIRA-tracked test cases in an
|
||||
/// internal QA tab; users with the developer role claim a case,
|
||||
/// run it in the named room, then submit a Pass/Fail status.
|
||||
///
|
||||
/// Field names + types match the client's
|
||||
/// <c>TestCase.Deserialize</c> exactly. <see cref="Status"/> is the
|
||||
/// <c>TestCaseStatus</c> enum: 0=NotYetTested, 1=Claimed, 2=Failed,
|
||||
/// 3=Passed.
|
||||
/// </summary>
|
||||
public class TestCaseEntity
|
||||
{
|
||||
/// <summary>EF primary key (long autoincrement) — kept separate
|
||||
/// from the wire <see cref="Id"/> string so we can index cleanly.</summary>
|
||||
public long Pk { get; set; }
|
||||
|
||||
/// <summary>Wire field <c>Id</c> (string) — typically the JIRA
|
||||
/// issue key like <c>RR-1234</c>.</summary>
|
||||
[MaxLength(64)]
|
||||
public string Id { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(64)]
|
||||
public string Key { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(256)]
|
||||
public string Title { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(2000)]
|
||||
public string Description { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(128)]
|
||||
public string RoomName { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>TestCaseStatus enum: 0=NotYetTested, 1=Claimed,
|
||||
/// 2=Failed, 3=Passed.</summary>
|
||||
public int Status { get; set; } = 0;
|
||||
|
||||
public int MinNumAssignedPlayers { get; set; } = 1;
|
||||
|
||||
/// <summary>JSON list of player ids currently claimed on this
|
||||
/// test case. Mirrors wire <c>AssignedPlayerIds</c> (List<int>).</summary>
|
||||
public string AssignedPlayerIdsJson { get; set; } = "[]";
|
||||
|
||||
/// <summary>Sibling JSON list of names for display (kept in sync
|
||||
/// with <see cref="AssignedPlayerIdsJson"/>).</summary>
|
||||
public string AssignedPlayerNamesJson { get; set; } = "[]";
|
||||
|
||||
/// <summary>JSON list of tag strings.</summary>
|
||||
public string TagsJson { get; set; } = "[]";
|
||||
|
||||
[MaxLength(512)]
|
||||
public string JiraUrl { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(512)]
|
||||
public string JiraBugUrl { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>Optional FK to the <see cref="TestPassEntity"/> this
|
||||
/// case belongs to (null = orphan / standalone).</summary>
|
||||
public uint? TestPassId { get; set; }
|
||||
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
/// <summary>Wire type <c>RecNet.TestPass</c> — a versioned bundle of
|
||||
/// test cases the QA team groups for a release pass. Listed via
|
||||
/// <c>GET api/testcasemanagement/v1/testpasssummary</c>; one fetched
|
||||
/// in detail via <c>GET api/testcasemanagement/v1/testpass/{id}</c>.
|
||||
/// </summary>
|
||||
public class TestPassEntity
|
||||
{
|
||||
/// <summary>Wire <c>Id</c> is uint — store as long PK and cast.</summary>
|
||||
public uint Id { get; set; }
|
||||
|
||||
[MaxLength(128)]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(2000)]
|
||||
public string Description { get; set; } = string.Empty;
|
||||
|
||||
public DateTime StartDate { get; set; } = DateTime.UtcNow;
|
||||
|
||||
/// <summary>Null while the pass is still active.</summary>
|
||||
public DateTime? EndDate { get; set; }
|
||||
|
||||
public bool WasManuallyClosed { get; set; } = false;
|
||||
|
||||
/// <summary>JSON list of tag strings.</summary>
|
||||
public string TagsJson { get; set; } = "[]";
|
||||
}
|
||||
@@ -0,0 +1,2646 @@
|
||||
{
|
||||
"matches": [
|
||||
{
|
||||
"swatch_name": "Windbreaker_Red_Swatch",
|
||||
"swatch_guid": "grutFwJD_0Cb3t6fddNg6w",
|
||||
"color": "Red",
|
||||
"item_name": "(Wrist_80sWindbreaker)",
|
||||
"item_guid": "52VsI_lKlkSUAOJlfDnyrQ",
|
||||
"item_outfit_type": 200,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Windbreaker_Blue_Swatch",
|
||||
"swatch_guid": "EbVDqEJQOk6j0UvX3t-8rQ",
|
||||
"color": "Blue",
|
||||
"item_name": "(Wrist_80sWindbreaker)",
|
||||
"item_guid": "52VsI_lKlkSUAOJlfDnyrQ",
|
||||
"item_outfit_type": 200,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Windbreaker_Yellow_Swatch",
|
||||
"swatch_guid": "C3ll7uPfUkeZ1QLX80_BpQ",
|
||||
"color": "Yellow",
|
||||
"item_name": "(Wrist_80sWindbreaker)",
|
||||
"item_guid": "52VsI_lKlkSUAOJlfDnyrQ",
|
||||
"item_outfit_type": 200,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Windbreaker_Salmon_Swatch",
|
||||
"swatch_guid": "JS7aa4QSUUOpUYPqRZEb5g",
|
||||
"color": "Salmon",
|
||||
"item_name": "(Wrist_80sWindbreaker)",
|
||||
"item_guid": "52VsI_lKlkSUAOJlfDnyrQ",
|
||||
"item_outfit_type": 200,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Knight_SRank_Swatch",
|
||||
"swatch_guid": "ITH2OpzjP022vZ5JgxV_iQ",
|
||||
"color": "SRank",
|
||||
"item_name": "(Shirt_KnightTorso)",
|
||||
"item_guid": "739fd42a-8a8c-44a5-afa3-e0974802c6ae",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Knight_Blue_Swatch",
|
||||
"swatch_guid": "ed134bee-d199-43eb-98bd-206571603f40",
|
||||
"color": "Blue",
|
||||
"item_name": "(Shirt_KnightTorso)",
|
||||
"item_guid": "739fd42a-8a8c-44a5-afa3-e0974802c6ae",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Knight_Red_Swatch",
|
||||
"swatch_guid": "59866578-d4e0-417b-9483-233ab108b1ac",
|
||||
"color": "Red",
|
||||
"item_name": "(Shirt_KnightTorso)",
|
||||
"item_guid": "739fd42a-8a8c-44a5-afa3-e0974802c6ae",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Knight_Black_Swatch",
|
||||
"swatch_guid": "e1f49b74-b071-4bd1-9c4b-af36d24d45c5",
|
||||
"color": "Black",
|
||||
"item_name": "(Shirt_KnightTorso)",
|
||||
"item_guid": "739fd42a-8a8c-44a5-afa3-e0974802c6ae",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Knight_Green_Swatch",
|
||||
"swatch_guid": "PMa9370LPEig_7pKwCceEQ",
|
||||
"color": "Green",
|
||||
"item_name": "(Shirt_KnightTorso)",
|
||||
"item_guid": "739fd42a-8a8c-44a5-afa3-e0974802c6ae",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Knight_White_Swatch",
|
||||
"swatch_guid": "22dc463a-a89b-46ad-9a0d-557c742b4a80",
|
||||
"color": "White",
|
||||
"item_name": "(Shirt_KnightTorso)",
|
||||
"item_guid": "739fd42a-8a8c-44a5-afa3-e0974802c6ae",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "LumberJack_Blue_Swatch",
|
||||
"swatch_guid": "cKHAetNcgUOxFfDkAPPF9w",
|
||||
"color": "Blue",
|
||||
"item_name": "(Shirt_Lumberjack)",
|
||||
"item_guid": "350c5c1e-318b-4233-a7e5-1f49909d8e65",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "LumberJack_Green_Swatch",
|
||||
"swatch_guid": "7amHTgEv-UOJSGl0ofo4mw",
|
||||
"color": "Green",
|
||||
"item_name": "(Shirt_Lumberjack)",
|
||||
"item_guid": "350c5c1e-318b-4233-a7e5-1f49909d8e65",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "SpaceMarine_Red_Swatch",
|
||||
"swatch_guid": "d78643e4-c0d2-4836-bf22-b5a0e2d65b28",
|
||||
"color": "Red",
|
||||
"item_name": "(Shirt_SpaceMarine)",
|
||||
"item_guid": "4ce7a70f-15a0-4cad-98ee-5cbb40827338",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "SpaceMarine_Pink_Swatch",
|
||||
"swatch_guid": "a36d252b-16ac-4a82-bece-de145147e7d9",
|
||||
"color": "Pink",
|
||||
"item_name": "(Shirt_SpaceMarine)",
|
||||
"item_guid": "4ce7a70f-15a0-4cad-98ee-5cbb40827338",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "SpaceMarine_Cyan_Swatch",
|
||||
"swatch_guid": "c8cc9589-4831-4e73-a865-ef8c139a2ba7",
|
||||
"color": "Cyan",
|
||||
"item_name": "(Shirt_SpaceMarine)",
|
||||
"item_guid": "4ce7a70f-15a0-4cad-98ee-5cbb40827338",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "SpaceMarine_Light_Swatch",
|
||||
"swatch_guid": "68273c9e-96d6-4ddb-aaab-d99229e864d5",
|
||||
"color": "Light",
|
||||
"item_name": "(Shirt_SpaceMarine)",
|
||||
"item_guid": "4ce7a70f-15a0-4cad-98ee-5cbb40827338",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "SpaceMarine_Dark_Swatch",
|
||||
"swatch_guid": "a089bcc6-798d-4777-98e2-7afd290dc6b6",
|
||||
"color": "Dark",
|
||||
"item_name": "(Shirt_SpaceMarine)",
|
||||
"item_guid": "4ce7a70f-15a0-4cad-98ee-5cbb40827338",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "SpaceMarine_SRank_Swatch",
|
||||
"swatch_guid": "4ElTihrMA0ipcgeb9UG01Q",
|
||||
"color": "SRank",
|
||||
"item_name": "(Shirt_SpaceMarine)",
|
||||
"item_guid": "4ce7a70f-15a0-4cad-98ee-5cbb40827338",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Hibiscus_Yellow_Swatch",
|
||||
"swatch_guid": "596097a8-d545-4256-959d-1d3cd96fc64c",
|
||||
"color": "Yellow",
|
||||
"item_name": "(Hat_Hibiscus)",
|
||||
"item_guid": "a61e86cd-f7e7-4ac7-a6e8-df269bc5cb01",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Hibiscus_White_Swatch",
|
||||
"swatch_guid": "ce465d53-3807-423f-baa0-bdba2a75ceb3",
|
||||
"color": "White",
|
||||
"item_name": "(Hat_Hibiscus)",
|
||||
"item_guid": "a61e86cd-f7e7-4ac7-a6e8-df269bc5cb01",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Blazer_CandyCane_Swatch",
|
||||
"swatch_guid": "_ycDQ6RcyEGAntVlSDpPeA",
|
||||
"color": "CandyCane",
|
||||
"item_name": "(Blazer)",
|
||||
"item_guid": "de0ac50d-2adb-4114-bd2e-68953b13d706",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": "be2b9293-1d3c-4b1c-b4c5-fad3ab16cf54"
|
||||
},
|
||||
{
|
||||
"swatch_name": "Blazer_Shamrock_Swatch",
|
||||
"swatch_guid": "7WrSbK4Ml0K2z-ig5HIUCw",
|
||||
"color": "Shamrock",
|
||||
"item_name": "(Blazer)",
|
||||
"item_guid": "de0ac50d-2adb-4114-bd2e-68953b13d706",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": "be2b9293-1d3c-4b1c-b4c5-fad3ab16cf54"
|
||||
},
|
||||
{
|
||||
"swatch_name": "Raincoat_Shirt_Blue_Swatch",
|
||||
"swatch_guid": "GH9q8_0O9EqjGdz7lGWD2g",
|
||||
"color": "Blue",
|
||||
"item_name": "(Shirt_Raincoat)",
|
||||
"item_guid": "9e6397dd-b7b0-4d32-8c86-1910106a8478",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": "T7zwcIIc8Ee3ud8a2JCuwQ"
|
||||
},
|
||||
{
|
||||
"swatch_name": "Boxer_Green_Swatch",
|
||||
"swatch_guid": "rzUd1IMTKUmW0HeMPSIOBQ",
|
||||
"color": "Green",
|
||||
"item_name": "(Shirt_Boxer)",
|
||||
"item_guid": "ff15e25d-d467-47a8-9ecc-e415d5acb90c",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Boxer_Red_Swatch",
|
||||
"swatch_guid": "8c7b09f2-6213-4ef9-87ab-a2df72d07a22",
|
||||
"color": "Red",
|
||||
"item_name": "(Shirt_Boxer)",
|
||||
"item_guid": "ff15e25d-d467-47a8-9ecc-e415d5acb90c",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Headphones_Red_Swatch",
|
||||
"swatch_guid": "viL4CPch2ECwG-RNaWcyZw",
|
||||
"color": "Red",
|
||||
"item_name": "(Hat_Headphones)",
|
||||
"item_guid": "UcPo9SsF3EGTCBB2J-Efdw",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Headphones_EmissiveBlack_Swatch",
|
||||
"swatch_guid": "Uz2hrptCa0erjqyPoiZxew",
|
||||
"color": "EmissiveBlack",
|
||||
"item_name": "(Hat_Headphones)",
|
||||
"item_guid": "UcPo9SsF3EGTCBB2J-Efdw",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Headphones_EmissiveRed_Swatch",
|
||||
"swatch_guid": "I1J-xY4YNU2dB_od4P_7Dg",
|
||||
"color": "EmissiveRed",
|
||||
"item_name": "(Hat_Headphones)",
|
||||
"item_guid": "UcPo9SsF3EGTCBB2J-Efdw",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Headphones_TwoRed_Swatch",
|
||||
"swatch_guid": "hf0gkFVS8ESvceRsC3LAXQ",
|
||||
"color": "TwoRed",
|
||||
"item_name": "(Hat_Headphones)",
|
||||
"item_guid": "UcPo9SsF3EGTCBB2J-Efdw",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Headphones_EmissiveBlue_Swatch",
|
||||
"swatch_guid": "2sf-FU4WckGBDWUkVz4z1g",
|
||||
"color": "EmissiveBlue",
|
||||
"item_name": "(Hat_Headphones)",
|
||||
"item_guid": "UcPo9SsF3EGTCBB2J-Efdw",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Headphones_Purple_Swatch",
|
||||
"swatch_guid": "a5nUvJZgTEGBUvdHx0Y6Ng",
|
||||
"color": "Purple",
|
||||
"item_name": "(Hat_Headphones)",
|
||||
"item_guid": "UcPo9SsF3EGTCBB2J-Efdw",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Headphones_EmissiveOrange_Swatch",
|
||||
"swatch_guid": "d9mwowRelE2lDKEA0UQMZQ",
|
||||
"color": "EmissiveOrange",
|
||||
"item_name": "(Hat_Headphones)",
|
||||
"item_guid": "UcPo9SsF3EGTCBB2J-Efdw",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Headphones_Orange_Swatch",
|
||||
"swatch_guid": "JWBK5v78Y0uRVEXlD-Qk6Q",
|
||||
"color": "Orange",
|
||||
"item_name": "(Hat_Headphones)",
|
||||
"item_guid": "UcPo9SsF3EGTCBB2J-Efdw",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Headphones_Blue_Swatch",
|
||||
"swatch_guid": "8ANbOhNnO0yLQOCIBsDwfg",
|
||||
"color": "Blue",
|
||||
"item_name": "(Hat_Headphones)",
|
||||
"item_guid": "UcPo9SsF3EGTCBB2J-Efdw",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Headphones_TwoBlue_Swatch",
|
||||
"swatch_guid": "4scG_UBlzE-5DWRhSrtm6g",
|
||||
"color": "TwoBlue",
|
||||
"item_name": "(Hat_Headphones)",
|
||||
"item_guid": "UcPo9SsF3EGTCBB2J-Efdw",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Headphones_TwoOrange_Swatch",
|
||||
"swatch_guid": "nX7krD8e2km_ZlOLWcoxdQ",
|
||||
"color": "TwoOrange",
|
||||
"item_name": "(Hat_Headphones)",
|
||||
"item_guid": "UcPo9SsF3EGTCBB2J-Efdw",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Headphones_TwoPurple_Swatch",
|
||||
"swatch_guid": "OqsbZ8Xls0i8uA6ha7H3qQ",
|
||||
"color": "TwoPurple",
|
||||
"item_name": "(Hat_Headphones)",
|
||||
"item_guid": "UcPo9SsF3EGTCBB2J-Efdw",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Headphones_EmissivePurple_Swatch",
|
||||
"swatch_guid": "3PfP661Fg0CruzRxis9EiA",
|
||||
"color": "EmissivePurple",
|
||||
"item_name": "(Hat_Headphones)",
|
||||
"item_guid": "UcPo9SsF3EGTCBB2J-Efdw",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Headphones_TwoBlack_Swatch",
|
||||
"swatch_guid": "ns5tIRishUOp-nYqLedcwA",
|
||||
"color": "TwoBlack",
|
||||
"item_name": "(Hat_Headphones)",
|
||||
"item_guid": "UcPo9SsF3EGTCBB2J-Efdw",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "JackfrostHair_Hat_Lilac_Swatch",
|
||||
"swatch_guid": "KwhdQ1deNE6Y6jzO9vaAnQ",
|
||||
"color": "Lilac",
|
||||
"item_name": "(Hat_JackfrostHair)",
|
||||
"item_guid": "e6216087-fb37-46f1-bda4-a88c4640f339",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Baseball_Red_Swatch",
|
||||
"swatch_guid": "de0a5a3a-8aff-4799-8269-9efa3aeb383a",
|
||||
"color": "Red",
|
||||
"item_name": "(Hat_Baseball)",
|
||||
"item_guid": "14ef6b00-debf-4a85-9755-b4d37df496d3",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Baseball_Green_Swatch",
|
||||
"swatch_guid": "e5de2e45-207c-46af-9a5e-eb01a0c621fe",
|
||||
"color": "Green",
|
||||
"item_name": "(Hat_Baseball)",
|
||||
"item_guid": "14ef6b00-debf-4a85-9755-b4d37df496d3",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "ButtonTop_Orange_Swatch",
|
||||
"swatch_guid": "e0397982-c2c2-4733-9a40-46e18675b5af",
|
||||
"color": "Orange",
|
||||
"item_name": "(ButtonTop)",
|
||||
"item_guid": "9c8fc7f0-8f99-4aad-a34f-8d979f6ae352",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "ButtonTop_Tan_Swatch",
|
||||
"swatch_guid": "49f5864f-9d40-497c-88c8-e87f64d41d74",
|
||||
"color": "Tan",
|
||||
"item_name": "(ButtonTop)",
|
||||
"item_guid": "9c8fc7f0-8f99-4aad-a34f-8d979f6ae352",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "MagicalGirl_Blue_Swatch",
|
||||
"swatch_guid": "VQjkyb5aoEKHKo_eZsq9ug",
|
||||
"color": "Blue",
|
||||
"item_name": "(Wrist_MagicalGirl)",
|
||||
"item_guid": "eS_or4AnMka9M_bD7YN28g",
|
||||
"item_outfit_type": 200,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "MagicalGirl_Red_Swatch",
|
||||
"swatch_guid": "FE7_gQNBt0CXzMN6di5HWA",
|
||||
"color": "Red",
|
||||
"item_name": "(Wrist_MagicalGirl)",
|
||||
"item_guid": "eS_or4AnMka9M_bD7YN28g",
|
||||
"item_outfit_type": 200,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "MagicalGirl_Green_Swatch",
|
||||
"swatch_guid": "kTP3xKhzBkuQF3SqvmYFKA",
|
||||
"color": "Green",
|
||||
"item_name": "(Wrist_MagicalGirl)",
|
||||
"item_guid": "eS_or4AnMka9M_bD7YN28g",
|
||||
"item_outfit_type": 200,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "MagicalGirl_Orange_Swatch",
|
||||
"swatch_guid": "hYu9itGe1Ee5Neanhj9VtQ",
|
||||
"color": "Orange",
|
||||
"item_name": "(Wrist_MagicalGirl)",
|
||||
"item_guid": "eS_or4AnMka9M_bD7YN28g",
|
||||
"item_outfit_type": 200,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Wizard_SRank_Swatch",
|
||||
"swatch_guid": "RKmRHk2N_U2gd91nybo6vg",
|
||||
"color": "SRank",
|
||||
"item_name": "(Hat_Wizard)",
|
||||
"item_guid": "01689baf-405e-4b38-9f09-b624e03865b8",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Wizard_Purple_Swatch",
|
||||
"swatch_guid": "d3KmqVuMQkCYK6sVTMOTOA",
|
||||
"color": "Purple",
|
||||
"item_name": "(Hat_Wizard)",
|
||||
"item_guid": "01689baf-405e-4b38-9f09-b624e03865b8",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Wizard_White_Swatch",
|
||||
"swatch_guid": "d3a9b576-5433-4305-bd96-b08820c09212",
|
||||
"color": "White",
|
||||
"item_name": "(Hat_Wizard)",
|
||||
"item_guid": "01689baf-405e-4b38-9f09-b624e03865b8",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Wizard_Green_Swatch",
|
||||
"swatch_guid": "357eb160-360b-4a63-840d-65d11cc8ffc2",
|
||||
"color": "Green",
|
||||
"item_name": "(Hat_Wizard)",
|
||||
"item_guid": "01689baf-405e-4b38-9f09-b624e03865b8",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Wizard_Black_Swatch",
|
||||
"swatch_guid": "7afe1bb0-5ca9-4263-8f85-49d3a18353c7",
|
||||
"color": "Black",
|
||||
"item_name": "(Hat_Wizard)",
|
||||
"item_guid": "01689baf-405e-4b38-9f09-b624e03865b8",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Wizard_Red_Swatch",
|
||||
"swatch_guid": "a38254c0-00e3-429b-9d5d-b9e6a9812e69",
|
||||
"color": "Red",
|
||||
"item_name": "(Hat_Wizard)",
|
||||
"item_guid": "01689baf-405e-4b38-9f09-b624e03865b8",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Punk_Pink_Swatch",
|
||||
"swatch_guid": "4169bfed-8403-4590-a29d-4941275ac0b6",
|
||||
"color": "Pink",
|
||||
"item_name": "(Wrist_Punk)",
|
||||
"item_guid": "28374ebc-4050-4ea0-b3b6-41ebe75cedf7",
|
||||
"item_outfit_type": 200,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Punk_WristPink_Swatch",
|
||||
"swatch_guid": "f3b2330a-b981-4c7e-902f-1f57382f2388",
|
||||
"color": "WristPink",
|
||||
"item_name": "(Wrist_Punk)",
|
||||
"item_guid": "28374ebc-4050-4ea0-b3b6-41ebe75cedf7",
|
||||
"item_outfit_type": 200,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Punk_WristRed_Swatch",
|
||||
"swatch_guid": "baffdefe-de21-4551-9330-b50873965bdd",
|
||||
"color": "WristRed",
|
||||
"item_name": "(Wrist_Punk)",
|
||||
"item_guid": "28374ebc-4050-4ea0-b3b6-41ebe75cedf7",
|
||||
"item_outfit_type": 200,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Punk_Green_Swatch",
|
||||
"swatch_guid": "0724b166-9ace-46ff-a191-b13f135b00a8",
|
||||
"color": "Green",
|
||||
"item_name": "(Wrist_Punk)",
|
||||
"item_guid": "28374ebc-4050-4ea0-b3b6-41ebe75cedf7",
|
||||
"item_outfit_type": 200,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Punk_WristGreen_Swatch",
|
||||
"swatch_guid": "a6796264-9c7e-4605-830c-06db8d0dc780",
|
||||
"color": "WristGreen",
|
||||
"item_name": "(Wrist_Punk)",
|
||||
"item_guid": "28374ebc-4050-4ea0-b3b6-41ebe75cedf7",
|
||||
"item_outfit_type": 200,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Hat_GraduationCap_Green_Swatch",
|
||||
"swatch_guid": "FaWMLkJJgEKFIO493fzGxg",
|
||||
"color": "Green",
|
||||
"item_name": "(Hat_GraduationCap)",
|
||||
"item_guid": "KPmC_wyX_ECe7fdKwoLMGg",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": "yzL0M_N5Q0eAa8IxACHPAQ"
|
||||
},
|
||||
{
|
||||
"swatch_name": "EquestrianJacket_Maroon_Swatch",
|
||||
"swatch_guid": "d6823e01-69f0-4f85-b94a-74894356a2cf",
|
||||
"color": "Maroon",
|
||||
"item_name": "(EquestrianJacket)",
|
||||
"item_guid": "896c2491-2f96-4986-9cbd-b3b31ef5d8c5",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "EquestrianJacket_Gray_Swatch",
|
||||
"swatch_guid": "4828b50c-95b6-466a-bb25-514891d78202",
|
||||
"color": "Gray",
|
||||
"item_name": "(EquestrianJacket)",
|
||||
"item_guid": "896c2491-2f96-4986-9cbd-b3b31ef5d8c5",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Shirt_VampireHunter_White_Swatch",
|
||||
"swatch_guid": "9QG6qp5FBU-u0-JK-yMMqA",
|
||||
"color": "White",
|
||||
"item_name": "(Shirt_VampireHunter)",
|
||||
"item_guid": "JWfs9IiQs0Weu8MmyGpqLQ",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": "x10FeRBsQU2DIIpG8XIlwg"
|
||||
},
|
||||
{
|
||||
"swatch_name": "Shirt_VampireHunter_Midnight_Swatch",
|
||||
"swatch_guid": "CavRDqIlmUeTZBtCLn1hZQ",
|
||||
"color": "Midnight",
|
||||
"item_name": "(Shirt_VampireHunter)",
|
||||
"item_guid": "JWfs9IiQs0Weu8MmyGpqLQ",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": "x10FeRBsQU2DIIpG8XIlwg"
|
||||
},
|
||||
{
|
||||
"swatch_name": "Shirt_VampireHunter_Leather_Swatch",
|
||||
"swatch_guid": "Z8Bfk0MTb0evZehvvgzuBA",
|
||||
"color": "Leather",
|
||||
"item_name": "(Shirt_VampireHunter)",
|
||||
"item_guid": "JWfs9IiQs0Weu8MmyGpqLQ",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": "x10FeRBsQU2DIIpG8XIlwg"
|
||||
},
|
||||
{
|
||||
"swatch_name": "Scallywag_Bracelet_SRank_Swatch",
|
||||
"swatch_guid": "X3MkhL55Rk-0UK6h4dw0Eg",
|
||||
"color": "SRank",
|
||||
"item_name": "(Wrist_Scallywag_Bracelet)",
|
||||
"item_guid": "b9e0f03b-2609-4911-82e9-1e324dbbe8be",
|
||||
"item_outfit_type": 200,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Scallywag_Bracelet_Red_Swatch",
|
||||
"swatch_guid": "62bd5dda-08da-4528-83c1-f0ca3812dc6e",
|
||||
"color": "Red",
|
||||
"item_name": "(Wrist_Scallywag_Bracelet)",
|
||||
"item_guid": "b9e0f03b-2609-4911-82e9-1e324dbbe8be",
|
||||
"item_outfit_type": 200,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Scallywag_Bracelet_Blue_Swatch",
|
||||
"swatch_guid": "cdca593a-8840-4140-9145-fe962732040c",
|
||||
"color": "Blue",
|
||||
"item_name": "(Wrist_Scallywag_Bracelet)",
|
||||
"item_guid": "b9e0f03b-2609-4911-82e9-1e324dbbe8be",
|
||||
"item_outfit_type": 200,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "PurpleJacket_Red_Swatch",
|
||||
"swatch_guid": "657f28d5-672a-4f27-86c6-3cb00f25bb84",
|
||||
"color": "Red",
|
||||
"item_name": "(PurpleJacket)",
|
||||
"item_guid": "745c5110-104e-4b37-aabf-7c690fd54811",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": "3ba69a39-a4e7-4505-bae7-8db31360ec1c"
|
||||
},
|
||||
{
|
||||
"swatch_name": "PurpleJacket_Blue_Swatch",
|
||||
"swatch_guid": "b42d903b-b393-4f49-af5e-38d0fb6c42b0",
|
||||
"color": "Blue",
|
||||
"item_name": "(PurpleJacket)",
|
||||
"item_guid": "745c5110-104e-4b37-aabf-7c690fd54811",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": "3ba69a39-a4e7-4505-bae7-8db31360ec1c"
|
||||
},
|
||||
{
|
||||
"swatch_name": "PurpleJacket_Black_Swatch",
|
||||
"swatch_guid": "8cab8cc6-9a2d-434c-8b72-e66edbdd223c",
|
||||
"color": "Black",
|
||||
"item_name": "(PurpleJacket)",
|
||||
"item_guid": "745c5110-104e-4b37-aabf-7c690fd54811",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": "3ba69a39-a4e7-4505-bae7-8db31360ec1c"
|
||||
},
|
||||
{
|
||||
"swatch_name": "FighterPilot_Orange_Swatch",
|
||||
"swatch_guid": "cea53c7f-24a9-4e3b-80b9-fbf95738f973",
|
||||
"color": "Orange",
|
||||
"item_name": "(Wrist_FighterPilot)",
|
||||
"item_guid": "5800d2b5-75b8-442f-8b10-63bd3d73a1b8",
|
||||
"item_outfit_type": 200,
|
||||
"mask_guid": "435eba0d-d8f9-43cc-91aa-2959d63c6fa7"
|
||||
},
|
||||
{
|
||||
"swatch_name": "FighterPilot_Black_Swatch",
|
||||
"swatch_guid": "8c74ee27-3d56-401b-8a8c-7868a80770e8",
|
||||
"color": "Black",
|
||||
"item_name": "(Wrist_FighterPilot)",
|
||||
"item_guid": "5800d2b5-75b8-442f-8b10-63bd3d73a1b8",
|
||||
"item_outfit_type": 200,
|
||||
"mask_guid": "435eba0d-d8f9-43cc-91aa-2959d63c6fa7"
|
||||
},
|
||||
{
|
||||
"swatch_name": "FighterPilot_Blue_Swatch",
|
||||
"swatch_guid": "e37b07d1-6b9d-49b9-94ca-1c728e228cfe",
|
||||
"color": "Blue",
|
||||
"item_name": "(Wrist_FighterPilot)",
|
||||
"item_guid": "5800d2b5-75b8-442f-8b10-63bd3d73a1b8",
|
||||
"item_outfit_type": 200,
|
||||
"mask_guid": "435eba0d-d8f9-43cc-91aa-2959d63c6fa7"
|
||||
},
|
||||
{
|
||||
"swatch_name": "Neck_Grillmaster_Denim_Swatch",
|
||||
"swatch_guid": "eV3Nv6SWS0yl3f-fgjPb-w",
|
||||
"color": "Denim",
|
||||
"item_name": "(Neck_Grillmaster)",
|
||||
"item_guid": "tTKv7eRODka2KC_hsY2O3Q",
|
||||
"item_outfit_type": 100,
|
||||
"mask_guid": "t-ZEWJCgFEyGP2PjNblQMA"
|
||||
},
|
||||
{
|
||||
"swatch_name": "Neck_Grillmaster_White_Swatch",
|
||||
"swatch_guid": "Lxx3q6JRnUW_cPG_kGG4ag",
|
||||
"color": "White",
|
||||
"item_name": "(Neck_Grillmaster)",
|
||||
"item_guid": "tTKv7eRODka2KC_hsY2O3Q",
|
||||
"item_outfit_type": 100,
|
||||
"mask_guid": "t-ZEWJCgFEyGP2PjNblQMA"
|
||||
},
|
||||
{
|
||||
"swatch_name": "BabydollDress_Green_Swatch",
|
||||
"swatch_guid": "c9589974-c261-485e-b571-cb2f34fb178f",
|
||||
"color": "Green",
|
||||
"item_name": "(BabydollDress)",
|
||||
"item_guid": "da55bfc3-47b7-46f6-b548-7fb2c2a5e0bf",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "BabydollDress_Black_Swatch",
|
||||
"swatch_guid": "e13cf33d-7588-4e2e-955e-f0a29d6380b7",
|
||||
"color": "Black",
|
||||
"item_name": "(BabydollDress)",
|
||||
"item_guid": "da55bfc3-47b7-46f6-b548-7fb2c2a5e0bf",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "BabydollDress_Pink_Swatch",
|
||||
"swatch_guid": "da6d0ced-3d43-4878-a868-925f2ed6fd5b",
|
||||
"color": "Pink",
|
||||
"item_name": "(BabydollDress)",
|
||||
"item_guid": "da55bfc3-47b7-46f6-b548-7fb2c2a5e0bf",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "WitchHunter_Purple_Swatch",
|
||||
"swatch_guid": "71e5a0fe-fc8d-420b-af3b-e74160e0d1f3",
|
||||
"color": "Purple",
|
||||
"item_name": "(Shirt_WitchHunter)",
|
||||
"item_guid": "418db0e0-c7af-40c2-9cac-d461ce41e210",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "WitchHunter_Green_Swatch",
|
||||
"swatch_guid": "64545dcc-a8eb-4c69-a539-78ee73a2d327",
|
||||
"color": "Green",
|
||||
"item_name": "(Shirt_WitchHunter)",
|
||||
"item_guid": "418db0e0-c7af-40c2-9cac-d461ce41e210",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "WitchHunter_Blue_Swatch",
|
||||
"swatch_guid": "aBQ3R9boek-mYeSYSNvDbQ",
|
||||
"color": "Blue",
|
||||
"item_name": "(Shirt_WitchHunter)",
|
||||
"item_guid": "418db0e0-c7af-40c2-9cac-d461ce41e210",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "WitchHunter_SRank_Swatch",
|
||||
"swatch_guid": "Tbrc2MlSlE6mKua8qSoluQ",
|
||||
"color": "SRank",
|
||||
"item_name": "(Shirt_WitchHunter)",
|
||||
"item_guid": "418db0e0-c7af-40c2-9cac-d461ce41e210",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "WitchHunter_White_Swatch",
|
||||
"swatch_guid": "e02838f8-4029-455a-b35c-dd40f972b05b",
|
||||
"color": "White",
|
||||
"item_name": "(Shirt_WitchHunter)",
|
||||
"item_guid": "418db0e0-c7af-40c2-9cac-d461ce41e210",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "WitchHunter_Red_Swatch",
|
||||
"swatch_guid": "909ed249-ce09-4304-8b02-56794fa7567d",
|
||||
"color": "Red",
|
||||
"item_name": "(Shirt_WitchHunter)",
|
||||
"item_guid": "418db0e0-c7af-40c2-9cac-d461ce41e210",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Smuggler_Green_Swatch",
|
||||
"swatch_guid": "076c96ae-9f9b-45bf-9dc7-ce73d5ddf422",
|
||||
"color": "Green",
|
||||
"item_name": "(Shirt_Smuggler)",
|
||||
"item_guid": "25d4c652-1730-4925-925e-31a290a2272a",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Smuggler_SRank_Swatch",
|
||||
"swatch_guid": "bzYdPb8GWUS-CgT4wrziIA",
|
||||
"color": "SRank",
|
||||
"item_name": "(Shirt_Smuggler)",
|
||||
"item_guid": "25d4c652-1730-4925-925e-31a290a2272a",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Smuggler_Grey_Swatch",
|
||||
"swatch_guid": "90869e86-cbc5-4024-9d08-fcdc41c64eb5",
|
||||
"color": "Grey",
|
||||
"item_name": "(Shirt_Smuggler)",
|
||||
"item_guid": "25d4c652-1730-4925-925e-31a290a2272a",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Smuggler_Dark_Swatch",
|
||||
"swatch_guid": "e821aa74-2d47-4388-bcfb-1893b8a83a52",
|
||||
"color": "Dark",
|
||||
"item_name": "(Shirt_Smuggler)",
|
||||
"item_guid": "25d4c652-1730-4925-925e-31a290a2272a",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Smuggler_Cherry_Swatch",
|
||||
"swatch_guid": "fed760b2-15e2-46b2-b1e3-cc3c8d780d5d",
|
||||
"color": "Cherry",
|
||||
"item_name": "(Shirt_Smuggler)",
|
||||
"item_guid": "25d4c652-1730-4925-925e-31a290a2272a",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Smuggler_Yellow_Swatch",
|
||||
"swatch_guid": "002b07bb-4256-44ce-8ca4-25510e70b6b5",
|
||||
"color": "Yellow",
|
||||
"item_name": "(Shirt_Smuggler)",
|
||||
"item_guid": "25d4c652-1730-4925-925e-31a290a2272a",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "SodaJerk_Green_Swatch",
|
||||
"swatch_guid": "oKxmH-1s2EyIDkZoOQSQQw",
|
||||
"color": "Green",
|
||||
"item_name": "(Shirt_SodaJerk)",
|
||||
"item_guid": "iai6P7dDTUq8S4hqQmY1YA",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "SodaJerk_Mustard_Swatch",
|
||||
"swatch_guid": "MxnAq_XOw0uTzQ8IIxqb_Q",
|
||||
"color": "Mustard",
|
||||
"item_name": "(Shirt_SodaJerk)",
|
||||
"item_guid": "iai6P7dDTUq8S4hqQmY1YA",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "SodaJerk_Blue_Swatch",
|
||||
"swatch_guid": "XFCpIdeDXUqeYCIgh4fGtg",
|
||||
"color": "Blue",
|
||||
"item_name": "(Shirt_SodaJerk)",
|
||||
"item_guid": "iai6P7dDTUq8S4hqQmY1YA",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Hat_TutorialCap_2_Swatch",
|
||||
"swatch_guid": "gDH1WmW5rk2RdY4wJYYZow",
|
||||
"color": "2",
|
||||
"item_name": "(Hat_TutorialCap)",
|
||||
"item_guid": "M9weaekvIUimiJSVJqZl-w",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": "GV8z2dlqGEqIAYaGrF1ZYQ"
|
||||
},
|
||||
{
|
||||
"swatch_name": "Hat_TutorialCap_3_Swatch",
|
||||
"swatch_guid": "wHJnbDOo8ESmUbQDr0k31w",
|
||||
"color": "3",
|
||||
"item_name": "(Hat_TutorialCap)",
|
||||
"item_guid": "M9weaekvIUimiJSVJqZl-w",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": "GV8z2dlqGEqIAYaGrF1ZYQ"
|
||||
},
|
||||
{
|
||||
"swatch_name": "BaseballHelmet_Red_Swatch",
|
||||
"swatch_guid": "a1c51d1e-1d5f-4f8a-bc0f-6a20eddfe58a",
|
||||
"color": "Red",
|
||||
"item_name": "(Hat_BaseballHelmet)",
|
||||
"item_guid": "293e7ad3-01c9-43af-96e3-06c34145ff12",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "BaseballHelmet_Green_Swatch",
|
||||
"swatch_guid": "9967ce54-c2b7-437a-946e-11f8ee6d6fdd",
|
||||
"color": "Green",
|
||||
"item_name": "(Hat_BaseballHelmet)",
|
||||
"item_guid": "293e7ad3-01c9-43af-96e3-06c34145ff12",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "TruckerOveralls_Mustard_Swatch",
|
||||
"swatch_guid": "nKauYAyWhkm2AMHFyC-fLg",
|
||||
"color": "Mustard",
|
||||
"item_name": "(Shirt_TruckerOveralls)",
|
||||
"item_guid": "b080e2f4-c699-4cca-bb9e-7cfc4bafcbfc",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "TruckerOveralls_Red_Swatch",
|
||||
"swatch_guid": "iokdlBfjuEuAwqIMOQwxdA",
|
||||
"color": "Red",
|
||||
"item_name": "(Shirt_TruckerOveralls)",
|
||||
"item_guid": "b080e2f4-c699-4cca-bb9e-7cfc4bafcbfc",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "TruckerOveralls_Green_Swatch",
|
||||
"swatch_guid": "EiGgN7uVukqoRE7UJcMLTw",
|
||||
"color": "Green",
|
||||
"item_name": "(Shirt_TruckerOveralls)",
|
||||
"item_guid": "b080e2f4-c699-4cca-bb9e-7cfc4bafcbfc",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "PirateCaptain_Black_Swatch",
|
||||
"swatch_guid": "d81d0b62-e052-46c2-9252-4bc5fb219f53",
|
||||
"color": "Black",
|
||||
"item_name": "(Neck_PirateCaptain)",
|
||||
"item_guid": "38b38e24-d636-41c6-b80e-a285ae3106dc",
|
||||
"item_outfit_type": 102,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "PirateCaptain_SRank_Swatch",
|
||||
"swatch_guid": "xGmnUGF-Ck-jP43r8tVVjg",
|
||||
"color": "SRank",
|
||||
"item_name": "(Neck_PirateCaptain)",
|
||||
"item_guid": "38b38e24-d636-41c6-b80e-a285ae3106dc",
|
||||
"item_outfit_type": 102,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "PirateCaptain_Red_Swatch",
|
||||
"swatch_guid": "556141f7-6fbc-4065-9faa-8d8240a93d7f",
|
||||
"color": "Red",
|
||||
"item_name": "(Neck_PirateCaptain)",
|
||||
"item_guid": "38b38e24-d636-41c6-b80e-a285ae3106dc",
|
||||
"item_outfit_type": 102,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Bowtie_SodaJerk_Swatch",
|
||||
"swatch_guid": "e4IDo-fuH0C9YByzcX5k-A",
|
||||
"color": "SodaJerk",
|
||||
"item_name": "(Bowtie)",
|
||||
"item_guid": "83be5ba4-525a-4781-a5f6-839c22e4d1d3",
|
||||
"item_outfit_type": 100,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "FlapperGlove_Black_Swatch",
|
||||
"swatch_guid": "30c61e63-5e09-4a6f-8915-1e1fe4d55cf0",
|
||||
"color": "Black",
|
||||
"item_name": "(Wrist_FlapperGlove)",
|
||||
"item_guid": "473c672d-2b79-48a2-a49d-fd68160c5bde",
|
||||
"item_outfit_type": 200,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "FlapperGlove_Gold_Swatch",
|
||||
"swatch_guid": "2cf2b644-3fa6-449c-9fe8-d0ab917f3106",
|
||||
"color": "Gold",
|
||||
"item_name": "(Wrist_FlapperGlove)",
|
||||
"item_guid": "473c672d-2b79-48a2-a49d-fd68160c5bde",
|
||||
"item_outfit_type": 200,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "BusinessTie_Valentine_Swatch",
|
||||
"swatch_guid": "31jelNWFyk6FlWt4HyPAlw",
|
||||
"color": "Valentine",
|
||||
"item_name": "(BusinessTie)",
|
||||
"item_guid": "c6c08eb5-381a-4193-9722-80da95d62abe",
|
||||
"item_outfit_type": 100,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "BusinessTie_CandyCane_Swatch",
|
||||
"swatch_guid": "W4a144so90eRzCojUnDowA",
|
||||
"color": "CandyCane",
|
||||
"item_name": "(BusinessTie)",
|
||||
"item_guid": "c6c08eb5-381a-4193-9722-80da95d62abe",
|
||||
"item_outfit_type": 100,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Vest_Red_Swatch",
|
||||
"swatch_guid": "ffHKr5EcIU24PbAtWSnalw",
|
||||
"color": "Red",
|
||||
"item_name": "(Shirt_Vest)",
|
||||
"item_guid": "3d9d52cb-6a3d-436b-90e7-e76f238329ee",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "HeadBackBow_Blue_Swatch",
|
||||
"swatch_guid": "GmS0wKwzVEqdf3NoTMHG5A",
|
||||
"color": "Blue",
|
||||
"item_name": "(Hat_HeadBackBow)",
|
||||
"item_guid": "JTrfBXhIT02o2-ssP94zew",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "HeadBackBow_Red_Swatch",
|
||||
"swatch_guid": "ZNKGkou_gU-1cxBFy7pDKw",
|
||||
"color": "Red",
|
||||
"item_name": "(Hat_HeadBackBow)",
|
||||
"item_guid": "JTrfBXhIT02o2-ssP94zew",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "HeadBackBow_White_Swatch",
|
||||
"swatch_guid": "-Iqmonry4EKoqAULCKzRPA",
|
||||
"color": "White",
|
||||
"item_name": "(Hat_HeadBackBow)",
|
||||
"item_guid": "JTrfBXhIT02o2-ssP94zew",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "HeadBackBow_SolidBlack_Swatch",
|
||||
"swatch_guid": "f_c50saStkaGJuhLjJ9lfA",
|
||||
"color": "SolidBlack",
|
||||
"item_name": "(Hat_HeadBackBow)",
|
||||
"item_guid": "JTrfBXhIT02o2-ssP94zew",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "HeadBackBow_Hearts_Swatch",
|
||||
"swatch_guid": "D-SngK7hhkOpoZ2aMWv9EA",
|
||||
"color": "Hearts",
|
||||
"item_name": "(Hat_HeadBackBow)",
|
||||
"item_guid": "JTrfBXhIT02o2-ssP94zew",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "HeadBackBow_SolidBlue_Swatch",
|
||||
"swatch_guid": "8iZO162KNUiMC8l_z3OC_A",
|
||||
"color": "SolidBlue",
|
||||
"item_name": "(Hat_HeadBackBow)",
|
||||
"item_guid": "JTrfBXhIT02o2-ssP94zew",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "HeadBackBow_SolidPink_Swatch",
|
||||
"swatch_guid": "FUP4iRnoc0ikNmjrFD06lg",
|
||||
"color": "SolidPink",
|
||||
"item_name": "(Hat_HeadBackBow)",
|
||||
"item_guid": "JTrfBXhIT02o2-ssP94zew",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "FurCoat_Black_Swatch",
|
||||
"swatch_guid": "43501b0c-eaaa-4ab3-9d03-2ca61d2e8fc9",
|
||||
"color": "Black",
|
||||
"item_name": "(FurCoat)",
|
||||
"item_guid": "77c37481-a185-47ff-af55-65f9fdfcf9e5",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": "2c0d912d-c184-4eab-8ee4-73b90ba7b0a6"
|
||||
},
|
||||
{
|
||||
"swatch_name": "FurCoat_White_Swatch",
|
||||
"swatch_guid": "643b5f2d-0666-4869-b699-03742de34d16",
|
||||
"color": "White",
|
||||
"item_name": "(FurCoat)",
|
||||
"item_guid": "77c37481-a185-47ff-af55-65f9fdfcf9e5",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": "2c0d912d-c184-4eab-8ee4-73b90ba7b0a6"
|
||||
},
|
||||
{
|
||||
"swatch_name": "FlapperHeadband_Gold_Swatch",
|
||||
"swatch_guid": "b6c25a3b-125b-4aab-bed0-e6e5ced2c21c",
|
||||
"color": "Gold",
|
||||
"item_name": "(Hat_FlapperHeadband)",
|
||||
"item_guid": "18feb3c2-049f-4f91-9f4e-6b5fcb4ab70c",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "FlapperHeadband_Black_Swatch",
|
||||
"swatch_guid": "565c17e0-496d-45bd-a2c3-564e118c06cc",
|
||||
"color": "Black",
|
||||
"item_name": "(Hat_FlapperHeadband)",
|
||||
"item_guid": "18feb3c2-049f-4f91-9f4e-6b5fcb4ab70c",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Wrist_VampireHunter_Red_Swatch",
|
||||
"swatch_guid": "iJW8XGJfU0G12iXarjxhdQ",
|
||||
"color": "Red",
|
||||
"item_name": "(Wrist_VampireHunter)",
|
||||
"item_guid": "_OWVy3z6iU-M3-zbQgSLig",
|
||||
"item_outfit_type": 200,
|
||||
"mask_guid": "N5wN1l0tYEau5np-9PoIiA"
|
||||
},
|
||||
{
|
||||
"swatch_name": "Wrist_VampireHunter_Black_Swatch",
|
||||
"swatch_guid": "Vxq6v55a_kGPODzwB5MC1g",
|
||||
"color": "Black",
|
||||
"item_name": "(Wrist_VampireHunter)",
|
||||
"item_guid": "_OWVy3z6iU-M3-zbQgSLig",
|
||||
"item_outfit_type": 200,
|
||||
"mask_guid": "N5wN1l0tYEau5np-9PoIiA"
|
||||
},
|
||||
{
|
||||
"swatch_name": "Wrist_VampireHunter_Leather_Swatch",
|
||||
"swatch_guid": "D0tP58wC30mJ00vNxw8hqA",
|
||||
"color": "Leather",
|
||||
"item_name": "(Wrist_VampireHunter)",
|
||||
"item_guid": "_OWVy3z6iU-M3-zbQgSLig",
|
||||
"item_outfit_type": 200,
|
||||
"mask_guid": "N5wN1l0tYEau5np-9PoIiA"
|
||||
},
|
||||
{
|
||||
"swatch_name": "PeaCoat_Purple_Swatch",
|
||||
"swatch_guid": "uiBklotTUEqRI2F67vyJyA",
|
||||
"color": "Purple",
|
||||
"item_name": "(Shirt_Peacoat)",
|
||||
"item_guid": "ab15ef15-a97c-4ab1-896b-bd4d7e1cd9f5",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "PeaCoat_Navy_Swatch",
|
||||
"swatch_guid": "fvoaMN4M10WS6jiA6XlOJQ",
|
||||
"color": "Navy",
|
||||
"item_name": "(Shirt_Peacoat)",
|
||||
"item_guid": "ab15ef15-a97c-4ab1-896b-bd4d7e1cd9f5",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "PeaCoat_Tan_Swatch",
|
||||
"swatch_guid": "PwsLxCnzOkSW-RGz3tNb1w",
|
||||
"color": "Tan",
|
||||
"item_name": "(Shirt_Peacoat)",
|
||||
"item_guid": "ab15ef15-a97c-4ab1-896b-bd4d7e1cd9f5",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "PeaCoat_Red_Swatch",
|
||||
"swatch_guid": "jXBi28cRV0CEQgKIrpD0_A",
|
||||
"color": "Red",
|
||||
"item_name": "(Shirt_Peacoat)",
|
||||
"item_guid": "ab15ef15-a97c-4ab1-896b-bd4d7e1cd9f5",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Hat_CatEars_Gray_Swatch",
|
||||
"swatch_guid": "96e42c7a-2881-4299-a2fe-80c0d4d5ca26",
|
||||
"color": "Gray",
|
||||
"item_name": "(Hat_CatEars)",
|
||||
"item_guid": "3d5184e1-0201-4476-bf4b-4eb28190de62",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": "1e3195ab-f7f6-41f4-a5ec-378d09ecdf69"
|
||||
},
|
||||
{
|
||||
"swatch_name": "Hat_CatEars_Brown_Swatch",
|
||||
"swatch_guid": "713781e5-ce47-41c6-a24f-94d42a565e30",
|
||||
"color": "Brown",
|
||||
"item_name": "(Hat_CatEars)",
|
||||
"item_guid": "3d5184e1-0201-4476-bf4b-4eb28190de62",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": "1e3195ab-f7f6-41f4-a5ec-378d09ecdf69"
|
||||
},
|
||||
{
|
||||
"swatch_name": "Hat_CatEars_White_Swatch",
|
||||
"swatch_guid": "c1e430c5-fd8d-4032-9e3f-8d87cc8784da",
|
||||
"color": "White",
|
||||
"item_name": "(Hat_CatEars)",
|
||||
"item_guid": "3d5184e1-0201-4476-bf4b-4eb28190de62",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": "1e3195ab-f7f6-41f4-a5ec-378d09ecdf69"
|
||||
},
|
||||
{
|
||||
"swatch_name": "Hat_CatEars_Gold_Swatch",
|
||||
"swatch_guid": "37f8378b-b98c-477a-b8c9-9340772800b5",
|
||||
"color": "Gold",
|
||||
"item_name": "(Hat_CatEars)",
|
||||
"item_guid": "3d5184e1-0201-4476-bf4b-4eb28190de62",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": "1e3195ab-f7f6-41f4-a5ec-378d09ecdf69"
|
||||
},
|
||||
{
|
||||
"swatch_name": "TruckerJacket_White_Swatch",
|
||||
"swatch_guid": "yA0KhVg19kWqG1UkyxQogQ",
|
||||
"color": "White",
|
||||
"item_name": "(Shirt_TruckerJacket)",
|
||||
"item_guid": "8b065e2a-b106-4f11-b415-4c47ce87993e",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "TruckerJacket_Tan_Swatch",
|
||||
"swatch_guid": "o2WfRyjJy0CKoUg8YIxNjQ",
|
||||
"color": "Tan",
|
||||
"item_name": "(Shirt_TruckerJacket)",
|
||||
"item_guid": "8b065e2a-b106-4f11-b415-4c47ce87993e",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "TruckerJacket_RebelRose_Swatch",
|
||||
"swatch_guid": "4Eck_dNL1UKlIZWsA1YppQ",
|
||||
"color": "RebelRose",
|
||||
"item_name": "(Shirt_TruckerJacket)",
|
||||
"item_guid": "8b065e2a-b106-4f11-b415-4c47ce87993e",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "TruckerJacket_Black_Swatch",
|
||||
"swatch_guid": "P9bBSL0YLEyjN8PxMfgbKQ",
|
||||
"color": "Black",
|
||||
"item_name": "(Shirt_TruckerJacket)",
|
||||
"item_guid": "8b065e2a-b106-4f11-b415-4c47ce87993e",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "TruckerJacket_Olive_Swatch",
|
||||
"swatch_guid": "bgRKH1wfqkWVHcuSnFYnlQ",
|
||||
"color": "Olive",
|
||||
"item_name": "(Shirt_TruckerJacket)",
|
||||
"item_guid": "8b065e2a-b106-4f11-b415-4c47ce87993e",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "80sSpandex_White_Swatch",
|
||||
"swatch_guid": "zu0Jk24WTkan6XWSwGU1Uw",
|
||||
"color": "White",
|
||||
"item_name": "(Shirt_80sSpandex)",
|
||||
"item_guid": "17236d76-e3b6-42f6-9179-6fcf0479436f",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "80sSpandex_Red_Swatch",
|
||||
"swatch_guid": "6t2rCb6WWEW6pJbcjsAFCw",
|
||||
"color": "Red",
|
||||
"item_name": "(Shirt_80sSpandex)",
|
||||
"item_guid": "17236d76-e3b6-42f6-9179-6fcf0479436f",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "80sSpandex_Green_Swatch",
|
||||
"swatch_guid": "3frH6KxZ9kGUYkjeCDpylQ",
|
||||
"color": "Green",
|
||||
"item_name": "(Shirt_80sSpandex)",
|
||||
"item_guid": "17236d76-e3b6-42f6-9179-6fcf0479436f",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "80sSpandex_Blue_Swatch",
|
||||
"swatch_guid": "Lf4FjROSAEqXedFxpXFQfg",
|
||||
"color": "Blue",
|
||||
"item_name": "(Shirt_80sSpandex)",
|
||||
"item_guid": "17236d76-e3b6-42f6-9179-6fcf0479436f",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "80sSpandex_Yellow_Swatch",
|
||||
"swatch_guid": "i1XbjBqTu0CILIuJClWimA",
|
||||
"color": "Yellow",
|
||||
"item_name": "(Shirt_80sSpandex)",
|
||||
"item_guid": "17236d76-e3b6-42f6-9179-6fcf0479436f",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "WaitressApron_Red_Swatch",
|
||||
"swatch_guid": "HdwZhjrqxE6wuf68MnDhDw",
|
||||
"color": "Red",
|
||||
"item_name": "(Belt_WaitressApron)",
|
||||
"item_guid": "204bc384-e6d2-41b8-8ce9-0b26be5d85b7",
|
||||
"item_outfit_type": 102,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "WaitressApron_Mustard_Swatch",
|
||||
"swatch_guid": "b7oobDcDtE-69fhM-5g5AQ",
|
||||
"color": "Mustard",
|
||||
"item_name": "(Belt_WaitressApron)",
|
||||
"item_guid": "204bc384-e6d2-41b8-8ce9-0b26be5d85b7",
|
||||
"item_outfit_type": 102,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "WaitressApron_Green_Swatch",
|
||||
"swatch_guid": "Blev_VFjRUysY_nymGWAVg",
|
||||
"color": "Green",
|
||||
"item_name": "(Belt_WaitressApron)",
|
||||
"item_guid": "204bc384-e6d2-41b8-8ce9-0b26be5d85b7",
|
||||
"item_outfit_type": 102,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Shirt_MartyRecFly_Hipster_Swatch",
|
||||
"swatch_guid": "kkvNbVRjcEKtChpy3W1bqQ",
|
||||
"color": "Hipster",
|
||||
"item_name": "(Shirt_MartyRecFly)",
|
||||
"item_guid": "74c65554-0d15-409b-b9a8-0b2620a7d7e2",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Hat_SkiBuddy_White_Swatch",
|
||||
"swatch_guid": "KwCEye0nsESFs-yj4h9sjQ",
|
||||
"color": "White",
|
||||
"item_name": "(Hat_SkiBuddy)",
|
||||
"item_guid": "6QT99hx6DE6t9cKAs61i3w",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": "c_t9XDbn-Eqml1O-wC5zJQ"
|
||||
},
|
||||
{
|
||||
"swatch_name": "Wrist_Grillmaster_Blue_Swatch",
|
||||
"swatch_guid": "90qQe0AR3kOou0MsuoTmPA",
|
||||
"color": "Blue",
|
||||
"item_name": "(Wrist_Grillmaster)",
|
||||
"item_guid": "q7pSsRMNHkqEJmYHuhhG6g",
|
||||
"item_outfit_type": 200,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Wrist_Grillmaster_Black_Swatch",
|
||||
"swatch_guid": "hZKPr4sg10SRj9DLuEgOrw",
|
||||
"color": "Black",
|
||||
"item_name": "(Wrist_Grillmaster)",
|
||||
"item_guid": "q7pSsRMNHkqEJmYHuhhG6g",
|
||||
"item_outfit_type": 200,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Scientist_Blue_Swatch",
|
||||
"swatch_guid": "KTidYfH0ckWxJGs5qzUBTQ",
|
||||
"color": "Blue",
|
||||
"item_name": "(Hair_Scientist)",
|
||||
"item_guid": "f17a2f9e-1eab-44e8-b10a-1f53c5d0778c",
|
||||
"item_outfit_type": 2,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "RedFlowerDress_Gray_Swatch",
|
||||
"swatch_guid": "1acb1f56-4509-449f-9c6a-065bdeaa9ee3",
|
||||
"color": "Gray",
|
||||
"item_name": "(RedFlowerDress)",
|
||||
"item_guid": "515dfc36-7f7b-47bc-abee-380d68f41be6",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": "2d7361d2-31a2-404b-90da-10e89114e1f2"
|
||||
},
|
||||
{
|
||||
"swatch_name": "RedFlowerDress_Yellow_Swatch",
|
||||
"swatch_guid": "e98c3f98-7844-4d6e-a21c-05027033c18c",
|
||||
"color": "Yellow",
|
||||
"item_name": "(RedFlowerDress)",
|
||||
"item_guid": "515dfc36-7f7b-47bc-abee-380d68f41be6",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": "2d7361d2-31a2-404b-90da-10e89114e1f2"
|
||||
},
|
||||
{
|
||||
"swatch_name": "YellowBlueDress_White_Swatch",
|
||||
"swatch_guid": "bbfa08e3-8e6b-4e0f-b264-1b398d7cd44a",
|
||||
"color": "White",
|
||||
"item_name": "(YellowBlueDress)",
|
||||
"item_guid": "2296ed0d-df56-4d46-b33a-aae9230a47fc",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "YellowBlueDress_Purple_Swatch",
|
||||
"swatch_guid": "830be2fa-60a5-48cc-931f-34b670eae4bd",
|
||||
"color": "Purple",
|
||||
"item_name": "(YellowBlueDress)",
|
||||
"item_guid": "2296ed0d-df56-4d46-b33a-aae9230a47fc",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "TennisSkirt_Yellow_Swatch",
|
||||
"swatch_guid": "c5deba2a-6e35-4b13-8e94-8ba5457f39df",
|
||||
"color": "Yellow",
|
||||
"item_name": "(TennisSkirt)",
|
||||
"item_guid": "21caa68e-c3fa-474c-af5e-af1e742b7a60",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": "b75ef67d-00c3-4ac1-9b72-212032460294"
|
||||
},
|
||||
{
|
||||
"swatch_name": "TennisSkirt_Red_Swatch",
|
||||
"swatch_guid": "758752bd-db2f-43d2-b580-55b3e1efffd5",
|
||||
"color": "Red",
|
||||
"item_name": "(TennisSkirt)",
|
||||
"item_guid": "21caa68e-c3fa-474c-af5e-af1e742b7a60",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": "b75ef67d-00c3-4ac1-9b72-212032460294"
|
||||
},
|
||||
{
|
||||
"swatch_name": "LaserTag_Cyan_Swatch",
|
||||
"swatch_guid": "08b7c12d-3317-4d27-9b40-34737a709454",
|
||||
"color": "Cyan",
|
||||
"item_name": "(Hat_LaserTag)",
|
||||
"item_guid": "123de433-a005-4994-8a11-d2d84ad66b11",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "LaserTag_Green_Swatch",
|
||||
"swatch_guid": "2Z_FxSPiyUODtlFZWF9DFQ",
|
||||
"color": "Green",
|
||||
"item_name": "(Hat_LaserTag)",
|
||||
"item_guid": "123de433-a005-4994-8a11-d2d84ad66b11",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "LaserTag_Orange_Swatch",
|
||||
"swatch_guid": "jkuw9EhCpEKn-2lKJXWd3Q",
|
||||
"color": "Orange",
|
||||
"item_name": "(Hat_LaserTag)",
|
||||
"item_guid": "123de433-a005-4994-8a11-d2d84ad66b11",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Letterman_Red_Swatch",
|
||||
"swatch_guid": "VpqHNpPiY0CfRJEjRRM-mw",
|
||||
"color": "Red",
|
||||
"item_name": "(Wrist_Letterman)",
|
||||
"item_guid": "2dFMy4zc7ky_Fd5fzfgInw",
|
||||
"item_outfit_type": 200,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Letterman_Purple_Swatch",
|
||||
"swatch_guid": "iufpnteVCEiiZu_m-yPovQ",
|
||||
"color": "Purple",
|
||||
"item_name": "(Wrist_Letterman)",
|
||||
"item_guid": "2dFMy4zc7ky_Fd5fzfgInw",
|
||||
"item_outfit_type": 200,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Letterman_Black_Swatch",
|
||||
"swatch_guid": "Z1F9rjKqCE-Hd2-Ip5g3gA",
|
||||
"color": "Black",
|
||||
"item_name": "(Wrist_Letterman)",
|
||||
"item_guid": "2dFMy4zc7ky_Fd5fzfgInw",
|
||||
"item_outfit_type": 200,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Letterman_Green_Swatch",
|
||||
"swatch_guid": "apSQiQ1eO0mEzRsbugeu9w",
|
||||
"color": "Green",
|
||||
"item_name": "(Wrist_Letterman)",
|
||||
"item_guid": "2dFMy4zc7ky_Fd5fzfgInw",
|
||||
"item_outfit_type": 200,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "TrackSuit_Pink_Swatch",
|
||||
"swatch_guid": "026ca50e-3a81-43cf-87f5-950687b7bbdd",
|
||||
"color": "Pink",
|
||||
"item_name": "(TrackSuit)",
|
||||
"item_guid": "d766c8d3-76e8-4021-b0a4-24b78fb7eaba",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": "adae82eb-a4b9-4541-acf2-76cea839a593"
|
||||
},
|
||||
{
|
||||
"swatch_name": "QuiltedCoat_Orange_Swatch",
|
||||
"swatch_guid": "-HYrY2A5Tk2UWMi4_hmYbg",
|
||||
"color": "Orange",
|
||||
"item_name": "(Shirt_Quiltedcoat)",
|
||||
"item_guid": "0ab5790f-a537-4306-ba66-5eb87c02ec7d",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "QuiltedCoat_Green_Swatch",
|
||||
"swatch_guid": "QBglgj80zkuvUkk55Y5Feg",
|
||||
"color": "Green",
|
||||
"item_name": "(Shirt_Quiltedcoat)",
|
||||
"item_guid": "0ab5790f-a537-4306-ba66-5eb87c02ec7d",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "QuiltedCoat_Plum_Swatch",
|
||||
"swatch_guid": "IjRMopsYlUqSE6327I9TIQ",
|
||||
"color": "Plum",
|
||||
"item_name": "(Shirt_Quiltedcoat)",
|
||||
"item_guid": "0ab5790f-a537-4306-ba66-5eb87c02ec7d",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Shirt_SkiBuddy_Blue_Swatch",
|
||||
"swatch_guid": "fXNkMWFMV0aXalK_y_8SHw",
|
||||
"color": "Blue",
|
||||
"item_name": "(Shirt_SkiBuddy)",
|
||||
"item_guid": "6RhwWExXekaYpK0NGHSXGQ",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": "HQQWccdyakaEmntPhvC6CQ"
|
||||
},
|
||||
{
|
||||
"swatch_name": "Dodgeball_Gray_Swatch",
|
||||
"swatch_guid": "0ba92db2-690a-44ce-92f4-130e9503b6c1",
|
||||
"color": "Gray",
|
||||
"item_name": "(Shirt_Dodgeball)",
|
||||
"item_guid": "d3d69bee-60bc-44a3-ad7c-65b3b69d1e59",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": "944d934d-5e21-42d7-8196-fff9a81ee469"
|
||||
},
|
||||
{
|
||||
"swatch_name": "Dodgeball_Black_Swatch",
|
||||
"swatch_guid": "4a85c181-92fe-47a5-925e-05f0ccb25006",
|
||||
"color": "Black",
|
||||
"item_name": "(Shirt_Dodgeball)",
|
||||
"item_guid": "d3d69bee-60bc-44a3-ad7c-65b3b69d1e59",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": "944d934d-5e21-42d7-8196-fff9a81ee469"
|
||||
},
|
||||
{
|
||||
"swatch_name": "Hoodie_Gray_Swatch",
|
||||
"swatch_guid": "JTgXKeT7w0K2Mw4Jk2HCqg",
|
||||
"color": "Gray",
|
||||
"item_name": "(Shirt_Hoodie)",
|
||||
"item_guid": "b6rLwzD4NkKV7xKn9ZYVkA",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Hoodie_Green_Swatch",
|
||||
"swatch_guid": "ytmSzjhCr0Sm58MSNbwJUA",
|
||||
"color": "Green",
|
||||
"item_name": "(Shirt_Hoodie)",
|
||||
"item_guid": "b6rLwzD4NkKV7xKn9ZYVkA",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Hoodie_Blue_Swatch",
|
||||
"swatch_guid": "u_Gzj9Nro0WS48xKnH9few",
|
||||
"color": "Blue",
|
||||
"item_name": "(Shirt_Hoodie)",
|
||||
"item_guid": "b6rLwzD4NkKV7xKn9ZYVkA",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Hoodie_Pink_Swatch",
|
||||
"swatch_guid": "TEgugZRs80iJbhL87RdYwg",
|
||||
"color": "Pink",
|
||||
"item_name": "(Shirt_Hoodie)",
|
||||
"item_guid": "b6rLwzD4NkKV7xKn9ZYVkA",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Hoodie_Orange_Swatch",
|
||||
"swatch_guid": "rNhOQoP3XkOBHV28ze2NpA",
|
||||
"color": "Orange",
|
||||
"item_name": "(Shirt_Hoodie)",
|
||||
"item_guid": "b6rLwzD4NkKV7xKn9ZYVkA",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Hoodie_Purple_Swatch",
|
||||
"swatch_guid": "mvMeyStxGUGlNLSYNeSubQ",
|
||||
"color": "Purple",
|
||||
"item_name": "(Shirt_Hoodie)",
|
||||
"item_guid": "b6rLwzD4NkKV7xKn9ZYVkA",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Hoodie_Red_Swatch",
|
||||
"swatch_guid": "yM5xRrd9OkmDGyQddwOP6g",
|
||||
"color": "Red",
|
||||
"item_name": "(Shirt_Hoodie)",
|
||||
"item_guid": "b6rLwzD4NkKV7xKn9ZYVkA",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Hoodie_White_Swatch",
|
||||
"swatch_guid": "-Nf7WM2TeEKujB637h3tRA",
|
||||
"color": "White",
|
||||
"item_name": "(Shirt_Hoodie)",
|
||||
"item_guid": "b6rLwzD4NkKV7xKn9ZYVkA",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "DeepSeaDiver_Black_Swatch",
|
||||
"swatch_guid": "CahBzgN3D0y46AQsvGC14A",
|
||||
"color": "Black",
|
||||
"item_name": "(Hat_DeepSeaDiver)",
|
||||
"item_guid": "4fcb5b84-13a9-43e6-9680-72b17874ae53",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "DeepSeaDiver_Beige_Swatch",
|
||||
"swatch_guid": "Su7kiW24d0KapNns96JoFQ",
|
||||
"color": "Beige",
|
||||
"item_name": "(Hat_DeepSeaDiver)",
|
||||
"item_guid": "4fcb5b84-13a9-43e6-9680-72b17874ae53",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "QueenCrown_Black_Swatch",
|
||||
"swatch_guid": "rmq1AOQvtUGOHvbPUximwg",
|
||||
"color": "Black",
|
||||
"item_name": "(Hat_QueenCrown)",
|
||||
"item_guid": "9d395a84-4342-4b1c-940c-213ec2eb56f9",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "QueenCrown_White_Swatch",
|
||||
"swatch_guid": "Zljmtj5WqUaRvB3XQTgJXg",
|
||||
"color": "White",
|
||||
"item_name": "(Hat_QueenCrown)",
|
||||
"item_guid": "9d395a84-4342-4b1c-940c-213ec2eb56f9",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Jazzercise_Black_Swatch",
|
||||
"swatch_guid": "3b2cfc85-4e2a-4e0d-b738-c296ae8692f8",
|
||||
"color": "Black",
|
||||
"item_name": "(Hair_Jazzercise)",
|
||||
"item_guid": "49397e16-1027-4286-9bc4-b59eae565ff0",
|
||||
"item_outfit_type": 2,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Jazzercise_Yellow_Swatch",
|
||||
"swatch_guid": "78eb0969-f246-4cac-acd6-295df7c092e4",
|
||||
"color": "Yellow",
|
||||
"item_name": "(Hair_Jazzercise)",
|
||||
"item_guid": "49397e16-1027-4286-9bc4-b59eae565ff0",
|
||||
"item_outfit_type": 2,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "FieldHockey_Blue_Swatch",
|
||||
"swatch_guid": "7b0d6661-e856-4ec1-ab90-d89c28a70826",
|
||||
"color": "Blue",
|
||||
"item_name": "(FieldHockey)",
|
||||
"item_guid": "a986ff33-9e16-4219-8ebb-2e7b4c772ca7",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": "1fede91a-434e-49a5-882e-e6db107112a8"
|
||||
},
|
||||
{
|
||||
"swatch_name": "FlowerSwimsuit_Green_Swatch",
|
||||
"swatch_guid": "cf515c87-3c0a-4443-9f63-5ea1bdbaa61a",
|
||||
"color": "Green",
|
||||
"item_name": "(FlowerSwimsuit)",
|
||||
"item_guid": "f41653f9-ae02-443c-aaf4-1c6f4e49035d",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": "3248a3ec-50d1-4c0a-96ae-25eb9d8ed622"
|
||||
},
|
||||
{
|
||||
"swatch_name": "FlowerSwimsuit_Pink_Swatch",
|
||||
"swatch_guid": "27680277-aec1-41be-a476-9f51cf775580",
|
||||
"color": "Pink",
|
||||
"item_name": "(FlowerSwimsuit)",
|
||||
"item_guid": "f41653f9-ae02-443c-aaf4-1c6f4e49035d",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": "3248a3ec-50d1-4c0a-96ae-25eb9d8ed622"
|
||||
},
|
||||
{
|
||||
"swatch_name": "FlowerSwimsuit_Gray_Swatch",
|
||||
"swatch_guid": "5a96ac4d-03c3-4214-9dcb-c2044ff28f2e",
|
||||
"color": "Gray",
|
||||
"item_name": "(FlowerSwimsuit)",
|
||||
"item_guid": "f41653f9-ae02-443c-aaf4-1c6f4e49035d",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": "3248a3ec-50d1-4c0a-96ae-25eb9d8ed622"
|
||||
},
|
||||
{
|
||||
"swatch_name": "Angler_Blue_Swatch",
|
||||
"swatch_guid": "6e0f3af8-297f-4ea7-8f9e-4a1bc57d3e35",
|
||||
"color": "Blue",
|
||||
"item_name": "(Hat_Angler)",
|
||||
"item_guid": "03f8c394-28fa-4087-978b-8d108f0bd969",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Angler_Tan_Swatch",
|
||||
"swatch_guid": "cac27853-e2df-4d77-b3fd-af3bc0813f01",
|
||||
"color": "Tan",
|
||||
"item_name": "(Hat_Angler)",
|
||||
"item_guid": "03f8c394-28fa-4087-978b-8d108f0bd969",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Angler_Gray_Swatch",
|
||||
"swatch_guid": "97938f4c-52b8-4c85-8575-856654666316",
|
||||
"color": "Gray",
|
||||
"item_name": "(Hat_Angler)",
|
||||
"item_guid": "03f8c394-28fa-4087-978b-8d108f0bd969",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Artist_Blue_Swatch",
|
||||
"swatch_guid": "8c94e45c-6605-4b4f-9ba4-2c6c6e557228",
|
||||
"color": "Blue",
|
||||
"item_name": "(Shirt_Artist)",
|
||||
"item_guid": "02077915-57d3-4e26-b4fe-8e0399cbb293",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Artist_Red_Swatch",
|
||||
"swatch_guid": "17b16982-871c-476a-860f-f6953c89ee8c",
|
||||
"color": "Red",
|
||||
"item_name": "(Shirt_Artist)",
|
||||
"item_guid": "02077915-57d3-4e26-b4fe-8e0399cbb293",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "HockeyShirt_Red_Swatch",
|
||||
"swatch_guid": "b1ea158d-1663-4db1-bb09-9847f6e9d1e6",
|
||||
"color": "Red",
|
||||
"item_name": "(HockeyShirt)",
|
||||
"item_guid": "d6b0a1e7-e918-43e5-8191-3a8d9d01df7c",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": "e5635772-4e84-4b30-b77f-4a1196cb599b"
|
||||
},
|
||||
{
|
||||
"swatch_name": "HockeyShirt_Teal_Swatch",
|
||||
"swatch_guid": "fcbdfbfd-254a-4538-b119-43e23404b8b5",
|
||||
"color": "Teal",
|
||||
"item_name": "(HockeyShirt)",
|
||||
"item_guid": "d6b0a1e7-e918-43e5-8191-3a8d9d01df7c",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": "e5635772-4e84-4b30-b77f-4a1196cb599b"
|
||||
},
|
||||
{
|
||||
"swatch_name": "HockeyShirt_Purple_Swatch",
|
||||
"swatch_guid": "d5efaf80-7f34-4c9a-bc3a-b80b1ac70ace",
|
||||
"color": "Purple",
|
||||
"item_name": "(HockeyShirt)",
|
||||
"item_guid": "d6b0a1e7-e918-43e5-8191-3a8d9d01df7c",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": "e5635772-4e84-4b30-b77f-4a1196cb599b"
|
||||
},
|
||||
{
|
||||
"swatch_name": "Hat_SeaCaptain_Contest_Swatch",
|
||||
"swatch_guid": "hhs9GY3XZkWb-8TXODvo6A",
|
||||
"color": "Contest",
|
||||
"item_name": "(Hat_SeaCaptain)",
|
||||
"item_guid": "f5c9743f-e77c-42f2-ba63-9843342cbf8e",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": "a4e51b6b-fdfd-47dc-9d0e-f26f383e03e9"
|
||||
},
|
||||
{
|
||||
"swatch_name": "LaserTagGlove_Orange_Swatch",
|
||||
"swatch_guid": "EC0ttvk6eU2HEMacLAx2Iw",
|
||||
"color": "Orange",
|
||||
"item_name": "(Wrist_LaserTagGlove)",
|
||||
"item_guid": "3044adce-90c0-4f66-81f5-39c4fca86fdf",
|
||||
"item_outfit_type": 200,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "LaserTagGlove_Green_Swatch",
|
||||
"swatch_guid": "mhsglVEtREmElF5wuLw3NQ",
|
||||
"color": "Green",
|
||||
"item_name": "(Wrist_LaserTagGlove)",
|
||||
"item_guid": "3044adce-90c0-4f66-81f5-39c4fca86fdf",
|
||||
"item_outfit_type": 200,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "50sDress_Red_Swatch",
|
||||
"swatch_guid": "Yr0mF1EWzEaIyRMOWFiY6w",
|
||||
"color": "Red",
|
||||
"item_name": "(Shirt_50sDress)",
|
||||
"item_guid": "439d1e24-d67f-4b8a-8fb3-8bf589d5a8ee",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "50sDress_Pink_Swatch",
|
||||
"swatch_guid": "eb3SmJTIh0628LrZUkI4KQ",
|
||||
"color": "Pink",
|
||||
"item_name": "(Shirt_50sDress)",
|
||||
"item_guid": "439d1e24-d67f-4b8a-8fb3-8bf589d5a8ee",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "50sDress_Teal_Swatch",
|
||||
"swatch_guid": "QzjakcO8tUaPeiI5KBLKtg",
|
||||
"color": "Teal",
|
||||
"item_name": "(Shirt_50sDress)",
|
||||
"item_guid": "439d1e24-d67f-4b8a-8fb3-8bf589d5a8ee",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "50sDress_White_Swatch",
|
||||
"swatch_guid": "BLgkgLeS-EyazgPQxGcavg",
|
||||
"color": "White",
|
||||
"item_name": "(Shirt_50sDress)",
|
||||
"item_guid": "439d1e24-d67f-4b8a-8fb3-8bf589d5a8ee",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "50sDress_CandyCane_Swatch",
|
||||
"swatch_guid": "PEGqjoxP6E2yRx_A-HphrQ",
|
||||
"color": "CandyCane",
|
||||
"item_name": "(Shirt_50sDress)",
|
||||
"item_guid": "439d1e24-d67f-4b8a-8fb3-8bf589d5a8ee",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "50sDress_Halloween_Swatch",
|
||||
"swatch_guid": "ZvPidQ57rUS50Qz89ERmLw",
|
||||
"color": "Halloween",
|
||||
"item_name": "(Shirt_50sDress)",
|
||||
"item_guid": "439d1e24-d67f-4b8a-8fb3-8bf589d5a8ee",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "50sDress_Shamrock_Swatch",
|
||||
"swatch_guid": "K17dIz_TRUq5D50NBfLjyw",
|
||||
"color": "Shamrock",
|
||||
"item_name": "(Shirt_50sDress)",
|
||||
"item_guid": "439d1e24-d67f-4b8a-8fb3-8bf589d5a8ee",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "TopHat_White_Swatch",
|
||||
"swatch_guid": "DzgN67HoikexE2rTlZLdYQ",
|
||||
"color": "White",
|
||||
"item_name": "(Hat_TopHat)",
|
||||
"item_guid": "102c625b-b988-4bf8-a2aa-a31ad7029cdc",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Shirt_GraduationGown_Green_Swatch",
|
||||
"swatch_guid": "iZy7RmfAz0603oMO-jD-WA",
|
||||
"color": "Green",
|
||||
"item_name": "(Shirt_GraduationGown)",
|
||||
"item_guid": "U_H976qYRUmg9e2clsAflg",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": "ica0LZyM_kOox8gxW7CaMw"
|
||||
},
|
||||
{
|
||||
"swatch_name": "DrumMajor_Orange_Swatch",
|
||||
"swatch_guid": "82de1ca3-67d6-454d-84fb-0eeece71fcbc",
|
||||
"color": "Orange",
|
||||
"item_name": "(Hat_DrumMajor)",
|
||||
"item_guid": "1a028850-64ee-40ab-b547-ebbcfa1b04b3",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "DrumMajor_Green_Swatch",
|
||||
"swatch_guid": "fe5288bc-0e02-4ea3-b17d-dee0e576979d",
|
||||
"color": "Green",
|
||||
"item_name": "(Hat_DrumMajor)",
|
||||
"item_guid": "1a028850-64ee-40ab-b547-ebbcfa1b04b3",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "DrumMajor_Purple_Swatch",
|
||||
"swatch_guid": "54d3c589-30ba-44c1-a77c-8f9e16eb0b20",
|
||||
"color": "Purple",
|
||||
"item_name": "(Hat_DrumMajor)",
|
||||
"item_guid": "1a028850-64ee-40ab-b547-ebbcfa1b04b3",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Harness_Teal_Swatch",
|
||||
"swatch_guid": "TnEDe1QoMUCUdqPL_7CxTA",
|
||||
"color": "Teal",
|
||||
"item_name": "(Shirt_Harness)",
|
||||
"item_guid": "ca7a3ccb-2bc9-4c93-a6a8-6f22b38526af",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Harness_Black_Swatch",
|
||||
"swatch_guid": "AC3zfm38JEyBZWuXDh4Ukg",
|
||||
"color": "Black",
|
||||
"item_name": "(Shirt_Harness)",
|
||||
"item_guid": "ca7a3ccb-2bc9-4c93-a6a8-6f22b38526af",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Harness_Yellow_Swatch",
|
||||
"swatch_guid": "dyEaPloE8kazWC7Zblv8uQ",
|
||||
"color": "Yellow",
|
||||
"item_name": "(Shirt_Harness)",
|
||||
"item_guid": "ca7a3ccb-2bc9-4c93-a6a8-6f22b38526af",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Harness_Blue_Swatch",
|
||||
"swatch_guid": "RfZNDPUok0WyQEa3Ko08ow",
|
||||
"color": "Blue",
|
||||
"item_name": "(Shirt_Harness)",
|
||||
"item_guid": "ca7a3ccb-2bc9-4c93-a6a8-6f22b38526af",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Harness_Orange_Swatch",
|
||||
"swatch_guid": "sX0ZZDcCUkyFSJISfvq0vg",
|
||||
"color": "Orange",
|
||||
"item_name": "(Shirt_Harness)",
|
||||
"item_guid": "ca7a3ccb-2bc9-4c93-a6a8-6f22b38526af",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Unicorn_Pastel_Swatch",
|
||||
"swatch_guid": "FNe9LkWJMUeC3frYJMyEaQ",
|
||||
"color": "Pastel",
|
||||
"item_name": "(Hat_Unicorn)",
|
||||
"item_guid": "2caHvVQ1vECrPv-YcdxdyA",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Unicorn_Glowing_Swatch",
|
||||
"swatch_guid": "mudt-Z5-5USdnIq-xaDgOw",
|
||||
"color": "Glowing",
|
||||
"item_name": "(Hat_Unicorn)",
|
||||
"item_guid": "2caHvVQ1vECrPv-YcdxdyA",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Countess_Black_Swatch",
|
||||
"swatch_guid": "i5RKLo-RbEqisnGII1wpaQ",
|
||||
"color": "Black",
|
||||
"item_name": "(Shirt_Countess)",
|
||||
"item_guid": "QCtqxbvYOkan79YFugH_Cw",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Countess_Purple_Swatch",
|
||||
"swatch_guid": "IzkFARlv6EenmrfcNkcOuw",
|
||||
"color": "Purple",
|
||||
"item_name": "(Shirt_Countess)",
|
||||
"item_guid": "QCtqxbvYOkan79YFugH_Cw",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Countess_Green_Swatch",
|
||||
"swatch_guid": "LyVf9lnzdku1F4iPBGqk-g",
|
||||
"color": "Green",
|
||||
"item_name": "(Shirt_Countess)",
|
||||
"item_guid": "QCtqxbvYOkan79YFugH_Cw",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "CheerDress_Blue_Swatch",
|
||||
"swatch_guid": "faedf215-289b-40f7-90cc-f5b98517d133",
|
||||
"color": "Blue",
|
||||
"item_name": "(FemaleCheerTorso)",
|
||||
"item_guid": "657efe89-620a-46a2-8b58-cafd855c7cd5",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": "93987d32-7a6e-45df-af56-76f912969ce7"
|
||||
},
|
||||
{
|
||||
"swatch_name": "CheerDress_Red_Swatch",
|
||||
"swatch_guid": "1773d5d8-4714-4721-b30c-97e25d6f2a5a",
|
||||
"color": "Red",
|
||||
"item_name": "Cheerful Dress",
|
||||
"item_guid": "b02053b3-013f-42b0-8881-85f5be2b8cda",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": "93987d32-7a6e-45df-af56-76f912969ce7"
|
||||
},
|
||||
{
|
||||
"swatch_name": "Mobster_Valentine_Swatch",
|
||||
"swatch_guid": "4VkPVbBVLE-eJHilwGMAbQ",
|
||||
"color": "Valentine",
|
||||
"item_name": "(Wrist_Mobster)",
|
||||
"item_guid": "08d56627-4500-4724-8692-a23c96ddb3ec",
|
||||
"item_outfit_type": 200,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Mobster_WhiteHatHacker_Swatch",
|
||||
"swatch_guid": "40283127-2ffc-4989-82f6-29c3381bf9e2",
|
||||
"color": "WhiteHatHacker",
|
||||
"item_name": "(Wrist_Mobster)",
|
||||
"item_guid": "08d56627-4500-4724-8692-a23c96ddb3ec",
|
||||
"item_outfit_type": 200,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Luchador_Red_Swatch",
|
||||
"swatch_guid": "916384ca-e209-42a0-bd64-c64f5a40b56f",
|
||||
"color": "Red",
|
||||
"item_name": "(Hat_Luchador)",
|
||||
"item_guid": "1596c113-aa3a-4f5c-b398-e5c3575548e7",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Luchador_Blue_Swatch",
|
||||
"swatch_guid": "0217fd2e-ff9d-49f7-9bc8-8d0d6b8bf250",
|
||||
"color": "Blue",
|
||||
"item_name": "(Hat_Luchador)",
|
||||
"item_guid": "1596c113-aa3a-4f5c-b398-e5c3575548e7",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "BlueJacket_Mint_Swatch",
|
||||
"swatch_guid": "cd5d7285-202d-42d0-b93f-04245875793e",
|
||||
"color": "Mint",
|
||||
"item_name": "(BlueJacket)",
|
||||
"item_guid": "62ce4109-8dee-4895-bf1b-bfa143db4c7e",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Steampunk_Contest_Swatch",
|
||||
"swatch_guid": "fD5vtKxBWECH54Jj4FbnUg",
|
||||
"color": "Contest",
|
||||
"item_name": "(Shirt_SteamPunk)",
|
||||
"item_guid": "E9VTiIVFPEa-OuQRto0e_Q",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "GoldMedal_Bronze_Swatch",
|
||||
"swatch_guid": "iaDL2im4lkCXUo0NWM-F3g",
|
||||
"color": "Bronze",
|
||||
"item_name": "(GoldMedal)",
|
||||
"item_guid": "bf13fa1c-f991-4aaa-9402-aac109be9562",
|
||||
"item_outfit_type": 100,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "GoldMedal_Silver_Swatch",
|
||||
"swatch_guid": "ERnUPsyT6kuEnIRZF8zPwg",
|
||||
"color": "Silver",
|
||||
"item_name": "(GoldMedal)",
|
||||
"item_guid": "bf13fa1c-f991-4aaa-9402-aac109be9562",
|
||||
"item_outfit_type": 100,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Turtleneck_White_Swatch",
|
||||
"swatch_guid": "Zz4XatKfUEapReRAQHxKKA",
|
||||
"color": "White",
|
||||
"item_name": "(Shirt_Turtleneck)",
|
||||
"item_guid": "7e22a4bd-3e87-4d50-8843-9e2e3cf45285",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Turtleneck_Yellow_Swatch",
|
||||
"swatch_guid": "G4HIPUjekUigiU0-Kr9mdA",
|
||||
"color": "Yellow",
|
||||
"item_name": "(Shirt_Turtleneck)",
|
||||
"item_guid": "7e22a4bd-3e87-4d50-8843-9e2e3cf45285",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Turtleneck_Green_Swatch",
|
||||
"swatch_guid": "Jt0QqNrAp0qzUR_RQoivVg",
|
||||
"color": "Green",
|
||||
"item_name": "(Shirt_Turtleneck)",
|
||||
"item_guid": "7e22a4bd-3e87-4d50-8843-9e2e3cf45285",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Turtleneck_Red_Swatch",
|
||||
"swatch_guid": "lBePHNL9LkyaAjEFyFE8Sw",
|
||||
"color": "Red",
|
||||
"item_name": "(Shirt_Turtleneck)",
|
||||
"item_guid": "7e22a4bd-3e87-4d50-8843-9e2e3cf45285",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Turtleneck_Orange_Swatch",
|
||||
"swatch_guid": "9b9t8_aKH0-gQXMhZycaOA",
|
||||
"color": "Orange",
|
||||
"item_name": "(Shirt_Turtleneck)",
|
||||
"item_guid": "7e22a4bd-3e87-4d50-8843-9e2e3cf45285",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "PB_Trucker_Red_Swatch",
|
||||
"swatch_guid": "lDXambcP60CeY2C8qeGDFw",
|
||||
"color": "Red",
|
||||
"item_name": "(Hat_PB_TruckerHat)",
|
||||
"item_guid": "0c537a84-9095-406f-8c87-1464f3a774ba",
|
||||
"item_outfit_type": 0,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Witch_Contest_Swatch",
|
||||
"swatch_guid": "uTHwo8qd6Ei3Oy4gz_j9Ow",
|
||||
"color": "Contest",
|
||||
"item_name": "(Shirt_Witch)",
|
||||
"item_guid": "7LSm-xCYakmgcAr--Fn-JA",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": ""
|
||||
},
|
||||
{
|
||||
"swatch_name": "Tennis_Pink_Swatch",
|
||||
"swatch_guid": "304e5cf1-5c94-481f-8e49-e6a943e6b300",
|
||||
"color": "Pink",
|
||||
"item_name": "(Shirt_Tennis)",
|
||||
"item_guid": "74b91f2b-d4d3-4e41-8946-b1296ab7a773",
|
||||
"item_outfit_type": 101,
|
||||
"mask_guid": "90e0da8b-1941-4ca8-b7e5-b4e31921873c"
|
||||
}
|
||||
],
|
||||
"unmatched": [
|
||||
"TShirt_SquadGoals_Swatch",
|
||||
"TShirt_HangInThere_Swatch",
|
||||
"TShirt_Orange_Swatch",
|
||||
"ZebraWhite_Swatch",
|
||||
"Winter_Gloves_Tree_Green_Swatch",
|
||||
"Cyber_Trash_Yellow_Swatch",
|
||||
"Cyber_Trash_Black_Swatch",
|
||||
"PoofyDress_Purple_Swatch",
|
||||
"PoofyDress_Orange_Swatch",
|
||||
"CowboyCherry_Swatch",
|
||||
"Mobster_HerringBone_Tan_Swatch",
|
||||
"Laser_Graffiti_Swatch",
|
||||
"Laser_Ham_Swatch",
|
||||
"Shuttershades_Salmon_Swatch",
|
||||
"Shuttershades_Red_Swatch",
|
||||
"Shuttershades_Blue_Swatch",
|
||||
"Shuttershades_Yellow_Swatch",
|
||||
"Countess_Wrist_Purple_Swatch",
|
||||
"Class_Of_2018_Swatch",
|
||||
"FighterPilot_Gloves_Orange_Swatch",
|
||||
"FighterPilot_Gloves_Blue_Swatch",
|
||||
"Aviator_Gloves_Tan_Swatch",
|
||||
"Aviator_Gloves_Black_Swatch",
|
||||
"Plaid_LightBlue_Swatch",
|
||||
"Plaid_Red_Swatch",
|
||||
"Astronaut_Glove_Orange_Swatch",
|
||||
"Fatigue_Swatch",
|
||||
"Wrist_CowboyWhite_Swatch",
|
||||
"Wrist_CowboyCherry_Swatch",
|
||||
"Wrist_CowboyBlack_Swatch",
|
||||
"Wrist_CowboyLight_Swatch",
|
||||
"Wrist_CowboyDark_Swatch",
|
||||
"Winter_Hat_Tree_Swatch",
|
||||
"Winter_Hat_Red_Swatch",
|
||||
"Harness_Hat_Teal_Swatch",
|
||||
"Harness_Hat_Yellow_Swatch",
|
||||
"Harness_Hat_White_Swatch",
|
||||
"Harness_Hat_Orange_Swatch",
|
||||
"Harness_Hat_Black_Swatch",
|
||||
"Sherlock_Torso_Gray_Swatch",
|
||||
"Sherlock_Torso_Black_Swatch",
|
||||
"BowlingShirt_CenterStripe_Burgandy_Swatch",
|
||||
"BowlingShirt_CenterStripe_Black_Swatch",
|
||||
"BowlingShirt_CenterStripe_Yellow_Swatch",
|
||||
"Scuba_Neck_Blue_Swatch",
|
||||
"Scuba_Neck_Contest_Swatch",
|
||||
"Cream_Swatch",
|
||||
"ArtistHat_Red_Swatch",
|
||||
"ArtistHat_Blue_Swatch",
|
||||
"ArcherBlack_Quiver_Swatch",
|
||||
"ArcherBlack_Swatch",
|
||||
"ArcherBlack_Glove_Swatch",
|
||||
"ArcherYellow_Swatch",
|
||||
"ArcherYellow_Glove_Swatch",
|
||||
"ArcherYellow_Quiver_Swatch",
|
||||
"Hat_SeaCaptainDarkDarkGold_Swatch",
|
||||
"Hat_SeaCaptainFushia_Swatch",
|
||||
"Hat_SeaCaptainDarkGold_Swatch",
|
||||
"Hat_SeaCaptainDarkSilver_Swatch",
|
||||
"PolkaBlue_Swatch",
|
||||
"Letterman_Wrist_Red_Swatch",
|
||||
"Letterman_Wrist_Purple_Swatch",
|
||||
"Letterman_Wrist_Green_Swatch",
|
||||
"Letterman_Wrist_Black_Swatch",
|
||||
"Yellow_Swatch",
|
||||
"Windbreaker_Wrist_Yellow_Swatch",
|
||||
"Windbreaker_Wrist_Red_Swatch",
|
||||
"Windbreaker_Wrist_Blue_Swatch",
|
||||
"Windbreaker_Wrist_Salmon_Swatch",
|
||||
"Beekeeper_Shirt_Teal_Swatch",
|
||||
"Beekeeper_Shirt_Lavender_Swatch",
|
||||
"Beekeeper_Shirt_Gold_Swatch",
|
||||
"2D_Contest_Winner_Swatch",
|
||||
"Scarecrow_Hat_Contest_Swatch",
|
||||
"Red_Swatch",
|
||||
"Hat_Baseball_ThreeColor_BlueRed_Swatch",
|
||||
"PirateCaptain_Hat_Black_Swatch",
|
||||
"PirateCaptain_Hat_SRank_Swatch",
|
||||
"PirateCaptain_Hat_Red_Swatch",
|
||||
"RoyalCape_Green_Swatch",
|
||||
"RoyalCape_Blue_Swatch",
|
||||
"RoyalCape_Purple_Swatch",
|
||||
"Grey_Swatch",
|
||||
"BlazerGreyDark_Swatch",
|
||||
"MagicalGirl_Wrist_Red_Swatch",
|
||||
"MagicalGirl_Wrist_Orange_Swatch",
|
||||
"MagicalGirl_Wrist_Green_Swatch",
|
||||
"MagicalGirl_Wrist_Blue_Swatch",
|
||||
"PirateCaptain_Belt_Black_Swatch",
|
||||
"PirateCaptain_Belt_Red_Swatch",
|
||||
"BowlingShirt_Flames_Red_Swatch",
|
||||
"BowlingShirt_Flames_Green_Swatch",
|
||||
"BowlingShirt_Flames_Pink_Swatch",
|
||||
"BowlingShirt_Flames_Blue_Swatch",
|
||||
"RoyalCape_Contest_White_Swatch",
|
||||
"Barber_Torso_Formal_Swatch",
|
||||
"Barber_Torso_Green_Swatch",
|
||||
"Aviator_Goggles_Gray_Swatch",
|
||||
"Aviator_Goggles_Black_Swatch",
|
||||
"Neck_TutorialGown3_Black_Swatch",
|
||||
"SafariTorso_Green_Swatch",
|
||||
"Scallywag_Hat_Blue_Swatch",
|
||||
"Scallywag_Hat_Red_Swatch",
|
||||
"TShirt_Laser_Unicorn_Purple_Swatch",
|
||||
"Astronaut_Helmet_Orange_Swatch",
|
||||
"ArcherGray_Quiver_Swatch",
|
||||
"ArcherGray_Swatch",
|
||||
"ArcherGray_Glove_Swatch",
|
||||
"Hoodie_Skeleton_NoGlow_Swatch",
|
||||
"AnglerHat_Blue_Swatch",
|
||||
"AnglerHat_Gray_Swatch",
|
||||
"AnglerHat_Tan_Swatch",
|
||||
"Scuba_eye_Contest_Swatch",
|
||||
"Scuba_eye_Blue_Swatch",
|
||||
"BowlingShirt_OneStripe_Green_Swatch",
|
||||
"BowlingShirt_OneStripe_Pink_Swatch",
|
||||
"BowlingShirt_OneStripe_Blue_Swatch",
|
||||
"Golfer_Shirt_Blue_Swatch",
|
||||
"Golfer_Shirt_Grey_Swatch",
|
||||
"PaintBallHat_Red_Swatch",
|
||||
"PaintBallHat_Green_Swatch",
|
||||
"PaintBallHat_Mustard_Swatch",
|
||||
"Shirt_TutorialGown3_Black_Swatch",
|
||||
"Winter_Scarf_Tree_Green_Swatch",
|
||||
"Blue_Swatch",
|
||||
"Barber_Hat_Formal_Swatch",
|
||||
"Barber_Hat_Green_Swatch",
|
||||
"Vest_HoundsTooth_Black_Swatch",
|
||||
"Neck_VampiteHunter_Opal_Swatch",
|
||||
"Neck_VampiteHunter_Ruby_Swatch",
|
||||
"Neck_VampiteHunter_Amethyst_Swatch",
|
||||
"Neck_VampiteHunter_Diamond_Swatch",
|
||||
"Neck_VampiteHunter_Emerald_Swatch",
|
||||
"Neck_VampiteHunter_Amber_Swatch",
|
||||
"Neck_VampiteHunter_Topaz_Swatch",
|
||||
"Winter_Scarf_Red_Swatch",
|
||||
"Winter_Scarf_Tree_Swatch",
|
||||
"Floatie_Donut_Swatch",
|
||||
"Floatie_Dinosaur_Swatch",
|
||||
"Rainhat_Hat_Red_Swatch",
|
||||
"Winter_Gloves_Red_Swatch",
|
||||
"Winter_Gloves_Tree_Swatch",
|
||||
"Scout_Sash_Blue_Swatch",
|
||||
"Scout_Sash_Brown_Swatch",
|
||||
"Scout_Sash_Red_Swatch",
|
||||
"RoyalLady_Green_Swatch",
|
||||
"RoyalLady_Black_Swatch",
|
||||
"RoyalLady_Burgandy_Swatch",
|
||||
"Mobster_Hat_Brown_Swatch",
|
||||
"Mobster_Hat_Purple_Swatch",
|
||||
"Mobster_Hat_Gray_Swatch",
|
||||
"ElectricianTorso_Gray_Swatch",
|
||||
"ElectricianTorso_Yellow_Swatch",
|
||||
"ElectricianTorso_Green_Swatch",
|
||||
"ElectricianTorso_Beige_Swatch",
|
||||
"White_Swatch",
|
||||
"BeltDress_Green_Swatch",
|
||||
"BeltDress_Black_Swatch",
|
||||
"BeltDress_Yellow_Swatch",
|
||||
"FootballHelmet_Orange_Swatch",
|
||||
"FootballHelmet_Dark_Swatch",
|
||||
"Aviator_Jacket_Tan_Swatch",
|
||||
"Aviator_Jacket_Black_Swatch",
|
||||
"RoyalCrown_Contest_Swatch",
|
||||
"RoyalCrown_White_Swatch",
|
||||
"RoyalCrown_Black_Swatch",
|
||||
"MagicalGirl_Hat_Blue_Swatch",
|
||||
"MagicalGirl_Hat_Green_Swatch",
|
||||
"MagicalGirl_Hat_Red_Swatch",
|
||||
"MagicalGirl_Hat_Orange_Swatch",
|
||||
"TShirt_KO_Skull_Swatch",
|
||||
"RoyalLord_Black_Swatch",
|
||||
"RoyalLord_Burgandy_Swatch",
|
||||
"RoyalLord_Green_Swatch",
|
||||
"Hat_Baseball_Logo_Ramen_Swatch",
|
||||
"Hat_Baseball_Logo_Bucketeers_Swatch",
|
||||
"Hat_Baseball_Logo_Goblins_Swatch",
|
||||
"TShirt_Orange_Video_Contest_Generic_Swatch",
|
||||
"TShirt_Scifi_Face_BLue_Swatch",
|
||||
"TShirt_Scifi_Face_Pink_Swatch",
|
||||
"Green_Swatch",
|
||||
"BlazerDark_Swatch",
|
||||
"Witch_Contest_Hat_Swatch",
|
||||
"Witch_Contest_Wrist_Swatch",
|
||||
"CowboyWhite_Swatch",
|
||||
"Aviator_Hat_Tan_Swatch",
|
||||
"Aviator_Hat_Black_Swatch",
|
||||
"GreenFlower_Swatch",
|
||||
"BowlingShirt_Diamonds_Purple_Swatch",
|
||||
"BowlingShirt_Diamonds_Teal_Swatch",
|
||||
"BowlingShirt_Diamonds_Blue_Swatch",
|
||||
"FormalDress_Black_Swatch",
|
||||
"Birthday01_Swatch",
|
||||
"Scallywag_Eye_SRank_Swatch",
|
||||
"Ranger_Shirt_Green_Swatch",
|
||||
"SciFiVisor_Peach_Swatch",
|
||||
"SciFiVisor_Blue_Swatch",
|
||||
"SciFiVisor_Orange_Swatch",
|
||||
"Shirt_TutorialGown2_Orange_Swatch",
|
||||
"Scifi_Carpet_Swatch",
|
||||
"Teal_Swatch",
|
||||
"Charcoal_Swatch",
|
||||
"Paintball_Red_Swatch",
|
||||
"Paintball_Blue_Swatch",
|
||||
"ArcherTan_Glove_Swatch",
|
||||
"ArcherTan_Quiver_Swatch",
|
||||
"ArcherTan_Swatch",
|
||||
"BicycleJacket_Black_Swatch",
|
||||
"BicycleJacket_DarkBlue_Swatch",
|
||||
"BicycleJacket_Blue_Swatch",
|
||||
"Argyle_Brown_Swatch",
|
||||
"Argyle_Red_Swatch",
|
||||
"BasketballShirt_Purple_Swatch",
|
||||
"BasketballShirt_Blue_Swatch",
|
||||
"Purple_Swatch",
|
||||
"ScoutSkirt_Shirt_Red_Swatch",
|
||||
"LaserTagVisor_Green_Swatch",
|
||||
"LaserTagVisor_Orange_Swatch",
|
||||
"LaserTagVisor_Cyan_Swatch",
|
||||
"TShirt_KO_Skull_Pink_Swatch",
|
||||
"CollarShirt_Torso_Red_Swatch",
|
||||
"CollarShirt_Torso_Blue_Swatch",
|
||||
"CollarShirt_Torso_Pink_Swatch",
|
||||
"CollarShirt_Torso_GoldYellow_Swatch",
|
||||
"CollarShirt_Torso_GreenFlower_Swatch",
|
||||
"CollarShirt_Torso_White_Swatch",
|
||||
"Pearls_Neck_Black_Swatch",
|
||||
"MagicalGirl_Neck_Orange_Swatch",
|
||||
"MagicalGirl_Neck_Red_Swatch",
|
||||
"MagicalGirl_Neck_Green_Swatch",
|
||||
"MagicalGirl_Neck_Blue_Swatch",
|
||||
"Cyber_Junk_City_Swatch",
|
||||
"Firefighter_Hat_Yellow_Swatch",
|
||||
"Firefighter_Hat_White_Swatch",
|
||||
"Scout_RaccoonHat_Gray_Swatch",
|
||||
"JackfrostWings_Neck_Lilac_Swatch",
|
||||
"CowboyBlack_Swatch",
|
||||
"Torso_SeaCaptainBlueWhite_Swatch",
|
||||
"Torso_SeaCaptainBlueDark2_Swatch",
|
||||
"Torso_SeaCaptainDark_Swatch",
|
||||
"Torso_SeaCaptainWhiteDark_Swatch",
|
||||
"Torso_SeaCaptainBlackDark_Swatch",
|
||||
"Torso_SeaCaptainBlueDark_Swatch",
|
||||
"Torso_SeaCaptainBlue_Swatch",
|
||||
"Astronaut_Torso_Orange_Swatch",
|
||||
"CowboyDark_Swatch",
|
||||
"Denim_Swatch",
|
||||
"FootballPads_Orange_Swatch",
|
||||
"FootballPads_Dark_Swatch",
|
||||
"RoyalLady_Contest_White_Swatch",
|
||||
"WaitressDress_Mustard_Swatch",
|
||||
"WaitressDress_Green_Swatch",
|
||||
"WaitressDress_Red_Swatch",
|
||||
"CollarDress_Pink_Swatch",
|
||||
"CollarDress_LightBlue_Swatch",
|
||||
"Scarecrow_Wrist_Contest_Swatch",
|
||||
"Pink_Swatch",
|
||||
"Mobster_Fashion_Gold_Swatch",
|
||||
"ArcherSRank_Glove_Swatch",
|
||||
"ArcherSRank_Quiver_Swatch",
|
||||
"ArcherSRank_Swatch",
|
||||
"Royal_Swatch",
|
||||
"GoldYellow_Swatch",
|
||||
"Sherlock_Hat_Gray_Swatch",
|
||||
"Sherlock_Hat_Black_Swatch",
|
||||
"Happy_Tree_Purple_Swatch",
|
||||
"Golfer_Glove_Blue_Swatch",
|
||||
"Golfer_Glove_Grey_Swatch",
|
||||
"Steampunk_Femme_Contest_Hat_Swatch",
|
||||
"TShirt_RECS_Logo_Blue_Swatch",
|
||||
"TShirt_RECS_Logo_Green_Swatch",
|
||||
"Scout_Shirt_Blue_Swatch",
|
||||
"DrumMajorGlove_Purple_Swatch",
|
||||
"DrumMajorGlove_Orange_Swatch",
|
||||
"ArcherRed_Glove_Swatch",
|
||||
"ArcherRed_Swatch",
|
||||
"ArcherRed_Quiver_Swatch",
|
||||
"Lacrosse_Stripe_Purple_Swatch",
|
||||
"Winter_Torso_Tree_Swatch",
|
||||
"Winter_Torso_Red_Swatch",
|
||||
"Scuba_Shirt_Contest_Swatch",
|
||||
"Scuba_Shirt_Blue_Swatch",
|
||||
"LightBlue_Swatch",
|
||||
"Winter_Hat_Tree_Green_Swatch",
|
||||
"CowboyLight_Swatch",
|
||||
"Happy_Tree_Swatch",
|
||||
"Winter_Torso_Tree_Green_Swatch",
|
||||
"BlazerMidnightBlue_Swatch",
|
||||
"Scifi_Carpet_TopHat_Swatch",
|
||||
"Rebel_Rose_Swatch",
|
||||
"Mobster_PinStripe_Purple_Swatch",
|
||||
"Soccer_Shirt_Blue_Swatch",
|
||||
"Barber_Wrist_Formal_Swatch",
|
||||
"Steampunk_Femme_Contest_Swatch",
|
||||
"StollDress_Green_Swatch",
|
||||
"StollDress_Blue_Swatch",
|
||||
"BlazerSeaDark_Swatch",
|
||||
"Orange_Swatch",
|
||||
"DrumMajorHat_Green_Swatch",
|
||||
"Golfer_Hat_Blue_Swatch",
|
||||
"Golfer_Hat_Grey_Swatch",
|
||||
"RoyalLord_Contest_White_Swatch",
|
||||
"Black_Swatch",
|
||||
"Jackfrost_Shirt_Lilac_Swatch",
|
||||
"CollarShirt_Torso_Plaid_Red_Swatch",
|
||||
"TShirt_LaserTag_Alpha_Swatch",
|
||||
"Countess_Green_Wrist_Swatch",
|
||||
"Hyper_Noodle_Ramen_Swatch",
|
||||
"Scarecrow_Shirt_Contest_Swatch",
|
||||
"BicycleHelmet_Yellow_Swatch",
|
||||
"Soccer_Glove_Blue_Swatch",
|
||||
"Steampunk_Contest_Hat_Swatch",
|
||||
"Emerald_Syndicate_Swatch",
|
||||
"Neck_TutorialGown2_Orange_Swatch",
|
||||
"Shirt_TutorialGown1_Purple_Swatch",
|
||||
"2D_Contest_Winner_Yellow_Swatch",
|
||||
"BlazerGrey_Swatch",
|
||||
"Stripe3_Swatch",
|
||||
"Ranger_Hat_Green_Swatch"
|
||||
],
|
||||
"ambiguous": [
|
||||
{
|
||||
"prefix": "windbreaker",
|
||||
"candidates": [
|
||||
"52VsI_lKlkSUAOJlfDnyrQ",
|
||||
"AIpF1QUeMUWytpHYBDBAkg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"prefix": "lumberjack",
|
||||
"candidates": [
|
||||
"350c5c1e-318b-4233-a7e5-1f49909d8e65",
|
||||
"61ba3c90-c81e-4deb-bc79-50c0f1fe3e83",
|
||||
"b537c30c-faef-4649-9a1f-be3985936f93"
|
||||
]
|
||||
},
|
||||
{
|
||||
"prefix": "magicalgirl",
|
||||
"candidates": [
|
||||
"eS_or4AnMka9M_bD7YN28g",
|
||||
"hT7nSD7Ts06F_1SNlOMLwg",
|
||||
"MJkDYDH510izAab13ZfXQw",
|
||||
"WuShlrJnHUKuscn8e6Rt2g"
|
||||
]
|
||||
},
|
||||
{
|
||||
"prefix": "wizard",
|
||||
"candidates": [
|
||||
"01689baf-405e-4b38-9f09-b624e03865b8",
|
||||
"22ef1089-d073-4fe8-b038-6f34adf0b85f",
|
||||
"97eae086-cfea-45ff-9b77-1d184256d493"
|
||||
]
|
||||
},
|
||||
{
|
||||
"prefix": "punk",
|
||||
"candidates": [
|
||||
"28374ebc-4050-4ea0-b3b6-41ebe75cedf7",
|
||||
"ce250e13-8137-4f62-9e52-2b1cebe7d0ad",
|
||||
"e4ba395e-f291-4e7b-8193-45f4422f41ce"
|
||||
]
|
||||
},
|
||||
{
|
||||
"prefix": "fighterpilot",
|
||||
"candidates": [
|
||||
"5800d2b5-75b8-442f-8b10-63bd3d73a1b8",
|
||||
"ec836d2a-b1b8-4566-b8eb-123ae2845956",
|
||||
"ff7e6d41-5c27-4516-930c-ad0e9a23cce2"
|
||||
]
|
||||
},
|
||||
{
|
||||
"prefix": "witchhunter",
|
||||
"candidates": [
|
||||
"418db0e0-c7af-40c2-9cac-d461ce41e210",
|
||||
"6d36091e-7083-4e3d-8729-94612602c8cb"
|
||||
]
|
||||
},
|
||||
{
|
||||
"prefix": "smuggler",
|
||||
"candidates": [
|
||||
"25d4c652-1730-4925-925e-31a290a2272a",
|
||||
"3dec4865-cf23-4c19-a460-dd2db80ee851"
|
||||
]
|
||||
},
|
||||
{
|
||||
"prefix": "sodajerk",
|
||||
"candidates": [
|
||||
"iai6P7dDTUq8S4hqQmY1YA",
|
||||
"Wua43ED71UqL71ATtyS0iQ"
|
||||
]
|
||||
},
|
||||
{
|
||||
"prefix": "piratecaptain",
|
||||
"candidates": [
|
||||
"38b38e24-d636-41c6-b80e-a285ae3106dc",
|
||||
"3b00c71f-79c2-4a04-9fc0-a23b4c85562f",
|
||||
"3df394de-9c3e-4141-aba4-12eac4742102",
|
||||
"eceb7d49-be41-4228-86a9-2973d62e7135"
|
||||
]
|
||||
},
|
||||
{
|
||||
"prefix": "truckerjacket",
|
||||
"candidates": [
|
||||
"8b065e2a-b106-4f11-b415-4c47ce87993e",
|
||||
"973d84ee-5b88-475c-b579-a76c34a7c533"
|
||||
]
|
||||
},
|
||||
{
|
||||
"prefix": "scientist",
|
||||
"candidates": [
|
||||
"f17a2f9e-1eab-44e8-b10a-1f53c5d0778c",
|
||||
"fe34adaf-47d3-435b-b2fd-b2fee05fceae"
|
||||
]
|
||||
},
|
||||
{
|
||||
"prefix": "lasertag",
|
||||
"candidates": [
|
||||
"123de433-a005-4994-8a11-d2d84ad66b11",
|
||||
"24d94673-f394-42e6-a3c8-276f8b8aa722"
|
||||
]
|
||||
},
|
||||
{
|
||||
"prefix": "letterman",
|
||||
"candidates": [
|
||||
"2dFMy4zc7ky_Fd5fzfgInw",
|
||||
"C4uuztTiYUe20PACMARksA"
|
||||
]
|
||||
},
|
||||
{
|
||||
"prefix": "deepseadiver",
|
||||
"candidates": [
|
||||
"4fcb5b84-13a9-43e6-9680-72b17874ae53",
|
||||
"8d97303c-5138-4da1-a74d-378da19d11cb",
|
||||
"b1c3ccc8-91d7-434e-b9cc-bd632fffc01b",
|
||||
"c3745cee-d87e-4a23-b6e2-64ebf05c8b11"
|
||||
]
|
||||
},
|
||||
{
|
||||
"prefix": "jazzercise",
|
||||
"candidates": [
|
||||
"49397e16-1027-4286-9bc4-b59eae565ff0",
|
||||
"5f492f8f-ab61-484a-9587-747132b54309"
|
||||
]
|
||||
},
|
||||
{
|
||||
"prefix": "angler",
|
||||
"candidates": [
|
||||
"03f8c394-28fa-4087-978b-8d108f0bd969",
|
||||
"b1bfe0b4-1ff6-420f-acfc-2331d34246dc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"prefix": "drummajor",
|
||||
"candidates": [
|
||||
"1a028850-64ee-40ab-b547-ebbcfa1b04b3",
|
||||
"a6f1825e-1647-4d06-85d7-ac2d139612c0"
|
||||
]
|
||||
},
|
||||
{
|
||||
"prefix": "countess",
|
||||
"candidates": [
|
||||
"QCtqxbvYOkan79YFugH_Cw",
|
||||
"t9co2516nkuJO4LIJA1bJA"
|
||||
]
|
||||
},
|
||||
{
|
||||
"prefix": "mobster",
|
||||
"candidates": [
|
||||
"08d56627-4500-4724-8692-a23c96ddb3ec",
|
||||
"4308da04-af84-40bb-845a-7a9e1a2726ec",
|
||||
"76369aef-aeda-46d2-996a-cd00594d0543"
|
||||
]
|
||||
},
|
||||
{
|
||||
"prefix": "steampunk",
|
||||
"candidates": [
|
||||
"E9VTiIVFPEa-OuQRto0e_Q",
|
||||
"gwLiwmqBIk6glFxvaTzxeA",
|
||||
"qxovV6Vym0ufL2cTCyKjOQ",
|
||||
"sOREgAGs-06CeGGsG-WIkw"
|
||||
]
|
||||
},
|
||||
{
|
||||
"prefix": "witch",
|
||||
"candidates": [
|
||||
"7LSm-xCYakmgcAr--Fn-JA",
|
||||
"s6mUIqiPCk6e57UYCx3SZA",
|
||||
"wy2cfgb8mUqjMrIOwHH2ew"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 291 KiB |
|
After Width: | Height: | Size: 312 KiB |
|
After Width: | Height: | Size: 312 KiB |
|
After Width: | Height: | Size: 329 KiB |
|
After Width: | Height: | Size: 2.8 MiB |
|
After Width: | Height: | Size: 341 KiB |
|
After Width: | Height: | Size: 255 KiB |
|
After Width: | Height: | Size: 267 KiB |
|
After Width: | Height: | Size: 274 KiB |
|
After Width: | Height: | Size: 260 KiB |
|
After Width: | Height: | Size: 3.1 MiB |
|
After Width: | Height: | Size: 313 KiB |
|
After Width: | Height: | Size: 312 KiB |
|
After Width: | Height: | Size: 303 KiB |
|
After Width: | Height: | Size: 275 KiB |
|
After Width: | Height: | Size: 224 KiB |
|
After Width: | Height: | Size: 293 KiB |
|
After Width: | Height: | Size: 311 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 18 KiB |
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"3DCharades": "aj7w8q5nrfyt2ssfoovawtz4l.png",
|
||||
"BowlingAlley": "8gwqibu0anm4j0rw54xo2y0yd.png",
|
||||
"CrimsonCauldron": "ae6yh8p6y8p3cuyqkc4l8wi4z.png",
|
||||
"DiscGolfLake": "86s8y4ihyhx7n9ac41gwahwze.png",
|
||||
"DiscGolfPropulsion": "6wvnxmrmsw98wsttajp0nreci.png",
|
||||
"Dodgeball": "086ug40lugly2prjest6kw4dz.png",
|
||||
"GoldenTrophy": "1g7pq04z9xseircwla8sf9py5.png",
|
||||
"IsleOfLostSkulls": "3v6ak7k2ljui4ubj0xh21sjys.png",
|
||||
"LaserTag": "4xy3n0voagf6t9bbfnxft1txt.png",
|
||||
"Paddleball": "61qgagldqpy5opgpbrbg5wxvo.png",
|
||||
"Paintball": "d1es44q1u6hlhykxpy8uq0lci.png",
|
||||
"Park": "4o5lschc01nani8xeywao622n.png",
|
||||
"RecCenter": "50xrbhogfdae0mcgzfkomlghu.png",
|
||||
"RecRoyaleSolos": "8ners1eg89dy974ixbim40sky.png",
|
||||
"RecRoyaleSquads": "0c1qdk77fbl8c5slphl3k1t8e.png",
|
||||
"Soccer": "apo2sd115tuwueyoprp8jhx7b.png",
|
||||
"StuntRunner": "8j4f516axpnpjgnj342t85vkd.png",
|
||||
"TheRiseofJumbotron": "8x6qaj4nlbudf1412tupxkq9n.png"
|
||||
}
|
||||
@@ -0,0 +1,584 @@
|
||||
[
|
||||
{
|
||||
"Name": "AR Room",
|
||||
"ReplicationId": "bf268f5f-b55b-41af-8628-32fa4b5d70b6",
|
||||
"SceneName": "AR_room",
|
||||
"foundAt": "0x06515e64"
|
||||
},
|
||||
{
|
||||
"Name": "Animation Recording Studio",
|
||||
"ReplicationId": "a95c349c-0f96-4c2d-a4c8-4969ffa8ea44",
|
||||
"SceneName": "AnimationRecordingStudio",
|
||||
"foundAt": "0x065158ac"
|
||||
},
|
||||
{
|
||||
"Name": "AnimationRecordingStudio",
|
||||
"ReplicationId": "3c6fd16c-43c7-4c0e-bfd9-f90eaf077ba7",
|
||||
"SceneName": "Record Animations",
|
||||
"foundAt": "0x06519064"
|
||||
},
|
||||
{
|
||||
"Name": "Art Testing",
|
||||
"ReplicationId": "42699ed2-0c1b-4f3d-93a2-ce01dfce7a79",
|
||||
"SceneName": "ArtTesting",
|
||||
"foundAt": "0x065150a8"
|
||||
},
|
||||
{
|
||||
"Name": "ArtTesting",
|
||||
"ReplicationId": "cc338cd1-9883-0c14-99b3-ab069a360ee3",
|
||||
"SceneName": "bla",
|
||||
"foundAt": "0x06517f04"
|
||||
},
|
||||
{
|
||||
"Name": "Bowling Alley",
|
||||
"ReplicationId": "ae929543-9a07-41d5-8ee9-dbbee8c36800",
|
||||
"SceneName": "BowlingAlley",
|
||||
"foundAt": "0x06515828"
|
||||
},
|
||||
{
|
||||
"Name": "Calibration",
|
||||
"ReplicationId": "30040e05-b7b9-9f44-eb08-b9f154d2ecfc",
|
||||
"SceneName": "PSVR room calibration",
|
||||
"foundAt": "0x06515fe8"
|
||||
},
|
||||
{
|
||||
"Name": "Charades",
|
||||
"ReplicationId": "4078dfed-24bb-4db7-863f-578ba48d726b",
|
||||
"SceneName": "charades",
|
||||
"foundAt": "0x06514438"
|
||||
},
|
||||
{
|
||||
"Name": "Clear Cut",
|
||||
"ReplicationId": "380d18b5-de9c-49f3-80f7-f4a95c1de161",
|
||||
"SceneName": "Paintball_ClearCut",
|
||||
"foundAt": "0x065148ac"
|
||||
},
|
||||
{
|
||||
"Name": "Clearcut",
|
||||
"ReplicationId": "28363a22-f0bb-4e46-8346-d76e8ac634f7",
|
||||
"SceneName": "380d18b5-de9c-49f3-80f7-f4a95c1de161",
|
||||
"foundAt": "0x06516ae0"
|
||||
},
|
||||
{
|
||||
"Name": "Clearcut",
|
||||
"ReplicationId": "1636a319-9826-bfc4-18f8-ee1b1be6f806",
|
||||
"SceneName": "380d18b5-de9c-49f3-80f7-f4a95c1de161",
|
||||
"foundAt": "0x06516e78"
|
||||
},
|
||||
{
|
||||
"Name": "Crescendo of the Blood Moon",
|
||||
"ReplicationId": "49cb8993-a956-43e2-86f4-1318f279b22a",
|
||||
"SceneName": "Quest_Dracula1_additive",
|
||||
"foundAt": "0x065155e4"
|
||||
},
|
||||
{
|
||||
"Name": "Curse of the Crimson Cauldron",
|
||||
"ReplicationId": "949fa41f-4347-45c0-b7ac-489129174045",
|
||||
"SceneName": "Quest_Goblin2_additive",
|
||||
"foundAt": "0x06514cd4"
|
||||
},
|
||||
{
|
||||
"Name": "CyberJunk City",
|
||||
"ReplicationId": "9d6456ce-6264-48b4-808d-2d96b3d91038",
|
||||
"SceneName": "Arena_Cyberjunk_City",
|
||||
"foundAt": "0x0651537c"
|
||||
},
|
||||
{
|
||||
"Name": "CyberJunkCity",
|
||||
"ReplicationId": "333f409d-f9ad-46c9-b6fb-b0bbd30cb0b2",
|
||||
"SceneName": "9d6456ce-6264-48b4-808d-2d96b3d91038",
|
||||
"foundAt": "0x065176a0"
|
||||
},
|
||||
{
|
||||
"Name": "Dodgeball",
|
||||
"ReplicationId": "3d474b26-26f7-45e9-9a36-9b02847d5e6f",
|
||||
"SceneName": "dodgeball",
|
||||
"foundAt": "0x065145ac"
|
||||
},
|
||||
{
|
||||
"Name": "Dorm Room",
|
||||
"ReplicationId": "76d98498-60a1-430c-ab76-b54a29b7a163",
|
||||
"SceneName": "dormroom2",
|
||||
"foundAt": "0x06514338"
|
||||
},
|
||||
{
|
||||
"Name": "DormRoom",
|
||||
"ReplicationId": "68251132-5662-5c34-08b1-4a830a27955b",
|
||||
"SceneName": "Your private room",
|
||||
"foundAt": "0x065160dc"
|
||||
},
|
||||
{
|
||||
"Name": "Drive-in",
|
||||
"ReplicationId": "dc185520-0fa2-46d5-bc27-a613c6679c7c",
|
||||
"SceneName": "65ddbb48-5a01-4e3e-972d-e5c7419e2bc3",
|
||||
"foundAt": "0x06516bd8"
|
||||
},
|
||||
{
|
||||
"Name": "DriveIn",
|
||||
"ReplicationId": "65ddbb48-5a01-4e3e-972d-e5c7419e2bc3",
|
||||
"SceneName": "DriveIn",
|
||||
"foundAt": "0x06515f6c"
|
||||
},
|
||||
{
|
||||
"Name": "Frontier Solos",
|
||||
"ReplicationId": "b010171f-4875-4e89-baba-61e878cd41e1",
|
||||
"SceneName": "RecRoyale_Frontier",
|
||||
"foundAt": "0x06515558"
|
||||
},
|
||||
{
|
||||
"Name": "Frontier Squads",
|
||||
"ReplicationId": "253fa009-6e65-4c90-91a1-7137a56a267f",
|
||||
"SceneName": "RecRoyale_Frontier",
|
||||
"foundAt": "0x065154cc"
|
||||
},
|
||||
{
|
||||
"Name": "Hangar",
|
||||
"ReplicationId": "8f8fcaf8-7b13-e114-880c-72ee8c9fcb78",
|
||||
"SceneName": "239e676c-f12f-489f-bf3a-d4c383d692c3",
|
||||
"foundAt": "0x06517624"
|
||||
},
|
||||
{
|
||||
"Name": "Home",
|
||||
"ReplicationId": "fe66923e-4034-4ec4-4bca-11a973bf5515",
|
||||
"SceneName": "f5fbd9c9-e853-4036-9d48-5f68e861af04",
|
||||
"foundAt": "0x06516064"
|
||||
},
|
||||
{
|
||||
"Name": "Home",
|
||||
"ReplicationId": "92084aee-1f44-a3b4-18f1-375601606506",
|
||||
"SceneName": "76d98498-60a1-430c-ab76-b54a29b7a163",
|
||||
"foundAt": "0x06516150"
|
||||
},
|
||||
{
|
||||
"Name": "Home",
|
||||
"ReplicationId": "6016e455-652d-54d4-3838-ecc6c9aa4ca8",
|
||||
"SceneName": "cbad71af-0831-44d8-b8ef-69edafa841f6",
|
||||
"foundAt": "0x06516268"
|
||||
},
|
||||
{
|
||||
"Name": "Home",
|
||||
"ReplicationId": "b7150f3d-393e-ac74-2801-8a834b13e2bc",
|
||||
"SceneName": "4078dfed-24bb-4db7-863f-578ba48d726b",
|
||||
"foundAt": "0x06516390"
|
||||
},
|
||||
{
|
||||
"Name": "Home",
|
||||
"ReplicationId": "6cd09971-c9fb-8e44-9b7f-3cb9ff5f6bd0",
|
||||
"SceneName": "f6f7256c-e438-4299-b99e-d20bef8cf7e0",
|
||||
"foundAt": "0x065164c4"
|
||||
},
|
||||
{
|
||||
"Name": "Home",
|
||||
"ReplicationId": "e687ebed-6502-ad24-2ae1-d4a1db441d34",
|
||||
"SceneName": "d9378c9f-80bc-46fb-ad1e-1bed8a674f55",
|
||||
"foundAt": "0x065165fc"
|
||||
},
|
||||
{
|
||||
"Name": "Home",
|
||||
"ReplicationId": "27dd5218-dbea-b444-9b7c-a64e687aae67",
|
||||
"SceneName": "3d474b26-26f7-45e9-9a36-9b02847d5e6f",
|
||||
"foundAt": "0x06516718"
|
||||
},
|
||||
{
|
||||
"Name": "Home",
|
||||
"ReplicationId": "11512b3c-bf64-acc4-7bf6-139786237328",
|
||||
"SceneName": "d89f74fa-d51e-477a-a425-025a891dd499",
|
||||
"foundAt": "0x06516844"
|
||||
},
|
||||
{
|
||||
"Name": "Home",
|
||||
"ReplicationId": "3518de14-8412-96f4-db0a-41abe0196bbe",
|
||||
"SceneName": "91e16e35-f48f-4700-ab8a-a1b79e50e51b",
|
||||
"foundAt": "0x06517034"
|
||||
},
|
||||
{
|
||||
"Name": "Home",
|
||||
"ReplicationId": "4a6968bf-0283-2d34-ca18-29f1145e1f69",
|
||||
"SceneName": "acc06e66-c2d0-4361-b0cd-46246a4c455c",
|
||||
"foundAt": "0x06517170"
|
||||
},
|
||||
{
|
||||
"Name": "Home",
|
||||
"ReplicationId": "4a169c2f-28b2-e9a4-7ab1-61c9c270b1ab",
|
||||
"SceneName": "949fa41f-4347-45c0-b7ac-489129174045",
|
||||
"foundAt": "0x065172b4"
|
||||
},
|
||||
{
|
||||
"Name": "Home",
|
||||
"ReplicationId": "02d23e1d-4c1a-15b4-aba5-98458d750417",
|
||||
"SceneName": "7e01cfe0-820a-406f-b1b3-0a5bf575235c",
|
||||
"foundAt": "0x065173f4"
|
||||
},
|
||||
{
|
||||
"Name": "Home",
|
||||
"ReplicationId": "9a4b4871-28dc-4b24-8b8f-e0914db002eb",
|
||||
"SceneName": "6d5eea4b-f069-4ed0-9916-0e2f07df0d03",
|
||||
"foundAt": "0x06517520"
|
||||
},
|
||||
{
|
||||
"Name": "Home",
|
||||
"ReplicationId": "d59f7e16-9f27-6924-a899-2739bfc056fe",
|
||||
"SceneName": "9d6456ce-6264-48b4-808d-2d96b3d91038",
|
||||
"foundAt": "0x065177e0"
|
||||
},
|
||||
{
|
||||
"Name": "Home",
|
||||
"ReplicationId": "1d282c2d-6edc-4910-afb3-48fbb9ad74a4",
|
||||
"SceneName": "253fa009-6e65-4c90-91a1-7137a56a267f",
|
||||
"foundAt": "0x0651790c"
|
||||
},
|
||||
{
|
||||
"Name": "Home",
|
||||
"ReplicationId": "85b43509-77f7-3884-3a6b-9a4e737d6d11",
|
||||
"SceneName": "b010171f-4875-4e89-baba-61e878cd41e1",
|
||||
"foundAt": "0x06517a28"
|
||||
},
|
||||
{
|
||||
"Name": "Home",
|
||||
"ReplicationId": "c9e928de-ed1f-d564-38af-9bf525ac0feb",
|
||||
"SceneName": "a067557f-ca32-43e6-b6e5-daaec60b4f5a",
|
||||
"foundAt": "0x06517b48"
|
||||
},
|
||||
{
|
||||
"Name": "Home",
|
||||
"ReplicationId": "b55204c1-9a48-6ea4-fbd0-69fb125a68cf",
|
||||
"SceneName": "9932f88f-3929-43a0-a012-a40b5128e346",
|
||||
"foundAt": "0x06517c64"
|
||||
},
|
||||
{
|
||||
"Name": "Home",
|
||||
"ReplicationId": "aa889faf-91c8-b7d4-5945-ab7e714f7efa",
|
||||
"SceneName": "a75f7547-79eb-47c6-8986-6767abcb4f92",
|
||||
"foundAt": "0x06517d7c"
|
||||
},
|
||||
{
|
||||
"Name": "Home",
|
||||
"ReplicationId": "570a59bf-b4e2-6db4-ca9a-42329563dd30",
|
||||
"SceneName": "0a864c86-5a71-4e18-8041-8124e4dc9d98",
|
||||
"foundAt": "0x06517e8c"
|
||||
},
|
||||
{
|
||||
"Name": "Home",
|
||||
"ReplicationId": "33bdd61b-bd99-abe4-6943-3032c741f5e8",
|
||||
"SceneName": "42699ed2-0c1b-4f3d-93a2-ce01dfce7a79",
|
||||
"foundAt": "0x06517f6c"
|
||||
},
|
||||
{
|
||||
"Name": "Home",
|
||||
"ReplicationId": "dc445d24-01cf-43f9-a7c4-33f432514735",
|
||||
"SceneName": "e122fe98-e7db-49e8-a1b1-105424b6e1f0",
|
||||
"foundAt": "0x06518088"
|
||||
},
|
||||
{
|
||||
"Name": "Home",
|
||||
"ReplicationId": "daaa8763-868d-4081-9e8d-e931c111cc90",
|
||||
"SceneName": "a785267d-c579-42ea-be43-fec1992d1ca7",
|
||||
"foundAt": "0x06518198"
|
||||
},
|
||||
{
|
||||
"Name": "Home",
|
||||
"ReplicationId": "f083ff9a-98af-4d8b-b7ff-5b84a66367d5",
|
||||
"SceneName": "ff4c6427-7079-4f59-b22a-69b089420827",
|
||||
"foundAt": "0x065182c0"
|
||||
},
|
||||
{
|
||||
"Name": "Home",
|
||||
"ReplicationId": "c5f45037-8c60-494d-ad62-3e5168560b36",
|
||||
"SceneName": "380d18b5-de9c-49f3-80f7-f4a95c1de161",
|
||||
"foundAt": "0x065183e8"
|
||||
},
|
||||
{
|
||||
"Name": "Home",
|
||||
"ReplicationId": "d336999f-9db0-42fc-8af5-592e9043102f",
|
||||
"SceneName": "58763055-2dfb-4814-80b8-16fac5c85709",
|
||||
"foundAt": "0x06518508"
|
||||
},
|
||||
{
|
||||
"Name": "Home",
|
||||
"ReplicationId": "28253579-64cb-421b-988b-9fea890fd129",
|
||||
"SceneName": "f6f7256c-e438-4299-b99e-d20bef8cf7e0",
|
||||
"foundAt": "0x06518608"
|
||||
},
|
||||
{
|
||||
"Name": "Home",
|
||||
"ReplicationId": "cd82c0aa-5dbc-4db3-ade3-30576d3bc473",
|
||||
"SceneName": "d9378c9f-80bc-46fb-ad1e-1bed8a674f55",
|
||||
"foundAt": "0x06518748"
|
||||
},
|
||||
{
|
||||
"Name": "Home",
|
||||
"ReplicationId": "8cecdc5b-d17b-4eba-9dd3-7b0ca54d3fd2",
|
||||
"SceneName": "3d474b26-26f7-45e9-9a36-9b02847d5e6f",
|
||||
"foundAt": "0x0651884c"
|
||||
},
|
||||
{
|
||||
"Name": "Home",
|
||||
"ReplicationId": "b4f8632d-ae8b-4c3d-a433-0687131f8507",
|
||||
"SceneName": "6d5eea4b-f069-4ed0-9916-0e2f07df0d03",
|
||||
"foundAt": "0x06518958"
|
||||
},
|
||||
{
|
||||
"Name": "Home",
|
||||
"ReplicationId": "26330026-ebc7-4d44-8c85-4f38d2ad30a1",
|
||||
"SceneName": "239e676c-f12f-489f-bf3a-d4c383d692c3",
|
||||
"foundAt": "0x06518a60"
|
||||
},
|
||||
{
|
||||
"Name": "Home",
|
||||
"ReplicationId": "6e0edd15-b904-f074-3b1f-cec488eba1a3",
|
||||
"SceneName": "9d6456ce-6264-48b4-808d-2d96b3d91038",
|
||||
"foundAt": "0x06518b80"
|
||||
},
|
||||
{
|
||||
"Name": "Home",
|
||||
"ReplicationId": "bcbda991-93e7-4d05-b2e2-7c9512e4d4f2",
|
||||
"SceneName": "3d474b26-26f7-45e9-9a36-9b02847d5e6f",
|
||||
"foundAt": "0x06518c9c"
|
||||
},
|
||||
{
|
||||
"Name": "Home",
|
||||
"ReplicationId": "66726423-6e03-4548-9990-f1b10e8c5c2e",
|
||||
"SceneName": "49cb8993-a956-43e2-86f4-1318f279b22a",
|
||||
"foundAt": "0x06518dd4"
|
||||
},
|
||||
{
|
||||
"Name": "Home",
|
||||
"ReplicationId": "d61f36d3-f702-4002-a065-e1b6a59d4036",
|
||||
"SceneName": "ae929543-9a07-41d5-8ee9-dbbee8c36800",
|
||||
"foundAt": "0x06518ee0"
|
||||
},
|
||||
{
|
||||
"Name": "Home",
|
||||
"ReplicationId": "b492f0d4-5f72-4429-9ea5-decf369e7aa7",
|
||||
"SceneName": "ae929543-9a07-41d5-8ee9-dbbee8c36800",
|
||||
"foundAt": "0x06518fec"
|
||||
},
|
||||
{
|
||||
"Name": "Home",
|
||||
"ReplicationId": "8fe5818c-d466-4ffb-b502-f7d5f67efc7a",
|
||||
"SceneName": "a95c349c-0f96-4c2d-a4c8-4969ffa8ea44",
|
||||
"foundAt": "0x065190e8"
|
||||
},
|
||||
{
|
||||
"Name": "Home",
|
||||
"ReplicationId": "57ec15a2-34b5-42d4-a5d8-ddad6888e0e3",
|
||||
"SceneName": "882e9b96-7115-4b03-86f6-c0c9d8e22e00",
|
||||
"foundAt": "0x065193d4"
|
||||
},
|
||||
{
|
||||
"Name": "Home",
|
||||
"ReplicationId": "c300e175-8420-44fd-9966-c422275993f1",
|
||||
"SceneName": "cf61556d-68fd-4288-9ae5-7a512621e569",
|
||||
"foundAt": "0x065194bc"
|
||||
},
|
||||
{
|
||||
"Name": "Home",
|
||||
"ReplicationId": "9fc2886b-3508-4191-9389-ccd0a6ee8a29",
|
||||
"SceneName": "bf268f5f-b55b-41af-8628-32fa4b5d70b6",
|
||||
"foundAt": "0x065195a4"
|
||||
},
|
||||
{
|
||||
"Name": "Homestead",
|
||||
"ReplicationId": "f6709dc2-af81-46fc-88ba-f88f6c5035aa",
|
||||
"SceneName": "a785267d-c579-42ea-be43-fec1992d1ca7",
|
||||
"foundAt": "0x065169e4"
|
||||
},
|
||||
{
|
||||
"Name": "Homestead",
|
||||
"ReplicationId": "d686129f-fdf7-1954-a9f6-f0a80d1af234",
|
||||
"SceneName": "a785267d-c579-42ea-be43-fec1992d1ca7",
|
||||
"foundAt": "0x06516d7c"
|
||||
},
|
||||
{
|
||||
"Name": "Homestead",
|
||||
"ReplicationId": "a785267d-c579-42ea-be43-fec1992d1ca7",
|
||||
"SceneName": "paintball2_open",
|
||||
"foundAt": "0x065147a8"
|
||||
},
|
||||
{
|
||||
"Name": "Lake",
|
||||
"ReplicationId": "f6f7256c-e438-4299-b99e-d20bef8cf7e0",
|
||||
"SceneName": "discgolf",
|
||||
"foundAt": "0x065144b0"
|
||||
},
|
||||
{
|
||||
"Name": "Maker Room",
|
||||
"ReplicationId": "a75f7547-79eb-47c6-8986-6767abcb4f92",
|
||||
"SceneName": "Basement",
|
||||
"foundAt": "0x06515450"
|
||||
},
|
||||
{
|
||||
"Name": "PSVR Room Calibration",
|
||||
"ReplicationId": "f5fbd9c9-e853-4036-9d48-5f68e861af04",
|
||||
"SceneName": "room_calibration",
|
||||
"foundAt": "0x065151b0"
|
||||
},
|
||||
{
|
||||
"Name": "Paddleball",
|
||||
"ReplicationId": "d89f74fa-d51e-477a-a425-025a891dd499",
|
||||
"SceneName": "paddleball",
|
||||
"foundAt": "0x065146ac"
|
||||
},
|
||||
{
|
||||
"Name": "Park",
|
||||
"ReplicationId": "0a864c86-5a71-4e18-8041-8124e4dc9d98",
|
||||
"SceneName": "Park",
|
||||
"foundAt": "0x06515240"
|
||||
},
|
||||
{
|
||||
"Name": "Performance Hall",
|
||||
"ReplicationId": "9932f88f-3929-43a0-a012-a40b5128e346",
|
||||
"SceneName": "PerformanceHall",
|
||||
"foundAt": "0x06515128"
|
||||
},
|
||||
{
|
||||
"Name": "PhotonServerSettings",
|
||||
"ReplicationId": "<your-photon-realtime-app-id>",
|
||||
"SceneName": "1917ff4a-b7ad-4ad6-9ea2-9642bc174b70",
|
||||
"foundAt": "0x064fa5f4"
|
||||
},
|
||||
{
|
||||
"Name": "Propulsion",
|
||||
"ReplicationId": "d9378c9f-80bc-46fb-ad1e-1bed8a674f55",
|
||||
"SceneName": "Discgolf_Propulsion",
|
||||
"foundAt": "0x06514524"
|
||||
},
|
||||
{
|
||||
"Name": "Quarry",
|
||||
"ReplicationId": "1c549cfb-455b-4f5e-b15e-467702a71240",
|
||||
"SceneName": "ff4c6427-7079-4f59-b22a-69b089420827",
|
||||
"foundAt": "0x06516a64"
|
||||
},
|
||||
{
|
||||
"Name": "Quarry",
|
||||
"ReplicationId": "a5ba53f2-a7cf-d3b4-8836-80fa08e02a27",
|
||||
"SceneName": "ff4c6427-7079-4f59-b22a-69b089420827",
|
||||
"foundAt": "0x06516dfc"
|
||||
},
|
||||
{
|
||||
"Name": "Quarry",
|
||||
"ReplicationId": "ff4c6427-7079-4f59-b22a-69b089420827",
|
||||
"SceneName": "Paintball_Castle",
|
||||
"foundAt": "0x0651482c"
|
||||
},
|
||||
{
|
||||
"Name": "Quest For The Golden Trophy",
|
||||
"ReplicationId": "91e16e35-f48f-4700-ab8a-a1b79e50e51b",
|
||||
"SceneName": "Quest_additive",
|
||||
"foundAt": "0x065149b4"
|
||||
},
|
||||
{
|
||||
"Name": "Rec Center",
|
||||
"ReplicationId": "cbad71af-0831-44d8-b8ef-69edafa841f6",
|
||||
"SceneName": "reccenter",
|
||||
"foundAt": "0x065143b8"
|
||||
},
|
||||
{
|
||||
"Name": "Registration",
|
||||
"ReplicationId": "8719e5b5-4ca5-463c-af8d-30c5e286d6e4",
|
||||
"SceneName": "Registration",
|
||||
"foundAt": "0x0651944c"
|
||||
},
|
||||
{
|
||||
"Name": "Registration",
|
||||
"ReplicationId": "cf61556d-68fd-4288-9ae5-7a512621e569",
|
||||
"SceneName": "registration",
|
||||
"foundAt": "0x06515d54"
|
||||
},
|
||||
{
|
||||
"Name": "River",
|
||||
"ReplicationId": "84545710-2bb4-4867-ad8b-24863a16d1b2",
|
||||
"SceneName": "e122fe98-e7db-49e8-a1b1-105424b6e1f0",
|
||||
"foundAt": "0x06516968"
|
||||
},
|
||||
{
|
||||
"Name": "River",
|
||||
"ReplicationId": "a4d7afc1-ae7a-8e04-1bea-f7d71df384fd",
|
||||
"SceneName": "e122fe98-e7db-49e8-a1b1-105424b6e1f0",
|
||||
"foundAt": "0x06516d00"
|
||||
},
|
||||
{
|
||||
"Name": "River",
|
||||
"ReplicationId": "e122fe98-e7db-49e8-a1b1-105424b6e1f0",
|
||||
"SceneName": "paintball",
|
||||
"foundAt": "0x0651472c"
|
||||
},
|
||||
{
|
||||
"Name": "Soccer",
|
||||
"ReplicationId": "6d5eea4b-f069-4ed0-9916-0e2f07df0d03",
|
||||
"SceneName": "soccer",
|
||||
"foundAt": "0x06515030"
|
||||
},
|
||||
{
|
||||
"Name": "Spillway",
|
||||
"ReplicationId": "7d661e29-f036-4fe9-8e9d-4b919fee638d",
|
||||
"SceneName": "58763055-2dfb-4814-80b8-16fac5c85709",
|
||||
"foundAt": "0x06516b5c"
|
||||
},
|
||||
{
|
||||
"Name": "Spillway",
|
||||
"ReplicationId": "9a5a9875-67bb-f444-e804-0e0296d3c19c",
|
||||
"SceneName": "58763055-2dfb-4814-80b8-16fac5c85709",
|
||||
"foundAt": "0x06516ef4"
|
||||
},
|
||||
{
|
||||
"Name": "Spillway",
|
||||
"ReplicationId": "58763055-2dfb-4814-80b8-16fac5c85709",
|
||||
"SceneName": "Paintball_Dam",
|
||||
"foundAt": "0x06514934"
|
||||
},
|
||||
{
|
||||
"Name": "StuntRunner",
|
||||
"ReplicationId": "f8a71ce1-c989-4e00-9e10-3f04c241f6f3",
|
||||
"SceneName": "b7281665-a715-4051-826b-8e08e69c6172",
|
||||
"foundAt": "0x06519220"
|
||||
},
|
||||
{
|
||||
"Name": "StuntRunner",
|
||||
"ReplicationId": "b7281665-a715-4051-826b-8e08e69c6172",
|
||||
"SceneName": "StuntRunner_Lobby",
|
||||
"foundAt": "0x06515948"
|
||||
},
|
||||
{
|
||||
"Name": "StuntRunner Base Room",
|
||||
"ReplicationId": "882e9b96-7115-4b03-86f6-c0c9d8e22e00",
|
||||
"SceneName": "StuntRunner_Baseroom",
|
||||
"foundAt": "0x06515c30"
|
||||
},
|
||||
{
|
||||
"Name": "StuntRunner The Main Event",
|
||||
"ReplicationId": "3a636bd2-f896-424c-9225-c184522c0d87",
|
||||
"SceneName": "StuntRunner_additive",
|
||||
"foundAt": "0x06515a60"
|
||||
},
|
||||
{
|
||||
"Name": "The Isle of Lost Skulls",
|
||||
"ReplicationId": "7e01cfe0-820a-406f-b1b3-0a5bf575235c",
|
||||
"SceneName": "Quest_Pirate1_additive",
|
||||
"foundAt": "0x06514eac"
|
||||
},
|
||||
{
|
||||
"Name": "The Lounge",
|
||||
"ReplicationId": "a067557f-ca32-43e6-b6e5-daaec60b4f5a",
|
||||
"SceneName": "eventroom",
|
||||
"foundAt": "0x0651462c"
|
||||
},
|
||||
{
|
||||
"Name": "The Rise Of JumboTron",
|
||||
"ReplicationId": "acc06e66-c2d0-4361-b0cd-46246a4c455c",
|
||||
"SceneName": "Quest_Scifi_Additive",
|
||||
"foundAt": "0x06514b20"
|
||||
},
|
||||
{
|
||||
"Name": "TheMainEvent",
|
||||
"ReplicationId": "cacc6e68-644a-448d-b83f-59ea690318ec",
|
||||
"SceneName": "3a636bd2-f896-424c-9225-c184522c0d87",
|
||||
"foundAt": "0x065192a0"
|
||||
},
|
||||
{
|
||||
"Name": "Warehouse",
|
||||
"ReplicationId": "239e676c-f12f-489f-bf3a-d4c383d692c3",
|
||||
"SceneName": "Arena_Hangar3",
|
||||
"foundAt": "0x065152b0"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,106 @@
|
||||
{
|
||||
"rooms": [
|
||||
{
|
||||
"Name": "River",
|
||||
"ReplicationId": "84545710-2bb4-4867-ad8b-24863a16d1b2",
|
||||
"Description": "e122fe98-e7db-49e8-a1b1-105424b6e1f0",
|
||||
"Scenes": [
|
||||
{
|
||||
"Name": "Homestead",
|
||||
"ReplicationId": "f6709dc2-af81-46fc-88ba-f88f6c5035aa",
|
||||
"RoomSceneLocationId": "a785267d-c579-42ea-be43-fec1992d1ca7"
|
||||
},
|
||||
{
|
||||
"Name": "",
|
||||
"ReplicationId": "",
|
||||
"RoomSceneLocationId": "\u0002\u0000\u0000\u0000\u0006\u0000\u0000\u0000"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Clearcut",
|
||||
"ReplicationId": "28363a22-f0bb-4e46-8346-d76e8ac634f7",
|
||||
"Description": "380d18b5-de9c-49f3-80f7-f4a95c1de161",
|
||||
"Scenes": [
|
||||
{
|
||||
"Name": "Spillway",
|
||||
"ReplicationId": "7d661e29-f036-4fe9-8e9d-4b919fee638d",
|
||||
"RoomSceneLocationId": "58763055-2dfb-4814-80b8-16fac5c85709"
|
||||
},
|
||||
{
|
||||
"Name": "",
|
||||
"ReplicationId": "",
|
||||
"RoomSceneLocationId": "\u0002\u0000\u0000\u0000\b\u0000\u0000\u0000"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "a4d7afc1-ae7a-8e04-1bea-f7d71df384fd",
|
||||
"ReplicationId": "e122fe98-e7db-49e8-a1b1-105424b6e1f0",
|
||||
"Description": "",
|
||||
"Scenes": [
|
||||
{
|
||||
"Name": "Homestead",
|
||||
"ReplicationId": "d686129f-fdf7-1954-a9f6-f0a80d1af234",
|
||||
"RoomSceneLocationId": "a785267d-c579-42ea-be43-fec1992d1ca7"
|
||||
},
|
||||
{
|
||||
"Name": "",
|
||||
"ReplicationId": "",
|
||||
"RoomSceneLocationId": "\u0002\u0000\u0000\u0000\u0006\u0000\u0000\u0000"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "1636a319-9826-bfc4-18f8-ee1b1be6f806",
|
||||
"ReplicationId": "380d18b5-de9c-49f3-80f7-f4a95c1de161",
|
||||
"Description": "",
|
||||
"Scenes": [
|
||||
{
|
||||
"Name": "Spillway",
|
||||
"ReplicationId": "9a5a9875-67bb-f444-e804-0e0296d3c19c",
|
||||
"RoomSceneLocationId": "58763055-2dfb-4814-80b8-16fac5c85709"
|
||||
},
|
||||
{
|
||||
"Name": "",
|
||||
"ReplicationId": "",
|
||||
"RoomSceneLocationId": "\u0002\u0000\u0000\u0000\f\u0000\u0000\u0000"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Hangar",
|
||||
"ReplicationId": "8f8fcaf8-7b13-e114-880c-72ee8c9fcb78",
|
||||
"Description": "239e676c-f12f-489f-bf3a-d4c383d692c3",
|
||||
"Scenes": [
|
||||
{
|
||||
"Name": "CyberJunkCity",
|
||||
"ReplicationId": "333f409d-f9ad-46c9-b6fb-b0bbd30cb0b2",
|
||||
"RoomSceneLocationId": "9d6456ce-6264-48b4-808d-2d96b3d91038"
|
||||
},
|
||||
{
|
||||
"Name": "",
|
||||
"ReplicationId": "",
|
||||
"RoomSceneLocationId": "\u0002\u0000\u0000\u0000\u0011\u0000\u0000\u0000"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "StuntRunner",
|
||||
"ReplicationId": "f8a71ce1-c989-4e00-9e10-3f04c241f6f3",
|
||||
"Description": "b7281665-a715-4051-826b-8e08e69c6172",
|
||||
"Scenes": [
|
||||
{
|
||||
"Name": "TheMainEvent",
|
||||
"ReplicationId": "cacc6e68-644a-448d-b83f-59ea690318ec",
|
||||
"RoomSceneLocationId": "3a636bd2-f896-424c-9225-c184522c0d87"
|
||||
},
|
||||
{
|
||||
"Name": "",
|
||||
"ReplicationId": "",
|
||||
"RoomSceneLocationId": "\u0002\u0000\u0000\u0000"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,428 @@
|
||||
# URL coverage — Rec Room 2020 client vs DorkNet server
|
||||
|
||||
Generated: 2026-05-09. Source: client URLs from `Cpp2IL_ISIL` ISIL dump (curated list provided to this report); server routes harvested via grep of `[HttpGet]`/`[HttpPost]`/`[HttpPut]`/`[HttpDelete]`/`[Route]` attributes across `Controllers/**/*.cs` plus the namespace-wildcard fall-throughs in `ApiNamespaceStubsController` and the global `ApiCatchAllController` / `GlobalCatchAllController`.
|
||||
|
||||
## How this matrix is built
|
||||
|
||||
Each client URL is matched against the server's full route table. ASP.NET Core routes resolve "specific wins over wildcard", so a route literally registered as `api/foo/v1/bar` always wins over `api/foo/{*path}`. The `Status` column reflects the route that actually wins:
|
||||
|
||||
- **REAL** — a specific route exists and the body does real work: hits `DorkNetDbContext`, mutates entities, looks up presence, computes results, etc. Round-trips across sessions.
|
||||
- **STUB** — a specific route exists but the body just returns `Ok(new { })`, `Ok(Array.Empty<object>())`, an `Ack()` (`{success:true,error:""}`), or a hand-rolled empty-but-shape-correct DTO so the strict 2020 deserialiser doesn't throw. No persistence; the client thinks it succeeded but nothing is actually stored.
|
||||
- **WILDCARD** — no specific route exists. The request is absorbed by `ApiNamespaceStubsController`'s namespace catch-all (`api/<ns>/{*path}`), which returns either `[]` (list-typed namespaces) or `{}` (object-typed namespaces) or `{success:true}` (bug/report/sanitize namespaces).
|
||||
- **MISSING** — neither a specific route nor a namespace wildcard handles it. Falls through to the very last-resort `GlobalCatchAllController` (`/{*path}`), which logs the URL and returns `200 {}`. From the client's point of view this looks like an empty object response — usually triggers a deserialiser crash on the watch unless the call site happened to be the rare one that tolerates `{}`.
|
||||
|
||||
The `Handler` column points at the controller method (or wildcard route attribute) that wins. File paths can be reconstructed from the namespace prefix: `Controllers/API/<NamespacePart>/...`.
|
||||
|
||||
## Summary
|
||||
|
||||
- Total client URLs (api/*): 156
|
||||
- Total client URLs (non-api goto/heartbeat): 7
|
||||
- REAL: 88
|
||||
- STUB: 67
|
||||
- WILDCARD: 6
|
||||
- MISSING: 2 (both covered by the global `{*path}` returning `200 {}` — neither has a specific or namespace handler)
|
||||
|
||||
Note: counts are approximate because several client URLs (`api/avatar/v3/saved`, the `groups/v1/{groupId}` GET vs POST pair, `playerevents/v2`) collapse to the same handler under different verbs. They're listed separately below.
|
||||
|
||||
## Coverage by API prefix
|
||||
|
||||
### `api/announcement/`
|
||||
|
||||
| Verb | URL | Status | Handler |
|
||||
|---|---|---|---|
|
||||
| GET | `api/announcement/v1/get` | STUB | `AllEndpointsController.MiscLists` → `[]` |
|
||||
|
||||
### `api/avatar/`
|
||||
|
||||
| Verb | URL | Status | Handler |
|
||||
|---|---|---|---|
|
||||
| GET | `api/avatar/v2` | REAL | `AvatarV2Controller.GetAvatar` (reads `AvatarEntity` for current player) |
|
||||
| GET | `api/avatar/v2/gifts` | REAL | `AvatarGiftsController.GetGifts` |
|
||||
| POST | `api/avatar/v2/gifts` | REAL | `AvatarGiftsController.GenerateGifts` (`api/avatar/v2/gifts/generate` + the bare `gifts` POST verb-overlap) — actually the bare-path POST falls through to `ApiNamespaceStubsController`'s `api/avatar/{*path}` is **not** registered (`api/avatar/` is NOT in the namespace wildcard list), so this lands on the global `{*path}` returning `{}`. Treat as STUB-via-global. |
|
||||
| POST | `api/avatar/v2/gifts/consume/{giftId}` | REAL | `AvatarGiftsController.ConsumeGift` (id) — `Controllers/API/Avatar/V2/AvatarGiftsController.cs` line 99 |
|
||||
| POST | `api/avatar/v2/set` | REAL | `AvatarV2Controller.SetAvatar` (writes `AvatarEntity`) |
|
||||
| GET | `api/avatar/v3/saved` | REAL | `AvatarSavedOutfitsController.GetSaved` (V3) — pulls saved outfit slots from DB |
|
||||
| POST | `api/avatar/v3/saved/set` | REAL | `AvatarSavedOutfitsController.SetSaved` (writes the slot) |
|
||||
| GET | `api/avatar/v4/items` | REAL | `AvatarItemsController.GetItems` — returns owned-item ids from inventory tables |
|
||||
|
||||
### `api/bugreporting/`
|
||||
|
||||
| Verb | URL | Status | Handler |
|
||||
|---|---|---|---|
|
||||
| POST | `api/bugreporting/v2/reportbug` | REAL | `BugReportsController.ReportBugV2` (persists `BugReportEntity`) |
|
||||
|
||||
### `api/catalog/`
|
||||
|
||||
| Verb | URL | Status | Handler |
|
||||
|---|---|---|---|
|
||||
| GET | `api/catalog/v1/all` | STUB | `ApiNamespaceStubsController.CatalogAll` → `[]` (explicit override of the namespace wildcard so the SKU shape matches) |
|
||||
|
||||
### `api/challenge/`
|
||||
|
||||
| Verb | URL | Status | Handler |
|
||||
|---|---|---|---|
|
||||
| GET | `api/challenge/v2/getCurrent` | REAL | `ProgressionController.GetChallengeV2` — pulls active challenge for the player from the progression tables |
|
||||
| POST | `api/challenge/v2/updateProgress` | REAL | `ProgressionController.UpdateChallengeProgress` — writes back delta into progression rows |
|
||||
|
||||
### `api/checklist/`
|
||||
|
||||
| Verb | URL | Status | Handler |
|
||||
|---|---|---|---|
|
||||
| GET | `api/checklist/v1/current` | REAL | `ProgressionController.GetChecklistV1` |
|
||||
| POST | `api/checklist/v1/complete` | REAL | `ProgressionController.CompleteChecklistV1` (marks checklist item done in progression) |
|
||||
|
||||
### `api/communityboard/`
|
||||
|
||||
| Verb | URL | Status | Handler |
|
||||
|---|---|---|---|
|
||||
| GET | `api/communityboard/v1/current` | REAL | `CommunityBoardController.Current` — reads `data/community_board.json` via `CommunityBoardService`, returns `FeaturedPlayer` / `CurrentAnnouncement` shape |
|
||||
|
||||
### `api/config/`
|
||||
|
||||
| Verb | URL | Status | Handler |
|
||||
|---|---|---|---|
|
||||
| GET | `api/config/v2` | REAL | `Config.V2.ConfigController.GetConfig` — returns the full `RecRoomConfig` populated by `ConfigService.GetConfig(baseUrl)` |
|
||||
| GET | `api/config/v1/amplitude` | STUB | `Config.V1.ConfigController.Amplitude` (returns `{ AmplitudeKey = "" }`) — also has a duplicate stub at `AllEndpointsController.Amplitude`; the V1 ConfigController route wins via more-specific match |
|
||||
| GET | `api/config/v1/cohortnux/{cohortId}` | STUB | `Config.V1.ConfigController.CohortNux` — returns the empty cohort NUX shape |
|
||||
|
||||
### `api/consumables/`
|
||||
|
||||
| Verb | URL | Status | Handler |
|
||||
|---|---|---|---|
|
||||
| POST | `api/consumables/v1/updateActive` | REAL | `InventoryController.UpdateActiveConsumable` (writes the active-consumable row) |
|
||||
| POST | `api/consumables/v1/consume` | REAL | `InventoryController.ConsumeConsumable` (decrements inventory count) |
|
||||
| GET | `api/consumables/v1/getUnlocked` | REAL | `InventoryController.GetUnlockedConsumables` — reads the player's consumable inventory |
|
||||
|
||||
### `api/equipment/`
|
||||
|
||||
| Verb | URL | Status | Handler |
|
||||
|---|---|---|---|
|
||||
| POST | `api/equipment/v1/update` | REAL | `InventoryController.UpdateEquipment` — persists the equip-loadout selections |
|
||||
| GET | `api/equipment/v2/getUnlocked` | REAL | `InventoryController.GetUnlockedEquipment` (V2) — reads the player's owned equipment list |
|
||||
|
||||
### `api/gameconfigs/`
|
||||
|
||||
| Verb | URL | Status | Handler |
|
||||
|---|---|---|---|
|
||||
| GET | `api/gameconfigs/v1/all` | STUB | `GameConfigurationsController.GameConfigsAll` (also shadowed by `AllEndpointsController.GameConfigs` — the explicit `gameconfigs/v1/all` route wins). Returns `[]`. |
|
||||
|
||||
### `api/groups/`
|
||||
|
||||
| Verb | URL | Status | Handler |
|
||||
|---|---|---|---|
|
||||
| GET | `api/groups/v1/{groupId}` | REAL | `GroupsController.GetGroup` — reads `GroupEntity` |
|
||||
| GET | `api/groups/v1/memberships/{groupId}` | REAL | `GroupsController.GetMemberships` (pulls members from `GroupMembershipEntity`) |
|
||||
| POST | `api/groups/v1` | REAL | `GroupsController.CreateGroup` — inserts `GroupEntity` + creator membership |
|
||||
| POST | `api/groups/v1/delete/{groupId}` | REAL | `GroupsController.DeleteGroup` |
|
||||
| POST | `api/groups/v1/{groupId}` | WILDCARD | No specific POST `api/groups/v1/{id}` route exists — only the GET. Falls through to `ApiNamespaceStubsController` `api/groups/{*path}` → `[]`. The 2020 client likely uses this verb to update group metadata; nothing is persisted. |
|
||||
| POST | `api/groups/v1/name/{groupId}` | WILDCARD | Same as above — only the GET-by-name (`api/groups/v1/name/{name}`) is implemented. The `name/{groupId}` POST hits the namespace wildcard. |
|
||||
|
||||
### `api/images/`
|
||||
|
||||
| Verb | URL | Status | Handler |
|
||||
|---|---|---|---|
|
||||
| GET | `api/images/v1/listsaved` | STUB | `MissingEndpointsController.ImagesListSaved` → `[]` (the real saved-image list is served at `api/images/v2/saved`+ via `ImagesController`; the v1 surface is empty for the 2020 client) |
|
||||
| POST | `api/images/v1/modifyaccessibility` | STUB | `MissingEndpointsController.ImagesAck` → `Ack()` |
|
||||
| POST | `api/images/v1/deletesaved` | STUB | `MissingEndpointsController.ImagesDeleteSaved` → `Ack()` |
|
||||
| POST | `api/images/v1/sendlink` | STUB | `MissingEndpointsController.ImagesAck` → `Ack()` |
|
||||
| POST | `api/images/v1/cheer` | STUB | `MissingEndpointsController.ImagesAck` → `Ack()` |
|
||||
| GET | `api/images/v2/named` | STUB | `MiscStubsController.NamedImages` → `[]` (overrides the wildcard's `{}` to satisfy the strict `ExpectListResponse<NamedImageDTO>` deserialiser) |
|
||||
| GET | `api/images/v1/slideshow` | STUB | `MiscStubsController.SlideshowInfo` — returns `{ ValidTill = 9999-12-31, Images = [] }`; required keys present so `SlideshowInfoDTO.Deserialize` succeeds, but no actual slideshow images |
|
||||
|
||||
### `api/inventions/`
|
||||
|
||||
| Verb | URL | Status | Handler |
|
||||
|---|---|---|---|
|
||||
| GET | `api/inventions/v1/personaldetails/{playerId}` | WILDCARD | `InventionsController` only registers `api/inventions/v1/personaldetails/{id:long}` for the SAVED count by player — wait — re-reading: route IS registered (line 173 in `InventionsController.cs`). REAL. → `InventionsController.PersonalDetails` reads invention saved-count for the target player |
|
||||
| GET | `api/inventions/v1?inventionId={id}` | REAL | `InventionsController.GetInvention` (`api/inventions/v1`) reads `InventionEntity` by query param |
|
||||
| GET | `api/inventions/v1/update` | REAL | `InventionsController.Update` — yes, the client uses GET for "update invention metadata" (the ISIL routing tag uses `Core.Get`); writes back the invention row |
|
||||
| POST | `api/inventions/v1/settags` | REAL | `InventionsController.SetTags` — replaces the `Tags` column on the invention |
|
||||
| POST | `api/inventions/v1/batch` | REAL | `InventionsController.Batch` — bulk-fetch inventions by id list, returns multi-row payload |
|
||||
| GET | `api/inventions/v1/details` | REAL | `InventionsController.Details` — extended invention payload with version/creator metadata |
|
||||
| GET | `api/inventions/v1/versions` | REAL | `InventionsController.Versions` — list of `InventionVersionEntity` rows for an invention |
|
||||
| GET | `api/inventions/v1/creatorIds` | REAL | `InventionsController.CreatorIds` — list of distinct creator player ids over the matching invention set |
|
||||
| GET | `api/inventions/v1/tagfilters` | REAL | `InventionsController.TagFilters` — returns the curated tag-filter set (currently empty list, but registered as a real handler) |
|
||||
| GET | `api/inventions/v1/delete` | REAL | `InventionsController.Delete` — soft-deletes an invention the caller owns |
|
||||
| GET | `api/inventions/v2/publish` | REAL | `InventionsController.PublishV2` — flips `IsPublished=true`, sets `FirstPublishedAt` |
|
||||
| GET | `api/inventions/v1/unpublish` | REAL | `InventionsController.Unpublish` — flips `IsPublished=false` |
|
||||
| GET | `api/inventions/v1/download` | REAL | `InventionsController.Download` — streams the invention payload + bumps `NumDownloads` |
|
||||
| GET | `api/inventions/v1/search` | REAL | `InventionsController.Search` — text/`@username` search over the inventions table |
|
||||
| POST | `api/inventions/v1/report` | REAL | `InventionsController.Report` — persists `InventionReportEntity` |
|
||||
| POST | `api/inventions/v1/cheer` | REAL | `InventionsController.Cheer` — increments `CheerCount` and inserts cheer row, fires notification |
|
||||
| GET | `api/inventions/v1/mine` | REAL | `InventionsController.Mine` (delegates to the SAVED-by-creator query, returns the caller's own creations) |
|
||||
| GET | `api/inventions/v3/popular` | REAL | `InventionsController.Popular` — most-cheered published inventions |
|
||||
| GET | `api/inventions/v3/saved` | REAL | `InventionsController.Saved` — caller's own creations (SAVED list) |
|
||||
| POST | `api/inventions/v3/save` | REAL | `InventionsController.Save` — creates a new `InventionEntity` (initial save) |
|
||||
| POST | `api/inventions/v3/addversion` | REAL | `InventionsController.AddVersion` — appends `InventionVersionEntity`, bumps `CurrentVersionNumber` |
|
||||
|
||||
### `api/Leaderboard/`
|
||||
|
||||
| Verb | URL | Status | Handler |
|
||||
|---|---|---|---|
|
||||
| GET | `api/Leaderboard/v2/getPlayerRank` | STUB | `AllEndpointsController.MiscLists` (matched via the `api/Leaderboard/v1/{*path}` GET stub for v1; v2/getPlayerRank specifically falls into the `ApiNamespaceStubsController` `api/Leaderboard/{*path}` → `[]`). Functionally STUB-via-WILDCARD. |
|
||||
| POST | `api/Leaderboard/v1/SetStats` | WILDCARD | No specific route. `ApiNamespaceStubsController` `api/Leaderboard/{*path}` → `[]` — the stat row isn't persisted. |
|
||||
|
||||
### `api/messages/`
|
||||
|
||||
| Verb | URL | Status | Handler |
|
||||
|---|---|---|---|
|
||||
| GET | `api/messages/v1/favoriteFriendOnlineStatus` | REAL | `Messages.V2.MessagesController.FavoriteFriendOnlineStatus` — joins relationships+presence to return a per-friend online/offline list |
|
||||
| POST | `api/messages/v1/sendMultiple` | REAL | `MissingEndpointsController.MessagesSendMultiple` — fan-out: persists one `MessageEntity` per recipient |
|
||||
| POST | `api/messages/v2/send` | REAL | `Messages.V2.MessagesController.Send` — inserts a `MessageEntity` and fires the SignalR notify |
|
||||
| GET | `api/messages/v2/get` | REAL | `Messages.V2.MessagesController.Get` — returns the recipient inbox from `MessageEntity` rows |
|
||||
| GET | `api/messages/v1/IOSGetNotificationPreferences` | REAL | `IOSNotificationPrefsController.Get` — reads per-player iOS pref settings (table-backed) |
|
||||
| POST | `api/messages/v1/IOSModifyNotificationPreferences` | REAL | `IOSNotificationPrefsController.Modify` — upserts the prefs row |
|
||||
| POST | `api/messages/v1/send` | STUB | No `api/messages/v1/send` POST route. Falls through to global `{*path}` → `200 {}`. The v1 send was superseded by v2; the 2020 client almost always hits v2 instead. MISSING-via-global. |
|
||||
|
||||
### `api/notification/`
|
||||
|
||||
| Verb | URL | Status | Handler |
|
||||
|---|---|---|---|
|
||||
| GET | `api/notification/hub/v1` | STUB | `Notification.V2.NotificationController.Connect` returns 410 Gone with a hint to connect to `notify.rec.net/hub/v1` instead — not the same path, so the bare `/hub/v1` GET is intercepted by the V2 controller's `[Route("api/[controller]/v2")]` only when the URL path is `api/notification/v2`. The literal client URL `api/notification/hub/v1` has no specific handler; it lands on the global `{*path}` → `200 {}`. The actual notification stream the client wants is the SignalR hub at `notify.rec.net/hub/v1`. |
|
||||
|
||||
### `api/objectives/`
|
||||
|
||||
| Verb | URL | Status | Handler |
|
||||
|---|---|---|---|
|
||||
| GET | `api/objectives/v1/myprogress` | REAL | `MiscStubsController.MyObjectiveProgress` — reads `ObjectiveProgressEntity` rows for the player and emits the strict `Objectives` + `ObjectiveGroups` shape the client's `MyProgress.Deserialize` requires |
|
||||
| POST | `api/objectives/v1/updateobjective` | WILDCARD | No specific route. `ApiNamespaceStubsController` `api/objectives/{*path}` → `[]`. Per-objective progress increments aren't actually persisted — only the `cleargroup` route below writes anything. |
|
||||
| POST | `api/objectives/v1/cleargroup` | REAL | `MiscStubsController.ClearGroup` — upserts an `ObjectiveProgressEntity` row keyed `group:{n}`, sets `IsCompleted=true`, returns the wire-shape the client's `ObjectiveGroupProgress.Deserialize` requires |
|
||||
| POST | `api/objectives/v1/completegroup` | REAL | `ProgressionController.CompleteObjectiveGroup` — same as ClearGroup but also grants the group's reward |
|
||||
|
||||
### `api/PlayerCheer/`
|
||||
|
||||
| Verb | URL | Status | Handler |
|
||||
|---|---|---|---|
|
||||
| POST | `api/PlayerCheer/v1/create` | REAL | `MissingEndpointsController.PlayerCheerCreate` — inserts `CheerEntity` for the target player |
|
||||
| POST | `api/PlayerCheer/v1/SetSelectedCheer` | REAL | `MissingEndpointsController.SetSelectedCheer` — upserts `PlayerSettings[SelectedCheer]` for the caller |
|
||||
|
||||
### `api/PlayerElo/`
|
||||
|
||||
| Verb | URL | Status | Handler |
|
||||
|---|---|---|---|
|
||||
| POST | `api/PlayerElo/v1/reportPlayerElo` | WILDCARD | `ApiNamespaceStubsController` `api/PlayerElo/{*path}` → `Object()` `{}`. Match-result Elo deltas aren't recorded. |
|
||||
|
||||
### `api/playerevents/`
|
||||
|
||||
| Verb | URL | Status | Handler |
|
||||
|---|---|---|---|
|
||||
| POST | `api/playerevents/v1/{eventId}/responses` | WILDCARD | No specific `responses` POST route — only `{eventId}/rsvp` (POST) and `respond` (POST). Falls into the global `{*path}` since `api/playerevents/` is NOT in the namespace wildcard list. Effectively MISSING-via-global. |
|
||||
| GET | `api/playerevents/v2` | STUB | No specific route at the bare `api/playerevents/v2` path; only `api/playerevents/v2/delete/{id}` (DELETE) exists. Falls into the global `{*path}` → `{}`. The 2020 watch usually reads the per-player feed from `api/playerevents/v1/all` (REAL) instead. |
|
||||
| GET | `api/playerevents/v2/{eventId}` | STUB | Same — no specific GET route for a single v2 event. Global `{*path}` → `{}`. |
|
||||
| POST | `api/playerevents/v1/respond` | REAL | `MissingEndpointsController.PlayerEventRespond` — upserts `PlayerEventResponseEntity` (RSVP yes/no/maybe) |
|
||||
| POST | `api/playerevents/v1/deleteResponse` | REAL | `MissingEndpointsController.PlayerEventDeleteResponse` — deletes the RSVP row |
|
||||
| POST | `api/playerevents/v1/bulkInvite` | REAL | `PlayerEventsController.BulkInvite` — fires per-recipient invite notifications via the notification service |
|
||||
| GET | `api/playerevents/v1/all` | REAL | `MiscStubsController.AllPlayerEvents` — joins `PlayerEvents` (caller-created) + `PlayerEventResponses` (caller-RSVPed) for the player's local "my events" panel |
|
||||
|
||||
### `api/PlayerReporting/`
|
||||
|
||||
| Verb | URL | Status | Handler |
|
||||
|---|---|---|---|
|
||||
| GET | `api/PlayerReporting/v2/detail` | WILDCARD | `ApiNamespaceStubsController` `api/PlayerReporting/{*path}` → `Ack()` `{success:true}`. The 2020 watch reads moderation detail; we ack so the UI doesn't crash, but no real moderation history is returned. |
|
||||
| POST | `api/PlayerReporting/v2/ban` | WILDCARD | Same wildcard `Ack()`. Bans posted via this v2 path aren't persisted (the canonical persistence path is `api/PlayersBanned/v2/ban` REAL below). |
|
||||
| POST | `api/PlayerReporting/v1/deviceId` | REAL | `InGameModerationController.ReportDeviceId` — persists the device ID -> player association for moderation lookups |
|
||||
| POST | `api/PlayerReporting/v1/hile` | WILDCARD | `ApiNamespaceStubsController` `api/PlayerReporting/{*path}` → `Ack()`. Steam signature/anti-cheat ping; intentionally not stored. |
|
||||
| POST | `api/PlayerReporting/v3/create` | REAL | `InGameModerationController.CreateReport` — inserts a `PlayerReportEntity` and notifies moderators |
|
||||
| POST | `api/PlayerReporting/v3/voteToKick` | REAL | `InGameModerationController.VoteToKick` — records the kick vote and triggers room-instance kick if threshold met |
|
||||
| POST | `api/PlayerReporting/v1/instantKick` | REAL | `InGameModerationController.InstantKick` — moderator-only; ejects target from current room |
|
||||
|
||||
### `api/playersubscriptions/`
|
||||
|
||||
| Verb | URL | Status | Handler |
|
||||
|---|---|---|---|
|
||||
| GET | `api/playersubscriptions/v1/my` | REAL | `PlayerSubscriptionsController.My` — returns the caller's subscription list from `SubscriptionEntity` |
|
||||
| POST | `api/playersubscriptions/v1/subscribe/{playerId}` | REAL | `PlayerSubscriptionsController.Subscribe` (also covered by `MissingEndpointsController.Subscribe` — the V1 controller's specific route wins). Inserts `SubscriptionEntity`. |
|
||||
| POST | `api/playersubscriptions/v1/unsubscribe/{playerId}` | REAL | `PlayerSubscriptionsController.Unsubscribe` — removes the row |
|
||||
|
||||
### `api/PlayersBanned/`
|
||||
|
||||
| Verb | URL | Status | Handler |
|
||||
|---|---|---|---|
|
||||
| POST | `api/PlayersBanned/v2/ban` | REAL | `InGameModerationController.PlayersBannedV2Ban` — persists `PlayerBanEntity` (room/global ban depending on payload) |
|
||||
|
||||
### `api/quickPlay/`
|
||||
|
||||
| Verb | URL | Status | Handler |
|
||||
|---|---|---|---|
|
||||
| GET | `api/quickPlay/v1/getandclear` | REAL | `QuickPlayController.GetAndClear` — reads + drains the caller's pending quick-play invite row |
|
||||
| POST | `api/quickPlay/v1/set` | REAL | `QuickPlayController.Set` — writes a quick-play invite for the target player |
|
||||
|
||||
### `api/relationships/`
|
||||
|
||||
| Verb | URL | Status | Handler |
|
||||
|---|---|---|---|
|
||||
| GET | `api/relationships/v2/get` | REAL | `Relationships.V2.RelationshipsController.Get` — reads the friends/blocked list from `RelationshipEntity` |
|
||||
| GET | `api/relationships/v2/personaldetails/{playerId}` | WILDCARD | No specific `personaldetails` route in the v2 controller. Falls into the global `{*path}` → `{}` (the namespace `api/relationships/` is NOT in the wildcard list, so the global one is the only fallback). |
|
||||
| POST | `api/relationships/v2/addfriend` | REAL | `Relationships.V2.RelationshipsController.AddFriend` (POST + GET both registered) — upserts the relationship row |
|
||||
| POST | `api/relationships/v2/removefriend` | REAL | `Relationships.V2.RelationshipsController.RemoveFriend` |
|
||||
| POST | `api/relationships/v2/sendfriendrequest` | REAL | `Relationships.V2.RelationshipsController.SendFriendRequest` — fires a friend-request notification |
|
||||
| POST | `api/relationships/v2/acceptfriendrequest` | REAL | `Relationships.V2.RelationshipsController.AcceptFriendRequest` — flips the relationship to mutual |
|
||||
| POST | `api/relationships/v1/favorite` | REAL | `Relationships.V2.RelationshipsController.Favorite` — sets the IsFavorite flag |
|
||||
| POST | `api/relationships/v1/unfavorite` | REAL | `Relationships.V2.RelationshipsController.Unfavorite` |
|
||||
| POST | `api/relationships/v1/bulkignoreplatformusers` | STUB | `MissingEndpointsController.BulkIgnore` → `Ack()` (platform-block import is a no-op on a private server) |
|
||||
|
||||
### `api/role/`
|
||||
|
||||
| Verb | URL | Status | Handler |
|
||||
|---|---|---|---|
|
||||
| GET | `api/role/developer/{accountId}` | REAL | `RoleController.IsDeveloper` — reads the developer-flag from the player's roles |
|
||||
|
||||
### `api/rooms/`
|
||||
|
||||
| Verb | URL | Status | Handler |
|
||||
|---|---|---|---|
|
||||
| GET | `api/rooms/v1/featuredRoomGroup` | REAL | `MissingEndpointsController.FeaturedRooms` — returns the top-12 hot AG rooms wrapped in the `{Name, FeaturedRooms}` shape |
|
||||
| GET | `api/rooms/v3/featured` | REAL | Same handler — `MissingEndpointsController.FeaturedRooms` (route also registered for v3) |
|
||||
| GET | `api/rooms/v2/myRecent` | REAL | `Rooms.V2.RoomsController.MyRecent` (`api/rooms/v2/myrecent`) — reads the caller's recent-room history |
|
||||
| GET | `api/rooms/v2/mySubscriptions` | REAL | `Rooms.V2.RoomsController.MySubscribed` (`api/rooms/v2/mysubscribed`) — rooms the caller has subscribed to |
|
||||
| GET | `api/rooms/v2/baserooms` | REAL | `Rooms.V2.RoomsController.BaseRooms` — list of "base" world templates / Rec Center rooms |
|
||||
| GET | `api/rooms/v1/filters` | REAL | `Rooms.V2.RoomsController.Filters` — discovery filter chips |
|
||||
| GET | `api/rooms/v2/search` | WILDCARD | No `api/rooms/v2/search` route — only `api/rooms/v1/search` is registered. Lands on the global `{*path}` → `{}`. The 2020 client probably falls back gracefully or the watch uses v1/search. STUB-via-global. |
|
||||
| GET | `api/rooms/v2/live` | WILDCARD | No specific route. Global `{*path}` → `{}`. The "live rooms" panel will be empty. |
|
||||
| GET | `api/rooms/v1/hot` | REAL | `Rooms.V2.RoomsController.Hot` — top rooms by `HotScore` |
|
||||
| GET | `api/rooms/v2/name/{roomId}` | REAL | `Rooms.V2.RoomsController.ByName` — lookup by room name (NOT id, despite the variable token) |
|
||||
| GET | `api/rooms/v2/{roomId}` | REAL | `Rooms.V2.RoomsController.ById` |
|
||||
| GET | `api/rooms/v4/details/{roomId}` | REAL | `Rooms.V2.RoomsController.Details` — full room blob with scenes/permissions/etc. |
|
||||
| GET | `api/rooms/v2/personaldetails/{creatorId}` | REAL | `Rooms.V2.RoomsController.PersonalDetails` — caller-relative bookmark/cheer flags for the room |
|
||||
| POST | `api/rooms/v1/clone` | REAL | `Rooms.V2.RoomsController.Clone` — clones the room row + scenes for the caller |
|
||||
| POST | `api/rooms/v1/modify/sceneParent` | REAL | `RoomsModerationController.ModifyParentScene` — re-parents a scene tree node |
|
||||
| POST | `api/rooms/v1/modify/tags` | REAL | `RoomsModerationController.ModifyTags` — replaces the room's tag CSV |
|
||||
| POST | `api/rooms/v2/modify` | REAL | `RoomsModerationController.Modify` — patches mutable room metadata (name, description, image) |
|
||||
| POST | `api/rooms/v2/modifyPermissions` | REAL | `RoomsModerationController.ModifyPermissions` — updates per-role permission masks |
|
||||
| POST | `api/rooms/v1/roombans/{roomId}` | WILDCARD | Only the GET `api/rooms/v1/roombans/{roomId}` is implemented; the POST falls into `ApiNamespaceStubsController.List()` (because `api/rooms/` is intentionally NOT in the namespace wildcard list per the comment in that file — actually re-reading: `api/rooms/` is excluded, so the global `{*path}` is what catches this. STUB-via-global.) |
|
||||
| POST | `api/rooms/v2/banfromroom` | REAL | `RoomsModerationController.BanFromRoom` — inserts `RoomBanEntity` |
|
||||
| POST | `api/rooms/v1/importroombans` | REAL | `RoomsModerationController.ImportRoomBans` — bulk insert |
|
||||
| POST | `api/rooms/v1/cheer` | REAL | `MissingEndpointsController.CheerRoom` — bumps `Rooms.CheerCount` (also `PlayerStateController.CheerRoom` at the per-id route `api/rooms/v1/cheer/{roomId}`) |
|
||||
| POST | `api/rooms/v1/bookmark` | REAL | `MissingEndpointsController.BookmarkRoom` — upserts/removes a `RoomBookmarkEntity` based on the `Bookmark` form field |
|
||||
| GET | `api/rooms/v1/datahistory/{roomId}` | REAL | `Rooms.V2.RoomsController.DataHistory` — list of historical scene snapshots |
|
||||
| POST | `api/rooms/v1/datahistory/restore` | REAL | `Rooms.V2.RoomsController.RestoreDataHistory` — rolls a room's scenes back to a snapshot |
|
||||
| POST | `api/rooms/v2/report` | REAL | `RoomsModerationController.Report` — files a room report |
|
||||
| GET | `api/rooms/v1/modrooms` | REAL | `Rooms.V2.RoomsController.MyModerated` (route alias `api/rooms/v1/modrooms`) — rooms the caller moderates |
|
||||
| GET | `api/rooms/v2/myrooms` | REAL | `Rooms.V2.RoomsController.MyRooms` |
|
||||
| GET | `api/rooms/v2/mybookmarkedrooms` | REAL | `Rooms.V2.RoomsController.MyBookmarks` (also aliased at `api/rooms/v2/mybookmarks`) |
|
||||
| POST | `api/rooms/v1/roomRolePermissions` | STUB | `MiscStubsController.ValidateRoomRolePermissions` → `{success:true,error:""}` (the watch's local-role assumption is what gets used; no server-side recompute) |
|
||||
|
||||
### `api/royale/`
|
||||
|
||||
| Verb | URL | Status | Handler |
|
||||
|---|---|---|---|
|
||||
| GET | `api/royale/v1/current` | REAL | `RoyaleController.GetCurrent` — current Rec Royale season metadata + leaderboard summary |
|
||||
| POST | `api/royale/v2/matchcomplete` | REAL | `RoyaleController.MatchComplete` — records the match result row + grants rewards |
|
||||
|
||||
### `api/purchase/`
|
||||
|
||||
| Verb | URL | Status | Handler |
|
||||
|---|---|---|---|
|
||||
| POST | `api/purchase/v1/initiatepurchase` | REAL | `PurchaseController.Initiate` — creates a pending `PurchaseEntity`, returns the purchase id for the next step |
|
||||
| POST | `api/purchase/v1/completepurchase` | REAL | `PurchaseController.Complete` — finalises the row, grants the inventory/currency |
|
||||
| POST | `api/purchase/v1/processpurchase` | REAL | `PurchaseController.Process` — middle-step confirmation that the platform-side payment cleared (no real platform integration; just flips state) |
|
||||
| POST | `api/purchase/v1/cancelpurchase` | REAL | `PurchaseController.Cancel` — marks the pending row cancelled |
|
||||
| POST | `api/purchase/v1/cleanuppending` | REAL | `PurchaseController.CleanupPending` — sweeps dangling pending rows for the caller |
|
||||
|
||||
### `api/settings/`
|
||||
|
||||
| Verb | URL | Status | Handler |
|
||||
|---|---|---|---|
|
||||
| GET | `api/settings/v2/get` | REAL | The route `api/settings/v2/get` doesn't exist as a literal path — the controller registers the bare GET at `api/settings/v2`. The 2020 client appends `/get` and lands on the global `{*path}` → `{}`. STUB-via-global for the literal `/get` suffix. (`api/settings/v2` bare GET is REAL via `Settings.V2.SettingsController.GetSettings` reading `PlayerSettingEntity` rows.) |
|
||||
|
||||
### `api/storefronts/`
|
||||
|
||||
| Verb | URL | Status | Handler |
|
||||
|---|---|---|---|
|
||||
| GET | `api/storefronts/v1/current` | WILDCARD | No specific route. `ApiNamespaceStubsController` `api/storefronts/{*path}` → `[]`. The "current storefront" panel is empty. |
|
||||
| POST | `api/storefronts/v2/buyItem` | REAL | `StorefrontsBuyController.BuyItem` — debits the caller's currency, grants the item to inventory |
|
||||
| POST | `api/storefronts/v2/buyTier` | REAL | `StorefrontsBuyController.BuyTier` — purchases a season-pass tier |
|
||||
| POST | `api/storefronts/v2/buyElite` | REAL | `StorefrontsBuyController.BuyElite` — Elite (premium) purchase |
|
||||
| GET | `api/storefronts/v4/balance/{playerId}` | REAL | `StorefrontsController.BalanceByCurrency` — actually only `api/storefronts/v4/balance/{currencyType:int}` is registered, and `api/storefronts/v4/balance` (no segment) at line 388. The `/balance/{playerId}` shape lands on whichever of those route templates matches the int constraint. Returns the player's currency balance. |
|
||||
| POST | `api/storefronts/v1/balanceAddType/{type}/{playerId}` | STUB | Only the GET form is registered (`AllEndpointsController.StorefrontBalanceAddType` → `[]`). The POST falls into `ApiNamespaceStubsController` `api/storefronts/{*path}` → `[]`. Currency-add-tier purchases via the v1 path aren't credited. |
|
||||
| GET | `api/storefronts/v2/balance` | REAL | `MissingEndpointsController.StorefrontBalanceV2` — returns a single-row balance list `[{CurrencyType=2, Balance=0, Platform=0}]` (genuine zero balance, but no actual ledger lookup) |
|
||||
| GET | `api/storefronts/v3/giftdropstore/{storefront}` | STUB | `ApiNamespaceStubsController.GiftDropStorefront` — returns the BaseStorefrontDTO + `StoreItems=[]` shape with required keys present so the strict deserialiser passes |
|
||||
| GET | `api/storefronts/v1/season/{seasonId}` | STUB | `MissingEndpointsController.StorefrontSeason` — returns `{Tiers=[], Active=false, SeasonType=type}` |
|
||||
| GET | `api/storefronts/v1/objectives` | STUB | `MissingEndpointsController.StorefrontObjectives` → `[]` |
|
||||
|
||||
### `api/sanitize/`
|
||||
|
||||
| Verb | URL | Status | Handler |
|
||||
|---|---|---|---|
|
||||
| POST | `api/sanitize/v1/purifyString` | STUB | `AllEndpointsController.Sanitize` (registered at `api/sanitize/v1` and `api/sanitize/v1/text`) doesn't catch this exact suffix; falls into `ApiNamespaceStubsController.Sanitize` which echoes back `{Text=text}`. Functionally a passthrough — text is NOT actually filtered. |
|
||||
| POST | `api/sanitize/v1/requestIsStringPure` | STUB | Same — `ApiNamespaceStubsController.Sanitize` returns `{Text=text}`. The "is this string pure" boolean isn't surfaced; the client likely falls back to "treat as clean". |
|
||||
|
||||
### `api/testcasemanagement/`
|
||||
|
||||
| Verb | URL | Status | Handler |
|
||||
|---|---|---|---|
|
||||
| GET | `api/testcasemanagement/v1/testpasssummary` | REAL | `TestCaseManagementController.TestPassSummary` — reads the test-pass summary table (dev/QA tooling) |
|
||||
| GET | `api/testcasemanagement/v1/testpass/{passId}` | REAL | `TestCaseManagementController.GetTestPass` |
|
||||
| GET | `api/testcasemanagement/v1/testcase/{caseId}` | REAL | `TestCaseManagementController.GetTestCase` |
|
||||
| POST | `api/testcasemanagement/v1/testcase/{caseId}/claim` | REAL | `TestCaseManagementController.ClaimTestCase` — assigns the case to the caller |
|
||||
| POST | `api/testcasemanagement/v1/testcase/{caseId}/unclaim` | REAL | `TestCaseManagementController.UnclaimTestCase` |
|
||||
| POST | `api/testcasemanagement/v1/testcase/{caseId}/status` | REAL | `TestCaseManagementController.SetTestCaseStatus` — pass/fail/skip update |
|
||||
|
||||
### Non-API URLs (other subdomains)
|
||||
|
||||
These all live on `match.rec.net` (locally: `match.localhost`).
|
||||
|
||||
| Verb | URL | Status | Handler |
|
||||
|---|---|---|---|
|
||||
| POST | `goto/room/{roomName}` | REAL | `Match.GoToController.GoToRoom` — looks up the room by name, picks/creates a session, returns the connect blob |
|
||||
| POST | `goto/room/{room}/{subRoom}` | REAL | `Match.GoToController.GoToSubRoom` — same but for nested rooms (Rec Center subrooms) |
|
||||
| POST | `goto/event/{eventId}` | REAL | `Match.GoToController.GoToEvent` — resolves the event's room + start time, routes the player |
|
||||
| POST | `goto/player/{playerId}` | REAL | `Match.GoToController.GoToPlayer` — uses `PlayerPresenceService` to find where the target is and routes the caller there |
|
||||
| POST | `goto/instance/{instanceId}` | REAL | `Match.GoToController.GoToInstance` — direct join to a specific room instance |
|
||||
| POST | `goto/invite/{inviteId}` | REAL | `Match.GoToController.GoToInvite` — resolves an invite to its target room/instance |
|
||||
| POST | `player/heartbeat` | REAL | `Match.MatchPlayerController.Heartbeat` — refreshes the caller's `PlayerPresenceService` entry; also has a duplicate in `ApiNamespaceStubsController.Heartbeat` for the api-host case |
|
||||
|
||||
## Catch-all wildcards (informational)
|
||||
|
||||
Routes registered as `[Route("api/<ns>/{*path}")]` in `ApiNamespaceStubsController` (`Controllers/API/Stubs/ApiNamespaceStubsController.cs`):
|
||||
|
||||
List-typed namespaces (return `[]`):
|
||||
- `api/announcement/{*path}`
|
||||
- `api/challenge/{*path}`
|
||||
- `api/checklist/{*path}`
|
||||
- `api/PlayerCheer/{*path}`
|
||||
- `api/catalog/{*path}`
|
||||
- `api/communityboard/{*path}`
|
||||
- `api/consumables/{*path}`
|
||||
- `api/equipment/{*path}`
|
||||
- `api/groups/{*path}`
|
||||
- `api/inventions/{*path}`
|
||||
- `api/Leaderboard/{*path}`
|
||||
- `api/offlineinvite/{*path}`
|
||||
- `api/PlayersBanned/{*path}`
|
||||
- `api/objectives/{*path}`
|
||||
- `api/playersubscriptions/{*path}`
|
||||
- `api/storefronts/{*path}`
|
||||
|
||||
Object-typed namespaces (return `{}`):
|
||||
- `api/PlayerElo/{*path}`
|
||||
- `api/quickPlay/{*path}`
|
||||
- `api/royale/{*path}`
|
||||
|
||||
Ack namespaces (return `{success:true}`):
|
||||
- `api/bugreporting/{*path}`
|
||||
- `api/PlayerReporting/{*path}`
|
||||
|
||||
Sanitize passthrough (returns `{Text=<echo>}`):
|
||||
- `api/sanitize/{*path}` (GET + POST)
|
||||
|
||||
Notable namespaces NOT in the wildcard list (so unmatched URLs fall through to the global `/{*path}` returning `200 {}`):
|
||||
- `api/avatar/`
|
||||
- `api/messages/`
|
||||
- `api/notification/`
|
||||
- `api/playerevents/`
|
||||
- `api/relationships/`
|
||||
- `api/rooms/` — explicit comment in the source: "intentionally NOT in this list — RoomsController owns it"
|
||||
- `api/settings/`
|
||||
- `api/testcasemanagement/`
|
||||
- `api/account/`, `api/auth/`, `api/config/`, `api/players/`, `api/role/`, `api/version/`, `api/photos/`, `api/images/`, `api/gameconfigs/`, `api/playerReputation/`, `api/role/`, `api/cards/`, etc. (these all have specific controllers covering the URLs the 2020 client actually hits)
|
||||
|
||||
## Final-fallback catch-alls
|
||||
|
||||
If neither a specific route nor a namespace wildcard matches, the request hits one of these last-resort handlers:
|
||||
|
||||
- `Controllers/ApiCatchAllController.cs` — `[Route("/{*path}")]` constrained to API hosts. Returns `200 {}` with a log line. Mostly a defensive net so the watch never sees a 404.
|
||||
- `Controllers/GlobalCatchAllController.cs` — same shape, applies to non-API hosts.
|
||||
- `Controllers/Stub/StubController.cs` — `[Route("/{*path}")]` last-resort across all hosts; logs the URL+verb+host so we can see what the client tried but we never wired up.
|
||||
|
||||
These are the "MISSING" status entries in the matrix above. The body returned (`200 {}`) is enough for many client call-sites that tolerate `null`, but tends to crash strict `Util.Deserialize<T>` paths the next time the player exercises that feature.
|
||||
@@ -0,0 +1,2092 @@
|
||||
[
|
||||
{
|
||||
"name": "Hat_Knight_Helmet_Mask",
|
||||
"guid": "0dd6596c-b4ea-4d55-a219-e1f44e4a376d",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "TShirt_SquadGoals_Swatch",
|
||||
"guid": "941c046e-4e95-49f8-a7d7-19071fcc3c94",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "ZebraWhite_Swatch",
|
||||
"guid": "48abd952-214f-48b2-a8f1-1146f6f69aa2",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "FootballHelmet_Mask",
|
||||
"guid": "7660e11a-7ef0-43d3-bc02-76b3a4aab064",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "SpaceMarine_Red_Swatch",
|
||||
"guid": "d78643e4-c0d2-4836-bf22-b5a0e2d65b28",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Hibiscus_Yellow_Swatch",
|
||||
"guid": "596097a8-d545-4256-959d-1d3cd96fc64c",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Polkadot_Mask",
|
||||
"guid": "b292eb4b-07e3-4a48-99b5-3c6587a1e02e",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Artist_Hat_Mask",
|
||||
"guid": "3485a30d-27f8-450b-b5aa-1ff3cd227d19",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Boxer_Red_Swatch",
|
||||
"guid": "8c7b09f2-6213-4ef9-87ab-a2df72d07a22",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Baseball_Torso_Mask",
|
||||
"guid": "ca37823a-b8f3-4414-b38b-de0dc7fa4295",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "TShirt_Male_Mask",
|
||||
"guid": "0440f08f-ef1d-49d8-942b-523056e8bb45",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "Aviator_Shirt_Mask",
|
||||
"guid": "9009bcdf-b6f7-4dae-b2ec-895511d118ff",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "PoofyDress_Purple_Swatch",
|
||||
"guid": "31ac9d4d-3d6b-48f2-85d5-dc4b8165a17a",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Baseball_Red_Swatch",
|
||||
"guid": "de0a5a3a-8aff-4799-8269-9efa3aeb383a",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "ButtonTop_Orange_Swatch",
|
||||
"guid": "e0397982-c2c2-4733-9a40-46e18675b5af",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "CowboyCherry_Swatch",
|
||||
"guid": "624c85e5-095a-48b6-85fb-c9bbade19a8d",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Mobster_HerringBone_Tan_Swatch",
|
||||
"guid": "531b4297-b38b-4362-9854-4f2139ea43be",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Punk_Pink_Swatch",
|
||||
"guid": "4169bfed-8403-4590-a29d-4941275ac0b6",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Golfer_Shirt_Mask",
|
||||
"guid": "6ce21c65-f4e9-41ac-be94-8eb1a08d5c76",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "EquestrianJacket_Maroon_Swatch",
|
||||
"guid": "d6823e01-69f0-4f85-b94a-74894356a2cf",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "FighterPilot_Gloves_Orange_Swatch",
|
||||
"guid": "18b52db5-0261-46a0-9214-ff510d455ed9",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Aviator_Gloves_Tan_Swatch",
|
||||
"guid": "7fb8496f-0e6c-4e48-b8fa-5709ebbf4820",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Plaid_LightBlue_Swatch",
|
||||
"guid": "d6edbc00-3c1d-4f49-8412-3ef8c7c5f4c2",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Fatigue_Swatch",
|
||||
"guid": "6d703981-2734-4c45-8983-cdd5f328902f",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Hat_Safari_Mask",
|
||||
"guid": "0dabda0d-842c-4d39-a6b9-a8ca3ec20825",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Cream_Swatch",
|
||||
"guid": "7d8e55fe-3c34-4b4b-9753-0021f6cc6454",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "ArtistHat_Red_Swatch",
|
||||
"guid": "5c8f36c5-07da-49f4-af02-d23207a43216",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Dodgeball_Mask",
|
||||
"guid": "944d934d-5e21-42d7-8196-fff9a81ee469",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "ArcherBlack_Quiver_Swatch",
|
||||
"guid": "74b009f4-e128-4c59-8a6a-4c0ba6119bde",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "ArcherYellow_Swatch",
|
||||
"guid": "6e152cc7-e93a-4408-8092-236db420b680",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Torso_YellowPoofyDress_Mask",
|
||||
"guid": "d30e3afe-414c-4b60-8be9-6fa4156a4b65",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "PurpleJacket_Red_Swatch",
|
||||
"guid": "657f28d5-672a-4f27-86c6-3cb00f25bb84",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "FighterPilot_Orange_Swatch",
|
||||
"guid": "cea53c7f-24a9-4e3b-80b9-fbf95738f973",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "BabydollDress_Green_Swatch",
|
||||
"guid": "c9589974-c261-485e-b571-cb2f34fb178f",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "TennisSkirt_Mask",
|
||||
"guid": "b75ef67d-00c3-4ac1-9b72-212032460294",
|
||||
"category": "legs"
|
||||
},
|
||||
{
|
||||
"name": "Eye_MirroredGlasses_Silver_swatch",
|
||||
"guid": "f841cdfa-45ba-4f09-a117-503eef34cb4b",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Beekeeper_Glove_Mask",
|
||||
"guid": "1f18670d-df52-4d2b-8009-a32cf7c67b40",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "2017_Member_Decal",
|
||||
"guid": "75162f12-44e7-499f-bc6c-9b0612e9164b",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "HeadFlowers_Mask",
|
||||
"guid": "7d040391-03f7-4b3d-bcfd-a1278ff459c9",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Tshirt_Squad_Goals_Decal",
|
||||
"guid": "6c395d04-2aa6-4a3e-8c2c-695932bc9736",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "Hat_SeaCaptainDarkDarkGold_Swatch",
|
||||
"guid": "70112887-dc8d-49d5-96ed-0845204e0b58",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "ScoutSkirt_Shirt_Mask",
|
||||
"guid": "e65530f7-543c-43e9-bf12-b6cda2bc755c",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "PolkaBlue_Swatch",
|
||||
"guid": "ad61c418-6d77-4a99-8ac5-9f10f5a3d42f",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Wrist_CowboyCherry_Swatch",
|
||||
"guid": "17e44296-1cd9-4f8e-9aa7-3837dc69279a",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Yellow_Swatch",
|
||||
"guid": "d2b40639-5d34-45b6-904e-6dd29030ff44",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "WitchHunter_Purple_Swatch",
|
||||
"guid": "71e5a0fe-fc8d-420b-af3b-e74160e0d1f3",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Plaid_Mask",
|
||||
"guid": "cf119781-5bd9-4b85-9a0b-12e82e988c23",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Smuggler_Green_Swatch",
|
||||
"guid": "076c96ae-9f9b-45bf-9dc7-ce73d5ddf422",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Scallywag_Torso_Swatch_Red",
|
||||
"guid": "39f04eee-3a58-4e53-9f5e-7e995d46ed71",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Red_Swatch",
|
||||
"guid": "8377ab96-c908-457f-9fee-b784c9a759f3",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "TShirt_Male_LaserTag_Alpha_Mask",
|
||||
"guid": "3259238f-4a9e-4e06-99de-6e7324fa0894",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "PirateCaptain_Hat_Black_Swatch",
|
||||
"guid": "f9aaa7c5-59bc-486c-9a6e-27a8ac618f84",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Grey_Swatch",
|
||||
"guid": "0ecb8a2a-cffc-47db-aeda-fb0684aef1e5",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "BaseballHelmet_Red_Swatch",
|
||||
"guid": "a1c51d1e-1d5f-4f8a-bc0f-6a20eddfe58a",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "PirateCaptain_Black_Swatch",
|
||||
"guid": "d81d0b62-e052-46c2-9252-4bc5fb219f53",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "BlazerGreyDark_Swatch",
|
||||
"guid": "9374bf66-2ee5-493b-8439-efce4b201904",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Tshirt_LaserTag_Alpha_Decal",
|
||||
"guid": "e38294cf-6279-4863-9aea-1a19aeaf8476",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "PirateCaptain_Belt_Black_Swatch",
|
||||
"guid": "f4ad4b9e-dd42-4711-9437-5beae51966f6",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Firefighter_Hat_Mask",
|
||||
"guid": "c8ccb85e-52cd-4b3b-aadf-289819067125",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Barbershop_Torso_Mask",
|
||||
"guid": "15edb8d7-2ff6-4170-a7e6-acd9e965cab5",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "BabydollDress_Black_Swatch",
|
||||
"guid": "e13cf33d-7588-4e2e-955e-f0a29d6380b7",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Barber_Torso_Formal_Swatch",
|
||||
"guid": "a5925738-a451-4f25-b622-ccbfa12bd88c",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "FlowerSwimsuit_Mask",
|
||||
"guid": "3248a3ec-50d1-4c0a-96ae-25eb9d8ed622",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "FlapperGlove_Black_Swatch",
|
||||
"guid": "30c61e63-5e09-4a6f-8915-1e1fe4d55cf0",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "ButtonTop_Tan_Swatch",
|
||||
"guid": "49f5864f-9d40-497c-88c8-e87f64d41d74",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Tshirt_SciFi_Face_Decal",
|
||||
"guid": "4ca3347a-dc87-412f-9eb1-799372e6fdd1",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "Scifi_Carpet_Mask",
|
||||
"guid": "3290f148-1bd1-4ffd-a947-61fd0529af05",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Aviator_Goggles_Gray_Swatch",
|
||||
"guid": "23428ca9-be75-4146-b400-df01d1dadac9",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Knight_Blue_Swatch",
|
||||
"guid": "ed134bee-d199-43eb-98bd-206571603f40",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "SafariTorso_Green_Swatch",
|
||||
"guid": "49bbd11a-e5c9-47ff-b04d-72eb321e8a57",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Scallywag_Hat_Blue_Swatch",
|
||||
"guid": "53dd9e44-7096-438e-a7c3-11d7c307426f",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Wizard_Wrist_Mask",
|
||||
"guid": "47514b9b-0d17-4727-97ed-dab67e7fe031",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "ArcherTunic_Mask",
|
||||
"guid": "f88178b8-b204-4fa5-9dfd-6e438bf1e247",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Ranger_Hat_Mask",
|
||||
"guid": "0272eb19-fc0e-4ad6-8db9-cc0cda2528b0",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "SolidRed_Mask",
|
||||
"guid": "0b2395e1-ebcc-47e9-aaf1-faf9e9cec4cd",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "TShirt_Laser_Unicorn_Purple_Swatch",
|
||||
"guid": "befa2f11-b9fd-457c-b1d5-9d82e90b70ce",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "Hat_SpaceMarine_Mask",
|
||||
"guid": "b94411f6-5b71-48d0-ace1-ac6f63167065",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "EquestrianJacket_Gray_Swatch",
|
||||
"guid": "4828b50c-95b6-466a-bb25-514891d78202",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "Tshirt_Laser_Unicorn_Decal",
|
||||
"guid": "770e7674-6f9b-41f8-b023-ae79738db0d3",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "AnglerHat_Blue_Swatch",
|
||||
"guid": "d7f0ffd3-ccf9-465e-8afe-4d7efb78dd2c",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Lacrosse_Hat_Mask",
|
||||
"guid": "7e688b30-ed13-4790-9ad8-c49885d1b7e8",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "FurCoat_Black_Swatch",
|
||||
"guid": "43501b0c-eaaa-4ab3-9d03-2ca61d2e8fc9",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Angler_Torso_Mask",
|
||||
"guid": "cdbe2cc8-4fd7-451f-9b66-0df0e0e7a85e",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "FlapperHeadband_Gold_Swatch",
|
||||
"guid": "b6c25a3b-125b-4aab-bed0-e6e5ced2c21c",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Golfer_Shirt_Blue_Swatch",
|
||||
"guid": "96e2b29e-e553-40f1-9eb6-8a9f7e64da39",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "Hibiscus_White_Swatch",
|
||||
"guid": "ce465d53-3807-423f-baa0-bdba2a75ceb3",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "FlapperHeadband_Black_Swatch",
|
||||
"guid": "565c17e0-496d-45bd-a2c3-564e118c06cc",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Argyle_Mask",
|
||||
"guid": "d015cae7-a905-49e4-8823-6dec069689a6",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Scout_RaccoonHat_Mask",
|
||||
"guid": "f1cd10fb-3d0b-436f-a173-65bc0d88d8bf",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Blue_Swatch",
|
||||
"guid": "dee70c38-7a99-4c2b-9181-665f1bf75aca",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Shirt_Knight_Armor_Mask",
|
||||
"guid": "51a1809d-becd-42e0-8dfb-188d6f07ba1c",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "Barber_Hat_Formal_Swatch",
|
||||
"guid": "631c9015-2a00-47ea-bb35-465a2ddbca5d",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "DrumMajorHat_Mask",
|
||||
"guid": "a8a91216-0fcc-461e-a682-95ee82509cce",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Torso_Flapper_Mask",
|
||||
"guid": "a240d44f-963d-4d35-b22f-980938c7788d",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Artist_Torso_Mask",
|
||||
"guid": "5a6db6ba-2a0f-4399-b537-dd78db94bf90",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Blazer_Mask",
|
||||
"guid": "be2b9293-1d3c-4b1c-b4c5-fad3ab16cf54",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "TShirt_Female_Mask",
|
||||
"guid": "05f0ee6e-c824-470e-9178-5ed576c6fe0c",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "Shirt_Knight_Cape_Mask",
|
||||
"guid": "15099be7-38b7-4b0b-ac13-1bacedbf5fb2",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Aviator_Hat_Mask",
|
||||
"guid": "ff5ae41e-e446-4a96-8c11-49d85556fa81",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "FighterPilot_Glove_Mask",
|
||||
"guid": "7869b2a5-cd89-4033-b9f7-4f1451ecb47b",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Torso_OrangeDress_Mask",
|
||||
"guid": "2c8924aa-68f8-4912-9759-18992f72f08a",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "TShirt_HangInThere_Swatch",
|
||||
"guid": "815138e6-b0dc-459c-9538-20f5bbd37d6b",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "Knight_Red_Swatch",
|
||||
"guid": "59866578-d4e0-417b-9483-233ab108b1ac",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Hat_CatEars_Gray_Swatch",
|
||||
"guid": "96e42c7a-2881-4299-a2fe-80c0d4d5ca26",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Boxer_Torso_Mask",
|
||||
"guid": "0ec6628c-a106-4452-af82-105a3e3a9f2e",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "PirateCaptain_Hat_Red_Mask",
|
||||
"guid": "71fd06e3-cac8-4923-a09c-ef91183712d2",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Fatigue_Mask",
|
||||
"guid": "a0271cd0-e172-4d3f-aa2f-9806f21a82d2",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Hat_CatEars_Brown_Swatch",
|
||||
"guid": "713781e5-ce47-41c6-a24f-94d42a565e30",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "FurCoat_Mask",
|
||||
"guid": "2c0d912d-c184-4eab-8ee4-73b90ba7b0a6",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "WitchHunter_Green_Swatch",
|
||||
"guid": "64545dcc-a8eb-4c69-a539-78ee73a2d327",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Tshirt_Alpaca_Decal",
|
||||
"guid": "703ff56b-560d-4ff4-8c63-d195e879a328",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "Scout_Sash_Blue_Swatch",
|
||||
"guid": "67490e3b-0f9d-4bf8-84fb-54957b981c8c",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Hat_CatEars_Mask",
|
||||
"guid": "1e3195ab-f7f6-41f4-a5ec-378d09ecdf69",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "TShirt_Orange_Swatch",
|
||||
"guid": "95e4cc30-cb68-473d-a395-feadf5b51512",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "SpaceMarine_Pink_Swatch",
|
||||
"guid": "a36d252b-16ac-4a82-bece-de145147e7d9",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Torso_PinkStollDress_Mask",
|
||||
"guid": "91a451c1-b285-4c48-b14d-59ded8cc006f",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Mobster_Hat_Brown_Swatch",
|
||||
"guid": "1421caa9-9a0d-42c2-b847-1500ba2e483a",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "ElectricianTorso_Gray_Swatch",
|
||||
"guid": "b995b419-1897-4c1d-98be-83d551f7ba71",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "White_Swatch",
|
||||
"guid": "724c79a3-822c-422f-9462-a5374ee0211c",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "2016_Member_swatch",
|
||||
"guid": "5864d23d-1a86-40a6-a52c-46ee670e4508",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "BeltDress_Green_Swatch",
|
||||
"guid": "5b58d879-2bc4-47ed-a996-1af2ace16425",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "SmallBrimHat_Mask",
|
||||
"guid": "65ed43ff-dfc4-4cab-b0b9-77dc94165e24",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "FootballHelmet_Orange_Swatch",
|
||||
"guid": "d8d490aa-7088-4163-9305-1441367f490c",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Flower_3_Mask",
|
||||
"guid": "27a5df72-4095-4837-bf24-cdd3d95a43e9",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "RedFlowerDress_Gray_Swatch",
|
||||
"guid": "1acb1f56-4509-449f-9c6a-065bdeaa9ee3",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Aviator_Jacket_Tan_Swatch",
|
||||
"guid": "bea795cc-aabd-4229-84dd-49ab4f91a445",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "FootballPads_Mask",
|
||||
"guid": "e17481fc-b2b6-47a5-91e5-7205f45a3247",
|
||||
"category": "feet"
|
||||
},
|
||||
{
|
||||
"name": "Tennis_Mask",
|
||||
"guid": "90e0da8b-1941-4ca8-b7e5-b4e31921873c",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Punk_WristPink_Swatch",
|
||||
"guid": "f3b2330a-b981-4c7e-902f-1f57382f2388",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "BeltDress_Black_Swatch",
|
||||
"guid": "d320ad9b-ba5c-45ea-b2b8-0d3e409a9db1",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "FighterPilot_Black_Swatch",
|
||||
"guid": "8c74ee27-3d56-401b-8a8c-7868a80770e8",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "TShirt_KO_Skull_Swatch",
|
||||
"guid": "381a9f13-5b44-48e6-8a49-221422a963f5",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "TShirt_Scifi_Face_BLue_Swatch",
|
||||
"guid": "bda7a57e-5227-49f4-a119-e3f166604738",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "YellowBlueDress_White_Swatch",
|
||||
"guid": "bbfa08e3-8e6b-4e0f-b264-1b398d7cd44a",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Green_Swatch",
|
||||
"guid": "f8b0cfe8-e129-4578-8bb5-f60af5d38599",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "TennisSkirt_Yellow_Swatch",
|
||||
"guid": "c5deba2a-6e35-4b13-8e94-8ba5457f39df",
|
||||
"category": "legs"
|
||||
},
|
||||
{
|
||||
"name": "Smuggler_Grey_Swatch",
|
||||
"guid": "90869e86-cbc5-4024-9d08-fcdc41c64eb5",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "ArcherBlack_Swatch",
|
||||
"guid": "9ad37173-e640-4b9e-a474-716d482b73d2",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Beekeeper_Shirt_Mask",
|
||||
"guid": "afd88a79-7f03-40f6-bcb4-c247dd86edc4",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "LaserTag_Cyan_Swatch",
|
||||
"guid": "08b7c12d-3317-4d27-9b40-34737a709454",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "BlazerDark_Swatch",
|
||||
"guid": "05ac07e1-67f0-486c-abf5-a62866475abb",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "DrumMajorTorso_Mask",
|
||||
"guid": "b0298c45-0dd1-453e-bad4-41e4656bb38e",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "TrackSuit_Pink_Swatch",
|
||||
"guid": "026ca50e-3a81-43cf-87f5-950687b7bbdd",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Golfer_Glove_Mask",
|
||||
"guid": "f4cea991-fc3d-4715-bf82-8a8fb60e8799",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Aviator_Hat_Tan_Swatch",
|
||||
"guid": "c6cf096c-f0cb-4500-80a0-bc2916b5a426",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "MobsterWrist_HerringBone_Mask",
|
||||
"guid": "c2a9c007-2748-4fa2-ab9b-0081eef792f1",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Baseball_Green_Swatch",
|
||||
"guid": "e5de2e45-207c-46af-9a5e-eb01a0c621fe",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "GreenFlower_Swatch",
|
||||
"guid": "d66aa400-aa5a-4539-a25d-5f8ce94dc281",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Ranger_Torso_Mask",
|
||||
"guid": "d21e1b6f-9c9e-42b4-bad5-201ec43161e9",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Dodgeball_Gray_Swatch",
|
||||
"guid": "0ba92db2-690a-44ce-92f4-130e9503b6c1",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Aviator_Gloves_Black_Swatch",
|
||||
"guid": "97bbb384-b37e-4ea1-902c-88fbd6854ab5",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "MobsterTorso_HerringBone_Mask",
|
||||
"guid": "33ee376a-586e-4aff-a7e4-4213445a3e92",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Birthday01_Swatch",
|
||||
"guid": "922f229c-124f-4f07-b4e3-19138420ca19",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Wizard_White_Swatch",
|
||||
"guid": "d3a9b576-5433-4305-bd96-b08820c09212",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "PurpleJacket_Mask",
|
||||
"guid": "3ba69a39-a4e7-4505-bae7-8db31360ec1c",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "Quest_Crown_Decal",
|
||||
"guid": "f5270130-6634-4052-aa3e-9849ddf5314e",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Lacross_Stripe_Mask",
|
||||
"guid": "da36bbcc-2a9a-4ba2-9e4a-6f52c9b1ef74",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Happy_Tree_Decal",
|
||||
"guid": "d461ca71-45c9-415e-8e09-ba93e8d73450",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Ranger_Shirt_Green_Swatch",
|
||||
"guid": "b415fe60-3e9d-4f4d-a53a-ca15eac6af7d",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "Helixx_swatch",
|
||||
"guid": "f8635fe2-90bc-42c8-9bbe-3387b5157e18",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Scifi_Carpet_Swatch",
|
||||
"guid": "0809a5cf-a0f3-4614-9f98-71518524518a",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Golfer_Hat_Mask",
|
||||
"guid": "ddf429fd-a883-48a5-869b-bc12e44d30bf",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Teal_Swatch",
|
||||
"guid": "90bc2d31-1715-4d1a-813a-7c57e66cb017",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "ElectricianTorso_Yellow_Swatch",
|
||||
"guid": "b539777f-48b2-44a2-9d63-17ac703e4d57",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "WitchHunterShirt_Mask",
|
||||
"guid": "0f49ac81-63bd-4845-8bdc-1944181a8aa3",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "Scallywag_Torso_Swatch_Blue",
|
||||
"guid": "85eb7f47-bb31-4c66-a8b3-562d35028e6c",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Charcoal_Swatch",
|
||||
"guid": "1b1d08f2-12ca-43dd-a44f-ea2820b919b4",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Paintball_Red_Swatch",
|
||||
"guid": "2913bd93-bf35-4bdf-b83a-d40a10213adc",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Jazzercise_Black_Swatch",
|
||||
"guid": "3b2cfc85-4e2a-4e0d-b738-c296ae8692f8",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "FieldHockey_Blue_Swatch",
|
||||
"guid": "7b0d6661-e856-4ec1-ab90-d89c28a70826",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "ArcherTan_Glove_Swatch",
|
||||
"guid": "d5987fee-e3cc-4336-853a-5df57f73df05",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "BicycleJacket_Black_Swatch",
|
||||
"guid": "83522c12-9549-4d74-8c87-bae210bcd2bf",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "Hat_FlapperHeadband_Mask",
|
||||
"guid": "d9be3a98-9da9-419e-9dce-fe58a3ad9c4e",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "TShirt_Scifi_Face_Pink_Swatch",
|
||||
"guid": "4d52bbd6-ef74-45ae-a6c2-bde10ab8eb16",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "FlowerSwimsuit_Green_Swatch",
|
||||
"guid": "cf515c87-3c0a-4443-9f63-5ea1bdbaa61a",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Beekeeper_Shirt_Gold_Swatch",
|
||||
"guid": "1919d319-6cce-4500-8766-15fed6a13fa8",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "Argyle_Brown_Swatch",
|
||||
"guid": "bf82f2f6-9af8-431e-a296-0890dea48ba7",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Paintball_Blue_Swatch",
|
||||
"guid": "178c6beb-c737-434c-a53b-d14f438f6a98",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Tshirt_KO_Skull_Decal",
|
||||
"guid": "9e782751-71c6-4208-87da-3a3cffa6a4f0",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "Torso_SeaCaptain_Mask",
|
||||
"guid": "8ec5de40-73fc-4f09-9bf3-ddf4701107bc",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "BasketballShirt_Purple_Swatch",
|
||||
"guid": "4effd67c-a52f-4b41-a5b0-04287f91a7bc",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "Purple_Swatch",
|
||||
"guid": "c72911d0-453f-4732-b1bd-dad520220a06",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Scout_Shirt_Mask",
|
||||
"guid": "5814a331-6155-4df4-b921-3ffc6059e44c",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "Angler_Blue_Swatch",
|
||||
"guid": "6e0f3af8-297f-4ea7-8f9e-4a1bc57d3e35",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Hat_CatEars_White_Swatch",
|
||||
"guid": "c1e430c5-fd8d-4032-9e3f-8d87cc8784da",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Smuggler_Dark_Swatch",
|
||||
"guid": "e821aa74-2d47-4388-bcfb-1893b8a83a52",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "ScoutSkirt_Shirt_Red_Swatch",
|
||||
"guid": "2bb65868-ee12-4871-b50d-64bbc9066f0b",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "Artist_Blue_Swatch",
|
||||
"guid": "8c94e45c-6605-4b4f-9ba4-2c6c6e557228",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Knight_Black_Swatch",
|
||||
"guid": "e1f49b74-b071-4bd1-9c4b-af36d24d45c5",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Hat_CatEars_Gold_Swatch",
|
||||
"guid": "37f8378b-b98c-477a-b8c9-9340772800b5",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "TShirt_KO_Skull_Pink_Swatch",
|
||||
"guid": "fe304452-b57b-45bc-9c1c-b85b70bcec12",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "BeltDress_Yellow_Swatch",
|
||||
"guid": "d61711fd-589a-4669-b991-9408a58fffd9",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "ArcherYellow_Glove_Swatch",
|
||||
"guid": "47da86b9-4e6e-423c-b8c4-ea6bf8472509",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "PirateCaptain_Belt_Mask",
|
||||
"guid": "9b2102f0-e16b-464f-9f1c-f068de52bb89",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Luchador_Torso_Mask",
|
||||
"guid": "7ef7d0cf-99f1-4872-9d3d-8230cc9fa368",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "HockeyShirt_Red_Swatch",
|
||||
"guid": "b1ea158d-1663-4db1-bb09-9847f6e9d1e6",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "YellowBlueDress_Purple_Swatch",
|
||||
"guid": "830be2fa-60a5-48cc-931f-34b670eae4bd",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Electrician_Torso_Mask",
|
||||
"guid": "daa38a31-fb7b-4e26-a2f5-728d6dcec81a",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Torso_Cowboy_Mask",
|
||||
"guid": "98553538-cafd-4df9-8f37-bb0a4bb478a5",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Firefighter_Hat_Yellow_Swatch",
|
||||
"guid": "4c26d1e7-2382-4478-b9c4-a068ed01a607",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Aviator_Goggles_Mask",
|
||||
"guid": "556f876a-70da-4104-b792-fca8ad67be0c",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Scallywag_Bracelet_Red_Swatch",
|
||||
"guid": "62bd5dda-08da-4528-83c1-f0ca3812dc6e",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Hat_Hockey_Mask",
|
||||
"guid": "7c4d447c-6594-4bd8-9510-12ad683ab116",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "DrumMajorGlove_Mask",
|
||||
"guid": "6b38ab79-142b-446e-978c-ad829ade8823",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Hat_Cowboy_Mask",
|
||||
"guid": "54778d93-2cff-48db-b25b-65c08b0e5be8",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Scout_RaccoonHat_Gray_Swatch",
|
||||
"guid": "926ae943-76cb-46dd-9c66-a6ee44ea9194",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Scallywag_Hat_Mask",
|
||||
"guid": "a4903da3-249d-4f0a-a746-b547fda371ff",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Denim_Mask",
|
||||
"guid": "f600037d-c9c0-43fa-b45b-02f456f9dd5f",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "DrumMajor_Orange_Swatch",
|
||||
"guid": "82de1ca3-67d6-454d-84fb-0eeece71fcbc",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "LaserTag_Wrist_Mask",
|
||||
"guid": "3b825377-d2eb-41e4-a736-b107f88f62d6",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "PurpleJacket_Blue_Swatch",
|
||||
"guid": "b42d903b-b393-4f49-af5e-38d0fb6c42b0",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "Angler_Tan_Swatch",
|
||||
"guid": "cac27853-e2df-4d77-b3fd-af3bc0813f01",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "MobsterWrist_Fashion_Gold_Mask",
|
||||
"guid": "05cff8b8-d437-485a-b4b8-41d35becd022",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Scout_Sash_Brown_Swatch",
|
||||
"guid": "639f5e2c-6fbd-4ab4-aa10-7772e0932798",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Torso_SeaCaptainBlueWhite_Swatch",
|
||||
"guid": "857fdcd8-704f-43d0-92b9-bca26619b153",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Scallywag_Torso_Stripped_Mask",
|
||||
"guid": "9f1dd474-34a3-47eb-bb72-dbfc8d2d6ecf",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Zebra_Mask",
|
||||
"guid": "b78008e8-abbd-4ece-be34-9a911f721fcc",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Smuggler_Cherry_Swatch",
|
||||
"guid": "fed760b2-15e2-46b2-b1e3-cc3c8d780d5d",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Beekeeper_Hat_Mask",
|
||||
"guid": "e4b53a9a-ac95-49ae-bf68-615bb23fa075",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "HeadBand_Royal_Mask",
|
||||
"guid": "56a92c8d-af53-413e-929e-4a9a3cfad780",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "AnglerHat_Gray_Swatch",
|
||||
"guid": "225209dc-3afc-40cf-858e-89f7afa00c0d",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "BaseballHelmet_Green_Swatch",
|
||||
"guid": "9967ce54-c2b7-437a-946e-11f8ee6d6fdd",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Glasses_Smuggler_Mask",
|
||||
"guid": "fe01b6ed-3c36-47b6-bcfa-47864ef9d610",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Scallywag_Bracelet_Blue_Swatch",
|
||||
"guid": "cdca593a-8840-4140-9145-fe962732040c",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Wrist_Smuggler_Mask",
|
||||
"guid": "8ffce0d6-d03e-4097-bc46-09b8894bc1d3",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "CowboyDark_Swatch",
|
||||
"guid": "192ba73d-6990-42da-8fe0-914c2a7181eb",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "BikeHelmet_Mask",
|
||||
"guid": "5fd9e83a-cfaf-4c98-bd31-91a7484c26dd",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Torso_ButtonTop_Mask",
|
||||
"guid": "dafa658e-753b-46cb-bd85-85c1de5e6ea7",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "FlowerSwimsuit_Pink_Swatch",
|
||||
"guid": "27680277-aec1-41be-a476-9f51cf775580",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Artist_Red_Swatch",
|
||||
"guid": "17b16982-871c-476a-860f-f6953c89ee8c",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "2016_Member_Decal",
|
||||
"guid": "167ba0d4-4fac-4143-b5ae-1dbd8e02dc76",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Scout_Sash_Red_Swatch",
|
||||
"guid": "b520f3bc-599a-498c-8a4f-97cc25aa741f",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Glove_Safari_Mask",
|
||||
"guid": "fa9a3d8e-16c9-4a7e-9166-3226e0d13c39",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "DrumMajor_Green_Swatch",
|
||||
"guid": "fe5288bc-0e02-4ea3-b17d-dee0e576979d",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "CheerDress_Blue_Swatch",
|
||||
"guid": "faedf215-289b-40f7-90cc-f5b98517d133",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "SpaceMarine_Cyan_Swatch",
|
||||
"guid": "c8cc9589-4831-4e73-a865-ef8c139a2ba7",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Denim_Swatch",
|
||||
"guid": "55901f12-d5b5-4fa8-b4c8-e479689ee39d",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "FootballPads_Orange_Swatch",
|
||||
"guid": "32dde6dc-e3dc-43ee-9b7c-987bc6778c17",
|
||||
"category": "feet"
|
||||
},
|
||||
{
|
||||
"name": "SFVRCC_swatch",
|
||||
"guid": "14afd295-bcd0-4595-80dc-d477618b9ab9",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "BikeJersey_Mask",
|
||||
"guid": "1695608b-e9cc-4a03-b56d-0f09d2804379",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Torso_SeaCaptainBlueDark2_Swatch",
|
||||
"guid": "3df5d13b-ba77-4b51-90b2-7a946e4d0be7",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "PirateCaptain_Hat_Red_Swatch",
|
||||
"guid": "17040a88-87f1-4613-b439-3316e33dbd48",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "CollarDress_Pink_Swatch",
|
||||
"guid": "6564acf1-4d70-4f92-92ac-08e2b76dbb6b",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Torso_SeaCaptainDark_Swatch",
|
||||
"guid": "b9f51861-ad10-4878-a9b1-d849bccf532a",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "PurpleJacket_Black_Swatch",
|
||||
"guid": "8cab8cc6-9a2d-434c-8b72-e66edbdd223c",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "Hat_SeaCaptainFushia_Swatch",
|
||||
"guid": "2738ab5f-8c94-46b3-bac6-4a8111c41c21",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Luchador_Red_Swatch",
|
||||
"guid": "916384ca-e209-42a0-bd64-c64f5a40b56f",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "FlapperGlove_Gold_Swatch",
|
||||
"guid": "2cf2b644-3fa6-449c-9fe8-d0ab917f3106",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "BlueJacket_Mint_Swatch",
|
||||
"guid": "cd5d7285-202d-42d0-b93f-04245875793e",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "FootballPads_Dark_Swatch",
|
||||
"guid": "88c3ed05-ce41-4a9d-a4a7-8a428d240b3f",
|
||||
"category": "feet"
|
||||
},
|
||||
{
|
||||
"name": "Pink_Swatch",
|
||||
"guid": "cbe29e9f-f2ac-47fb-97e1-8bad16abb89d",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Aviator_Hat_Black_Swatch",
|
||||
"guid": "a8de80d3-286a-4fdc-bed2-75d52f8c0964",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Aviator_Goggles_Black_Swatch",
|
||||
"guid": "7b82c3c5-fd1f-45ec-b83f-e32668aa8dce",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Mobster_Fashion_Gold_Swatch",
|
||||
"guid": "46970903-9799-4d25-b90a-7162c1f5dbef",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Golfer_Shirt_Grey_Swatch",
|
||||
"guid": "4c845dbb-26c3-48a1-b562-e28a7416b154",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "Royal_Swatch",
|
||||
"guid": "6dd95046-acf8-42fe-ab78-80a334096a9d",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "GoldYellow_Swatch",
|
||||
"guid": "67bcca75-4ab1-4964-8688-9908c464d355",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Hat_SeaCaptainDarkGold_Swatch",
|
||||
"guid": "f5403c89-9769-479b-8a05-c71607f9b189",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "LaserTag_Torso_Mask",
|
||||
"guid": "959ed05b-0215-4bbe-bb3d-64e4448d676b",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "DrumMajor_Purple_Swatch",
|
||||
"guid": "54d3c589-30ba-44c1-a77c-8f9e16eb0b20",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Hat_TopHat_Mask",
|
||||
"guid": "ccf1ccc1-e229-4157-bb74-f2cdef01e547",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "PirateCaptain_Belt_Red_Swatch",
|
||||
"guid": "0f71b9a2-dd88-435c-a571-4503d12dcf2d",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "ArcherBlack_Glove_Swatch",
|
||||
"guid": "2be2f040-68e4-44dd-9099-29f11110f3a4",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Barbershop_Hat_Mask",
|
||||
"guid": "83158223-e268-4036-8a6a-218a8430eb2c",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Wizard_Torso_Mask",
|
||||
"guid": "8768aa33-b014-4062-b323-b146dd7d78d2",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "JerseyOutline_Mask",
|
||||
"guid": "d2a692e6-e1a9-4cfe-8154-10b52be7f8c8",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Hat_HairBow_Mask",
|
||||
"guid": "e0186718-4a18-434b-b96e-0c9c912f0d1f",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Basketball_Shirt_Mask",
|
||||
"guid": "54a5c055-f757-4c00-a1e1-8b0b6552c608",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "Equestrian_Jacket_Mask",
|
||||
"guid": "d344b8cc-85a8-4ace-9f92-38c84f396e99",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "Barber_Torso_Green_Swatch",
|
||||
"guid": "c64ac7a9-7fd4-4587-8626-0413a190b706",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "FighterPilot_Blue_Swatch",
|
||||
"guid": "e37b07d1-6b9d-49b9-94ca-1c728e228cfe",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "MobsterTorso_Fashion_Gold_Mask",
|
||||
"guid": "c2052d8c-fbcd-4462-8f08-bcf5b3dfde2f",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "AnglerHat_Tan_Swatch",
|
||||
"guid": "3f6c8bd2-2c1d-4c8c-a9de-16600fee9645",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "CheerDress_Red_Swatch",
|
||||
"guid": "1773d5d8-4714-4721-b30c-97e25d6f2a5a",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "FlatCap_Hat_Mask",
|
||||
"guid": "73fc2e2a-a036-410b-bafa-3a07658245b5",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Golfer_Glove_Blue_Swatch",
|
||||
"guid": "32a5e42d-2b60-40b1-a145-ed96fc91af8e",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "TShirt_RECS_Logo_Blue_Swatch",
|
||||
"guid": "bde08851-a9e4-4faa-8f04-a0a661672472",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "Scout_Shirt_Blue_Swatch",
|
||||
"guid": "0d2830e7-8eb0-4fa3-99bc-7c80f01dd991",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "DrumMajorGlove_Purple_Swatch",
|
||||
"guid": "8053b5e5-0f67-4329-a45d-1ee9fc830820",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Shirt_SpaceMarine_Mask",
|
||||
"guid": "7ac81d60-05b8-4a85-982c-f69213a93818",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "SFVRCC_Decal",
|
||||
"guid": "a74e6c0d-1300-4928-9141-977a711b71c4",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "BlueJacket_Torso_Mask",
|
||||
"guid": "0f36bb97-c61b-4281-929f-ff1d0d11be86",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "Wizard_Hat_Mask",
|
||||
"guid": "abdf525b-b871-41be-a1c8-810f49740ad4",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Wrist_SpaceMarine_Mask",
|
||||
"guid": "7634b7ef-9607-497a-b41f-c0191dc75998",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "ElectricianTorso_Green_Swatch",
|
||||
"guid": "67fc9269-8dd8-4d6f-b594-c77e716f2482",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "TrackSuit_Mask",
|
||||
"guid": "adae82eb-a4b9-4541-acf2-76cea839a593",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Tshirt_HangInThere_Decal",
|
||||
"guid": "8f19d7f9-4f28-48ab-a1c5-d8f4f788514c",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "DrumMajorGlove_Orange_Swatch",
|
||||
"guid": "b444ed0a-eab5-4bd6-af34-d080de74a149",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Punk_WristRed_Swatch",
|
||||
"guid": "baffdefe-de21-4551-9330-b50873965bdd",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "PirateCaptain_Wrist_Red_Mask",
|
||||
"guid": "7a7bc314-4ffd-4ac8-9ed6-6ca73589c132",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Punk_Green_Swatch",
|
||||
"guid": "0724b166-9ace-46ff-a191-b13f135b00a8",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "ArcherRed_Glove_Swatch",
|
||||
"guid": "0c433086-9501-48c4-8d0e-4474eb420c61",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Tshirt_KO_Skull_Pink_Decal",
|
||||
"guid": "6a007c73-d930-408a-93df-041a715e0dd4",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "Wrist_Knight_Gauntlet_Mask",
|
||||
"guid": "fd67ec40-f898-4df6-b846-8bf350f362b8",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Lacrosse_Stripe_Purple_Swatch",
|
||||
"guid": "e3454bc7-c88d-4958-8b81-db3fe5472a1e",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "SciFi_CarpetTie_Mask",
|
||||
"guid": "8212812b-e7e7-4f6d-aa27-d1112af45473",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "PirateCaptain_Torso_Mask",
|
||||
"guid": "52053afd-9f12-4fec-a358-7eb3fe8c19bb",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Scallywag_Bracer_Mask",
|
||||
"guid": "ce3782aa-56cc-40d7-9019-8ce714cb7748",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "CheerDress_Mask",
|
||||
"guid": "93987d32-7a6e-45df-af56-76f912969ce7",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "TShirt_RECS_Logo_Green_Swatch",
|
||||
"guid": "5e7a48ed-8f08-4990-a3ae-05722c9f59a8",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "Wrist_Cowboy_Mask",
|
||||
"guid": "8eef8837-9141-4088-835a-b2f47f4126f8",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "HorizontalStripe3_Mask",
|
||||
"guid": "9c03f381-7357-4d0f-8cda-8737d4c43d25",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "PirateCaptain_Torso_Striped_Mask",
|
||||
"guid": "00ac4e37-6eac-4ed5-b46c-2c075038bc3f",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Wizard_Green_Swatch",
|
||||
"guid": "357eb160-360b-4a63-840d-65d11cc8ffc2",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Angler_Gray_Swatch",
|
||||
"guid": "97938f4c-52b8-4c85-8575-856654666316",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "FootballHelmet_Dark_Swatch",
|
||||
"guid": "61ff7a02-50ff-49ea-b95e-c31b95a30c8e",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Torso_BabydollDress_Mask",
|
||||
"guid": "cb9e9e05-c481-4397-86e7-c2111bc0e817",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "LaserTagVisor_Cyan_Swatch",
|
||||
"guid": "426d0592-f8e4-4bc6-9fe1-a62b91fd57d5",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Torso_SeaCaptainWhiteDark_Swatch",
|
||||
"guid": "b5d62931-e756-4a8a-8f3b-760beba49319",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Wrist_FlapperGlove_Mask",
|
||||
"guid": "0e42108e-3b08-49b4-86c0-7984719e8380",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "LightBlue_Swatch",
|
||||
"guid": "484b6c13-af22-4ad5-8c43-34c0de095d49",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Aviator_Gloves_Mask",
|
||||
"guid": "5659ce2c-9cb0-49da-8c39-4b7df0f8deec",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Hat_SeaCaptain_Mask",
|
||||
"guid": "a4e51b6b-fdfd-47dc-9d0e-f26f383e03e9",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "CowboyLight_Swatch",
|
||||
"guid": "5e00a832-3f25-4dd3-84d2-b6ed6a4b4c37",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Happy_Tree_Swatch",
|
||||
"guid": "ba6b6e1a-a09a-4ba0-9523-552869f03336",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Smuggler_Yellow_Swatch",
|
||||
"guid": "002b07bb-4256-44ce-8ca4-25510e70b6b5",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "BlazerMidnightBlue_Swatch",
|
||||
"guid": "6f2e74bf-1e95-463d-97db-d5d1a53b2c28",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "BicycleJacket_Blue_Swatch",
|
||||
"guid": "c5884778-a87f-4612-9717-86fbb65d440f",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "Mobster_WhiteHatHacker_Swatch",
|
||||
"guid": "40283127-2ffc-4989-82f6-29c3381bf9e2",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Torso_SeaCaptainBlackDark_Swatch",
|
||||
"guid": "6145292a-9002-41c6-8cd5-43679b6f542f",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Mobster_Hat_Gray_Swatch",
|
||||
"guid": "390a476a-5545-48eb-955c-1bf1a16012bf",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "SpaceMarine_Light_Swatch",
|
||||
"guid": "68273c9e-96d6-4ddb-aaab-d99229e864d5",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Shirt_Punk_Mask",
|
||||
"guid": "d738ad4c-c9b5-41e6-8979-d586c964fb6c",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "Aviator_Jacket_Black_Swatch",
|
||||
"guid": "da185fbb-ad2b-4f30-87a2-491f24b78ebb",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "Scifi_Carpet_TopHat_Swatch",
|
||||
"guid": "bd4a84e2-b67a-4269-a26a-17fb23ddb09e",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Torso_Jazzercise_Mask",
|
||||
"guid": "f6f26e2b-657b-454a-8663-55d6b9b6e50c",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "RedFlowerDress_Yellow_Swatch",
|
||||
"guid": "e98c3f98-7844-4d6e-a21c-05027033c18c",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Eye_MirroredGlasses_Mask",
|
||||
"guid": "9c55b609-b7dc-4070-a3ad-6351a0054a06",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Plaid_Red_Swatch",
|
||||
"guid": "827a1538-51bb-4fef-99c1-7f1bebd9866c",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Scout_Sash_Mask",
|
||||
"guid": "66cc536d-8cb5-4262-b7f0-49a33b97ea10",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "ArcherGlove_Mask",
|
||||
"guid": "7b187c06-7ba2-4f3c-bca9-fdf98146f385",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Wizard_Black_Swatch",
|
||||
"guid": "7afe1bb0-5ca9-4263-8f85-49d3a18353c7",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Wrist_CowboyLight_Swatch",
|
||||
"guid": "c0c33a35-494c-4a1a-aa53-d27d9b9ef5a4",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "FlowerSwimsuit_Gray_Swatch",
|
||||
"guid": "5a96ac4d-03c3-4214-9dcb-c2044ff28f2e",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "SafariTorso_Mask",
|
||||
"guid": "84c016ad-133f-45e3-a412-cac35612540b",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "BabydollDress_Pink_Swatch",
|
||||
"guid": "da6d0ced-3d43-4878-a868-925f2ed6fd5b",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Barber_Wrist_Formal_Swatch",
|
||||
"guid": "bb01b51e-a95f-441e-8c52-abc3aeed7145",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "PirateCaptain_Red_Swatch",
|
||||
"guid": "556141f7-6fbc-4065-9faa-8d8240a93d7f",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "FighterPilot_Mask",
|
||||
"guid": "435eba0d-d8f9-43cc-91aa-2959d63c6fa7",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Luchador_Blue_Swatch",
|
||||
"guid": "0217fd2e-ff9d-49f7-9bc8-8d0d6b8bf250",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Jazzercise_Yellow_Swatch",
|
||||
"guid": "78eb0969-f246-4cac-acd6-295df7c092e4",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "RecRoom_FACE_DEFAULT_Decal",
|
||||
"guid": "0c496f32-0011-4c4d-9778-59446f70c032",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "HockeyShirt_Mask",
|
||||
"guid": "e5635772-4e84-4b30-b77f-4a1196cb599b",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "2016Member_Mask",
|
||||
"guid": "2ee3944d-e9fb-4959-973e-570a7fc6cc57",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Tshirt_RECS_Logo_Decal",
|
||||
"guid": "237e0aa2-5911-4704-8d2a-d446ddd2d842",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "Barbershop_Wrist_Mask",
|
||||
"guid": "f7c7d05f-5454-445a-af38-25f110bd204a",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "VerticalStripe_Mask",
|
||||
"guid": "c2a91a10-2f5b-4ab0-a79f-51408cf4b047",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Scallywag_Torso_Mask",
|
||||
"guid": "005699fe-2c69-4bec-831f-031fe8ad7f0a",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Golfer_Glove_Grey_Swatch",
|
||||
"guid": "72a010c0-bddd-4e5d-bca6-9821d82de9a6",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "StollDress_Green_Swatch",
|
||||
"guid": "a819f49b-6c7a-49d3-9e6a-d9d79ef5019f",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Torso_SeaCaptainBlueDark_Swatch",
|
||||
"guid": "7c1aaa7e-503b-46ef-b1c5-0c61a75b916e",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "BlazerSeaDark_Swatch",
|
||||
"guid": "0ffad843-d6c9-425a-8686-7217009c867e",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Torso_SeaCaptainBlue_Swatch",
|
||||
"guid": "27af51bc-8226-4911-8d47-22d28ea8e378",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Helixx_Decal",
|
||||
"guid": "49934059-cc45-46ce-8277-f96959e1f6ba",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "HibiscusFlower_Mask",
|
||||
"guid": "65b89eae-347e-4eff-9ff3-7f25cace0125",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "HeadBand_Trim_Mask",
|
||||
"guid": "018a5c07-e956-457d-a540-a5e2cd68da09",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "HockeyShirt_Teal_Swatch",
|
||||
"guid": "fcbdfbfd-254a-4538-b119-43e23404b8b5",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "Orange_Swatch",
|
||||
"guid": "51ef8d39-2b94-4f9e-9620-07b6b0a913a5",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Shirt_Smuggler_Mask",
|
||||
"guid": "970a8c7e-d091-4719-bb9c-e3be8d46ee68",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "LaserTag_Head_Mask",
|
||||
"guid": "4e378419-d043-4e86-ad0e-66288ac21cf4",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "ArcherTan_Quiver_Swatch",
|
||||
"guid": "d1eb3573-672c-4bb4-9ec5-7c81e6a38d3d",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Barber_Hat_Green_Swatch",
|
||||
"guid": "7f9cb939-36a4-40da-8337-025e1d7bf8e5",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Punk_WristGreen_Swatch",
|
||||
"guid": "a6796264-9c7e-4605-830c-06db8d0dc780",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "FieldHockey_Mask",
|
||||
"guid": "1fede91a-434e-49a5-882e-e6db107112a8",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Firefighter_Hat_White_Swatch",
|
||||
"guid": "891d902e-3257-4a8c-9001-858046007997",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Scallywag_Hat_Red_Swatch",
|
||||
"guid": "c3c9f89c-580c-43c4-b38b-07394044e0e1",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "SpaceMarine_Dark_Swatch",
|
||||
"guid": "a089bcc6-798d-4777-98e2-7afd290dc6b6",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "PirateCaptain_Hat_Black_Mask",
|
||||
"guid": "4cc0ea9f-65af-486f-8319-02b85ab5197f",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "DrumMajorHat_Green_Swatch",
|
||||
"guid": "5a614f97-ef7f-4b70-afff-9ed837a86407",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Golfer_Hat_Blue_Swatch",
|
||||
"guid": "6584dada-499e-4d7c-958d-466955b20640",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "RecRoom_Birthday01_Decal",
|
||||
"guid": "ceb07e4f-50a9-4ed0-b50b-c59d92ba66b5",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Black_Swatch",
|
||||
"guid": "e69372eb-2fd8-4e17-a448-ee0be61a2c7a",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "ArcherRed_Swatch",
|
||||
"guid": "5b5281c9-b795-4bb2-ba7b-ba52047ebe3f",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "CollarDress_LightBlue_Swatch",
|
||||
"guid": "f750de46-3758-4f7d-9709-0a84b1027009",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "StollDress_Blue_Swatch",
|
||||
"guid": "761a3193-60f0-4190-80c7-285b8192e794",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Torso_YellowBlueDress_Mask",
|
||||
"guid": "cfabdefe-0890-436e-b2a3-b5c712e22955",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Boxer_Glove_Mask",
|
||||
"guid": "f79f8a46-ef1d-4d8c-a4fc-383e3a9eb10b",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Torso_RedBeltDress_Mask",
|
||||
"guid": "3d971439-41d1-43a2-8434-704f9ec8d906",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Argyle_Red_Swatch",
|
||||
"guid": "071d1bf3-86dc-4a31-b54a-e6579fab8649",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "WitchHunter_White_Swatch",
|
||||
"guid": "e02838f8-4029-455a-b35c-dd40f972b05b",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "RedFlowerDress_Mask",
|
||||
"guid": "2d7361d2-31a2-404b-90da-10e89114e1f2",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "TShirt_LaserTag_Alpha_Swatch",
|
||||
"guid": "c0ff7719-c56a-4934-831b-506ad0f51cca",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "Wrist_Punk_Mask",
|
||||
"guid": "dd7472ed-bdcb-4811-81ba-5ed682fb7675",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Angler_Hat_Mask",
|
||||
"guid": "efeb07ab-6253-436d-bb66-991ddad72e58",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "ArcherHat_Mask",
|
||||
"guid": "1ba65dd5-9df9-4ff3-be96-f83a7abf67b3",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "ArcherRed_Quiver_Swatch",
|
||||
"guid": "7221132e-053a-4c58-b719-ed3c8558907d",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Luchador_Head_Mask",
|
||||
"guid": "96b36c98-cba1-4337-91dd-c74c00316f97",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Tennis_Pink_Swatch",
|
||||
"guid": "304e5cf1-5c94-481f-8e49-e6a943e6b300",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "PoofyDress_Orange_Swatch",
|
||||
"guid": "64850553-cdfe-455a-ac00-dafbe63d613e",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "ElectricianTorso_Beige_Swatch",
|
||||
"guid": "5fb2e235-8c67-4335-b432-edb10db2b139",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "WitchHunterGlove_Mask",
|
||||
"guid": "5b8d9490-e5bc-480e-91bc-65d1797b52ad",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Knight_White_Swatch",
|
||||
"guid": "22dc463a-a89b-46ad-9a0d-557c742b4a80",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Mobster_Hat_Mask",
|
||||
"guid": "d759c88d-a159-4c26-86dd-b054bb05b3ed",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "BicycleHelmet_Yellow_Swatch",
|
||||
"guid": "4398ce1a-e6ee-4da4-ad0d-7abfab41020c",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Golfer_Hat_Grey_Swatch",
|
||||
"guid": "48c18418-01dd-40ff-9dfe-c4cf5f4e1245",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "BasketballShirt_Blue_Swatch",
|
||||
"guid": "59a62fa3-9e15-463e-9bd5-3aecdf604c1b",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "FurCoat_White_Swatch",
|
||||
"guid": "643b5f2d-0666-4869-b699-03742de34d16",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Wrist_CowboyDark_Swatch",
|
||||
"guid": "c4ebfd1a-fcda-4b98-a151-a941b1801867",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Hat_SeaCaptainDarkSilver_Swatch",
|
||||
"guid": "36e63797-5a42-4779-a5cc-ef5c2e7d17d4",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "HockeyShirt_Purple_Swatch",
|
||||
"guid": "d5efaf80-7f34-4c9a-bc3a-b80b1ac70ace",
|
||||
"category": "torso"
|
||||
},
|
||||
{
|
||||
"name": "ArcherYellow_Quiver_Swatch",
|
||||
"guid": "e548124c-d7f3-45de-aaa0-f66130eca576",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "ArcherTan_Swatch",
|
||||
"guid": "9b35ae52-febe-486a-8557-ec7190a9756e",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Paintball_Torso_Mask",
|
||||
"guid": "0189ec4c-0389-4ebc-b9ba-32303a6341c2",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Boxer_Helmet_Mask",
|
||||
"guid": "92714eac-cc07-4f74-a6f5-cfbbadd07e06",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "FighterPilot_Hat_Mask",
|
||||
"guid": "9d6ac0b7-bbef-40bc-9173-effe65d7c0ff",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "WitchHunter_Red_Swatch",
|
||||
"guid": "909ed249-ce09-4304-8b02-56794fa7567d",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "Dodgeball_Black_Swatch",
|
||||
"guid": "4a85c181-92fe-47a5-925e-05f0ccb25006",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "BlazerGrey_Swatch",
|
||||
"guid": "272fe8eb-5061-4729-a7a8-414ff667a82f",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "TennisSkirt_Red_Swatch",
|
||||
"guid": "758752bd-db2f-43d2-b580-55b3e1efffd5",
|
||||
"category": "legs"
|
||||
},
|
||||
{
|
||||
"name": "Hat_Equestrian_Mask",
|
||||
"guid": "be6b3fa1-3388-48ac-8957-d7b8c85ff968",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Wizard_Red_Swatch",
|
||||
"guid": "a38254c0-00e3-429b-9d5d-b9e6a9812e69",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "FighterPilot_Gloves_Blue_Swatch",
|
||||
"guid": "55b4e661-43e1-4708-82d5-2dd2bebd4f45",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "WitchHunterHat_Mask",
|
||||
"guid": "32d91d32-b102-4093-927a-6dc3ac2e9e86",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Stripe3_Swatch",
|
||||
"guid": "5c4a2b35-0e1c-44de-8c3a-96d4a6458b1b",
|
||||
"category": "accessory"
|
||||
},
|
||||
{
|
||||
"name": "ArtistHat_Blue_Swatch",
|
||||
"guid": "14b43bf9-5ba0-484e-ae5d-55cfeb09a70d",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "ArcherQuiver_Mask",
|
||||
"guid": "6094370d-5e28-473a-b422-f3f1c75d5db8",
|
||||
"category": "face"
|
||||
},
|
||||
{
|
||||
"name": "Scout_Hat_Mask",
|
||||
"guid": "464fcf20-361f-4dc9-b074-150c3bc27523",
|
||||
"category": "head"
|
||||
},
|
||||
{
|
||||
"name": "Ranger_Hat_Green_Swatch",
|
||||
"guid": "d0bb468c-b78f-4e80-916d-65fec3ec0010",
|
||||
"category": "head"
|
||||
}
|
||||
]
|
||||