Show time passed since ban instead of "forever"

reworked event api to include all events (sans unknown)
This commit is contained in:
RaidMax 2018-06-16 21:11:25 -05:00
parent 5be6b75ccf
commit e7c7145da1
19 changed files with 861 additions and 128 deletions

View File

@ -10,66 +10,69 @@ namespace IW4MAdmin.Application.API
{
class EventApi : IEventApi
{
Queue<EventInfo> Events = new Queue<EventInfo>();
DateTime LastFlagEvent;
static string[] FlaggedMessageContains =
{
" wh ",
"hax",
"cheat",
" hack ",
"aim",
"wall",
"cheto",
"hak",
"bot"
};
int FlaggedMessageCount;
private const int MaxEvents = 32;
private Queue<EventInfo> RecentEvents = new Queue<EventInfo>();
public Queue<EventInfo> GetEvents() => Events;
public IEnumerable<EventInfo> GetEvents(bool shouldConsume)
{
var eventList = RecentEvents.ToArray();
// clear queue if events should be consumed
if (shouldConsume)
{
RecentEvents.Clear();
}
return eventList;
}
public void OnServerEvent(object sender, GameEvent E)
{
if (E.Type == GameEvent.EventType.Say && E.Origin.Level < Player.Permission.Trusted)
// don't want to clog up the api with unknown events
if (E.Type == GameEvent.EventType.Unknown)
return;
var apiEvent = new EventInfo()
{
bool flaggedMessage = false;
foreach (string msg in FlaggedMessageContains)
flaggedMessage = flaggedMessage ? flaggedMessage : E.Data.ToLower().Contains(msg);
if (flaggedMessage)
FlaggedMessageCount++;
if (FlaggedMessageCount > 3)
ExtraInfo = E.Extra?.ToString() ?? E.Data,
OwnerEntity = new EntityInfo()
{
if (Events.Count > 20)
Events.Dequeue();
Name = E.Owner.Hostname,
Id = E.Owner.GetHashCode()
},
OriginEntity = E.Origin == null ? null : new EntityInfo()
{
Id = E.Origin.ClientId,
Name = E.Origin.Name
},
TargetEntity = E.Target == null ? null : new EntityInfo()
{
Id = E.Target.ClientId,
Name = E.Target.Name
},
EventType = new EntityInfo()
{
Id = (int)E.Type,
Name = E.Type.ToString()
},
EventTime = E.Time
};
FlaggedMessageCount = 0;
E.Owner.Broadcast(Utilities.CurrentLocalization.LocalizationIndex["GLOBAL_REPORT"]).Wait(5000);
Events.Enqueue(new EventInfo(
EventInfo.EventType.ALERT,
EventInfo.EventVersion.IW4MAdmin,
"Chat indicates there may be a cheater",
"Alert",
E.Owner.Hostname, ""));
// add the new event to the list
AddNewEvent(apiEvent);
}
if ((DateTime.UtcNow - LastFlagEvent).Minutes >= 3)
/// <summary>
/// Adds event to the list and removes first added if reached max capacity
/// </summary>
/// <param name="info">EventInfo to add</param>
private void AddNewEvent(EventInfo info)
{
FlaggedMessageCount = 0;
LastFlagEvent = DateTime.Now;
}
}
// remove the first added event
if (RecentEvents.Count >= MaxEvents)
RecentEvents.Dequeue();
if (E.Type == GameEvent.EventType.Report)
{
Events.Enqueue(new EventInfo(
EventInfo.EventType.ALERT,
EventInfo.EventVersion.IW4MAdmin,
$"**{E.Origin.Name}** has reported **{E.Target.Name}** for: {E.Data.Trim()}",
E.Target.Name, E.Origin.Name, ""));
}
RecentEvents.Enqueue(info);
}
}
}

View File

@ -37,7 +37,7 @@ namespace IW4MAdmin.Application.EventParsers
{
Type = GameEvent.EventType.JoinTeam,
Data = cleanedEventLine,
//Origin = server.GetPlayersAsList().First(c => c.NetworkId == lineSplit[1].ConvertLong()),
Origin = server.GetPlayersAsList().FirstOrDefault(c => c.NetworkId == lineSplit[1].ConvertLong()),
Owner = server
};
}

