huge commit for advanced stats feature.
broke data out into its own library. may be breaking changes with existing plugins
This commit is contained in:
23
Data/Models/Client/EFACSnapshotVector3.cs
Normal file
23
Data/Models/Client/EFACSnapshotVector3.cs
Normal file
@ -0,0 +1,23 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Numerics;
|
||||
using Data.Models.Client.Stats;
|
||||
|
||||
namespace Data.Models.Client
|
||||
{
|
||||
public class EFACSnapshotVector3 : SharedEntity
|
||||
{
|
||||
[Key]
|
||||
public int ACSnapshotVector3Id { get; set; }
|
||||
|
||||
public int SnapshotId { get; set; }
|
||||
|
||||
[ForeignKey("SnapshotId")]
|
||||
public EFACSnapshot Snapshot { get; set; }
|
||||
|
||||
public int Vector3Id { get; set; }
|
||||
|
||||
[ForeignKey("Vector3Id")]
|
||||
public Vector3 Vector { get; set;}
|
||||
}
|
||||
}
|
86
Data/Models/Client/EFClient.cs
Normal file
86
Data/Models/Client/EFClient.cs
Normal file
@ -0,0 +1,86 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Data.Models.Client
|
||||
{
|
||||
public class EFClient : SharedEntity
|
||||
{
|
||||
public enum Permission
|
||||
{
|
||||
/// <summary>
|
||||
/// client has been banned
|
||||
/// </summary>
|
||||
Banned = -1,
|
||||
/// <summary>
|
||||
/// default client state upon first connect
|
||||
/// </summary>
|
||||
User = 0,
|
||||
/// <summary>
|
||||
/// client has been flagged
|
||||
/// </summary>
|
||||
Flagged = 1,
|
||||
/// <summary>
|
||||
/// client is trusted
|
||||
/// </summary>
|
||||
Trusted = 2,
|
||||
/// <summary>
|
||||
/// client is a moderator
|
||||
/// </summary>
|
||||
Moderator = 3,
|
||||
/// <summary>
|
||||
/// client is an administrator
|
||||
/// </summary>
|
||||
Administrator = 4,
|
||||
/// <summary>
|
||||
/// client is a senior administrator
|
||||
/// </summary>
|
||||
SeniorAdmin = 5,
|
||||
/// <summary>
|
||||
/// client is a owner
|
||||
/// </summary>
|
||||
Owner = 6,
|
||||
/// <summary>
|
||||
/// not used
|
||||
/// </summary>
|
||||
Creator = 7,
|
||||
/// <summary>
|
||||
/// reserved for default account
|
||||
/// </summary>
|
||||
Console = 8
|
||||
}
|
||||
|
||||
[Key]
|
||||
public int ClientId { get; set; }
|
||||
public long NetworkId { get; set; }
|
||||
[Required]
|
||||
public int Connections { get; set; }
|
||||
[Required]
|
||||
// in seconds
|
||||
public int TotalConnectionTime { get; set; }
|
||||
[Required]
|
||||
public DateTime FirstConnection { get; set; }
|
||||
[Required]
|
||||
public DateTime LastConnection { get; set; }
|
||||
public bool Masked { get; set; }
|
||||
[Required]
|
||||
public int AliasLinkId { get; set; }
|
||||
[ForeignKey("AliasLinkId")]
|
||||
public virtual EFAliasLink AliasLink { get; set; }
|
||||
[Required]
|
||||
public Permission Level { get; set; }
|
||||
|
||||
[Required]
|
||||
public int CurrentAliasId { get; set; }
|
||||
[ForeignKey("CurrentAliasId")]
|
||||
public virtual EFAlias CurrentAlias { get; set; }
|
||||
|
||||
public string Password { get; set; }
|
||||
public string PasswordSalt { get; set; }
|
||||
// list of meta for the client
|
||||
public virtual ICollection<EFMeta> Meta { get; set; }
|
||||
public virtual ICollection<EFPenalty> ReceivedPenalties { get; set; }
|
||||
public virtual ICollection<EFPenalty> AdministeredPenalties { get; set; }
|
||||
}
|
||||
}
|
52
Data/Models/Client/EFClientKill.cs
Normal file
52
Data/Models/Client/EFClientKill.cs
Normal file
@ -0,0 +1,52 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Data.Models.Server;
|
||||
|
||||
namespace Data.Models.Client
|
||||
{
|
||||
public class EFClientKill : SharedEntity
|
||||
{
|
||||
[Key] public long KillId { get; set; }
|
||||
public int VictimId { get; set; }
|
||||
[ForeignKey("VictimId")] public virtual EFClient Victim { get; set; }
|
||||
public int AttackerId { get; set; }
|
||||
[ForeignKey("AttackerId")] public virtual EFClient Attacker { get; set; }
|
||||
public long ServerId { get; set; }
|
||||
[ForeignKey("ServerId")] public virtual EFServer Server { get; set; }
|
||||
public int HitLoc { get; set; }
|
||||
public int DeathType { get; set; }
|
||||
public int Damage { get; set; }
|
||||
public int Weapon { get; set; }
|
||||
public Vector3 KillOrigin { get; set; }
|
||||
public Vector3 DeathOrigin { get; set; }
|
||||
public Vector3 ViewAngles { get; set; }
|
||||
public DateTime When { get; set; }
|
||||
public double Fraction { get; set; }
|
||||
public bool IsKill { get; set; }
|
||||
|
||||
public double VisibilityPercentage { get; set; }
|
||||
|
||||
// http://wiki.modsrepository.com/index.php?title=Call_of_Duty_5:_Gameplay_standards for conversion to meters
|
||||
[NotMapped] public double Distance => Vector3.Distance(KillOrigin, DeathOrigin) * 0.0254;
|
||||
public int Map { get; set; }
|
||||
[NotMapped] public long TimeOffset { get; set; }
|
||||
[NotMapped] public bool IsKillstreakKill { get; set; }
|
||||
[NotMapped] public float AdsPercent { get; set; }
|
||||
[NotMapped] public List<Vector3> AnglesList { get; set; }
|
||||
[NotMapped] public int GameName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if the attacker was alive after last captured angle
|
||||
/// </summary>
|
||||
[NotMapped]
|
||||
public bool IsAlive { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the last time the attack button was detected as pressed
|
||||
/// </summary>
|
||||
[NotMapped]
|
||||
public long TimeSinceLastAttack { get; set; }
|
||||
}
|
||||
}
|
22
Data/Models/Client/EFClientMessage.cs
Normal file
22
Data/Models/Client/EFClientMessage.cs
Normal file
@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Data.Models.Server;
|
||||
|
||||
namespace Data.Models.Client
|
||||
{
|
||||
public class EFClientMessage : SharedEntity
|
||||
{
|
||||
[Key]
|
||||
public long MessageId { get; set; }
|
||||
public long ServerId { get; set; }
|
||||
[ForeignKey("ServerId")]
|
||||
public virtual EFServer Server { get; set; }
|
||||
public int ClientId { get; set; }
|
||||
[ForeignKey("ClientId")]
|
||||
public virtual EFClient Client { get; set; }
|
||||
public string Message { get; set; }
|
||||
public DateTime TimeSent { get; set; }
|
||||
public bool SentIngame { get; set; }
|
||||
}
|
||||
}
|
59
Data/Models/Client/Stats/EFACSnapshot.cs
Normal file
59
Data/Models/Client/Stats/EFACSnapshot.cs
Normal file
@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Data.Models.Client.Stats
|
||||
{
|
||||
/// <summary>
|
||||
/// This class houses the information for anticheat snapshots (used for validating a ban)
|
||||
/// </summary>
|
||||
public class EFACSnapshot : SharedEntity
|
||||
{
|
||||
[Key]
|
||||
public int SnapshotId { get; set; }
|
||||
public int ClientId { get; set; }
|
||||
[ForeignKey("ClientId")]
|
||||
public EFClient Client { get; set; }
|
||||
|
||||
public DateTime When { get; set; }
|
||||
public int CurrentSessionLength { get; set; }
|
||||
public int TimeSinceLastEvent { get; set; }
|
||||
public double EloRating { get; set; }
|
||||
public int SessionScore { get; set; }
|
||||
public double SessionSPM { get; set; }
|
||||
public int Hits { get; set; }
|
||||
public int Kills { get; set; }
|
||||
public int Deaths { get; set; }
|
||||
public double CurrentStrain { get; set; }
|
||||
public double StrainAngleBetween { get; set; }
|
||||
public double SessionAngleOffset { get; set; }
|
||||
public double RecoilOffset { get; set; }
|
||||
public int LastStrainAngleId { get; set; }
|
||||
[ForeignKey("LastStrainAngleId")]
|
||||
public Vector3 LastStrainAngle { get; set; }
|
||||
public int HitOriginId { get; set; }
|
||||
[ForeignKey("HitOriginId")]
|
||||
public Vector3 HitOrigin { get; set; }
|
||||
public int HitDestinationId { get; set; }
|
||||
[ForeignKey("HitDestinationId")]
|
||||
public Vector3 HitDestination { get; set; }
|
||||
public double Distance { get; set; }
|
||||
public double SessionAverageSnapValue { get; set; }
|
||||
public int SessionSnapHits { get; set; }
|
||||
public int CurrentViewAngleId { get; set; }
|
||||
[ForeignKey("CurrentViewAngleId")]
|
||||
public Vector3 CurrentViewAngle { get; set; }
|
||||
public int WeaponId { get; set; }
|
||||
public int HitLocation { get; set; }
|
||||
public int HitType { get; set; }
|
||||
public virtual ICollection<EFACSnapshotVector3> PredictedViewAngles { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
public string CapturedViewAngles => PredictedViewAngles?.Count > 0 ?
|
||||
string.Join(", ", PredictedViewAngles.OrderBy(_angle => _angle.ACSnapshotVector3Id).Select(_angle => _angle.Vector.ToString())) :
|
||||
"";
|
||||
}
|
||||
}
|
91
Data/Models/Client/Stats/EFClientHitStatistic.cs
Normal file
91
Data/Models/Client/Stats/EFClientHitStatistic.cs
Normal file
@ -0,0 +1,91 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Data.Models.Client.Stats.Reference;
|
||||
using Data.Models.Server;
|
||||
using Stats.Models;
|
||||
|
||||
namespace Data.Models.Client.Stats
|
||||
{
|
||||
public class EFClientHitStatistic : AuditFields
|
||||
{
|
||||
[Key]
|
||||
public int ClientHitStatisticId { get; set; }
|
||||
|
||||
[Required]
|
||||
public int ClientId { get; set; }
|
||||
|
||||
[ForeignKey(nameof(ClientId))]
|
||||
public virtual EFClient Client { get; set; }
|
||||
|
||||
public long? ServerId { get; set; }
|
||||
|
||||
[ForeignKey(nameof(ServerId))]
|
||||
public virtual EFServer Server { get; set; }
|
||||
|
||||
public int? HitLocationId { get; set; }
|
||||
|
||||
[ForeignKey(nameof(HitLocationId))]
|
||||
public virtual EFHitLocation HitLocation { get; set; }
|
||||
|
||||
public int? MeansOfDeathId { get; set; }
|
||||
|
||||
[ForeignKey(nameof(MeansOfDeathId))]
|
||||
public virtual EFMeansOfDeath MeansOfDeath { get; set; }
|
||||
|
||||
public int? WeaponId { get; set; }
|
||||
|
||||
[ForeignKey(nameof(WeaponId))]
|
||||
public virtual EFWeapon Weapon { get; set; }
|
||||
|
||||
public int? WeaponAttachmentComboId { get; set; }
|
||||
|
||||
[ForeignKey(nameof(WeaponAttachmentComboId))]
|
||||
public virtual EFWeaponAttachmentCombo WeaponAttachmentCombo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// how many hits the player got
|
||||
/// </summary>
|
||||
public int HitCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// how many kills the player got
|
||||
/// </summary>
|
||||
public int KillCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// how much damage the player inflicted
|
||||
/// </summary>
|
||||
public int DamageInflicted { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// how many hits the player received
|
||||
/// </summary>
|
||||
public int ReceivedHitCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// how many kills the player received
|
||||
/// </summary>
|
||||
public int DeathCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// how much damage the player received
|
||||
/// </summary>
|
||||
public int DamageReceived { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// how many times the player killed themself
|
||||
/// </summary>
|
||||
public int SuicideCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// estimation of time spent with the configuration
|
||||
/// </summary>
|
||||
public int? UsageSeconds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// total in-game score
|
||||
/// </summary>
|
||||
public int? Score { get; set; }
|
||||
}
|
||||
}
|
31
Data/Models/Client/Stats/EFClientRankingHistory.cs
Normal file
31
Data/Models/Client/Stats/EFClientRankingHistory.cs
Normal file
@ -0,0 +1,31 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Data.Models.Server;
|
||||
using Stats.Models;
|
||||
|
||||
namespace Data.Models.Client.Stats
|
||||
{
|
||||
public class EFClientRankingHistory: AuditFields
|
||||
{
|
||||
public const int MaxRankingCount = 30;
|
||||
|
||||
[Key]
|
||||
public long ClientRankingHistoryId { get; set; }
|
||||
|
||||
[Required]
|
||||
public int ClientId { get; set; }
|
||||
|
||||
[ForeignKey(nameof(ClientId))]
|
||||
public virtual EFClient Client { get; set; }
|
||||
|
||||
public long? ServerId { get; set; }
|
||||
|
||||
[ForeignKey(nameof(ServerId))]
|
||||
public virtual EFServer Server { get; set; }
|
||||
|
||||
public bool Newest { get; set; }
|
||||
public int? Ranking { get; set; }
|
||||
public double? ZScore { get; set; }
|
||||
public double? PerformanceMetric { get; set; }
|
||||
}
|
||||
}
|
16
Data/Models/Client/Stats/EFClientRatingHistory.cs
Normal file
16
Data/Models/Client/Stats/EFClientRatingHistory.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Data.Models.Client.Stats
|
||||
{
|
||||
public class EFClientRatingHistory : SharedEntity
|
||||
{
|
||||
[Key]
|
||||
public int RatingHistoryId { get; set; }
|
||||
public int ClientId { get; set; }
|
||||
[ForeignKey("ClientId")]
|
||||
public virtual EFClient Client { get; set; }
|
||||
public virtual ICollection<EFRating> Ratings { get; set; }
|
||||
}
|
||||
}
|
114
Data/Models/Client/Stats/EFClientStatistics.cs
Normal file
114
Data/Models/Client/Stats/EFClientStatistics.cs
Normal file
@ -0,0 +1,114 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Data.Models.Server;
|
||||
|
||||
namespace Data.Models.Client.Stats
|
||||
{
|
||||
public class EFClientStatistics : SharedEntity
|
||||
{
|
||||
public EFClientStatistics()
|
||||
{
|
||||
ProcessingHit = new SemaphoreSlim(1, 1);
|
||||
}
|
||||
|
||||
~EFClientStatistics()
|
||||
{
|
||||
ProcessingHit.Dispose();
|
||||
}
|
||||
|
||||
public int ClientId { get; set; }
|
||||
[ForeignKey("ClientId")]
|
||||
public virtual EFClient Client { get; set; }
|
||||
public long ServerId { get; set; }
|
||||
[ForeignKey("ServerId")]
|
||||
public virtual EFServer Server { get; set; }
|
||||
[Required]
|
||||
public int Kills { get; set; }
|
||||
[Required]
|
||||
public int Deaths { get; set; }
|
||||
public double EloRating { get; set; }
|
||||
public double ZScore { get; set; }
|
||||
public DateTime? UpdatedAt { get; set; }
|
||||
public virtual ICollection<EFHitLocationCount> HitLocations { get; set; }
|
||||
public double RollingWeightedKDR { get; set; }
|
||||
public double AverageSnapValue { get; set; }
|
||||
public int SnapHitCount { get; set; }
|
||||
[NotMapped]
|
||||
public double Performance
|
||||
{
|
||||
get => Math.Round(EloRating * 1/3.0 + Skill * 2/3.0, 2);
|
||||
}
|
||||
[NotMapped]
|
||||
public double KDR
|
||||
{
|
||||
get => Deaths == 0 ? Kills : Math.Round(Kills / (double)Deaths, 2);
|
||||
}
|
||||
[Required]
|
||||
public double SPM { get; set; }
|
||||
[Required]
|
||||
public double Skill { get; set; }
|
||||
[Required]
|
||||
public int TimePlayed { get; set; }
|
||||
[Required]
|
||||
public double MaxStrain { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
public float AverageHitOffset
|
||||
{
|
||||
get => (float)Math.Round(HitLocations.Sum(c => c.HitOffsetAverage) / Math.Max(1, HitLocations.Where(c => c.HitOffsetAverage > 0).Count()), 4);
|
||||
}
|
||||
[NotMapped]
|
||||
public int SessionKills { get; set; }
|
||||
[NotMapped]
|
||||
public int SessionDeaths { get; set; }
|
||||
[NotMapped]
|
||||
public int KillStreak { get; set; }
|
||||
[NotMapped]
|
||||
public int DeathStreak { get; set; }
|
||||
[NotMapped]
|
||||
public DateTime LastStatCalculation { get; set; }
|
||||
[NotMapped]
|
||||
public int LastScore { get; set; }
|
||||
[NotMapped]
|
||||
public DateTime LastActive { get; set; }
|
||||
[NotMapped]
|
||||
public double MaxSessionStrain { get; set; }
|
||||
public void StartNewSession()
|
||||
{
|
||||
KillStreak = 0;
|
||||
DeathStreak = 0;
|
||||
LastScore = 0;
|
||||
SessionScores.Add(0);
|
||||
Team = 0;
|
||||
}
|
||||
[NotMapped]
|
||||
public int SessionScore
|
||||
{
|
||||
set => SessionScores[SessionScores.Count - 1] = value;
|
||||
|
||||
get
|
||||
{
|
||||
lock (SessionScores)
|
||||
{
|
||||
return new List<int>(SessionScores).Sum();
|
||||
}
|
||||
}
|
||||
}
|
||||
[NotMapped]
|
||||
public int RoundScore => SessionScores[SessionScores.Count - 1];
|
||||
[NotMapped]
|
||||
private readonly List<int> SessionScores = new List<int>() { 0 };
|
||||
[NotMapped]
|
||||
public int Team { get; set; }
|
||||
[NotMapped]
|
||||
public DateTime LastStatHistoryUpdate { get; set; } = DateTime.UtcNow;
|
||||
[NotMapped]
|
||||
public double SessionSPM { get; set; }
|
||||
[NotMapped]
|
||||
public SemaphoreSlim ProcessingHit { get; private set; }
|
||||
}
|
||||
}
|
29
Data/Models/Client/Stats/EFHitLocationCount.cs
Normal file
29
Data/Models/Client/Stats/EFHitLocationCount.cs
Normal file
@ -0,0 +1,29 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Data.Models.Server;
|
||||
|
||||
namespace Data.Models.Client.Stats
|
||||
{
|
||||
public class EFHitLocationCount : SharedEntity
|
||||
{
|
||||
[Key]
|
||||
public int HitLocationCountId { get; set; }
|
||||
[Required]
|
||||
public int Location { get; set; }
|
||||
[Required]
|
||||
public int HitCount { get; set; }
|
||||
[Required]
|
||||
public float HitOffsetAverage { get; set; }
|
||||
[Required]
|
||||
public float MaxAngleDistance { get; set; }
|
||||
[Required]
|
||||
[Column("EFClientStatisticsClientId")]
|
||||
public int EFClientStatisticsClientId { get; set; }
|
||||
[ForeignKey("EFClientStatisticsClientId")]
|
||||
public EFClient Client { get; set; }
|
||||
[Column("EFClientStatisticsServerId")]
|
||||
public long EFClientStatisticsServerId { get; set; }
|
||||
[ForeignKey("EFClientStatisticsServerId")]
|
||||
public EFServer Server { get; set; }
|
||||
}
|
||||
}
|
31
Data/Models/Client/Stats/EFRating.cs
Normal file
31
Data/Models/Client/Stats/EFRating.cs
Normal file
@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Data.Models.Server;
|
||||
|
||||
namespace Data.Models.Client.Stats
|
||||
{
|
||||
public class EFRating : SharedEntity
|
||||
{
|
||||
[Key]
|
||||
public int RatingId { get; set; }
|
||||
public int RatingHistoryId { get; set; }
|
||||
[ForeignKey("RatingHistoryId")]
|
||||
public virtual EFClientRatingHistory RatingHistory { get; set; }
|
||||
// if null, indicates that the rating is an average rating
|
||||
public long? ServerId { get; set; }
|
||||
// [ForeignKey("ServerId")] can't make this nullable if this annotation is set
|
||||
public virtual EFServer Server { get; set; }
|
||||
[Required]
|
||||
public double Performance { get; set; }
|
||||
[Required]
|
||||
public int Ranking { get; set; }
|
||||
[Required]
|
||||
// indicates if the rating is the latest
|
||||
public bool Newest { get; set; }
|
||||
[Required]
|
||||
public int ActivityAmount { get; set; }
|
||||
[Required]
|
||||
public DateTime When { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
}
|
21
Data/Models/Client/Stats/Reference/EFHitLocation.cs
Normal file
21
Data/Models/Client/Stats/Reference/EFHitLocation.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Data.Abstractions;
|
||||
using Stats.Models;
|
||||
|
||||
namespace Data.Models.Client.Stats.Reference
|
||||
{
|
||||
public class EFHitLocation : AuditFields, IUniqueId
|
||||
{
|
||||
[Key]
|
||||
public int HitLocationId { get; set; }
|
||||
|
||||
[Required]
|
||||
public string Name { get; set; }
|
||||
|
||||
[Required]
|
||||
public Models.Reference.Game Game { get; set; }
|
||||
|
||||
public long Id => HitLocationId;
|
||||
public string Value => Name;
|
||||
}
|
||||
}
|
21
Data/Models/Client/Stats/Reference/EFMap.cs
Normal file
21
Data/Models/Client/Stats/Reference/EFMap.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Data.Abstractions;
|
||||
using Stats.Models;
|
||||
|
||||
namespace Data.Models.Client.Stats.Reference
|
||||
{
|
||||
public class EFMap : AuditFields, IUniqueId
|
||||
{
|
||||
[Key]
|
||||
public int MapId { get; set; }
|
||||
|
||||
[Required]
|
||||
public string Name { get; set; }
|
||||
|
||||
[Required]
|
||||
public Models.Reference.Game Game { get; set; }
|
||||
|
||||
public long Id => MapId;
|
||||
public string Value => Name;
|
||||
}
|
||||
}
|
21
Data/Models/Client/Stats/Reference/EFMeansOfDeath.cs
Normal file
21
Data/Models/Client/Stats/Reference/EFMeansOfDeath.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Data.Abstractions;
|
||||
using Stats.Models;
|
||||
|
||||
namespace Data.Models.Client.Stats.Reference
|
||||
{
|
||||
public class EFMeansOfDeath: AuditFields, IUniqueId
|
||||
{
|
||||
[Key]
|
||||
public int MeansOfDeathId { get; set; }
|
||||
|
||||
[Required]
|
||||
public string Name { get; set; }
|
||||
|
||||
[Required]
|
||||
public Models.Reference.Game Game { get; set; }
|
||||
|
||||
public long Id => MeansOfDeathId;
|
||||
public string Value => Name;
|
||||
}
|
||||
}
|
21
Data/Models/Client/Stats/Reference/EFWeapon.cs
Normal file
21
Data/Models/Client/Stats/Reference/EFWeapon.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Data.Abstractions;
|
||||
using Stats.Models;
|
||||
|
||||
namespace Data.Models.Client.Stats.Reference
|
||||
{
|
||||
public class EFWeapon : AuditFields, IUniqueId
|
||||
{
|
||||
[Key]
|
||||
public int WeaponId { get; set; }
|
||||
|
||||
[Required]
|
||||
public string Name { get; set; }
|
||||
|
||||
[Required]
|
||||
public Models.Reference.Game Game { get; set; }
|
||||
|
||||
public long Id => WeaponId;
|
||||
public string Value => Name;
|
||||
}
|
||||
}
|
21
Data/Models/Client/Stats/Reference/EFWeaponAttachment.cs
Normal file
21
Data/Models/Client/Stats/Reference/EFWeaponAttachment.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Data.Abstractions;
|
||||
using Stats.Models;
|
||||
|
||||
namespace Data.Models.Client.Stats.Reference
|
||||
{
|
||||
public class EFWeaponAttachment : AuditFields, IUniqueId
|
||||
{
|
||||
[Key]
|
||||
public int WeaponAttachmentId { get; set; }
|
||||
|
||||
[Required]
|
||||
public string Name { get; set; }
|
||||
|
||||
[Required]
|
||||
public Models.Reference.Game Game { get; set; }
|
||||
|
||||
public long Id => WeaponAttachmentId;
|
||||
public string Value => Name;
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
using Data.Abstractions;
|
||||
using Stats.Models;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Data.Models.Client.Stats.Reference
|
||||
{
|
||||
public class EFWeaponAttachmentCombo : AuditFields, IUniqueId
|
||||
{
|
||||
[Key]
|
||||
public int WeaponAttachmentComboId { get; set; }
|
||||
|
||||
[Required]
|
||||
public Models.Reference.Game Game { get; set; }
|
||||
|
||||
[Required]
|
||||
public int Attachment1Id { get; set; }
|
||||
|
||||
[ForeignKey(nameof(Attachment1Id))]
|
||||
public virtual EFWeaponAttachment Attachment1 { get; set; }
|
||||
|
||||
public int? Attachment2Id { get; set; }
|
||||
|
||||
[ForeignKey(nameof(Attachment2Id))]
|
||||
public virtual EFWeaponAttachment Attachment2 { get; set; }
|
||||
|
||||
public int? Attachment3Id { get; set; }
|
||||
|
||||
[ForeignKey(nameof(Attachment3Id))]
|
||||
public virtual EFWeaponAttachment Attachment3 { get; set; }
|
||||
|
||||
public long Id => WeaponAttachmentComboId;
|
||||
public string Value => $"{Attachment1Id}{Attachment2Id}{Attachment3Id}";
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user