using System.ComponentModel.DataAnnotations; namespace DorkNet.Server.Data.Entities; /// /// 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 /// storage.rec.net/upload with FileType=Invention (5). /// public class InventionEntity { public long Id { get; set; } public long CreatorPlayerId { get; set; } /// Stable opaque GUID the client uses to deduplicate /// instantiated inventions across rooms (matches /// Invention.ReplicationId). Generated server-side at /// create time. [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; /// Legacy permission column (private=0/friends=1/public=2) /// — kept for backward-compat with existing rows; new logic uses /// + /// (InventionPermission enum: Unassigned=0, LimitedOneUseOnly=10, /// UseOnly=20, EditAndSave=40, Publish=60, Charge=80, /// Unlimited=100). public int Permission { get; set; } = 0; /// InventionPermission value the creator gets when /// spawning their own creation (default Unlimited=100). public int CreatorPermission { get; set; } = 100; /// InventionPermission value other players get when /// spawning. Defaults Unassigned=0 (private). public int GeneralPermission { get; set; } = 0; /// True once POST api/inventions/v2/publish sets /// a non-Unassigned . Stays true /// across re-edits — the wire field tracks "has this ever been /// published". public bool IsPublished { get; set; } = false; /// 1-based latest version index. Bumped each time /// POST api/inventions/v3/addversion uploads new bytes. /// Mirrors Invention.CurrentVersionNumber. public int CurrentVersionNumber { get; set; } = 1; /// Set on first publish. Null until then. public DateTime? FirstPublishedAt { get; set; } /// If the creator was in a room when first saving, /// the originating room id for analytics. public long? CreationRoomId { get; set; } /// How many distinct players have spawned this /// invention in any room (rolling counter — increments on /// download). public int NumPlayersHaveUsedInRoom { get; set; } = 0; /// True for AG (community-built) inventions, false for /// "Rec Room Original" / staff-baked ones. public bool IsAgInvention { get; set; } = true; /// Most recent uploaded blob name. Format /// invention__v.dat; the cdn catch-all serves the /// matching bytes. [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; /// 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. public bool IsDeleted { get; set; } = false; public DateTime CreatedAt { get; set; } = DateTime.UtcNow; public DateTime UpdatedAt { get; set; } = DateTime.UtcNow; }