View File

@ -34,13 +34,6 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
Manager = mgr;
}
~StatManager()
{
Servers.Clear();
Log = null;
Servers = null;
}
public EFClientStatistics GetClientStats(int clientId, int serverId) => Servers[serverId].PlayerStats[clientId];
public async Task<List<TopStatsInfo>> GetTopStats(int start, int count)
@ -445,6 +438,8 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
switch (penalty.ClientPenalty)
{
case Penalty.PenaltyType.Ban:
if (attacker.Level == Player.Permission.Banned)
break;
await saveLog();
await attacker.Ban(Utilities.CurrentLocalization.LocalizationIndex["PLUGIN_STATS_CHEAT_DETECTED"], new Player()
{
@ -461,7 +456,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
});
break;
case Penalty.PenaltyType.Flag:
if (attacker.Level == Player.Permission.Flagged)
if (attacker.Level != Player.Permission.User)
break;
await saveLog();
var e = new GameEvent()

View File

@ -65,8 +65,6 @@ namespace IW4MAdmin.Plugins.Stats
break;
case GameEvent.EventType.Ban:
break;
case GameEvent.EventType.Remote:
break;
case GameEvent.EventType.Unknown:
break;
case GameEvent.EventType.Report:
@ -83,8 +81,6 @@ namespace IW4MAdmin.Plugins.Stats
if (!E.Owner.CustomCallback)
await Manager.AddStandardKill(E.Origin, E.Target);
break;
case GameEvent.EventType.Death:
break;
case GameEvent.EventType.Damage:
// if (!E.Owner.CustomCallback)
Manager.AddDamageEvent(E.Data, E.Origin.ClientId, E.Target.ClientId, E.Owner.GetHashCode());

View File

@ -117,9 +117,9 @@ namespace SharedLibraryCore.Commands
{
if (E.Origin.Level > E.Target.Level)
{
E.Owner.Manager.GetEventHandler().AddEvent(new GameEvent(GameEvent.EventType.Kick, E.Data, E.Origin, E.Target, E.Owner));
await E.Target.Kick(E.Data, E.Origin);
await E.Origin.Tell($"^5{E.Target} ^7{Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_KICK_SUCCESS"]}");
E.Owner.Manager.GetEventHandler().AddEvent(new GameEvent(GameEvent.EventType.Kick, E.Data, E.Origin, E.Target, E.Owner));
}
else
await E.Origin.Tell($"{Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_KICK_FAIL"]} {E.Target.Name}");
@ -179,6 +179,14 @@ namespace SharedLibraryCore.Commands
{
await E.Target.TempBan(Message, length, E.Origin);
await E.Origin.Tell($"^5{E.Target} ^7{Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_TEMPBAN_SUCCESS"]} ^5{length.TimeSpanText()}");
E.Owner.Manager.GetEventHandler().AddEvent(new GameEvent()
{
Type = GameEvent.EventType.TempBan,
Data = E.Data,
Origin = E.Origin,
Target = E.Target,
Owner = E.Owner
});
}
else
await E.Origin.Tell($"{Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_TEMPBAN_FAIL"]} {E.Target.Name}");
@ -209,6 +217,15 @@ namespace SharedLibraryCore.Commands
{
await E.Target.Ban(E.Data, E.Origin);
await E.Origin.Tell($"^5{E.Target} ^7{Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_BAN_SUCCESS"]}");
E.Owner.Manager.GetEventHandler().AddEvent(new GameEvent()
{
Type = GameEvent.EventType.Ban,
Data = E.Data,
Origin = E.Origin,
Target = E.Target,
Owner = E.Owner
});
}
else
await E.Origin.Tell($"{Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_BAN_FAIL"]} {E.Target.Name}");
@ -753,6 +770,16 @@ namespace SharedLibraryCore.Commands
E.Target.Level = Player.Permission.User;
await E.Owner.Manager.GetClientService().Update(E.Target);
await E.Origin.Tell($"{Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_FLAG_UNFLAG"]} ^5{E.Target.Name}");
E.Owner.Manager.GetEventHandler().AddEvent(new GameEvent()
{
Data = E.Data,
Origin = E.Origin,
Target = E.Target,
Owner = E.Owner,
Type = GameEvent.EventType.Unflag
});
}
else

