namespace BlueLaminate.EFCore.Entities; /// /// One physical CS2 item, identified by its fingerprint /// (Skin + FloatValue + PaintSeed + StatTrak + Souvenir) rather than its Steam /// asset id, which changes on every trade. Decoupled from Steam inventories on /// purpose: an instance exists from market observation alone, and the optional /// bridge ties it to a SteamUser only once we /// crawl inventories. /// /// Duping note: a duplicated item is a byte-for-byte copy with an identical /// fingerprint, so a fingerprint is NOT guaranteed unique to one physical item. /// We treat the fingerprint as the item, and flag /// when the same fingerprint is seen live under two or more different asset ids /// at once (see the sweep's dupe detection). /// public class SkinInstance { public int Id { get; set; } public int SkinId { get; set; } public Skin Skin { get; set; } = null!; // Nullable: market observation gives a float but not a derived wear bucket. // Condition can be backfilled later from the float without blocking ingest. public int? ConditionId { get; set; } public SkinCondition? Condition { get; set; } // The fingerprint. FloatValue is stored at full precision (see config) so // that exact-match dupe detection isn't fooled by rounding. An instance is // only created for items that have a float + paint seed (skins), so both are // non-null here even though some listings (e.g. vanilla knives) lack them. public decimal FloatValue { get; set; } public int PaintSeed { get; set; } public bool StatTrak { get; set; } public bool Souvenir { get; set; } public DateTimeOffset FirstSeenAt { get; set; } public DateTimeOffset LastSeenAt { get; set; } /// /// True once this fingerprint was observed live under 2+ distinct asset ids /// simultaneously — the signature of duplication. /// public bool SuspectedDupe { get; set; } /// When the dupe condition was first detected. Null until then. public DateTimeOffset? DupeFirstSeenAt { get; set; } /// Every market listing observed for this physical item over time. public ICollection Listings { get; set; } = new List(); public ICollection InventoryItems { get; set; } = new List(); }