View File

@ -17,6 +17,7 @@ namespace SharedLibraryCore.Database
public DbSet<EFAliasLink> AliasLinks { get; set; }
public DbSet<EFPenalty> Penalties { get; set; }
public DbSet<EFMeta> EFMeta { get; set; }
public DbSet<EFChangeHistory> EFChangeHistory { get; set; }
private static string _ConnectionString;
@ -79,6 +80,11 @@ namespace SharedLibraryCore.Database
.OnDelete(DeleteBehavior.Restrict);
});
modelBuilder.Entity<EFAlias>(ent =>
{
ent.HasIndex(a => a.IPAddress);
});
// force full name for database conversion
modelBuilder.Entity<EFClient>().ToTable("EFClients");
modelBuilder.Entity<EFAlias>().ToTable("EFAlias");

View File

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Text;
namespace SharedLibraryCore.Database.Models
{
/// <summary>
/// This class models the change to different entities
/// </summary>
public class EFChangeHistory : SharedEntity
{
public enum ChangeType
{
Permission
}
[Key]
public int ChangeHistoryId { get; set; }
public int OriginEntityId { get; set; }
public int TargetEntityId { get; set; }
public ChangeType TypeOfChange { get; set; }
public DateTime TimeChanged { get; set; } = DateTime.UtcNow;
[MaxLength(128)]
public string Comment { get; set; }
}
}

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace SharedLibraryCore.Dtos
{
/// <summary>
/// This class holds the basic info for api entities
/// </summary>
public class EntityInfo
{
public int Id { get; set; }
public string Name { get; set; }
}
}

View File

@ -1,39 +1,19 @@
using System;
using static SharedLibraryCore.GameEvent;
namespace SharedLibraryCore.Dtos
{
/// <summary>
/// This class wraps the information related to a generated event for the API
/// </summary>
public class EventInfo
{
public EventInfo(EventType Ty, EventVersion V, string M, string T, string O, string Ta)
{
Type = Ty;
Version = V;
Message = System.Web.HttpUtility.HtmlEncode(M);
Title = T;
Origin = System.Web.HttpUtility.HtmlEncode(O);
Target = System.Web.HttpUtility.HtmlEncode(Ta);
ID = Math.Abs(DateTime.Now.GetHashCode());
}
public enum EventType
{
NOTIFICATION,
STATUS,
ALERT,
}
public enum EventVersion
{
IW4MAdmin
}
public EventType Type;
public EventVersion Version;
public string Message;
public string Title;
public string Origin;
public string Target;
public int ID;
public EntityInfo OriginEntity { get; set; }
public EntityInfo TargetEntity { get; set; }
public EntityInfo EventType { get; set; }
public EntityInfo OwnerEntity { get; set; }
public DateTime EventTime { get; set; }
public string ExtraInfo { get; set; }
public string Id { get; private set; } = Guid.NewGuid().ToString();
}
}

View File

@ -8,36 +8,37 @@ namespace SharedLibraryCore
{
public enum EventType
{
//FROM SERVER
Unknown,
// events "generated" by the server
Start,
Stop,
Connect,
// this is for IW5 compatibility
Join,
Quit,
Disconnect,
Say,
MapChange,
MapEnd,
MapChange,
//FROM ADMIN
Broadcast,
Tell,
Kick,
Ban,
Remote,
Unknown,
//FROM PLAYER
// events "generated" by clients
Say,
Report,
Flag,
Unflag,
Kick,
TempBan,
Ban,
Command,
// FROM GAME
// events "generated" by IW4MAdmin
Broadcast,
Tell,
// events "generated" by script/log
ScriptDamage,
ScriptKill,
Kill,
Damage,
Death,
Kill,
JoinTeam,
}

View File

@ -5,7 +5,17 @@ namespace SharedLibraryCore.Interfaces
{
public interface IEventApi
{
/// <summary>
/// Processes event from server as event info
/// </summary>
/// <param name="sender">Object state from Delegate method call</param>
/// <param name="E">Event to process</param>
void OnServerEvent(object sender, GameEvent E);
Queue<EventInfo> GetEvents();
/// <summary>
/// Get list of recent events
/// </summary>
/// <param name="shouldConsume">specify wether the request should clear all events after retrieving</param>
/// <returns>List of recent event</returns>
IEnumerable<EventInfo> GetEvents(bool shouldConsume);
}
}

View File

@ -0,0 +1,639 @@
// <auto-generated />
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.EntityFrameworkCore.Storage.Internal;
using SharedLibraryCore.Database;
using SharedLibraryCore.Objects;
using System;
namespace SharedLibraryCore.Migrations
{
[DbContext(typeof(DatabaseContext))]
[Migration("20180614014303_IndexForEFAlias")]
partial class IndexForEFAlias
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "2.0.2-rtm-10011");
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot", b =>
{
b.Property<int>("SnapshotId")
.ValueGeneratedOnAdd();
b.Property<bool>("Active");
b.Property<int>("ClientId");
b.Property<int>("CurrentSessionLength");
b.Property<double>("CurrentStrain");
b.Property<int?>("CurrentViewAngleVector3Id");
b.Property<int>("Deaths");
b.Property<double>("Distance");
b.Property<double>("EloRating");
b.Property<int?>("HitDestinationVector3Id");
b.Property<int>("HitLocation");
b.Property<int?>("HitOriginVector3Id");
b.Property<int>("HitType");
b.Property<int>("Hits");
b.Property<int>("Kills");
b.Property<int?>("LastStrainAngleVector3Id");
b.Property<double>("SessionAngleOffset");
b.Property<double>("SessionSPM");
b.Property<int>("SessionScore");
b.Property<double>("StrainAngleBetween");
b.Property<int>("TimeSinceLastEvent");
b.Property<int>("WeaponId");
b.Property<DateTime>("When");
b.HasKey("SnapshotId");
b.HasIndex("ClientId");
b.HasIndex("CurrentViewAngleVector3Id");
b.HasIndex("HitDestinationVector3Id");
b.HasIndex("HitOriginVector3Id");
b.HasIndex("LastStrainAngleVector3Id");
b.ToTable("EFACSnapshot");
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientKill", b =>
{
b.Property<long>("KillId")
.ValueGeneratedOnAdd();
b.Property<bool>("Active");
b.Property<int>("AttackerId");
b.Property<int>("Damage");
b.Property<int?>("DeathOriginVector3Id");
b.Property<int>("DeathType");
b.Property<int>("HitLoc");
b.Property<int?>("KillOriginVector3Id");
b.Property<int>("Map");
b.Property<int>("ServerId");
b.Property<int>("VictimId");
b.Property<int?>("ViewAnglesVector3Id");
b.Property<int>("Weapon");
b.Property<DateTime>("When");
b.HasKey("KillId");
b.HasIndex("AttackerId");
b.HasIndex("DeathOriginVector3Id");
b.HasIndex("KillOriginVector3Id");
b.HasIndex("ServerId");
b.HasIndex("VictimId");
b.HasIndex("ViewAnglesVector3Id");
b.ToTable("EFClientKills");
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientMessage", b =>
{
b.Property<long>("MessageId")
.ValueGeneratedOnAdd();
b.Property<bool>("Active");
b.Property<int>("ClientId");
b.Property<string>("Message");
b.Property<int>("ServerId");
b.Property<DateTime>("TimeSent");
b.HasKey("MessageId");
b.HasIndex("ClientId");
b.HasIndex("ServerId");
b.ToTable("EFClientMessages");
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientRatingHistory", b =>
{
b.Property<int>("RatingHistoryId")
.ValueGeneratedOnAdd();
b.Property<bool>("Active");
b.Property<int>("ClientId");
b.HasKey("RatingHistoryId");
b.HasIndex("ClientId");
b.ToTable("EFClientRatingHistory");
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics", b =>
{
b.Property<int>("ClientId");
b.Property<int>("ServerId");
b.Property<bool>("Active");
b.Property<int>("Deaths");
b.Property<double>("EloRating");
b.Property<int>("Kills");
b.Property<double>("MaxStrain");
b.Property<double>("RollingWeightedKDR");
b.Property<double>("SPM");
b.Property<double>("Skill");
b.Property<int>("TimePlayed");
b.HasKey("ClientId", "ServerId");
b.HasIndex("ServerId");
b.ToTable("EFClientStatistics");
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFHitLocationCount", b =>
{
b.Property<int>("HitLocationCountId")
.ValueGeneratedOnAdd();
b.Property<bool>("Active");
b.Property<int>("ClientId")
.HasColumnName("EFClientStatistics_ClientId");
b.Property<int>("HitCount");
b.Property<float>("HitOffsetAverage");
b.Property<int>("Location");
b.Property<float>("MaxAngleDistance");
b.Property<int>("ServerId")
.HasColumnName("EFClientStatistics_ServerId");
b.HasKey("HitLocationCountId");
b.HasIndex("ServerId");
b.HasIndex("ClientId", "ServerId");
b.ToTable("EFHitLocationCounts");
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFRating", b =>
{
b.Property<int>("RatingId")
.ValueGeneratedOnAdd();
b.Property<bool>("Active");
b.Property<int>("ActivityAmount");
b.Property<bool>("Newest");
b.Property<double>("Performance");
b.Property<int>("Ranking");
b.Property<int>("RatingHistoryId");
b.Property<int?>("ServerId");
b.HasKey("RatingId");
b.HasIndex("RatingHistoryId");
b.HasIndex("ServerId");
b.ToTable("EFRating");
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServer", b =>
{
b.Property<int>("ServerId");
b.Property<bool>("Active");
b.Property<int>("Port");
b.HasKey("ServerId");
b.ToTable("EFServers");
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServerStatistics", b =>
{
b.Property<int>("StatisticId")
.ValueGeneratedOnAdd();
b.Property<bool>("Active");
b.Property<int>("ServerId");
b.Property<long>("TotalKills");
b.Property<long>("TotalPlayTime");
b.HasKey("StatisticId");
b.HasIndex("ServerId");
b.ToTable("EFServerStatistics");
});
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFAlias", b =>
{
b.Property<int>("AliasId")
.ValueGeneratedOnAdd();
b.Property<bool>("Active");
b.Property<DateTime>("DateAdded");
b.Property<int>("IPAddress");
b.Property<int>("LinkId");
b.Property<string>("Name")
.IsRequired();
b.HasKey("AliasId");
b.HasIndex("IPAddress");
b.HasIndex("LinkId");
b.ToTable("EFAlias");
});
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFAliasLink", b =>
{
b.Property<int>("AliasLinkId")
.ValueGeneratedOnAdd();
b.Property<bool>("Active");
b.HasKey("AliasLinkId");
b.ToTable("EFAliasLinks");
});
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFClient", b =>
{
b.Property<int>("ClientId")
.ValueGeneratedOnAdd();
b.Property<bool>("Active");
b.Property<int>("AliasLinkId");
b.Property<int>("Connections");
b.Property<int>("CurrentAliasId");
b.Property<DateTime>("FirstConnection");
b.Property<DateTime>("LastConnection");
b.Property<int>("Level");
b.Property<bool>("Masked");
b.Property<long>("NetworkId");
b.Property<string>("Password");
b.Property<string>("PasswordSalt");
b.Property<int>("TotalConnectionTime");
b.HasKey("ClientId");
b.HasIndex("AliasLinkId");
b.HasIndex("CurrentAliasId");
b.HasIndex("NetworkId")
.IsUnique();
b.ToTable("EFClients");
});
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFMeta", b =>
{
b.Property<int>("MetaId")
.ValueGeneratedOnAdd();
b.Property<bool>("Active");
b.Property<int>("ClientId");
b.Property<DateTime>("Created");
b.Property<string>("Extra");
b.Property<string>("Key")
.IsRequired();
b.Property<DateTime>("Updated");
b.Property<string>("Value")
.IsRequired();
b.HasKey("MetaId");
b.HasIndex("ClientId");
b.ToTable("EFMeta");
});
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFPenalty", b =>
{
b.Property<int>("PenaltyId")
.ValueGeneratedOnAdd();
b.Property<bool>("Active");
b.Property<string>("AutomatedOffense");
b.Property<DateTime>("Expires");
b.Property<int>("LinkId");
b.Property<int>("OffenderId");
b.Property<string>("Offense")
.IsRequired();
b.Property<int>("PunisherId");
b.Property<int>("Type");
b.Property<DateTime>("When");
b.HasKey("PenaltyId");
b.HasIndex("LinkId");
b.HasIndex("OffenderId");
b.HasIndex("PunisherId");
b.ToTable("EFPenalties");
});
modelBuilder.Entity("SharedLibraryCore.Helpers.Vector3", b =>
{
b.Property<int>("Vector3Id")
.ValueGeneratedOnAdd();
b.Property<int?>("EFACSnapshotSnapshotId");
b.Property<float>("X");
b.Property<float>("Y");
b.Property<float>("Z");
b.HasKey("Vector3Id");
b.ToTable("Vector3");
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot", b =>
{
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
.WithMany()
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("SharedLibraryCore.Helpers.Vector3", "CurrentViewAngle")
.WithMany()
.HasForeignKey("CurrentViewAngleVector3Id");
b.HasOne("SharedLibraryCore.Helpers.Vector3", "HitDestination")
.WithMany()
.HasForeignKey("HitDestinationVector3Id");
b.HasOne("SharedLibraryCore.Helpers.Vector3", "HitOrigin")
.WithMany()
.HasForeignKey("HitOriginVector3Id");
b.HasOne("SharedLibraryCore.Helpers.Vector3", "LastStrainAngle")
.WithMany()
.HasForeignKey("LastStrainAngleVector3Id");
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientKill", b =>
{
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Attacker")
.WithMany()
.HasForeignKey("AttackerId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("SharedLibraryCore.Helpers.Vector3", "DeathOrigin")
.WithMany()
.HasForeignKey("DeathOriginVector3Id");
b.HasOne("SharedLibraryCore.Helpers.Vector3", "KillOrigin")
.WithMany()
.HasForeignKey("KillOriginVector3Id");
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
.WithMany()
.HasForeignKey("ServerId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Victim")
.WithMany()
.HasForeignKey("VictimId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("SharedLibraryCore.Helpers.Vector3", "ViewAngles")
.WithMany()
.HasForeignKey("ViewAnglesVector3Id");
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientMessage", b =>
{
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
.WithMany()
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
.WithMany()
.HasForeignKey("ServerId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientRatingHistory", b =>
{
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
.WithMany()
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics", b =>
{
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
.WithMany()
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
.WithMany()
.HasForeignKey("ServerId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFHitLocationCount", b =>
{
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
.WithMany()
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
.WithMany()
.HasForeignKey("ServerId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics")
.WithMany("HitLocations")
.HasForeignKey("ClientId", "ServerId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFRating", b =>
{
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFClientRatingHistory", "RatingHistory")
.WithMany("Ratings")
.HasForeignKey("RatingHistoryId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
.WithMany()
.HasForeignKey("ServerId");
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServerStatistics", b =>
{
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
.WithMany()
.HasForeignKey("ServerId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFAlias", b =>
{
b.HasOne("SharedLibraryCore.Database.Models.EFAliasLink", "Link")
.WithMany("Children")
.HasForeignKey("LinkId")
.OnDelete(DeleteBehavior.Restrict);
});
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFClient", b =>
{
b.HasOne("SharedLibraryCore.Database.Models.EFAliasLink", "AliasLink")
.WithMany()
.HasForeignKey("AliasLinkId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("SharedLibraryCore.Database.Models.EFAlias", "CurrentAlias")
.WithMany()
.HasForeignKey("CurrentAliasId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFMeta", b =>
{
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
.WithMany("Meta")
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFPenalty", b =>
{
b.HasOne("SharedLibraryCore.Database.Models.EFAliasLink", "Link")
.WithMany("ReceivedPenalties")
.HasForeignKey("LinkId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Offender")
.WithMany("ReceivedPenalties")
.HasForeignKey("OffenderId")
.OnDelete(DeleteBehavior.Restrict);
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Punisher")
.WithMany("AdministeredPenalties")
.HasForeignKey("PunisherId")
.OnDelete(DeleteBehavior.Restrict);
});
modelBuilder.Entity("SharedLibraryCore.Helpers.Vector3", b =>
{
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot")
.WithMany("PredictedViewAngles")
.HasForeignKey("EFACSnapshotSnapshotId");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,24 @@
using Microsoft.EntityFrameworkCore.Migrations;
using System;
using System.Collections.Generic;
namespace SharedLibraryCore.Migrations
{
public partial class IndexForEFAlias : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateIndex(
name: "IX_EFAlias_IPAddress",
table: "EFAlias",
column: "IPAddress");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropIndex(
name: "IX_EFAlias_IPAddress",
table: "EFAlias");
}
}
}

View File

@ -312,6 +312,8 @@ namespace SharedLibraryCore.Migrations
b.HasKey("AliasId");
b.HasIndex("IPAddress");
b.HasIndex("LinkId");
b.ToTable("EFAlias");
@ -448,8 +450,6 @@ namespace SharedLibraryCore.Migrations
b.HasKey("Vector3Id");
//b.HasIndex("EFACSnapshotSnapshotId");
b.ToTable("Vector3");
});

View File

@ -139,6 +139,13 @@ namespace SharedLibraryCore
#else
Logger.WriteVerbose(Message.StripColors());
#endif
Manager.GetEventHandler().AddEvent(new GameEvent()
{
Type = GameEvent.EventType.Broadcast,
Data = Message,
Owner = this
});
await Task.CompletedTask;
}

View File

@ -59,7 +59,7 @@ namespace SharedLibraryCore.Services
Level = hasExistingAlias ?
(await context.Clients.Where(c => c.AliasLinkId == existingAlias.LinkId)
.OrderByDescending(c => c.Level)
.FirstAsync()).Level :
.FirstOrDefaultAsync())?.Level ?? Player.Permission.User :
Player.Permission.User,
FirstConnection = DateTime.UtcNow,
Connections = 1,
@ -170,11 +170,16 @@ namespace SharedLibraryCore.Services
{
// get all clients that use the same aliasId
var matchingClients = context.Clients
.Where(c => c.CurrentAliasId == client.CurrentAliasId);
.Where(c => c.CurrentAliasId == client.CurrentAliasId)
// make sure we don't select ourselves twice
.Where(c => c.ClientId != entity.ClientId);
// update all related clients level
await matchingClients.ForEachAsync(c => c.Level = (client.Level == Player.Permission.Banned) ?
client.Level : entity.Level);
await matchingClients.ForEachAsync(c =>
{
c.Level = (client.Level == Player.Permission.Banned) ? client.Level : entity.Level;
});
}
// their alias has been updated and not yet saved

View File

@ -9,13 +9,10 @@ namespace WebfrontCore.Controllers.API
{
[HttpGet]
[Route("event")]
public ActionResult Index()
public ActionResult Index(bool shouldConsume = true)
{
var events = Manager.GetEventApi().GetEvents();
var eventsDto = new List<EventInfo>();
while (events.Count > 0)
eventsDto.Add(events.Dequeue());
return Json(eventsDto);
var events = Manager.GetEventApi().GetEvents(shouldConsume);
return Json(events);
}
}
}

View File

@ -24,7 +24,8 @@ namespace WebfrontCore.ViewComponents
Offense = User.Identity.IsAuthenticated && !string.IsNullOrEmpty(p.AutomatedOffense) ? p.AutomatedOffense : p.Offense,
Type = p.Type.ToString(),
TimePunished = Utilities.GetTimePassed(p.When, false),
TimeRemaining = DateTime.UtcNow > p.Expires ? "" : Utilities.TimeSpanText(p.Expires - DateTime.UtcNow),
// show time passed if ban
TimeRemaining = DateTime.UtcNow > p.Expires ? "" : $"{(p.Expires.Year == DateTime.MaxValue.Year ? Utilities.GetTimePassed(p.When, true) : Utilities.TimeSpanText(p.Expires - DateTime.UtcNow))}",
Sensitive = p.Type == Penalty.PenaltyType.Flag,
AutomatedOffense = p.AutomatedOffense
});

View File

@ -70,7 +70,7 @@
}
else
{
<span> @Model.TimeRemaining @loc["WEBFRONT_PENALTY_TEMPLATE_REMAINING"]</span>
<span> @Model.TimeRemaining <!-- @loc["WEBFRONT_PENALTY_TEMPLATE_REMAINING"] --></span>
}
}
</td>